main
cpp 195 lines 5.93 KB
Raw
1 // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3 #include "precomp.h"
4
5 const DWORD TEST_UNKNOWN_MESSAGE_ID = 0xFFFE;
6 const HRESULT S_TEST_SUCCEEDED = 0x3133;
7 const DWORD TEST_EXIT_CODE = 666;
8
9 struct BUNDLE_RUNNER_CONTEXT
10 {
11 DWORD dwResult;
12 BURN_PIPE_CONNECTION connection;
13 };
14
15
16 static BOOL STDAPICALLTYPE EmbeddedTest_CreateProcessW(
17 __in_opt LPCWSTR lpApplicationName,
18 __inout_opt LPWSTR lpCommandLine,
19 __in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes,
20 __in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes,
21 __in BOOL bInheritHandles,
22 __in DWORD dwCreationFlags,
23 __in_opt LPVOID lpEnvironment,
24 __in_opt LPCWSTR lpCurrentDirectory,
25 __in LPSTARTUPINFOW lpStartupInfo,
26 __out LPPROCESS_INFORMATION lpProcessInformation
27 );
28 static DWORD CALLBACK EmbeddedTest_ThreadProc(
29 __in LPVOID lpThreadParameter
30 );
31 static int EmbeddedTest_GenericMessageHandler(
32 __in GENERIC_EXECUTE_MESSAGE* pMessage,
33 __in LPVOID pvContext
34 );
35
36 namespace Microsoft
37 {
38 namespace Tools
39 {
40 namespace WindowsInstallerXml
41 {
42 namespace Test
43 {
44 namespace Bootstrapper
45 {
46 using namespace System;
47 using namespace System::IO;
48 using namespace System::Threading;
49 using namespace Xunit;
50
51 public ref class EmbeddedTest : BurnUnitTest
52 {
53 public:
54 EmbeddedTest(BurnTestFixture^ fixture) : BurnUnitTest(fixture)
55 {
56 }
57
58 [Fact]
59 void EmbeddedProtocolTest()
60 {
61 HRESULT hr = S_OK;
62 BUNDLE_RUNNER_CONTEXT bundleRunnerContext = { };
63 DWORD dwExitCode = 0;
64
65 try
66 {
67 CoreFunctionOverride(EmbeddedTest_CreateProcessW, ThrdWaitForCompletion);
68
69 //
70 // bundle runner setup
71 //
72 hr = EmbeddedRunBundle(&bundleRunnerContext.connection, L"C:\\ignored\\target.exe", L"\"C:\\ignored\\target.exe\"", NULL, EmbeddedTest_GenericMessageHandler, &bundleRunnerContext, &dwExitCode);
73 TestThrowOnFailure(hr, L"Failed to run embedded bundle.");
74
75 // check results
76 Assert::Equal<HRESULT>(S_TEST_SUCCEEDED, (HRESULT)bundleRunnerContext.dwResult);
77 Assert::Equal<DWORD>(TEST_EXIT_CODE, dwExitCode);
78 }
79 finally
80 {
81 }
82 }
83 };
84 }
85 }
86 }
87 }
88 }
89
90
91 static BOOL STDAPICALLTYPE EmbeddedTest_CreateProcessW(
92 __in_opt LPCWSTR /*lpApplicationName*/,
93 __inout_opt LPWSTR lpCommandLine,
94 __in_opt LPSECURITY_ATTRIBUTES /*lpProcessAttributes*/,
95 __in_opt LPSECURITY_ATTRIBUTES /*lpThreadAttributes*/,
96 __in BOOL /*bInheritHandles*/,
97 __in DWORD /*dwCreationFlags*/,
98 __in_opt LPVOID /*lpEnvironment*/,
99 __in_opt LPCWSTR /*lpCurrentDirectory*/,
100 __in LPSTARTUPINFOW /*lpStartupInfo*/,
101 __out LPPROCESS_INFORMATION lpProcessInformation
102 )
103 {
104 HRESULT hr = S_OK;
105 LPWSTR scz = NULL;
106 LPCWSTR wzArgs = lpCommandLine + 24; //skip '"C:\ignored\target.exe" '
107
108 hr = StrAllocString(&scz, wzArgs, 0);
109 ExitOnFailure(hr, "Failed to copy arguments.");
110
111 // Pretend this thread is the embedded process.
112 lpProcessInformation->hProcess = ::CreateThread(NULL, 0, EmbeddedTest_ThreadProc, scz, 0, NULL);
113 ExitOnNullWithLastError(lpProcessInformation->hProcess, hr, "Failed to create thread.");
114
115 scz = NULL;
116
117 LExit:
118 ReleaseStr(scz);
119
120 return SUCCEEDED(hr);
121 }
122
123 static DWORD CALLBACK EmbeddedTest_ThreadProc(
124 __in LPVOID lpThreadParameter
125 )
126 {
127 HRESULT hr = S_OK;
128 LPWSTR sczArguments = (LPWSTR)lpThreadParameter;
129 BURN_ENGINE_STATE engineState = { };
130 BURN_PIPE_CONNECTION* pConnection = &engineState.embeddedConnection;
131 DWORD dwResult = 0;
132
133 engineState.internalCommand.mode = BURN_MODE_EMBEDDED;
134
135 BurnPipeConnectionInitialize(pConnection);
136
137 StrAlloc(&pConnection->sczName, MAX_PATH);
138 StrAlloc(&pConnection->sczSecret, MAX_PATH);
139
140 // parse command line arguments
141 if (3 != swscanf_s(sczArguments, L"-burn.embedded %s %s %u", pConnection->sczName, MAX_PATH, pConnection->sczSecret, MAX_PATH, &pConnection->dwProcessId))
142 {
143 ExitWithRootFailure(hr, E_INVALIDARG, "Failed to parse argument string.");
144 }
145
146 // set up connection with parent bundle runner
147 hr = BurnPipeChildConnect(pConnection, FALSE);
148 ExitOnFailure(hr, "Failed to connect to parent bundle runner.");
149
150 // post unknown message
151 hr = BurnPipeSendMessage(pConnection->hPipe, TEST_UNKNOWN_MESSAGE_ID, NULL, 0, NULL, NULL, &dwResult);
152 ExitOnFailure(hr, "Failed to post unknown message to parent bundle runner.");
153
154 if (E_NOTIMPL != dwResult)
155 {
156 ExitWithRootFailure(hr, E_UNEXPECTED, "Unexpected result from unknown message: %d", dwResult);
157 }
158
159 // post known message
160 hr = ExternalEngineSendEmbeddedError(&engineState, S_TEST_SUCCEEDED, NULL, 0, reinterpret_cast<int*>(&dwResult));
161 ExitOnFailure(hr, "Failed to post known message to parent bundle runner.");
162
163 LExit:
164 BurnPipeConnectionUninitialize(pConnection);
165 ReleaseStr(sczArguments);
166
167 return FAILED(hr) ? (DWORD)hr : dwResult;
168 }
169
170 static int EmbeddedTest_GenericMessageHandler(
171 __in GENERIC_EXECUTE_MESSAGE* pMessage,
172 __in LPVOID pvContext
173 )
174 {
175 BUNDLE_RUNNER_CONTEXT* pContext = reinterpret_cast<BUNDLE_RUNNER_CONTEXT*>(pvContext);
176 DWORD dwResult = 0;
177
178 if (GENERIC_EXECUTE_MESSAGE_ERROR == pMessage->type)
179 {
180 // post unknown message
181 HRESULT hr = BurnPipeSendMessage(pContext->connection.hPipe, TEST_UNKNOWN_MESSAGE_ID, NULL, 0, NULL, NULL, &dwResult);
182 ExitOnFailure(hr, "Failed to post unknown message to embedded bundle.");
183
184 if (E_NOTIMPL != dwResult)
185 {
186 ExitWithRootFailure(hr, E_UNEXPECTED, "Unexpected result from unknown message: %d", dwResult);
187 }
188
189 pContext->dwResult = pMessage->error.dwErrorCode;
190 dwResult = TEST_EXIT_CODE;
191 }
192
193 LExit:
194 return dwResult;
195 }