2 * Copyright (C) 2012-2015 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
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[]);
41 #define PROCESSORARCHITECTURE "x86"
43 #define PROCESSORARCHITECTURE "ia64"
45 #define PROCESSORARCHITECTURE "amd64"
47 #define PROCESSORARCHITECTURE "*"
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='*'\"")
55 static void enableTerminationOnHeapCorruption()
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
60 HEAP_INFORMATION_CLASS heapEnableTerminationOnCorruption
= static_cast<HEAP_INFORMATION_CLASS
>(1);
62 HMODULE
module = ::GetModuleHandleW(L
"kernel32.dll");
66 typedef BOOL (WINAPI
*HSI
)(HANDLE
, HEAP_INFORMATION_CLASS
, PVOID
, SIZE_T
);
67 HSI heapSetInformation
= reinterpret_cast<HSI
>(::GetProcAddress(module, "HeapSetInformation"));
68 if (!heapSetInformation
)
71 heapSetInformation(0, heapEnableTerminationOnCorruption
, 0, 0);
74 static wstring
getStringValue(HKEY key
, const wstring
& valueName
)
78 if (::RegQueryValueExW(key
, valueName
.c_str(), 0, &type
, 0, &bufferSize
) != ERROR_SUCCESS
|| type
!= REG_SZ
)
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
)
88 static wstring
applePathFromRegistry(const wstring
& key
, const wstring
& value
)
90 HKEY applePathKey
= 0;
91 if (::RegOpenKeyExW(HKEY_LOCAL_MACHINE
, key
.c_str(), 0, KEY_READ
, &applePathKey
) != ERROR_SUCCESS
)
93 wstring path
= getStringValue(applePathKey
, value
);
94 ::RegCloseKey(applePathKey
);
98 static wstring
appleApplicationSupportDirectory()
100 return applePathFromRegistry(L
"SOFTWARE\\Apple Inc.\\Apple Application Support", L
"InstallDir");
103 static wstring
copyEnvironmentVariable(const wstring
& variable
)
105 DWORD length
= ::GetEnvironmentVariableW(variable
.c_str(), 0, 0);
108 vector
<wchar_t> buffer(length
);
109 if (!GetEnvironmentVariable(variable
.c_str(), &buffer
[0], buffer
.size()) || !buffer
[0])
114 static bool prependPath(const wstring
& directoryToPrepend
)
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());
122 static int fatalError(const wstring
& programName
, const wstring
& message
)
124 wstring caption
= programName
+ L
" can't open.";
125 ::MessageBoxW(0, message
.c_str(), caption
.c_str(), MB_ICONERROR
);
129 static bool directoryExists(const wstring
& path
)
131 DWORD attrib
= ::GetFileAttributes(path
.c_str());
133 return ((attrib
!= INVALID_FILE_ATTRIBUTES
) && (attrib
& FILE_ATTRIBUTE_DIRECTORY
));
136 static bool modifyPath(const wstring
& programName
)
141 wstring pathWinCairo
= copyEnvironmentVariable(L
"WEBKIT_LIBRARIES") + L
"\\bin64";
143 wstring pathWinCairo
= copyEnvironmentVariable(L
"WEBKIT_LIBRARIES") + L
"\\bin32";
145 prependPath(pathWinCairo
);
150 const wstring
& pathPrefix
= appleApplicationSupportDirectory();
152 if (!directoryExists(pathPrefix
)) {
153 fatalError(programName
, L
"Failed to determine path to AAS directory.");
157 if (prependPath(pathPrefix
))
160 fatalError(programName
, L
"Failed to modify PATH environment variable.");
165 static wstring
getLastErrorString(HRESULT hr
)
167 static const DWORD kFlags
= FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_IGNORE_INSERTS
;
168 static const size_t bufSize
= 4096;
170 wchar_t errorMessage
[bufSize
];
171 DWORD len
= ::FormatMessageW(kFlags
, 0, hr
, 0, errorMessage
, bufSize
, 0);
175 errorMessage
[len
] = 0;
180 #if USE_CONSOLE_ENTRY_POINT
181 int main(int argc
, const char* argv
[])
183 int WINAPI
wWinMain(HINSTANCE hInstance
, HINSTANCE hPrevInstance
, LPWSTR lpstrCmdLine
, int nCmdShow
)
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+.
195 enableTerminationOnHeapCorruption();
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()));
202 ::PathRemoveExtensionW(exePath
);
204 wstring programName
= ::PathFindFileNameW(exePath
);
206 if (!modifyPath(programName
))
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
);
217 return fatalError(programName
, L
"::LoadLibraryW failed: \npath=" + wstring(exePath
) + L
"\n" + getLastErrorString(::GetLastError()));
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";
224 const char* entryPointName
= "_dllLauncherEntryPoint@8";
227 typedef int (WINAPI
*EntryPoint
)(HINSTANCE
, HINSTANCE
, LPWSTR
, int);
228 #if defined _M_AMD64 || defined _WIN64
229 const char* entryPointName
= "dllLauncherEntryPoint";
231 const char* entryPointName
= "_dllLauncherEntryPoint@16";
235 EntryPoint entryPoint
= reinterpret_cast<EntryPoint
>(::GetProcAddress(module, entryPointName
));
237 return fatalError(programName
, L
"Failed to find dllLauncherEntryPoint function: " + getLastErrorString(::GetLastError()));
239 #if USE_CONSOLE_ENTRY_POINT
240 return entryPoint(argc
, argv
);
242 return entryPoint(hInstance
, hPrevInstance
, lpstrCmdLine
, nCmdShow
);