[WinCairo] Preparation for GStreamer on Windows.
[WebKit-https.git] / Tools / win / DLLLauncher / DLLLauncherMain.cpp
1 /*
2  * Copyright (C) 2012-2013 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 // This file contains code for a launcher executable for WebKit apps. When compiled into foo.exe, it
27 // will set PATH so that Apple Application Support DLLs can be found, then will load foo.dll and
28 // call its dllLauncherEntryPoint function, which should be declared like so:
29 //     extern "C" __declspec(dllexport) int WINAPI dllLauncherEntryPoint(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpstCmdLine, int nCmdShow);
30 // If USE_CONSOLE_ENTRY_POINT is defined, this function will be called instead:
31 //     extern "C" __declspec(dllexport) int WINAPI dllLauncherEntryPoint(int argc, const char* argv[]);
32
33 #include <shlwapi.h>
34 #include <string>
35 #include <vector>
36 #include <windows.h>
37
38 using namespace std;
39
40 #if defined _M_IX86
41 #define PROCESSORARCHITECTURE "x86"
42 #elif defined _M_IA64
43 #define PROCESSORARCHITECTURE "ia64"
44 #elif defined _M_X64
45 #define PROCESSORARCHITECTURE "amd64"
46 #else
47 #define PROCESSORARCHITECTURE "*"
48 #endif
49
50 #pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='" PROCESSORARCHITECTURE "' publicKeyToken='6595b64144ccf1df' language='*'\"")
51 #if defined(_MSC_VER) && (_MSC_VER >= 1600) && !defined(WIN_CAIRO)
52 #pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.VC80.CRT' version='8.0.50727.6195' processorArchitecture='" PROCESSORARCHITECTURE "' publicKeyToken='1fc8b3b9a1e18e3b' language='*'\"")
53 #endif
54
55 static void enableTerminationOnHeapCorruption()
56 {
57     // Enable termination on heap corruption on OSes that support it (Vista and XPSP3).
58     // http://msdn.microsoft.com/en-us/library/aa366705(VS.85).aspx
59
60     HEAP_INFORMATION_CLASS heapEnableTerminationOnCorruption = static_cast<HEAP_INFORMATION_CLASS>(1);
61
62     HMODULE module = ::GetModuleHandleW(L"kernel32.dll");
63     if (!module)
64         return;
65
66     typedef BOOL (WINAPI*HSI)(HANDLE, HEAP_INFORMATION_CLASS, PVOID, SIZE_T);
67     HSI heapSetInformation = reinterpret_cast<HSI>(::GetProcAddress(module, "HeapSetInformation"));
68     if (!heapSetInformation)
69         return;
70
71     heapSetInformation(0, heapEnableTerminationOnCorruption, 0, 0);
72 }
73
74 static wstring getStringValue(HKEY key, const wstring& valueName)
75 {
76     DWORD type = 0;
77     DWORD bufferSize = 0;
78     if (::RegQueryValueExW(key, valueName.c_str(), 0, &type, 0, &bufferSize) != ERROR_SUCCESS || type != REG_SZ)
79         return wstring();
80
81     vector<wchar_t> buffer(bufferSize / sizeof(wchar_t));
82     if (::RegQueryValueExW(key, valueName.c_str(), 0, &type, reinterpret_cast<LPBYTE>(&buffer[0]), &bufferSize) != ERROR_SUCCESS)
83         return wstring();
84
85     return &buffer[0];
86 }
87
88 static wstring applePathFromRegistry(const wstring& key, const wstring& value)
89 {
90     HKEY applePathKey = 0;
91     if (::RegOpenKeyExW(HKEY_LOCAL_MACHINE, key.c_str(), 0, KEY_READ, &applePathKey) != ERROR_SUCCESS)
92         return wstring();
93     wstring path = getStringValue(applePathKey, value);
94     ::RegCloseKey(applePathKey);
95     return path;
96 }
97
98 static wstring copyEnvironmentVariable(const wstring& variable)
99 {
100     DWORD length = ::GetEnvironmentVariableW(variable.c_str(), 0, 0);
101     if (!length)
102         return wstring();
103     vector<wchar_t> buffer(length);
104     if (!GetEnvironmentVariable(variable.c_str(), &buffer[0], buffer.size()) || !buffer[0])
105         return wstring();
106     return &buffer[0];
107 }
108
109 static bool prependPath(const wstring& directoryToPrepend)
110 {
111     wstring pathVariable = L"PATH";
112     wstring oldPath = copyEnvironmentVariable(pathVariable);
113     wstring newPath = directoryToPrepend + L';' + oldPath;
114     return ::SetEnvironmentVariableW(pathVariable.c_str(), newPath.c_str());
115 }
116
117 static int fatalError(const wstring& programName, const wstring& message)
118 {
119     wstring caption = programName + L" can't open.";
120     ::MessageBoxW(0, message.c_str(), caption.c_str(), MB_ICONERROR);
121     return 1;
122 }
123
124 static bool directoryExists(const wstring& path)
125 {
126     DWORD attrib = ::GetFileAttributes(path.c_str());
127
128     return ((attrib != INVALID_FILE_ATTRIBUTES) && (attrib & FILE_ATTRIBUTE_DIRECTORY));
129 }
130
131 static bool modifyPath(const wstring& programName)
132 {
133 #ifdef WIN_CAIRO
134
135 #if defined(_M_X64)
136     wstring path = copyEnvironmentVariable(L"GSTREAMER_1_0_ROOT_X86_64") + L"bin";
137 #else
138     wstring path = copyEnvironmentVariable(L"GSTREAMER_1_0_ROOT_X86") + L"bin";
139 #endif
140     if (directoryExists(path))
141         prependPath(path);
142     return true;
143
144 #else
145
146 #if defined(_M_X64)
147     static const wstring pathPrefix = L"C:\\Program Files\\Common Files\\Apple\\Apple Application Support";
148 #else
149     static const wstring pathPrefix = L"C:\\Program Files (x86)\\Common Files\\Apple\\Apple Application Support";
150 #endif
151
152     if (!directoryExists(pathPrefix)) {
153         fatalError(programName, L"Failed to determine path to AAS directory.");
154         return false;
155     }
156
157     if (prependPath(pathPrefix))
158         return true;
159
160     fatalError(programName, L"Failed to modify PATH environment variable.");
161     return false;
162 #endif
163 }
164
165 static wstring getLastErrorString(HRESULT hr)
166 {
167     static const DWORD kFlags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
168     static const size_t bufSize = 4096;
169
170     wchar_t errorMessage[bufSize];
171     DWORD len = ::FormatMessageW(kFlags, 0, hr, 0, errorMessage, bufSize, 0);
172     if (len >= bufSize)
173         len = bufSize - 1;
174
175     errorMessage[len + 1] = 0;
176
177     return errorMessage;
178 }
179
180 #if USE_CONSOLE_ENTRY_POINT
181 int main(int argc, const char* argv[])
182 #else
183 int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpstrCmdLine, int nCmdShow)
184 #endif
185 {
186     enableTerminationOnHeapCorruption();
187
188     // Get the path of our executable.
189     wchar_t exePath[MAX_PATH];
190     if (!::GetModuleFileNameW(0, exePath, _countof(exePath)))
191         return fatalError(L"Unknown Program", L"Failed to determine name of executable: " + getLastErrorString(::GetLastError()));
192
193     ::PathRemoveExtensionW(exePath);
194
195     wstring programName = ::PathFindFileNameW(exePath);
196
197     if (!modifyPath(programName))
198         return 1;
199
200     // Load our corresponding DLL.
201     wstring dllName = programName + L".dll";
202     if (!::PathRemoveFileSpecW(exePath))
203         return fatalError(programName, L"::PathRemoveFileSpecW failed: " + getLastErrorString(::GetLastError()));
204     if (!::PathAppendW(exePath, dllName.c_str()))
205         return fatalError(programName, L"::PathAppendW failed: " + getLastErrorString(::GetLastError()));
206     HMODULE module = ::LoadLibraryW(exePath);
207     if (!module)
208         return fatalError(programName, L"::LoadLibraryW failed: \npath=" + wstring(exePath) + L"\n" + getLastErrorString(::GetLastError()));
209
210 #if USE_CONSOLE_ENTRY_POINT
211     typedef int (WINAPI*EntryPoint)(int, const char*[]);
212 #if defined _M_AMD64 || defined _WIN64
213     const char* entryPointName = "dllLauncherEntryPoint";
214 #else
215     const char* entryPointName = "_dllLauncherEntryPoint@8";
216 #endif
217 #else
218     typedef int (WINAPI*EntryPoint)(HINSTANCE, HINSTANCE, LPWSTR, int);
219 #if defined _M_AMD64 || defined _WIN64
220     const char* entryPointName = "dllLauncherEntryPoint";
221 #else
222     const char* entryPointName = "_dllLauncherEntryPoint@16";
223 #endif
224 #endif
225
226     EntryPoint entryPoint = reinterpret_cast<EntryPoint>(::GetProcAddress(module, entryPointName));
227     if (!entryPoint)
228         return fatalError(programName, L"Failed to find dllLauncherEntryPoint function: " + getLastErrorString(::GetLastError()));
229
230 #if USE_CONSOLE_ENTRY_POINT
231     return entryPoint(argc, argv);
232 #else
233     return entryPoint(hInstance, hPrevInstance, lpstrCmdLine, nCmdShow);
234 #endif
235 }