diff options
Diffstat (limited to 'src/api/burn/balutil/balutil.cpp')
-rw-r--r-- | src/api/burn/balutil/balutil.cpp | 300 |
1 files changed, 286 insertions, 14 deletions
diff --git a/src/api/burn/balutil/balutil.cpp b/src/api/burn/balutil/balutil.cpp index 2d80878c..a77ff7d0 100644 --- a/src/api/burn/balutil/balutil.cpp +++ b/src/api/burn/balutil/balutil.cpp | |||
@@ -3,8 +3,39 @@ | |||
3 | #include "precomp.h" | 3 | #include "precomp.h" |
4 | 4 | ||
5 | const DWORD VARIABLE_GROW_FACTOR = 80; | 5 | const DWORD VARIABLE_GROW_FACTOR = 80; |
6 | static DWORD vdwDebuggerCheck = 0; | ||
6 | static IBootstrapperEngine* vpEngine = NULL; | 7 | static IBootstrapperEngine* vpEngine = NULL; |
7 | 8 | ||
9 | static HRESULT ParseCommandLine( | ||
10 | __inout_z LPWSTR *psczPipeBaseName, | ||
11 | __inout_z LPWSTR *psczPipeSecret, | ||
12 | __out DWORD64 *pqwEngineAPIVersion | ||
13 | ); | ||
14 | static HRESULT ConnectToEngine( | ||
15 | __in_z LPCWSTR wzPipeBaseName, | ||
16 | __in_z LPCWSTR wzPipeSecret, | ||
17 | __out HANDLE *phBAPipe, | ||
18 | __out HANDLE *phEnginePipe | ||
19 | ); | ||
20 | static HRESULT ConnectAndVerify( | ||
21 | __in_z LPCWSTR wzPipeName, | ||
22 | __in_z LPCWSTR wzPipeSecret, | ||
23 | __in DWORD cbPipeSecret, | ||
24 | __out HANDLE *phPipe | ||
25 | ); | ||
26 | static HRESULT PumpMessages( | ||
27 | __in HANDLE hPipe, | ||
28 | __in IBootstrapperApplication* pApplication, | ||
29 | __in IBootstrapperEngine* pEngine | ||
30 | ); | ||
31 | static void MsgProc( | ||
32 | __in BOOTSTRAPPER_APPLICATION_MESSAGE messageType, | ||
33 | __in_bcount(cbData) LPVOID pvData, | ||
34 | __in DWORD cbData, | ||
35 | __in IBootstrapperApplication* pApplication, | ||
36 | __in IBootstrapperEngine* pEngine | ||
37 | ); | ||
38 | |||
8 | // prototypes | 39 | // prototypes |
9 | 40 | ||
10 | DAPI_(void) BalInitialize( | 41 | DAPI_(void) BalInitialize( |
@@ -17,38 +48,136 @@ DAPI_(void) BalInitialize( | |||
17 | vpEngine = pEngine; | 48 | vpEngine = pEngine; |
18 | } | 49 | } |
19 | 50 | ||
20 | DAPI_(HRESULT) BalInitializeFromCreateArgs( | 51 | DAPI_(void) BalUninitialize() |
21 | __in const BOOTSTRAPPER_CREATE_ARGS* pArgs, | 52 | { |
22 | __out_opt IBootstrapperEngine** ppEngine | 53 | ReleaseNullObject(vpEngine); |
54 | } | ||
55 | |||
56 | DAPI_(HRESULT) BootstrapperApplicationRun( | ||
57 | __in IBootstrapperApplication* pApplication | ||
23 | ) | 58 | ) |
24 | { | 59 | { |
25 | HRESULT hr = S_OK; | 60 | HRESULT hr = S_OK; |
61 | BOOL fComInitialized = FALSE; | ||
62 | DWORD64 qwEngineAPIVersion = 0; | ||
63 | LPWSTR sczPipeBaseName = NULL; | ||
64 | LPWSTR sczPipeSecret = NULL; | ||
65 | HANDLE hBAPipe = INVALID_HANDLE_VALUE; | ||
66 | HANDLE hEnginePipe = INVALID_HANDLE_VALUE; | ||
26 | IBootstrapperEngine* pEngine = NULL; | 67 | IBootstrapperEngine* pEngine = NULL; |
68 | BOOL fInitializedBal = FALSE; | ||
69 | |||
70 | // initialize COM | ||
71 | hr = ::CoInitializeEx(NULL, COINIT_MULTITHREADED); | ||
72 | ExitOnFailure(hr, "Failed to initialize COM."); | ||
73 | fComInitialized = TRUE; | ||
74 | |||
75 | hr = ParseCommandLine(&sczPipeBaseName, &sczPipeSecret, &qwEngineAPIVersion); | ||
76 | BalExitOnFailure(hr, "Failed to parse command line."); | ||
27 | 77 | ||
28 | hr = BalBootstrapperEngineCreate(pArgs->pfnBootstrapperEngineProc, pArgs->pvBootstrapperEngineProcContext, &pEngine); | 78 | // TODO: Validate the engine API version. |
29 | ExitOnFailure(hr, "Failed to create BalBootstrapperEngine."); | 79 | |
80 | hr = ConnectToEngine(sczPipeBaseName, sczPipeSecret, &hBAPipe, &hEnginePipe); | ||
81 | BalExitOnFailure(hr, "Failed to connect to engine."); | ||
82 | |||
83 | hr = BalBootstrapperEngineCreate(hEnginePipe, &pEngine); | ||
84 | BalExitOnFailure(hr, "Failed to create bootstrapper engine."); | ||
30 | 85 | ||
31 | BalInitialize(pEngine); | 86 | BalInitialize(pEngine); |
87 | fInitializedBal = TRUE; | ||
88 | |||
89 | BootstrapperApplicationDebuggerCheck(); | ||
32 | 90 | ||
33 | if (ppEngine) | 91 | hr = MsgPump(hBAPipe, pApplication, pEngine); |
92 | BalExitOnFailure(hr, "Failed while pumping messages."); | ||
93 | |||
94 | LExit: | ||
95 | if (fInitializedBal) | ||
34 | { | 96 | { |
35 | *ppEngine = pEngine; | 97 | BalUninitialize(); |
36 | } | 98 | } |
37 | pEngine = NULL; | ||
38 | 99 | ||
39 | LExit: | 100 | ReleaseNullObject(pEngine); |
40 | ReleaseObject(pEngine); | 101 | ReleasePipeHandle(hEnginePipe); |
102 | ReleasePipeHandle(hBAPipe); | ||
103 | ReleaseStr(sczPipeSecret); | ||
104 | ReleaseStr(sczPipeBaseName); | ||
105 | |||
106 | if (fComInitialized) | ||
107 | { | ||
108 | ::CoUninitialize(); | ||
109 | } | ||
41 | 110 | ||
42 | return hr; | 111 | return hr; |
43 | } | 112 | } |
44 | 113 | ||
45 | 114 | DAPI_(VOID) BootstrapperApplicationDebuggerCheck() | |
46 | DAPI_(void) BalUninitialize() | ||
47 | { | 115 | { |
48 | ReleaseNullObject(vpEngine); | 116 | HRESULT hr = S_OK; |
117 | HKEY hk = NULL; | ||
118 | BOOL fDebug = FALSE; | ||
119 | LPWSTR sczDebugBootstrapperApplications = NULL; | ||
120 | LPWSTR sczDebugBootstrapperApplication = NULL; | ||
121 | LPWSTR sczModulePath = NULL; | ||
122 | LPCWSTR wzModuleFilename = NULL; | ||
123 | WCHAR wzMessage[1024] = { }; | ||
124 | |||
125 | if (0 == vdwDebuggerCheck) | ||
126 | { | ||
127 | ++vdwDebuggerCheck; | ||
128 | |||
129 | hr = RegOpen(HKEY_LOCAL_MACHINE, L"System\\CurrentControlSet\\Control\\Session Manager\\Environment", KEY_QUERY_VALUE, &hk); | ||
130 | if (SUCCEEDED(hr)) | ||
131 | { | ||
132 | hr = RegReadString(hk, L"WixDebugBootstrapperApplications", &sczDebugBootstrapperApplications); | ||
133 | if (SUCCEEDED(hr) && sczDebugBootstrapperApplications && *sczDebugBootstrapperApplications && | ||
134 | sczDebugBootstrapperApplications[0] != L'0' && !sczDebugBootstrapperApplications[1]) | ||
135 | { | ||
136 | hr = PathForCurrentProcess(&sczModulePath, NULL); | ||
137 | if (SUCCEEDED(hr) && sczModulePath && *sczModulePath) | ||
138 | { | ||
139 | wzModuleFilename = PathFile(sczModulePath); | ||
140 | if (wzModuleFilename) | ||
141 | { | ||
142 | fDebug = TRUE; | ||
143 | } | ||
144 | } | ||
145 | } | ||
146 | else | ||
147 | { | ||
148 | hr = RegReadString(hk, L"WixDebugBootstrapperApplication", &sczDebugBootstrapperApplication); | ||
149 | if (SUCCEEDED(hr) && sczDebugBootstrapperApplication && *sczDebugBootstrapperApplication) | ||
150 | { | ||
151 | hr = PathForCurrentProcess(&sczModulePath, NULL); | ||
152 | if (SUCCEEDED(hr) && sczModulePath && *sczModulePath) | ||
153 | { | ||
154 | wzModuleFilename = PathFile(sczModulePath); | ||
155 | if (wzModuleFilename && CSTR_EQUAL == ::CompareStringOrdinal(sczDebugBootstrapperApplication, -1, wzModuleFilename, -1, TRUE)) | ||
156 | { | ||
157 | fDebug = TRUE; | ||
158 | } | ||
159 | } | ||
160 | } | ||
161 | } | ||
162 | |||
163 | if (fDebug) | ||
164 | { | ||
165 | hr = ::StringCchPrintfW(wzMessage, countof(wzMessage), L"To debug the boostrapper application process %ls\n\nSet breakpoints and attach a debugger to process id: %d (0x%x)", wzModuleFilename, ::GetCurrentProcessId(), ::GetCurrentProcessId()); | ||
166 | |||
167 | if (SUCCEEDED(hr)) | ||
168 | { | ||
169 | ::MessageBoxW(NULL, wzMessage, L"WiX Bootstrapper Application", MB_SERVICE_NOTIFICATION | MB_TOPMOST | MB_ICONQUESTION | MB_OK | MB_SYSTEMMODAL); | ||
170 | } | ||
171 | } | ||
172 | } | ||
173 | } | ||
174 | |||
175 | ReleaseRegKey(hk); | ||
176 | ReleaseStr(sczModulePath); | ||
177 | ReleaseStr(sczDebugBootstrapperApplication); | ||
178 | ReleaseStr(sczDebugBootstrapperApplications); | ||
49 | } | 179 | } |
50 | 180 | ||
51 | |||
52 | DAPI_(HRESULT) BalManifestLoad( | 181 | DAPI_(HRESULT) BalManifestLoad( |
53 | __in HMODULE hBootstrapperApplicationModule, | 182 | __in HMODULE hBootstrapperApplicationModule, |
54 | __out IXMLDOMDocument** ppixdManifest | 183 | __out IXMLDOMDocument** ppixdManifest |
@@ -671,3 +800,146 @@ LExit: | |||
671 | 800 | ||
672 | return hr; | 801 | return hr; |
673 | } | 802 | } |
803 | |||
804 | |||
805 | static HRESULT ParseCommandLine( | ||
806 | __inout_z LPWSTR *psczPipeBaseName, | ||
807 | __inout_z LPWSTR *psczPipeSecret, | ||
808 | __out DWORD64 *pqwEngineAPIVersion | ||
809 | ) | ||
810 | { | ||
811 | HRESULT hr = S_OK; | ||
812 | LPWSTR wzCommandLine = ::GetCommandLineW(); | ||
813 | int argc = 0; | ||
814 | LPWSTR* argv = NULL; | ||
815 | |||
816 | *pqwEngineAPIVersion = 0; | ||
817 | |||
818 | hr = AppParseCommandLine(wzCommandLine, &argc, &argv); | ||
819 | ExitOnFailure(hr, "Failed to parse command line."); | ||
820 | |||
821 | // Skip the executable full path in argv[0]. | ||
822 | for (int i = 1; i < argc; ++i) | ||
823 | { | ||
824 | if (argv[i][0] == L'-') | ||
825 | { | ||
826 | if (CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], -1, BOOTSTRAPPER_APPLICATION_COMMANDLINE_SWITCH_API_VERSION, -1, TRUE)) | ||
827 | { | ||
828 | if (i + 1 >= argc) | ||
829 | { | ||
830 | BalExitOnRootFailure(hr = E_INVALIDARG, "Must specify an api version."); | ||
831 | } | ||
832 | |||
833 | ++i; | ||
834 | |||
835 | hr = StrStringToUInt64(argv[i], 0, pqwEngineAPIVersion); | ||
836 | BalExitOnFailure(hr, "Failed to parse api version: %ls", argv[i]); | ||
837 | } | ||
838 | else if (CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], -1, BOOTSTRAPPER_APPLICATION_COMMANDLINE_SWITCH_PIPE_NAME, -1, TRUE)) | ||
839 | { | ||
840 | if (i + 2 >= argc) | ||
841 | { | ||
842 | BalExitOnRootFailure(hr = E_INVALIDARG, "Must specify a pipe name and pipe secret."); | ||
843 | } | ||
844 | |||
845 | ++i; | ||
846 | |||
847 | hr = StrAllocString(psczPipeBaseName, argv[i], 0); | ||
848 | BalExitOnFailure(hr, "Failed to copy pipe name."); | ||
849 | |||
850 | ++i; | ||
851 | |||
852 | hr = StrAllocString(psczPipeSecret, argv[i], 0); | ||
853 | BalExitOnFailure(hr, "Failed to copy pipe secret."); | ||
854 | } | ||
855 | } | ||
856 | else | ||
857 | { | ||
858 | BalExitWithRootFailure(hr, E_INVALIDARG, "Invalid argument: %ls", argv[i]); | ||
859 | } | ||
860 | } | ||
861 | |||
862 | LExit: | ||
863 | if (argv) | ||
864 | { | ||
865 | AppFreeCommandLineArgs(argv); | ||
866 | } | ||
867 | |||
868 | return hr; | ||
869 | } | ||
870 | |||
871 | static HRESULT ConnectToEngine( | ||
872 | __in_z LPCWSTR wzPipeBaseName, | ||
873 | __in_z LPCWSTR wzPipeSecret, | ||
874 | __out HANDLE *phBAPipe, | ||
875 | __out HANDLE *phEnginePipe | ||
876 | ) | ||
877 | { | ||
878 | HRESULT hr = S_OK; | ||
879 | LPWSTR sczBAPipeName = NULL; | ||
880 | LPWSTR sczEnginePipeName = NULL; | ||
881 | HANDLE hBAPipe = INVALID_HANDLE_VALUE; | ||
882 | HANDLE hEnginePipe = INVALID_HANDLE_VALUE; | ||
883 | |||
884 | DWORD cbPipeSecret = lstrlenW(wzPipeSecret) * sizeof(WCHAR); | ||
885 | |||
886 | hr = StrAllocFormatted(&sczBAPipeName, L"%ls%ls", wzPipeBaseName, L".BA"); | ||
887 | ExitOnFailure(hr, "Failed to allocate BA pipe name."); | ||
888 | |||
889 | hr = StrAllocFormatted(&sczEnginePipeName, L"%ls%ls", wzPipeBaseName, L".BAEngine"); | ||
890 | ExitOnFailure(hr, "Failed to allocate BA engine pipe name."); | ||
891 | |||
892 | hr = ConnectAndVerify(sczBAPipeName, wzPipeSecret, cbPipeSecret, &hBAPipe); | ||
893 | BalExitOnFailure(hr, "Failed to connect to bootstrapper application pipe."); | ||
894 | |||
895 | hr = ConnectAndVerify(sczEnginePipeName, wzPipeSecret, cbPipeSecret, &hEnginePipe); | ||
896 | BalExitOnFailure(hr, "Failed to connect to engine pipe."); | ||
897 | |||
898 | *phBAPipe = hBAPipe; | ||
899 | hBAPipe = INVALID_HANDLE_VALUE; | ||
900 | |||
901 | *phEnginePipe = hEnginePipe; | ||
902 | hEnginePipe = INVALID_HANDLE_VALUE; | ||
903 | |||
904 | LExit: | ||
905 | ReleasePipeHandle(hEnginePipe); | ||
906 | ReleasePipeHandle(hBAPipe); | ||
907 | ReleaseStr(sczEnginePipeName); | ||
908 | ReleaseStr(sczBAPipeName); | ||
909 | |||
910 | return hr; | ||
911 | } | ||
912 | |||
913 | static HRESULT ConnectAndVerify( | ||
914 | __in_z LPCWSTR wzPipeName, | ||
915 | __in_z LPCWSTR wzPipeSecret, | ||
916 | __in DWORD cbPipeSecret, | ||
917 | __out HANDLE *phPipe | ||
918 | ) | ||
919 | { | ||
920 | HRESULT hr = S_OK; | ||
921 | HRESULT hrConnect = S_OK; | ||
922 | HANDLE hPipe = INVALID_HANDLE_VALUE; | ||
923 | |||
924 | hr = PipeClientConnect(wzPipeName, &hPipe); | ||
925 | BalExitOnFailure(hr, "Failed to connect to pipe."); | ||
926 | |||
927 | hr = FileWriteHandle(hPipe, reinterpret_cast<LPCBYTE>(&cbPipeSecret), sizeof(cbPipeSecret)); | ||
928 | BalExitOnFailure(hr, "Failed to write secret size to pipe."); | ||
929 | |||
930 | hr = FileWriteHandle(hPipe, reinterpret_cast<LPCBYTE>(wzPipeSecret), cbPipeSecret); | ||
931 | BalExitOnFailure(hr, "Failed to write secret size to pipe."); | ||
932 | |||
933 | FileReadHandle(hPipe, reinterpret_cast<LPBYTE>(&hrConnect), sizeof(hrConnect)); | ||
934 | BalExitOnFailure(hr, "Failed to read connect result from pipe."); | ||
935 | |||
936 | BalExitOnFailure(hrConnect, "Failed connect result from pipe."); | ||
937 | |||
938 | *phPipe = hPipe; | ||
939 | hPipe = INVALID_HANDLE_VALUE; | ||
940 | |||
941 | LExit: | ||
942 | ReleasePipeHandle(hPipe); | ||
943 | |||
944 | return hr; | ||
945 | } | ||