]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright (C) 2012-2015 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 appleApplicationSupportDirectory() | |
99 | { | |
100 | return applePathFromRegistry(L"SOFTWARE\\Apple Inc.\\Apple Application Support", L"InstallDir"); | |
101 | } | |
102 | ||
103 | static wstring copyEnvironmentVariable(const wstring& variable) | |
104 | { | |
105 | DWORD length = ::GetEnvironmentVariableW(variable.c_str(), 0, 0); | |
106 | if (!length) | |
107 | return wstring(); | |
108 | vector<wchar_t> buffer(length); | |
109 | if (!GetEnvironmentVariable(variable.c_str(), &buffer[0], buffer.size()) || !buffer[0]) | |
110 | return wstring(); | |
111 | return &buffer[0]; | |
112 | } | |
113 | ||
114 | static bool prependPath(const wstring& directoryToPrepend) | |
115 | { | |
116 | wstring pathVariable = L"PATH"; | |
117 | wstring oldPath = copyEnvironmentVariable(pathVariable); | |
118 | wstring newPath = directoryToPrepend + L';' + oldPath; | |
119 | return ::SetEnvironmentVariableW(pathVariable.c_str(), newPath.c_str()); | |
120 | } | |
121 | ||
122 | static int fatalError(const wstring& programName, const wstring& message) | |
123 | { | |
124 | wstring caption = programName + L" can't open."; | |
125 | ::MessageBoxW(0, message.c_str(), caption.c_str(), MB_ICONERROR); | |
126 | return 1; | |
127 | } | |
128 | ||
129 | static bool directoryExists(const wstring& path) | |
130 | { | |
131 | DWORD attrib = ::GetFileAttributes(path.c_str()); | |
132 | ||
133 | return ((attrib != INVALID_FILE_ATTRIBUTES) && (attrib & FILE_ATTRIBUTE_DIRECTORY)); | |
134 | } | |
135 | ||
136 | static bool modifyPath(const wstring& programName) | |
137 | { | |
138 | #ifdef WIN_CAIRO | |
139 | ||
140 | #if defined(_M_X64) | |
141 | wstring pathWinCairo = copyEnvironmentVariable(L"WEBKIT_LIBRARIES") + L"\\bin64"; | |
142 | #else | |
143 | wstring pathWinCairo = copyEnvironmentVariable(L"WEBKIT_LIBRARIES") + L"\\bin32"; | |
144 | #endif | |
145 | prependPath(pathWinCairo); | |
146 | return true; | |
147 | ||
148 | #else | |
149 | ||
150 | const wstring& pathPrefix = appleApplicationSupportDirectory(); | |
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] = 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 | #if defined(_M_X64) || defined(__x86_64__) | |
187 | // The VS2013 runtime has a bug where it mis-detects AVX-capable processors | |
188 | // if the feature has been disabled in firmware. This causes us to crash | |
189 | // in some of the math functions. For now, we disable those optimizations | |
190 | // because Microsoft is not going to fix the problem in VS2013. | |
191 | // FIXME: http://webkit.org/b/141449: Remove this workaround when we switch to VS2015+. | |
192 | _set_FMA3_enable(0); | |
193 | #endif | |
194 | ||
195 | enableTerminationOnHeapCorruption(); | |
196 | ||
197 | // Get the path of our executable. | |
198 | wchar_t exePath[MAX_PATH]; | |
199 | if (!::GetModuleFileNameW(0, exePath, _countof(exePath))) | |
200 | return fatalError(L"Unknown Program", L"Failed to determine name of executable: " + getLastErrorString(::GetLastError())); | |
201 | ||
202 | ::PathRemoveExtensionW(exePath); | |
203 | ||
204 | wstring programName = ::PathFindFileNameW(exePath); | |
205 | ||
206 | if (!modifyPath(programName)) | |
207 | return 1; | |
208 | ||
209 | // Load our corresponding DLL. | |
210 | wstring dllName = programName + L".dll"; | |
211 | if (!::PathRemoveFileSpecW(exePath)) | |
212 | return fatalError(programName, L"::PathRemoveFileSpecW failed: " + getLastErrorString(::GetLastError())); | |
213 | if (!::PathAppendW(exePath, dllName.c_str())) | |
214 | return fatalError(programName, L"::PathAppendW failed: " + getLastErrorString(::GetLastError())); | |
215 | HMODULE module = ::LoadLibraryW(exePath); | |
216 | if (!module) | |
217 | return fatalError(programName, L"::LoadLibraryW failed: \npath=" + wstring(exePath) + L"\n" + getLastErrorString(::GetLastError())); | |
218 | ||
219 | #if USE_CONSOLE_ENTRY_POINT | |
220 | typedef int (WINAPI*EntryPoint)(int, const char*[]); | |
221 | #if defined _M_AMD64 || defined _WIN64 | |
222 | const char* entryPointName = "dllLauncherEntryPoint"; | |
223 | #else | |
224 | const char* entryPointName = "_dllLauncherEntryPoint@8"; | |
225 | #endif | |
226 | #else | |
227 | typedef int (WINAPI*EntryPoint)(HINSTANCE, HINSTANCE, LPWSTR, int); | |
228 | #if defined _M_AMD64 || defined _WIN64 | |
229 | const char* entryPointName = "dllLauncherEntryPoint"; | |
230 | #else | |
231 | const char* entryPointName = "_dllLauncherEntryPoint@16"; | |
232 | #endif | |
233 | #endif | |
234 | ||
235 | EntryPoint entryPoint = reinterpret_cast<EntryPoint>(::GetProcAddress(module, entryPointName)); | |
236 | if (!entryPoint) | |
237 | return fatalError(programName, L"Failed to find dllLauncherEntryPoint function: " + getLastErrorString(::GetLastError())); | |
238 | ||
239 | #if USE_CONSOLE_ENTRY_POINT | |
240 | return entryPoint(argc, argv); | |
241 | #else | |
242 | return entryPoint(hInstance, hPrevInstance, lpstrCmdLine, nCmdShow); | |
243 | #endif | |
244 | } |