diff options
| author | Rob Mensching <rob@firegiant.com> | 2024-01-11 18:26:20 -0800 |
|---|---|---|
| committer | Rob Mensching <rob@firegiant.com> | 2024-03-06 18:03:38 -0800 |
| commit | 0d3d54992104288e9ee0c834d0b96e8502fd2d42 (patch) | |
| tree | 9efa49c4983cd2ba1becab64bd1f2faccac88acf /src/api/burn/balutil/balutil.cpp | |
| parent | 2824298d9dd817a47527c920363556b54ead5d5d (diff) | |
| download | wix-0d3d54992104288e9ee0c834d0b96e8502fd2d42.tar.gz wix-0d3d54992104288e9ee0c834d0b96e8502fd2d42.tar.bz2 wix-0d3d54992104288e9ee0c834d0b96e8502fd2d42.zip | |
Move the BootstrapperApplication out of proc
Diffstat (limited to '')
| -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 | } | ||
