Thanks for reminding me about .desktop files! Indeed relative paths seem to be not working at all, but there's a workaround (thanks to this SO answer), use %k in Exec line of .desktop file to get path to .desktop file itself, and than extract directory name:
Exec=bash -c "$(dirname %k)/launch"
.desktop file is also better than bare bash script because it may be displayed with custom icon, and even localized name.
UPDATE about icon: looks like relative-path icon is not possible. This time really :(