[WinCairo][Clang] DLLLauncherMain.cpp: warning: unused function 'prependPath' and...
[WebKit-https.git] / Tools / win / DLLLauncher / DLLLauncherMain.cpp
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
52 static void enableTerminationOnHeapCorruption()
53 {
54     HEAP_INFORMATION_CLASS heapEnableTerminationOnCorruption = static_cast<HEAP_INFORMATION_CLASS>(1);
55     HeapSetInformation(0, heapEnableTerminationOnCorruption, 0, 0);
56 }
57
58 static wstring copyEnvironmentVariable(const wstring& variable)
59 {
60     DWORD length = ::GetEnvironmentVariableW(variable.c_str(), 0, 0);
61     if (!length)
62         return wstring();
63     vector<wchar_t> buffer(length);
64     if (!GetEnvironmentVariable(variable.c_str(), &buffer[0], buffer.size()) || !buffer[0])
65         return wstring();
66     return &buffer[0];
67 }
68
69 #if !defined(WIN_CAIRO)
70 static wstring getStringValue(HKEY key, const wstring& valueName)
71 {
72     DWORD type = 0;
73     DWORD bufferSize = 0;
74     if (::RegQueryValueExW(key, valueName.c_str(), 0, &type, 0, &bufferSize) != ERROR_SUCCESS || type != REG_SZ)
75         return wstring();
76
77     vector<wchar_t> buffer(bufferSize / sizeof(wchar_t));
78     if (::RegQueryValueExW(key, valueName.c_str(), 0, &type, reinterpret_cast<LPBYTE>(&buffer[0]), &bufferSize) != ERROR_SUCCESS)
79         return wstring();
80
81     return &buffer[0];
82 }
83
84 static wstring applePathFromRegistry(const wstring& key, const wstring& value)
85 {
86     HKEY applePathKey = 0;
87     if (::RegOpenKeyExW(HKEY_LOCAL_MACHINE, key.c_str(), 0, KEY_READ, &applePathKey) != ERROR_SUCCESS)
88         return wstring();
89     wstring path = getStringValue(applePathKey, value);
90     ::RegCloseKey(applePathKey);
91     return path;
92 }
93
94 static wstring appleApplicationSupportDirectory()
95 {
96     return applePathFromRegistry(L"SOFTWARE\\Apple Inc.\\Apple Application Support", L"InstallDir");
97 }
98
99 static bool prependPath(const wstring& directoryToPrepend)
100 {
101     wstring pathVariable = L"PATH";
102     wstring oldPath = copyEnvironmentVariable(pathVariable);
103     wstring newPath = directoryToPrepend + L';' + oldPath;
104     return ::SetEnvironmentVariableW(pathVariable.c_str(), newPath.c_str());
105 }
106 #endif
107
108 static int fatalError(const wstring& programName, const wstring& message)
109 {
110     wstring caption = programName + L" can't open.";
111     ::MessageBoxW(0, message.c_str(), caption.c_str(), MB_ICONERROR);
112     return 1;
113 }
114
115 static bool directoryExists(const wstring& path)
116 {
117     DWORD attrib = ::GetFileAttributes(path.c_str());
118
119     return ((attrib != INVALID_FILE_ATTRIBUTES) && (attrib & FILE_ATTRIBUTE_DIRECTORY));
120 }
121
122 static bool modifyPath(const wstring& programName)
123 {
124 #ifdef WIN_CAIRO
125
126     wstring pathWinCairo = copyEnvironmentVariable(L"WEBKIT_LIBRARIES");
127     if (!directoryExists(pathWinCairo))
128         return true;
129 #if defined(_M_X64)
130     pathWinCairo += L"\\bin64";
131 #else
132     pathWinCairo += L"\\bin32";
133 #endif
134     if (!SetDllDirectory(pathWinCairo.c_str())) {
135         fatalError(programName, L"Failed to SetDllDirectory");
136         return false;
137     }
138     return true;
139
140 #else
141
142     const wstring& pathPrefix = appleApplicationSupportDirectory();
143
144     if (!directoryExists(pathPrefix)) {
145         fatalError(programName, L"Failed to determine path to AAS directory.");
146         return false;
147     }
148
149     if (prependPath(pathPrefix))
150         return true;
151
152     fatalError(programName, L"Failed to modify PATH environment variable.");
153     return false;
154 #endif
155 }
156
157 static wstring getLastErrorString(HRESULT hr)
158 {
159     static const DWORD kFlags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
160     static const size_t bufSize = 4096;
161
162     wchar_t errorMessage[bufSize];
163     DWORD len = ::FormatMessageW(kFlags, 0, hr, 0, errorMessage, bufSize, 0);
164     if (len >= bufSize)
165         len = bufSize - 1;
166
167     errorMessage[len] = 0;
168
169     return errorMessage;
170 }
171
172 #if USE_CONSOLE_ENTRY_POINT
173 int main(int argc, const char* argv[])
174 #else
175 int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpstrCmdLine, _In_ int nCmdShow)
176 #endif
177 {
178 #ifdef _CRTDBG_MAP_ALLOC
179     _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
180     _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
181 #endif
182
183     _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_DELAY_FREE_MEM_DF | _CRTDBG_CHECK_ALWAYS_DF);
184
185     enableTerminationOnHeapCorruption();
186
187     // Get the path of our executable.
188     wchar_t exePath[MAX_PATH];
189     if (!::GetModuleFileNameW(0, exePath, _countof(exePath)))
190         return fatalError(L"Unknown Program", L"Failed to determine name of executable: " + getLastErrorString(::GetLastError()));
191
192     ::PathRemoveExtensionW(exePath);
193
194     wstring programName = ::PathFindFileNameW(exePath);
195
196     if (!modifyPath(programName))
197         return 1;
198
199     // Load our corresponding DLL.
200     wstring dllName = programName + L"Lib.dll";
201     if (!::PathRemoveFileSpecW(exePath))
202         return fatalError(programName, L"::PathRemoveFileSpecW failed: " + getLastErrorString(::GetLastError()));
203     if (!::PathAppendW(exePath, dllName.c_str()))
204         return fatalError(programName, L"::PathAppendW failed: " + getLastErrorString(::GetLastError()));
205     HMODULE module = ::LoadLibraryW(exePath);
206     if (!module)
207         return fatalError(programName, L"::LoadLibraryW failed: \npath=" + wstring(exePath) + L"\n" + getLastErrorString(::GetLastError()));
208
209 #if USE_CONSOLE_ENTRY_POINT
210     typedef int (WINAPI*EntryPoint)(int, const char*[]);
211 #if defined _M_AMD64 || defined _WIN64
212     const char* entryPointName = "dllLauncherEntryPoint";
213 #else
214     const char* entryPointName = "_dllLauncherEntryPoint@8";
215 #endif
216 #else
217     typedef int (WINAPI*EntryPoint)(HINSTANCE, HINSTANCE, LPWSTR, int);
218 #if defined _M_AMD64 || defined _WIN64
219     const char* entryPointName = "dllLauncherEntryPoint";
220 #else
221     const char* entryPointName = "_dllLauncherEntryPoint@16";
222 #endif
223 #endif
224
225     EntryPoint entryPoint = reinterpret_cast<EntryPoint>(::GetProcAddress(module, entryPointName));
226     if (!entryPoint)
227         return fatalError(programName, L"Failed to find dllLauncherEntryPoint function: " + getLastErrorString(::GetLastError()));
228
229 #if USE_CONSOLE_ENTRY_POINT
230     return entryPoint(argc, argv);
231 #else
232     return entryPoint(hInstance, hPrevInstance, lpstrCmdLine, nCmdShow);
233 #endif
234 }