#include #include #include #include #include #include #include using namespace std; // WinXP: launch_opera.exe (goes in same directory as opera.exe) // // Launches opera.exe with the JRE bin dir in the path so Java applets // can find msvcr71.dll when it's not in the system32 folder. wstring widenString(const string& s) { wstring ret; // Try with last arg as 0 and it gives you the required size int num = MultiByteToWideChar(CP_UTF8, NULL, s.c_str(), s.size(), &ret[0], 0); ret.resize(num); num = MultiByteToWideChar(CP_UTF8, NULL, s.c_str(), s.size(), &ret[0], ret.size()); if (num == 0) { throw runtime_error("MultiByteToWideChar failed"); } return ret; } // Wrapped RegKey reader so error handling and handle closing isn't so messy. // Don't really know how to do reg stuff, so pulled this out of my ass class RegKeyReader { public: RegKeyReader(HKEY root, const string& subkey) { if (RegOpenKeyEx(root, subkey.c_str(), 0, KEY_READ, &handle) != ERROR_SUCCESS) { throw runtime_error("RegOpenKeyEx failed to open key!"); } } ~RegKeyReader() { RegCloseKey(handle); } HKEY getHandle() const { return handle; } string getValue(const string& name) const { DWORD size = 1; // Try with 5th arg set to NULL and the size var will contain the required size DWORD result = RegQueryValueEx(handle, name.c_str(), NULL, NULL, NULL, &size); if (result != ERROR_SUCCESS) { throw runtime_error("RegQueryValueEx failed!"); } string ret; if (size > 0) { // - 1 because ReqQueryValueEx includes the terminating null byte // and we're writing directly to the underlying char*. ret.resize(size - 1); } result = RegQueryValueEx(handle, name.c_str(), NULL, NULL, reinterpret_cast(&ret[0]), &size); if (result != ERROR_SUCCESS) { throw runtime_error("RegQueryValueEx failed!"); } return ret; } private: HKEY handle; }; wstring getJREBinDirFromRegistry() { RegKeyReader jre_key(HKEY_LOCAL_MACHINE, "SOFTWARE\\JavaSoft\\Java Runtime Environment"); RegKeyReader versioned_sub_key(jre_key.getHandle(), jre_key.getValue("CurrentVersion")); return widenString(versioned_sub_key.getValue("JavaHome") + "\\bin"); } // Use this to create a path (absolute if necessary) to a file // in this exe's directory no matter from what working directory // this exe was called. wstring generatePath(const wstring& seed, const wstring& filename) { if (seed.find(L"/") != wstring::npos) { return seed.substr(0, seed.rfind( L"/") + 1) + filename; } else if (seed.find(L"\\") != wstring::npos) { return seed.substr(0, seed.rfind( L"\\" ) + 1) + filename; } else { return filename; } } // Get wide command line args (mingw doesn't have a wmain, so using // windows api) vector getArgs() { int argc; wchar_t** argv = CommandLineToArgvW(GetCommandLineW(), &argc); if (argv == NULL) { throw runtime_error("CommandLineToArgvW failed to get command line arguments"); } const vector args(argv, argv + argc); LocalFree(argv); return args; } // Need to be safe and pass command line args // properly quoted with quotes and backslashes // inside the quotes properly escaped (when necessary) wstring escapeAndQuote(const wstring& s) { wstring ret(L"\""); for (wstring::const_iterator i = s.begin(); i != s.end(); ++i) { const wchar_t c = *i; const wstring::const_iterator next = i + 1; if (c == L'"' || (c == L'\\' && (next == s.end() || *next == L'"'))) { ret += L'\\'; } ret += c; } ret += L"\""; return ret; } // Build a wide string consisting of a space-separated list // of quoted (and properly escaped) arguments for use with // ShellExuecuteW wstring createArgsString(const vector& argv) { wstring args; if (argv.size() > 1) { for (vector::const_iterator i = argv.begin() + 1; i != argv.end(); ++i) { if (i == argv.begin() + 1) { args += L" "; } args += escapeAndQuote(*i); } } return args; } // Get the PATH environment variable, prepend the JRE bin directory // (gotten from info in the registry) to it and reapply the new // PATH environment variable value void addJRE6BinDirToPathVar() { const wchar_t* const old_path = _wgetenv(L"Path"); if (old_path == NULL) { throw runtime_error("Path environment variable is not set!"); } const wstring java_path = getJREBinDirFromRegistry() + L";"; const wstring new_path = wstring(L"PATH=") + java_path + old_path; const int check = _wputenv(new_path.c_str()); if (check != 0) { throw runtime_error("Error setting Path environment variable"); } } int main() { try { // Set locale to the oem code page so any wchar_t convert functions // get utf-8 utf-16 right. setlocale(LC_CTYPE, ".OCP"); // Have to collect all the args so they can be passed // along to opera.exe const vector argv = getArgs(); const wstring args = createArgsString(argv); const wstring opera_path = escapeAndQuote(generatePath(argv[0], L"opera.exe")); addJRE6BinDirToPathVar(); const int result = reinterpret_cast( ShellExecuteW(NULL, L"open", opera_path.c_str() , args.c_str(), NULL, SW_SHOWNORMAL) ); if (result < 33) { throw runtime_error("ShellExecuteW failed"); } } catch (const exception& e) { MessageBox(NULL, e.what(), "Error launching Opera", MB_OK); return EXIT_FAILURE; } } // g++ -Wall -Wextra launch_opera.cc -o launch_opera -O3 -s -mwindows && upx --best launch_opera.exe