aboutsummaryrefslogtreecommitdiff
path: root/src/api/burn/balutil/balutil.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/api/burn/balutil/balutil.cpp')
-rw-r--r--src/api/burn/balutil/balutil.cpp300
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
5const DWORD VARIABLE_GROW_FACTOR = 80; 5const DWORD VARIABLE_GROW_FACTOR = 80;
6static DWORD vdwDebuggerCheck = 0;
6static IBootstrapperEngine* vpEngine = NULL; 7static IBootstrapperEngine* vpEngine = NULL;
7 8
9static HRESULT ParseCommandLine(
10 __inout_z LPWSTR *psczPipeBaseName,
11 __inout_z LPWSTR *psczPipeSecret,
12 __out DWORD64 *pqwEngineAPIVersion
13 );
14static HRESULT ConnectToEngine(
15 __in_z LPCWSTR wzPipeBaseName,
16 __in_z LPCWSTR wzPipeSecret,
17 __out HANDLE *phBAPipe,
18 __out HANDLE *phEnginePipe
19 );
20static HRESULT ConnectAndVerify(
21 __in_z LPCWSTR wzPipeName,
22 __in_z LPCWSTR wzPipeSecret,
23 __in DWORD cbPipeSecret,
24 __out HANDLE *phPipe
25 );
26static HRESULT PumpMessages(
27 __in HANDLE hPipe,
28 __in IBootstrapperApplication* pApplication,
29 __in IBootstrapperEngine* pEngine
30 );
31static 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
10DAPI_(void) BalInitialize( 41DAPI_(void) BalInitialize(
@@ -17,38 +48,136 @@ DAPI_(void) BalInitialize(
17 vpEngine = pEngine; 48 vpEngine = pEngine;
18} 49}
19 50
20DAPI_(HRESULT) BalInitializeFromCreateArgs( 51DAPI_(void) BalUninitialize()
21 __in const BOOTSTRAPPER_CREATE_ARGS* pArgs, 52{
22 __out_opt IBootstrapperEngine** ppEngine 53 ReleaseNullObject(vpEngine);
54}
55
56DAPI_(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
94LExit:
95 if (fInitializedBal)
34 { 96 {
35 *ppEngine = pEngine; 97 BalUninitialize();
36 } 98 }
37 pEngine = NULL;
38 99
39LExit: 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 114DAPI_(VOID) BootstrapperApplicationDebuggerCheck()
46DAPI_(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
52DAPI_(HRESULT) BalManifestLoad( 181DAPI_(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
805static 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
862LExit:
863 if (argv)
864 {
865 AppFreeCommandLineArgs(argv);
866 }
867
868 return hr;
869}
870
871static 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
904LExit:
905 ReleasePipeHandle(hEnginePipe);
906 ReleasePipeHandle(hBAPipe);
907 ReleaseStr(sczEnginePipeName);
908 ReleaseStr(sczBAPipeName);
909
910 return hr;
911}
912
913static 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
941LExit:
942 ReleasePipeHandle(hPipe);
943
944 return hr;
945}