@joebigelow / wix / commits / 7d813eaa

Import implementation of SqlCA from old repo's scasched/scaexec.

Sean Hall committed Dec 16, 2018 at 13:53 UTC 7d813eaad8eaca04a687d1bb942316232d1c54fd
14 files changed +2131 -1
src/ca/CustomMsiErrors.h new
+10
@@ -0,0 +1,10 @@
1 +#pragma once
2 +// 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.
3 +
4 +#define msierrSQLFailedCreateDatabase 26201
5 +#define msierrSQLFailedDropDatabase 26202
6 +#define msierrSQLFailedConnectDatabase 26203
7 +#define msierrSQLFailedExecString 26204
8 +#define msierrSQLDatabaseAlreadyExists 26205
9 +
10 +//Last available is 26250
\ No newline at end of file
src/ca/precomp.h
+14
@@ -2,12 +2,26 @@
2 // 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.
3
4
5 +#if _WIN32_MSI < 150
6 +#define _WIN32_MSI 150
7 +#endif
8 +
9 #include <windows.h>
10 #include <msiquery.h>
11
12 +#include <strsafe.h>
13 +
14 #define MAXUINT USHRT_MAX
15 #include <Setup.Configuration.h>
16
17 #include "wcautil.h"
18 #include "fileutil.h"
19 +#include "memutil.h"
20 #include "strutil.h"
21 +#include "wiutil.h"
22 +
23 +#include "CustomMsiErrors.h"
24 +
25 +#include "sca.h"
26 +#include "scacost.h"
27 +#include "scasqlstr.h"
src/ca/sca.h new
+33
@@ -0,0 +1,33 @@
1 +#pragma once
2 +// 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.
3 +
4 +// Generic action enum.
5 +enum SCA_ACTION
6 +{
7 + SCA_ACTION_NONE,
8 + SCA_ACTION_INSTALL,
9 + SCA_ACTION_UNINSTALL
10 +};
11 +
12 +// sql database attributes definitions
13 +enum SCADB_ATTRIBUTES
14 +{
15 + SCADB_CREATE_ON_INSTALL = 0x00000001,
16 + SCADB_DROP_ON_UNINSTALL = 0x00000002,
17 + SCADB_CONTINUE_ON_ERROR = 0x00000004,
18 + SCADB_DROP_ON_INSTALL = 0x00000008,
19 + SCADB_CREATE_ON_UNINSTALL = 0x00000010,
20 + SCADB_CONFIRM_OVERWRITE = 0x00000020,
21 + SCADB_CREATE_ON_REINSTALL = 0x00000040,
22 + SCADB_DROP_ON_REINSTALL = 0x00000080,
23 +};
24 +
25 +// sql string/script attributes definitions
26 +enum SCASQL_ATTRIBUTES
27 +{
28 + SCASQL_EXECUTE_ON_INSTALL = 0x00000001,
29 + SCASQL_EXECUTE_ON_UNINSTALL = 0x00000002,
30 + SCASQL_CONTINUE_ON_ERROR = 0x00000004,
31 + SCASQL_ROLLBACK = 0x00000008,
32 + SCASQL_EXECUTE_ON_REINSTALL = 0x00000010,
33 +};
src/ca/scacost.h new
+7
@@ -0,0 +1,7 @@
1 +#pragma once
2 +// 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.
3 +
4 +const UINT COST_SQL_CREATEDB = 10000;
5 +const UINT COST_SQL_DROPDB = 5000;
6 +const UINT COST_SQL_CONNECTDB = 5000;
7 +const UINT COST_SQL_STRING = 5000;
src/ca/scadb.cpp new
+587
@@ -0,0 +1,587 @@
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 +// sql queries
6 +LPCWSTR vcsSqlDatabaseQuery = L"SELECT `SqlDb`, `Server`, `Instance`, `Database`, "
7 + L"`Component_`, `User_`, `FileSpec_`, `FileSpec_Log`, `Attributes` "
8 + L"FROM `SqlDatabase`";
9 +enum eSqlDatabaseQuery { sdqSqlDb = 1, sdqServer, sdqInstance, sdqDatabase,
10 + sdqComponent, sdqUser, sdqDbFileSpec, sdqLogFileSpec, sdqAttributes };
11 +
12 +LPCWSTR vcsSqlFileSpecQuery = L"SELECT `FileSpec`, `Name`, `Filename`, `Size`, "
13 + L"`MaxSize`, `GrowthSize` FROM `SqlFileSpec` WHERE `FileSpec`=?";
14 +enum eSqlFileSpecQuery { sfsqFileSpec = 1, sfsqName, sfsqFilename, sfsqSize,
15 + sfsqMaxSize, sfsqGrowth };
16 +
17 +
18 +// prototypes for private helper functions
19 +static HRESULT NewDb(
20 + __out SCA_DB** ppsd
21 + );
22 +
23 +static SCA_DB* AddDbToList(
24 + __in SCA_DB* psdList,
25 + __in SCA_DB* psd
26 + );
27 +
28 +static HRESULT SchedCreateDatabase(
29 + __in SCA_DB* psd
30 + );
31 +
32 +static HRESULT SchedDropDatabase(
33 + __in LPCWSTR wzKey, LPCWSTR wzServer,
34 + __in LPCWSTR wzInstance,
35 + __in LPCWSTR wzDatabase,
36 + __in int iAttributes,
37 + __in BOOL fIntegratedAuth,
38 + __in LPCWSTR wzUser,
39 + __in LPCWSTR wzPassword
40 + );
41 +
42 +static HRESULT GetFileSpec(
43 + __in MSIHANDLE hViewFileSpec,
44 + __in LPCWSTR wzKey,
45 + __in SQL_FILESPEC* psf
46 + );
47 +
48 +
49 +HRESULT ScaDbsRead(
50 + __inout SCA_DB** ppsdList,
51 + __in SCA_ACTION saAction
52 + )
53 +{
54 + HRESULT hr = S_OK;
55 + UINT er = ERROR_SUCCESS;
56 + PMSIHANDLE hView;
57 + PMSIHANDLE hRec;
58 + PMSIHANDLE hViewFileSpec = NULL;
59 +
60 + LPWSTR pwzData = NULL;
61 + LPWSTR pwzId = NULL;
62 + LPWSTR pwzComponent = NULL;
63 +
64 + SCA_DB* psd = NULL;
65 +
66 + if (S_OK != WcaTableExists(L"SqlDatabase"))
67 + {
68 + WcaLog(LOGMSG_VERBOSE, "Skipping ScaCreateDatabase() - SqlDatabase table not present");
69 + ExitFunction1(hr = S_FALSE);
70 + }
71 +
72 + if (S_OK == WcaTableExists(L"SqlFileSpec"))
73 + {
74 + hr = WcaOpenView(vcsSqlFileSpecQuery, &hViewFileSpec);
75 + ExitOnFailure(hr, "failed to open view on SqlFileSpec table");
76 + }
77 +
78 + // loop through all the sql databases
79 + hr = WcaOpenExecuteView(vcsSqlDatabaseQuery, &hView);
80 + ExitOnFailure(hr, "Failed to open view on SqlDatabase table");
81 + while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
82 + {
83 + BOOL fHasComponent = FALSE;
84 + INSTALLSTATE isInstalled = INSTALLSTATE_UNKNOWN;
85 + INSTALLSTATE isAction = INSTALLSTATE_UNKNOWN;
86 +
87 + hr = WcaGetRecordString(hRec, sdqSqlDb, &pwzId);
88 + ExitOnFailure(hr, "Failed to get SqlDatabase.SqlDb");
89 +
90 + hr = WcaGetRecordString(hRec, sdqComponent, &pwzComponent);
91 + ExitOnFailure(hr, "Failed to get Component for database: '%ls'", psd->wzKey);
92 + if (pwzComponent && *pwzComponent)
93 + {
94 + fHasComponent = TRUE;
95 +
96 + er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzComponent, &isInstalled, &isAction);
97 + hr = HRESULT_FROM_WIN32(er);
98 + ExitOnFailure(hr, "Failed to get state for component: %ls", pwzComponent);
99 +
100 + // If we're doing install but the Component is not being installed or we're doing
101 + // uninstall but the Component is not being uninstalled, skip it.
102 + if ((WcaIsInstalling(isInstalled, isAction) && SCA_ACTION_INSTALL != saAction) ||
103 + (WcaIsUninstalling(isInstalled, isAction) && SCA_ACTION_UNINSTALL != saAction))
104 + {
105 + continue;
106 + }
107 + }
108 +
109 + hr = NewDb(&psd);
110 + ExitOnFailure(hr, "Failed to allocate memory for new database: %D", pwzId);
111 +
112 + hr = ::StringCchCopyW(psd->wzKey, countof(psd->wzKey), pwzId);
113 + ExitOnFailure(hr, "Failed to copy SqlDatabase.SqlDbL: %ls", pwzId);
114 +
115 + hr = ::StringCchCopyW(psd->wzComponent, countof(psd->wzComponent), pwzComponent);
116 + ExitOnFailure(hr, "Failed to copy SqlDatabase.Component_: %ls", pwzComponent);
117 +
118 + psd->fHasComponent = fHasComponent;
119 + psd->isInstalled = isInstalled;
120 + psd->isAction = isAction;
121 +
122 + hr = WcaGetRecordFormattedString(hRec, sdqServer, &pwzData);
123 + ExitOnFailure(hr, "Failed to get Server for database: '%ls'", psd->wzKey);
124 + hr = ::StringCchCopyW(psd->wzServer, countof(psd->wzServer), pwzData);
125 + ExitOnFailure(hr, "Failed to copy server string to database object:%ls", pwzData);
126 +
127 + hr = WcaGetRecordFormattedString(hRec, sdqInstance, &pwzData);
128 + ExitOnFailure(hr, "Failed to get Instance for database: '%ls'", psd->wzKey);
129 + hr = ::StringCchCopyW(psd->wzInstance, countof(psd->wzInstance), pwzData);
130 + ExitOnFailure(hr, "Failed to copy instance string to database object:%ls", pwzData);
131 +
132 + hr = WcaGetRecordFormattedString(hRec, sdqDatabase, &pwzData);
133 + ExitOnFailure(hr, "Failed to get Database for database: '%ls'", psd->wzKey);
134 + hr = ::StringCchCopyW(psd->wzDatabase, countof(psd->wzDatabase), pwzData);
135 + ExitOnFailure(hr, "Failed to copy database string to database object:%ls", pwzData);
136 +
137 + hr = WcaGetRecordInteger(hRec, sdqAttributes, &psd->iAttributes);
138 + ExitOnFailure(hr, "Failed to get SqlDatabase.Attributes");
139 +
140 + hr = WcaGetRecordFormattedString(hRec, sdqUser, &pwzData);
141 + ExitOnFailure(hr, "Failed to get User record for database: '%ls'", psd->wzKey);
142 +
143 + // if a user was specified
144 + if (*pwzData)
145 + {
146 + psd->fUseIntegratedAuth = FALSE;
147 + hr = ScaGetUser(pwzData, &psd->scau);
148 + ExitOnFailure(hr, "Failed to get user information for database: '%ls'", psd->wzKey);
149 + }
150 + else
151 + {
152 + psd->fUseIntegratedAuth = TRUE;
153 + // integrated authorization doesn't have a User record
154 + }
155 +
156 + hr = WcaGetRecordString(hRec, sdqDbFileSpec, &pwzData);
157 + ExitOnFailure(hr, "Failed to get Database FileSpec for database: '%ls'", psd->wzKey);
158 +
159 + // if a database filespec was specified
160 + if (*pwzData)
161 + {
162 + hr = GetFileSpec(hViewFileSpec, pwzData, &psd->sfDb);
163 + ExitOnFailure(hr, "failed to get FileSpec for: %ls", pwzData);
164 + if (S_OK == hr)
165 + {
166 + psd->fHasDbSpec = TRUE;
167 + }
168 + }
169 +
170 + hr = WcaGetRecordString(hRec, sdqLogFileSpec, &pwzData);
171 + ExitOnFailure(hr, "Failed to get Log FileSpec for database: '%ls'", psd->wzKey);
172 +
173 + // if a log filespec was specified
174 + if (*pwzData)
175 + {
176 + hr = GetFileSpec(hViewFileSpec, pwzData, &psd->sfLog);
177 + ExitOnFailure(hr, "failed to get FileSpec for: %ls", pwzData);
178 + if (S_OK == hr)
179 + {
180 + psd->fHasLogSpec = TRUE;
181 + }
182 + }
183 +
184 + *ppsdList = AddDbToList(*ppsdList, psd);
185 + psd = NULL; // set the db NULL so it doesn't accidentally get freed below
186 + }
187 +
188 + if (E_NOMOREITEMS == hr)
189 + {
190 + hr = S_OK;
191 + }
192 + ExitOnFailure(hr, "Failure occured while processing SqlDatabase table");
193 +
194 +LExit:
195 + if (psd)
196 + {
197 + ScaDbsFreeList(psd);
198 + }
199 +
200 + ReleaseStr(pwzComponent);
201 + ReleaseStr(pwzId);
202 + ReleaseStr(pwzData);
203 + return hr;
204 +}
205 +
206 +
207 +SCA_DB* ScaDbsFindDatabase(
208 + __in LPCWSTR wzSqlDb,
209 + __in SCA_DB* psdList
210 + )
211 +{
212 + SCA_DB* psd = NULL;
213 +
214 + for (psd = psdList; psd; psd = psd->psdNext)
215 + {
216 + if (0 == lstrcmpW(wzSqlDb, psd->wzKey))
217 + {
218 + break;
219 + }
220 + }
221 +
222 + return psd;
223 +}
224 +
225 +
226 +HRESULT ScaDbsInstall(
227 + __in SCA_DB* psdList
228 + )
229 +{
230 + HRESULT hr = S_FALSE; // assume nothing will be done
231 + SCA_DB* psd = NULL;
232 +
233 + for (psd = psdList; psd; psd = psd->psdNext)
234 + {
235 + if (psd->fHasComponent)
236 + {
237 + // if we need to drop, do that first
238 + if (((psd->iAttributes & SCADB_DROP_ON_INSTALL) && WcaIsInstalling(psd->isInstalled, psd->isAction) && !WcaIsReInstalling(psd->isInstalled, psd->isAction)) ||
239 + ((psd->iAttributes & SCADB_DROP_ON_REINSTALL) && WcaIsReInstalling(psd->isInstalled, psd->isAction)))
240 + {
241 + hr = SchedDropDatabase(psd->wzKey, psd->wzServer, psd->wzInstance, psd->wzDatabase, psd->iAttributes, psd->fUseIntegratedAuth, psd->scau.wzName, psd->scau.wzPassword);
242 + ExitOnFailure(hr, "Failed to drop database %ls", psd->wzKey);
243 + }
244 +
245 + // if installing this component
246 + if (((psd->iAttributes & SCADB_CREATE_ON_INSTALL) && WcaIsInstalling(psd->isInstalled, psd->isAction) && !WcaIsReInstalling(psd->isInstalled, psd->isAction)) ||
247 + ((psd->iAttributes & SCADB_CREATE_ON_REINSTALL) && WcaIsReInstalling(psd->isInstalled, psd->isAction)))
248 + {
249 + hr = SchedCreateDatabase(psd);
250 + ExitOnFailure(hr, "Failed to ensure database %ls exists", psd->wzKey);
251 + }
252 + }
253 + }
254 +
255 +LExit:
256 + return hr;
257 +}
258 +
259 +
260 +HRESULT ScaDbsUninstall(
261 + __in SCA_DB* psdList
262 + )
263 +{
264 + HRESULT hr = S_FALSE; // assume nothing will be done
265 + SCA_DB* psd = NULL;
266 +
267 + for (psd = psdList; psd; psd = psd->psdNext)
268 + {
269 + if (psd->fHasComponent)
270 + {
271 + // if we need to drop do that first
272 + if ((psd->iAttributes & SCADB_DROP_ON_UNINSTALL) && WcaIsUninstalling(psd->isInstalled, psd->isAction))
273 + {
274 + hr = SchedDropDatabase(psd->wzKey, psd->wzServer, psd->wzInstance, psd->wzDatabase, psd->iAttributes, psd->fUseIntegratedAuth, psd->scau.wzName, psd->scau.wzPassword);
275 + ExitOnFailure(hr, "Failed to drop database %ls", psd->wzKey);
276 + }
277 +
278 + // install the db
279 + if ((psd->iAttributes & SCADB_CREATE_ON_UNINSTALL) && WcaIsUninstalling(psd->isInstalled, psd->isAction))
280 + {
281 + hr = SchedCreateDatabase(psd);
282 + ExitOnFailure(hr, "Failed to ensure database %ls exists", psd->wzKey);
283 + }
284 + }
285 + }
286 +
287 +LExit:
288 + return hr;
289 +}
290 +
291 +
292 +void ScaDbsFreeList(
293 + __in SCA_DB* psdList
294 + )
295 +{
296 + SCA_DB* psdDelete = psdList;
297 + while (psdList)
298 + {
299 + psdDelete = psdList;
300 + psdList = psdList->psdNext;
301 +
302 + MemFree(psdDelete);
303 + }
304 +}
305 +
306 +
307 +// private helper functions
308 +
309 +static HRESULT NewDb(
310 + __out SCA_DB** ppsd
311 + )
312 +{
313 + HRESULT hr = S_OK;
314 + SCA_DB* psd = static_cast<SCA_DB*>(MemAlloc(sizeof(SCA_DB), TRUE));
315 + ExitOnNull(psd, hr, E_OUTOFMEMORY, "failed to allocate memory for new database element");
316 +
317 + *ppsd = psd;
318 +
319 +LExit:
320 + return hr;
321 +}
322 +
323 +
324 +static SCA_DB* AddDbToList(
325 + __in SCA_DB* psdList,
326 + __in SCA_DB* psd
327 + )
328 +{
329 + if (psdList)
330 + {
331 + SCA_DB* psdT = psdList;
332 + while (psdT->psdNext)
333 + {
334 + psdT = psdT->psdNext;
335 + }
336 +
337 + psdT->psdNext = psd;
338 + }
339 + else
340 + {
341 + psdList = psd;
342 + }
343 +
344 + return psdList;
345 +}
346 +
347 +
348 +static HRESULT SchedCreateDatabase(
349 + __in SCA_DB* psd
350 + )
351 +{
352 + HRESULT hr = S_OK;
353 + WCHAR* pwzCustomActionData = NULL;
354 +
355 + hr = WcaWriteStringToCaData(psd->wzKey, &pwzCustomActionData);
356 + ExitOnFailure(hr, "failed to add DBKey to CustomActionData");
357 +
358 + hr = WcaWriteStringToCaData(psd->wzServer, &pwzCustomActionData);
359 + ExitOnFailure(hr, "Failed to add server name to CustomActionData");
360 +
361 + hr = WcaWriteStringToCaData(psd->wzInstance, &pwzCustomActionData);
362 + ExitOnFailure(hr, "Failed to add server instance to CustomActionData");
363 +
364 + hr = WcaWriteStringToCaData(psd->wzDatabase, &pwzCustomActionData);
365 + ExitOnFailure(hr, "Failed to add database name to CustomActionData");
366 +
367 + hr = WcaWriteIntegerToCaData(psd->iAttributes, &pwzCustomActionData);
368 + ExitOnFailure(hr, "Failed to add Sql attributes to CustomActionData");
369 +
370 + hr = WcaWriteStringToCaData(psd->fUseIntegratedAuth ? L"1" : L"0", &pwzCustomActionData);
371 + ExitOnFailure(hr, "Failed to add if integrated connection to CustomActionData");
372 +
373 + hr = WcaWriteStringToCaData(psd->scau.wzName, &pwzCustomActionData);
374 + ExitOnFailure(hr, "Failed to add server user to CustomActionData");
375 +
376 + hr = WcaWriteStringToCaData(psd->scau.wzPassword, &pwzCustomActionData);
377 + ExitOnFailure(hr, "Failed to add user password to CustomActionData");
378 +
379 + // Check to see if the database exists, if it does not then schedule a rollback
380 + // so we clean up after ourselves if the creation of the database fails or is
381 + // aborted. It is interesting to note that we can do this check here because the
382 + // deferred CustomActions are Impersonated. That means this scheduling action and
383 + // the execution actions all run with the same user context, so it is safe to
384 + // to do the check.
385 + hr = SqlDatabaseExists(psd->wzServer, psd->wzInstance, psd->wzDatabase, psd->fUseIntegratedAuth, psd->scau.wzName, psd->scau.wzPassword, NULL);
386 + if (S_FALSE == hr)
387 + {
388 + hr = WcaDoDeferredAction(L"RollbackCreateDatabase", pwzCustomActionData, COST_SQL_CREATEDB);
389 + ExitOnFailure(hr, "Failed to schedule RollbackCreateDatabase action");
390 + }
391 +
392 + // database filespec
393 + if (psd->fHasDbSpec)
394 + {
395 + hr = WcaWriteStringToCaData(L"1", &pwzCustomActionData);
396 + ExitOnFailure(hr, "failed to specify that do have db.filespec to CustomActionData");
397 +
398 + hr = WcaWriteStringToCaData(psd->sfDb.wzName, &pwzCustomActionData);
399 + ExitOnFailure(hr, "failed to add FileSpec.Name to CustomActionData");
400 +
401 + hr = WcaWriteStringToCaData(psd->sfDb.wzFilename, &pwzCustomActionData);
402 + ExitOnFailure(hr, "failed to add FileSpec.Filename to CustomActionData");
403 +
404 + hr = WcaWriteStringToCaData(psd->sfDb.wzSize, &pwzCustomActionData);
405 + ExitOnFailure(hr, "Failed to add FileSpec.Size to CustomActionData");
406 +
407 + hr = WcaWriteStringToCaData(psd->sfDb.wzMaxSize, &pwzCustomActionData);
408 + ExitOnFailure(hr, "Failed to add FileSpec.MaxSize to CustomActionData");
409 +
410 + hr = WcaWriteStringToCaData(psd->sfDb.wzGrow, &pwzCustomActionData);
411 + ExitOnFailure(hr, "Failed to add FileSpec.GrowthSize to CustomActionData");
412 + }
413 + else
414 + {
415 + hr = WcaWriteStringToCaData(L"0", &pwzCustomActionData);
416 + ExitOnFailure(hr, "failed to specify that do not have db.filespec to CustomActionData");
417 + }
418 +
419 + // log filespec
420 + if (psd->fHasLogSpec)
421 + {
422 + hr = WcaWriteStringToCaData(L"1", &pwzCustomActionData);
423 + ExitOnFailure(hr, "failed to specify that do have log.filespec to CustomActionData");
424 +
425 + hr = WcaWriteStringToCaData(psd->sfLog.wzName, &pwzCustomActionData);
426 + ExitOnFailure(hr, "failed to add FileSpec.Name to CustomActionData");
427 +
428 + hr = WcaWriteStringToCaData(psd->sfLog.wzFilename, &pwzCustomActionData);
429 + ExitOnFailure(hr, "failed to add FileSpec.Filename to CustomActionData");
430 +
431 + hr = WcaWriteStringToCaData(psd->sfLog.wzSize, &pwzCustomActionData);
432 + ExitOnFailure(hr, "Failed to add FileSpec.Size to CustomActionData");
433 +
434 + hr = WcaWriteStringToCaData(psd->sfLog.wzMaxSize, &pwzCustomActionData);
435 + ExitOnFailure(hr, "Failed to add FileSpec.MaxSize to CustomActionData");
436 +
437 + hr = WcaWriteStringToCaData(psd->sfLog.wzGrow, &pwzCustomActionData);
438 + ExitOnFailure(hr, "Failed to add FileSpec.GrowthSize to CustomActionData");
439 + }
440 + else
441 + {
442 + hr = WcaWriteStringToCaData(L"0", &pwzCustomActionData);
443 + ExitOnFailure(hr, "failed to specify that do not have log.filespec to CustomActionData");
444 + }
445 +
446 + // schedule the CreateDatabase action
447 + hr = WcaDoDeferredAction(L"CreateDatabase", pwzCustomActionData, COST_SQL_CREATEDB);
448 + ExitOnFailure(hr, "Failed to schedule CreateDatabase action");
449 +
450 +LExit:
451 + ReleaseStr(pwzCustomActionData);
452 + return hr;
453 +}
454 +
455 +
456 +HRESULT SchedDropDatabase(
457 + __in LPCWSTR wzKey,
458 + __in LPCWSTR wzServer,
459 + __in LPCWSTR wzInstance,
460 + __in LPCWSTR wzDatabase,
461 + __in int iAttributes,
462 + __in BOOL fIntegratedAuth,
463 + __in LPCWSTR wzUser,
464 + __in LPCWSTR wzPassword
465 + )
466 +{
467 + HRESULT hr = S_OK;
468 + WCHAR* pwzCustomActionData = NULL;
469 +
470 + hr = WcaWriteStringToCaData(wzKey, &pwzCustomActionData);
471 + ExitOnFailure(hr, "failed to add DBKey to CustomActionData");
472 +
473 + hr = WcaWriteStringToCaData(wzServer, &pwzCustomActionData);
474 + ExitOnFailure(hr, "Failed to add server name to CustomActionData");
475 +
476 + hr = WcaWriteStringToCaData(wzInstance, &pwzCustomActionData);
477 + ExitOnFailure(hr, "Failed to add server instance to CustomActionData");
478 +
479 + hr = WcaWriteStringToCaData(wzDatabase, &pwzCustomActionData);
480 + ExitOnFailure(hr, "Failed to add database name to CustomActionData");
481 +
482 + hr = WcaWriteIntegerToCaData(iAttributes, &pwzCustomActionData);
483 + ExitOnFailure(hr, "Failed to add server name to CustomActionData");
484 +
485 + hr = WcaWriteStringToCaData(fIntegratedAuth ? L"1" : L"0", &pwzCustomActionData);
486 + ExitOnFailure(hr, "Failed to add server name to CustomActionData");
487 +
488 + hr = WcaWriteStringToCaData(wzUser, &pwzCustomActionData);
489 + ExitOnFailure(hr, "Failed to add server user to CustomActionData");
490 +
491 + hr = WcaWriteStringToCaData(wzPassword, &pwzCustomActionData);
492 + ExitOnFailure(hr, "Failed to add user password to CustomActionData");
493 +
494 + hr = WcaDoDeferredAction(L"DropDatabase", pwzCustomActionData, COST_SQL_DROPDB);
495 + ExitOnFailure(hr, "Failed to schedule DropDatabase action");
496 +
497 +LExit:
498 + ReleaseStr(pwzCustomActionData);
499 + return hr;
500 +}
501 +
502 +
503 +HRESULT GetFileSpec(
504 + __in MSIHANDLE hViewFileSpec,
505 + __in LPCWSTR wzKey,
506 + __in SQL_FILESPEC* psf
507 + )
508 +{
509 + HRESULT hr = S_OK;
510 + PMSIHANDLE hRecFileSpec, hRec;
511 + LPWSTR pwzData = NULL;
512 +
513 + // create a record to do the fetch
514 + hRecFileSpec = ::MsiCreateRecord(1);
515 + if (!hRecFileSpec)
516 + {
517 + ExitOnFailure(hr = E_UNEXPECTED, "failed to create record for filespec: %ls", wzKey);
518 + }
519 + hr = WcaSetRecordString(hRecFileSpec, 1, wzKey);
520 + ExitOnFailure(hr, "failed to set record string for filespec: %ls", wzKey);
521 +
522 + // get the FileSpec record
523 + hr = WcaExecuteView(hViewFileSpec, hRecFileSpec);
524 + ExitOnFailure(hr, "failed to execute view on SqlFileSpec table for filespec: %ls", wzKey);
525 + hr = WcaFetchSingleRecord(hViewFileSpec, &hRec);
526 + ExitOnFailure(hr, "failed to get record for filespec: %ls", wzKey);
527 +
528 + // read the data out of the filespec record
529 + hr = WcaGetRecordFormattedString(hRec, sfsqName, &pwzData);
530 + ExitOnFailure(hr, "Failed to get SqlFileSpec.Name for filespec: %ls", wzKey);
531 + hr = ::StringCchCopyW(psf->wzName, countof(psf->wzName), pwzData);
532 + ExitOnFailure(hr, "Failed to copy SqlFileSpec.Name string: %ls", pwzData);
533 +
534 + hr = WcaGetRecordFormattedString(hRec, sfsqFilename, &pwzData);
535 + ExitOnFailure(hr, "Failed to get SqlFileSpec.Filename for filespec: %ls", wzKey);
536 + if (*pwzData)
537 + {
538 + hr = ::StringCchCopyW(psf->wzFilename, countof(psf->wzFilename), pwzData);
539 + ExitOnFailure(hr, "Failed to copy filename to filespec object: %ls", pwzData);
540 + }
541 + else // if there is no file, skip this FILESPEC
542 + {
543 + WcaLog(LOGMSG_VERBOSE, "No filename specified, skipping FileSpec: %ls", psf->wzName);
544 + ExitFunction1(hr = S_FALSE);
545 + }
546 +
547 + hr = WcaGetRecordFormattedString(hRec, sfsqSize, &pwzData);
548 + ExitOnFailure(hr, "Failed to get SqlFileSpec.Size for filespec: %ls", wzKey);
549 + if (*pwzData)
550 + {
551 + hr = ::StringCchCopyW(psf->wzSize, countof(psf->wzSize), pwzData);
552 + ExitOnFailure(hr, "Failed to copy size to filespec object: %ls", pwzData);
553 + }
554 + else
555 + {
556 + psf->wzSize[0] = 0;
557 + }
558 +
559 + hr = WcaGetRecordFormattedString(hRec, sfsqMaxSize, &pwzData);
560 + ExitOnFailure(hr, "Failed to get SqlFileSpec.MaxSize for filespec: %ls", wzKey);
561 + if (*pwzData)
562 + {
563 + hr = ::StringCchCopyW(psf->wzMaxSize, countof(psf->wzMaxSize), pwzData);
564 + ExitOnFailure(hr, "Failed to copy max size to filespec object: %ls", pwzData);
565 + }
566 + else
567 + {
568 + psf->wzMaxSize[0] = 0;
569 + }
570 +
571 + hr = WcaGetRecordFormattedString(hRec, sfsqGrowth, &pwzData);
572 + ExitOnFailure(hr, "Failed to get SqlFileSpec.GrowthSize for filespec: %ls", wzKey);
573 + if (*pwzData)
574 + {
575 + hr = ::StringCchCopyW(psf->wzGrow, countof(psf->wzGrow), pwzData);
576 + ExitOnFailure(hr, "Failed to copy growth size to filespec object: %ls", pwzData);
577 + }
578 + else
579 + {
580 + psf->wzGrow[0] = 0;
581 + }
582 +
583 + hr = S_OK;
584 +LExit:
585 + ReleaseStr(pwzData);
586 + return hr;
587 +}
src/ca/scadb.h new
+55
@@ -0,0 +1,55 @@
1 +#pragma once
2 +// 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.
3 +
4 +
5 +#include "scauser.h"
6 +#include "sqlutil.h"
7 +
8 +struct SCA_DB
9 +{
10 + // darwin information
11 + WCHAR wzKey[MAX_DARWIN_KEY + 1];
12 + BOOL fHasComponent;
13 + WCHAR wzComponent[MAX_DARWIN_KEY + 1];
14 + INSTALLSTATE isInstalled, isAction;
15 +
16 + WCHAR wzServer[MAX_DARWIN_COLUMN + 1];
17 + WCHAR wzInstance[MAX_DARWIN_COLUMN + 1];
18 + WCHAR wzDatabase[MAX_DARWIN_COLUMN + 1];
19 +
20 + int iAttributes;
21 +
22 + BOOL fUseIntegratedAuth;
23 + SCA_USER scau;
24 +
25 + BOOL fHasDbSpec;
26 + SQL_FILESPEC sfDb;
27 + BOOL fHasLogSpec;
28 + SQL_FILESPEC sfLog;
29 +
30 + SCA_DB* psdNext;
31 +};
32 +
33 +
34 +// prototypes
35 +HRESULT ScaDbsRead(
36 + __inout SCA_DB** ppsdList,
37 + __in SCA_ACTION saAction
38 + );
39 +
40 +SCA_DB* ScaDbsFindDatabase(
41 + __in LPCWSTR wzSqlDb,
42 + __in SCA_DB* psdList
43 + );
44 +
45 +HRESULT ScaDbsInstall(
46 + __in SCA_DB* psdList
47 + );
48 +
49 +HRESULT ScaDbsUninstall(
50 + __in SCA_DB* psdList
51 + );
52 +
53 +void ScaDbsFreeList(
54 + __in SCA_DB* psdList
55 + );
src/ca/scaexec.cpp new
+393
@@ -0,0 +1,393 @@
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 +
6 +/********************************************************************
7 + * CreateDatabase - CUSTOM ACTION ENTRY POINT for creating databases
8 + *
9 + * Input: deferred CustomActionData - DbKey\tServer\tInstance\tDatabase\tAttributes\tIntegratedAuth\tUser\tPassword
10 + * ****************************************************************/
11 +extern "C" UINT __stdcall CreateDatabase(MSIHANDLE hInstall)
12 +{
13 +//AssertSz(FALSE, "debug CreateDatabase here");
14 + UINT er = ERROR_SUCCESS;
15 + HRESULT hr = S_OK;
16 +
17 + LPWSTR pwzData = NULL;
18 + IDBCreateSession* pidbSession = NULL;
19 + BSTR bstrErrorDescription = NULL;
20 + LPWSTR pwz = NULL;
21 + LPWSTR pwzDatabaseKey = NULL;
22 + LPWSTR pwzServer = NULL;
23 + LPWSTR pwzInstance = NULL;
24 + LPWSTR pwzDatabase = NULL;
25 + LPWSTR pwzTemp = NULL;
26 + int iAttributes;
27 + BOOL fIntegratedAuth;
28 + LPWSTR pwzUser = NULL;
29 + LPWSTR pwzPassword = NULL;
30 + BOOL fHaveDbFileSpec = FALSE;
31 + SQL_FILESPEC sfDb;
32 + BOOL fHaveLogFileSpec = FALSE;
33 + SQL_FILESPEC sfLog;
34 + BOOL fInitializedCom = FALSE;
35 +
36 + memset(&sfDb, 0, sizeof(sfDb));
37 + memset(&sfLog, 0, sizeof(sfLog));
38 +
39 + hr = WcaInitialize(hInstall, "CreateDatabase");
40 + ExitOnFailure(hr, "failed to initialize");
41 +
42 + hr = ::CoInitialize(NULL);
43 + ExitOnFailure(hr, "failed to intialize COM");
44 + fInitializedCom = TRUE;
45 +
46 + hr = WcaGetProperty( L"CustomActionData", &pwzData);
47 + ExitOnFailure(hr, "failed to get CustomActionData");
48 +
49 + WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData);
50 +
51 + pwz = pwzData;
52 + hr = WcaReadStringFromCaData(&pwz, &pwzDatabaseKey); // SQL Server
53 + ExitOnFailure(hr, "failed to read database key from custom action data: %ls", pwz);
54 + hr = WcaReadStringFromCaData(&pwz, &pwzServer); // SQL Server
55 + ExitOnFailure(hr, "failed to read server from custom action data: %ls", pwz);
56 + hr = WcaReadStringFromCaData(&pwz, &pwzInstance); // SQL Server Instance
57 + ExitOnFailure(hr, "failed to read server instance from custom action data: %ls", pwz);
58 + hr = WcaReadStringFromCaData(&pwz, &pwzDatabase); // SQL Database
59 + ExitOnFailure(hr, "failed to read server instance from custom action data: %ls", pwz);
60 + hr = WcaReadIntegerFromCaData(&pwz, &iAttributes);
61 + ExitOnFailure(hr, "failed to read attributes from custom action data: %ls", pwz);
62 + hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int *>(&fIntegratedAuth)); // Integrated Windows Authentication?
63 + ExitOnFailure(hr, "failed to read integrated auth flag from custom action data: %ls", pwz);
64 + hr = WcaReadStringFromCaData(&pwz, &pwzUser); // SQL User
65 + ExitOnFailure(hr, "failed to read user from custom action data: %ls", pwz);
66 + hr = WcaReadStringFromCaData(&pwz, &pwzPassword); // SQL User Password
67 + ExitOnFailure(hr, "failed to read user from custom action data: %ls", pwz);
68 +
69 + // db file spec
70 + hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int *>(&fHaveDbFileSpec));
71 + ExitOnFailure(hr, "failed to read db file spec from custom action data: %ls", pwz);
72 +
73 + if (fHaveDbFileSpec)
74 + {
75 + hr = WcaReadStringFromCaData(&pwz, &pwzTemp);
76 + ExitOnFailure(hr, "failed to read db file spec name from custom action data: %ls", pwz);
77 + hr = ::StringCchCopyW(sfDb.wzName, countof(sfDb.wzName), pwzTemp);
78 + ExitOnFailure(hr, "failed to copy db file spec name: %ls", pwzTemp);
79 +
80 + hr = WcaReadStringFromCaData(&pwz, &pwzTemp);
81 + ExitOnFailure(hr, "failed to read db file spec filename from custom action data: %ls", pwz);
82 + hr = ::StringCchCopyW(sfDb.wzFilename, countof(sfDb.wzFilename), pwzTemp);
83 + ExitOnFailure(hr, "failed to copy db file spec filename: %ls", pwzTemp);
84 +
85 + hr = WcaReadStringFromCaData(&pwz, &pwzTemp);
86 + ExitOnFailure(hr, "failed to read db file spec size from custom action data: %ls", pwz);
87 + hr = ::StringCchCopyW(sfDb.wzSize, countof(sfDb.wzSize), pwzTemp);
88 + ExitOnFailure(hr, "failed to copy db file spec size value: %ls", pwzTemp);
89 +
90 + hr = WcaReadStringFromCaData(&pwz, &pwzTemp);
91 + ExitOnFailure(hr, "failed to read db file spec max size from custom action data: %ls", pwz);
92 + hr = ::StringCchCopyW(sfDb.wzMaxSize, countof(sfDb.wzMaxSize), pwzTemp);
93 + ExitOnFailure(hr, "failed to copy db file spec max size: %ls", pwzTemp);
94 +
95 + hr = WcaReadStringFromCaData(&pwz, &pwzTemp);
96 + ExitOnFailure(hr, "failed to read db file spec grow from custom action data: %ls", pwz);
97 + hr = ::StringCchCopyW(sfDb.wzGrow, countof(sfDb.wzGrow), pwzTemp);
98 + ExitOnFailure(hr, "failed to copy db file spec grow value: %ls", pwzTemp);
99 + }
100 +
101 + // log file spec
102 + hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int *>(&fHaveLogFileSpec));
103 + ExitOnFailure(hr, "failed to read log file spec from custom action data: %ls", pwz);
104 + if (fHaveLogFileSpec)
105 + {
106 + hr = WcaReadStringFromCaData(&pwz, &pwzTemp);
107 + ExitOnFailure(hr, "failed to read log file spec name from custom action data: %ls", pwz);
108 + hr = ::StringCchCopyW(sfLog.wzName, countof(sfDb.wzName), pwzTemp);
109 + ExitOnFailure(hr, "failed to copy log file spec name: %ls", pwzTemp);
110 +
111 + hr = WcaReadStringFromCaData(&pwz, &pwzTemp);
112 + ExitOnFailure(hr, "failed to read log file spec filename from custom action data: %ls", pwz);
113 + hr = ::StringCchCopyW(sfLog.wzFilename, countof(sfDb.wzFilename), pwzTemp);
114 + ExitOnFailure(hr, "failed to copy log file spec filename: %ls", pwzTemp);
115 +
116 + hr = WcaReadStringFromCaData(&pwz, &pwzTemp);
117 + ExitOnFailure(hr, "failed to read log file spec size from custom action data: %ls", pwz);
118 + hr = ::StringCchCopyW(sfLog.wzSize, countof(sfDb.wzSize), pwzTemp);
119 + ExitOnFailure(hr, "failed to copy log file spec size value: %ls", pwzTemp);
120 +
121 + hr = WcaReadStringFromCaData(&pwz, &pwzTemp);
122 + ExitOnFailure(hr, "failed to read log file spec max size from custom action data: %ls", pwz);
123 + hr = ::StringCchCopyW(sfLog.wzMaxSize, countof(sfDb.wzMaxSize), pwzTemp);
124 + ExitOnFailure(hr, "failed to copy log file spec max size: %ls", pwzTemp);
125 +
126 + hr = WcaReadStringFromCaData(&pwz, &pwzTemp);
127 + ExitOnFailure(hr, "failed to read log file spec grow from custom action data: %ls", pwz);
128 + hr = ::StringCchCopyW(sfLog.wzGrow, countof(sfDb.wzGrow), pwzTemp);
129 + ExitOnFailure(hr, "failed to copy log file spec grow value: %ls", pwzTemp);
130 + }
131 +
132 + if (iAttributes & SCADB_CONFIRM_OVERWRITE)
133 + {
134 + // Check if the database already exists
135 + hr = SqlDatabaseExists(pwzServer, pwzInstance, pwzDatabase, fIntegratedAuth, pwzUser, pwzPassword, &bstrErrorDescription);
136 + MessageExitOnFailure(hr, msierrSQLFailedCreateDatabase, "failed to check if database exists: '%ls', error: %ls", pwzDatabase, NULL == bstrErrorDescription ? L"unknown error" : bstrErrorDescription);
137 +
138 + if (S_OK == hr) // found an existing database, confirm that they don't want to stop before it gets trampled, in no UI case just continue anyways
139 + {
140 + hr = HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS);
141 + if (IDNO == WcaErrorMessage(msierrSQLDatabaseAlreadyExists, hr, MB_YESNO, 1, pwzDatabase))
142 + ExitOnFailure(hr, "failed to initialize");
143 + }
144 + }
145 +
146 + hr = SqlDatabaseEnsureExists(pwzServer, pwzInstance, pwzDatabase, fIntegratedAuth, pwzUser, pwzPassword, fHaveDbFileSpec ? &sfDb : NULL, fHaveLogFileSpec ? &sfLog : NULL, &bstrErrorDescription);
147 + if ((iAttributes & SCADB_CONTINUE_ON_ERROR) && FAILED(hr))
148 + {
149 + WcaLog(LOGMSG_STANDARD, "Error 0x%x: failed to create SQL database but continuing, error: %ls, Database: %ls", hr, NULL == bstrErrorDescription ? L"unknown error" : bstrErrorDescription, pwzDatabase);
150 + hr = S_OK;
151 + }
152 + MessageExitOnFailure(hr, msierrSQLFailedCreateDatabase, "failed to create to database: '%ls', error: %ls", pwzDatabase, NULL == bstrErrorDescription ? L"unknown error" : bstrErrorDescription);
153 +
154 + hr = WcaProgressMessage(COST_SQL_CONNECTDB, FALSE);
155 +LExit:
156 + ReleaseStr(pwzDatabaseKey);
157 + ReleaseStr(pwzServer);
158 + ReleaseStr(pwzInstance);
159 + ReleaseStr(pwzDatabase);
160 + ReleaseStr(pwzUser);
161 + ReleaseStr(pwzPassword);
162 + ReleaseObject(pidbSession);
163 + ReleaseBSTR(bstrErrorDescription);
164 +
165 + if (fInitializedCom)
166 + {
167 + ::CoUninitialize();
168 + }
169 +
170 + if (FAILED(hr))
171 + {
172 + er = ERROR_INSTALL_FAILURE;
173 + }
174 + return WcaFinalize(er);
175 +}
176 +
177 +
178 +/********************************************************************
179 + DropDatabase - CUSTOM ACTION ENTRY POINT for removing databases
180 +
181 + Input: deferred CustomActionData - DbKey\tServer\tInstance\tDatabase\tAttributes\tIntegratedAuth\tUser\tPassword
182 + * ****************************************************************/
183 +extern "C" UINT __stdcall DropDatabase(MSIHANDLE hInstall)
184 +{
185 +//Assert(FALSE);
186 + UINT er = ERROR_SUCCESS;
187 + HRESULT hr = S_OK;
188 +
189 + LPWSTR pwzData = NULL;
190 + IDBCreateSession* pidbSession = NULL;
191 + BSTR bstrErrorDescription = NULL;
192 + LPWSTR pwz = NULL;
193 + LPWSTR pwzDatabaseKey = NULL;
194 + LPWSTR pwzServer = NULL;
195 + LPWSTR pwzInstance = NULL;
196 + LPWSTR pwzDatabase = NULL;
197 + long lAttributes;
198 + BOOL fIntegratedAuth;
199 + LPWSTR pwzUser = NULL;
200 + LPWSTR pwzPassword = NULL;
201 + BOOL fInitializedCom = TRUE;
202 +
203 + hr = WcaInitialize(hInstall, "DropDatabase");
204 + ExitOnFailure(hr, "failed to initialize");
205 +
206 + hr = ::CoInitialize(NULL);
207 + ExitOnFailure(hr, "failed to intialize COM");
208 + fInitializedCom = TRUE;
209 +
210 + hr = WcaGetProperty( L"CustomActionData", &pwzData);
211 + ExitOnFailure(hr, "failed to get CustomActionData");
212 +
213 + WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData);
214 +
215 + pwz = pwzData;
216 + hr = WcaReadStringFromCaData(&pwz, &pwzDatabaseKey);
217 + ExitOnFailure(hr, "failed to read database key");
218 + hr = WcaReadStringFromCaData(&pwz, &pwzServer);
219 + ExitOnFailure(hr, "failed to read server");
220 + hr = WcaReadStringFromCaData(&pwz, &pwzInstance);
221 + ExitOnFailure(hr, "failed to read instance");
222 + hr = WcaReadStringFromCaData(&pwz, &pwzDatabase);
223 + ExitOnFailure(hr, "failed to read database");
224 + hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int *>(&lAttributes));
225 + ExitOnFailure(hr, "failed to read attributes");
226 + hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int *>(&fIntegratedAuth)); // Integrated Windows Authentication?
227 + ExitOnFailure(hr, "failed to read integrated auth flag");
228 + hr = WcaReadStringFromCaData(&pwz, &pwzUser);
229 + ExitOnFailure(hr, "failed to read user");
230 + hr = WcaReadStringFromCaData(&pwz, &pwzPassword);
231 + ExitOnFailure(hr, "failed to read password");
232 +
233 + hr = SqlDropDatabase(pwzServer, pwzInstance, pwzDatabase, fIntegratedAuth, pwzUser, pwzPassword, &bstrErrorDescription);
234 + if ((lAttributes & SCADB_CONTINUE_ON_ERROR) && FAILED(hr))
235 + {
236 + WcaLog(LOGMSG_STANDARD, "Error 0x%x: failed to drop SQL database but continuing, error: %ls, Database: %ls", hr, NULL == bstrErrorDescription ? L"unknown error" : bstrErrorDescription, pwzDatabase);
237 + hr = S_OK;
238 + }
239 + MessageExitOnFailure(hr, msierrSQLFailedDropDatabase, "failed to drop to database: '%ls', error: %ls", pwzDatabase, NULL == bstrErrorDescription ? L"unknown error" : bstrErrorDescription);
240 +
241 + hr = WcaProgressMessage(COST_SQL_CONNECTDB, FALSE);
242 +
243 +LExit:
244 + ReleaseStr(pwzDatabaseKey);
245 + ReleaseStr(pwzServer);
246 + ReleaseStr(pwzInstance);
247 + ReleaseStr(pwzDatabase);
248 + ReleaseStr(pwzUser);
249 + ReleaseStr(pwzPassword);
250 + ReleaseStr(pwzData);
251 + ReleaseObject(pidbSession);
252 + ReleaseBSTR(bstrErrorDescription);
253 +
254 + if (fInitializedCom)
255 + {
256 + ::CoUninitialize();
257 + }
258 +
259 + if (FAILED(hr))
260 + {
261 + er = ERROR_INSTALL_FAILURE;
262 + }
263 + return WcaFinalize(er);
264 +}
265 +
266 +
267 +/********************************************************************
268 + ExecuteSqlStrings - CUSTOM ACTION ENTRY POINT for running SQL strings
269 +
270 + Input: deferred CustomActionData - DbKey\tServer\tInstance\tDatabase\tAttributes\tIntegratedAuth\tUser\tPassword\tSQLKey1\tSQLString1\tSQLKey2\tSQLString2\tSQLKey3\tSQLString3\t...
271 + rollback CustomActionData - same as above
272 + * ****************************************************************/
273 +extern "C" UINT __stdcall ExecuteSqlStrings(MSIHANDLE hInstall)
274 +{
275 +//Assert(FALSE);
276 + UINT er = ERROR_SUCCESS;
277 + HRESULT hr = S_OK;
278 + HRESULT hrDB = S_OK;
279 +
280 + LPWSTR pwzData = NULL;
281 + IDBCreateSession* pidbSession = NULL;
282 + BSTR bstrErrorDescription = NULL;
283 +
284 + LPWSTR pwz = NULL;
285 + LPWSTR pwzDatabaseKey = NULL;
286 + LPWSTR pwzServer = NULL;
287 + LPWSTR pwzInstance = NULL;
288 + LPWSTR pwzDatabase = NULL;
289 + int iAttributesDB;
290 + int iAttributesSQL;
291 + BOOL fIntegratedAuth;
292 + LPWSTR pwzUser = NULL;
293 + LPWSTR pwzPassword = NULL;
294 + LPWSTR pwzSqlKey = NULL;
295 + LPWSTR pwzSql = NULL;
296 + BOOL fInitializedCom = FALSE;
297 +
298 + hr = WcaInitialize(hInstall, "ExecuteSqlStrings");
299 + ExitOnFailure(hr, "failed to initialize");
300 +
301 + hr = ::CoInitialize(NULL);
302 + ExitOnFailure(hr, "failed to intialize COM");
303 + fInitializedCom = TRUE;
304 +
305 + hr = WcaGetProperty( L"CustomActionData", &pwzData);
306 + ExitOnFailure(hr, "failed to get CustomActionData");
307 +
308 + WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData);
309 +
310 + pwz = pwzData;
311 + hr = WcaReadStringFromCaData(&pwz, &pwzDatabaseKey);
312 + ExitOnFailure(hr, "failed to read database key");
313 + hr = WcaReadStringFromCaData(&pwz, &pwzServer);
314 + ExitOnFailure(hr, "failed to read server");
315 + hr = WcaReadStringFromCaData(&pwz, &pwzInstance);
316 + ExitOnFailure(hr, "failed to read instance");
317 + hr = WcaReadStringFromCaData(&pwz, &pwzDatabase);
318 + ExitOnFailure(hr, "failed to read database");
319 + hr = WcaReadIntegerFromCaData(&pwz, &iAttributesDB);
320 + ExitOnFailure(hr, "failed to read attributes");
321 + hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int *>(&fIntegratedAuth)); // Integrated Windows Authentication?
322 + ExitOnFailure(hr, "failed to read integrated auth flag");
323 + hr = WcaReadStringFromCaData(&pwz, &pwzUser);
324 + ExitOnFailure(hr, "failed to read user");
325 + hr = WcaReadStringFromCaData(&pwz, &pwzPassword);
326 + ExitOnFailure(hr, "failed to read password");
327 +
328 + // Store off the result of the connect, only exit if we don't care if the database connection succeeds
329 + // Wait to fail until later to see if we actually have work to do that is not set to continue on error
330 + hrDB = SqlConnectDatabase(pwzServer, pwzInstance, pwzDatabase, fIntegratedAuth, pwzUser, pwzPassword, &pidbSession);
331 + if ((iAttributesDB & SCADB_CONTINUE_ON_ERROR) && FAILED(hrDB))
332 + {
333 + WcaLog(LOGMSG_STANDARD, "Error 0x%x: continuing after failure to connect to database: %ls", hrDB, pwzDatabase);
334 + ExitFunction1(hr = S_OK);
335 + }
336 +
337 + while (S_OK == hr && S_OK == (hr = WcaReadStringFromCaData(&pwz, &pwzSqlKey)))
338 + {
339 + hr = WcaReadIntegerFromCaData(&pwz, &iAttributesSQL);
340 + ExitOnFailure(hr, "failed to read attributes for SQL string: %ls", pwzSqlKey);
341 +
342 + hr = WcaReadStringFromCaData(&pwz, &pwzSql);
343 + ExitOnFailure(hr, "failed to read SQL string for key: %ls", pwzSqlKey);
344 +
345 + // If the SqlString row is set to continue on error and the DB connection failed, skip attempting to execute
346 + if ((iAttributesSQL & SCASQL_CONTINUE_ON_ERROR) && FAILED(hrDB))
347 + {
348 + WcaLog(LOGMSG_STANDARD, "Error 0x%x: continuing after failure to connect to database: %ls", hrDB, pwzDatabase);
349 + continue;
350 + }
351 +
352 + // Now check if the DB connection succeeded
353 + MessageExitOnFailure(hr = hrDB, msierrSQLFailedConnectDatabase, "failed to connect to database: '%ls'", pwzDatabase);
354 +
355 + WcaLog(LOGMSG_VERBOSE, "Executing SQL string: %ls", pwzSql);
356 + hr = SqlSessionExecuteQuery(pidbSession, pwzSql, NULL, NULL, &bstrErrorDescription);
357 + if ((iAttributesSQL & SCASQL_CONTINUE_ON_ERROR) && FAILED(hr))
358 + {
359 + WcaLog(LOGMSG_STANDARD, "Error 0x%x: failed to execute SQL string but continuing, error: %ls, SQL key: %ls SQL string: %ls", hr, NULL == bstrErrorDescription ? L"unknown error" : bstrErrorDescription, pwzSqlKey, pwzSql);
360 + hr = S_OK;
361 + }
362 + MessageExitOnFailure(hr, msierrSQLFailedExecString, "failed to execute SQL string, error: %ls, SQL key: %ls SQL string: %ls", NULL == bstrErrorDescription ? L"unknown error" : bstrErrorDescription, pwzSqlKey, pwzSql);
363 +
364 + WcaProgressMessage(COST_SQL_STRING, FALSE);
365 + }
366 + if (E_NOMOREITEMS == hr)
367 + {
368 + hr = S_OK;
369 + }
370 +
371 +LExit:
372 + ReleaseStr(pwzDatabaseKey);
373 + ReleaseStr(pwzServer);
374 + ReleaseStr(pwzInstance);
375 + ReleaseStr(pwzDatabase);
376 + ReleaseStr(pwzUser);
377 + ReleaseStr(pwzPassword);
378 + ReleaseStr(pwzData);
379 +
380 + ReleaseBSTR(bstrErrorDescription);
381 + ReleaseObject(pidbSession);
382 +
383 + if (fInitializedCom)
384 + {
385 + ::CoUninitialize();
386 + }
387 +
388 + if (FAILED(hr))
389 + {
390 + er = ERROR_INSTALL_FAILURE;
391 + }
392 + return WcaFinalize(er);
393 +}
src/ca/scasql.cpp new
+113
@@ -0,0 +1,113 @@
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 +// prototypes
6 +static HRESULT ConfigureSqlData(
7 + __in SCA_ACTION saAction
8 + );
9 +
10 +
11 +/********************************************************************
12 +InstallSqlData - CUSTOM ACTION ENTRY POINT for installing
13 + SQL data
14 +
15 +********************************************************************/
16 +extern "C" UINT __stdcall InstallSqlData(
17 + __in MSIHANDLE hInstall
18 + )
19 +{
20 + HRESULT hr = S_OK;
21 + UINT er = ERROR_SUCCESS;
22 +
23 + // initialize
24 + hr = WcaInitialize(hInstall, "InstallSqlData");
25 + ExitOnFailure(hr, "Failed to initialize");
26 +
27 + hr = ConfigureSqlData(SCA_ACTION_INSTALL);
28 +
29 +LExit:
30 + er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
31 + return WcaFinalize(er);
32 +}
33 +
34 +
35 +/********************************************************************
36 +UninstallSqlData - CUSTOM ACTION ENTRY POINT for uninstalling
37 + SQL data
38 +
39 +********************************************************************/
40 +extern "C" UINT __stdcall UninstallSqlData(
41 + __in MSIHANDLE hInstall
42 + )
43 +{
44 + HRESULT hr = S_OK;
45 + UINT er = ERROR_SUCCESS;
46 +
47 + // initialize
48 + hr = WcaInitialize(hInstall, "UninstallCertificates");
49 + ExitOnFailure(hr, "Failed to initialize");
50 +
51 + hr = ConfigureSqlData(SCA_ACTION_UNINSTALL);
52 +
53 +LExit:
54 + er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
55 + return WcaFinalize(er);
56 +}
57 +
58 +
59 +static HRESULT ConfigureSqlData(
60 + __in SCA_ACTION saAction
61 + )
62 +{
63 + //AssertSz(FALSE, "debug ConfigureSqlData()");
64 + HRESULT hr = S_OK;
65 +
66 + SCA_DB* psdList = NULL;
67 + SCA_SQLSTR* psssList = NULL;
68 +
69 + // check for the prerequsite tables
70 + if (S_OK != WcaTableExists(L"SqlDatabase"))
71 + {
72 + WcaLog(LOGMSG_VERBOSE, "skipping SQL CustomAction, no SqlDatabase table");
73 + ExitFunction1(hr = S_FALSE);
74 + }
75 +
76 + // read tables
77 + hr = ScaDbsRead(&psdList, saAction);
78 + ExitOnFailure(hr, "failed to read SqlDatabase table");
79 +
80 + hr = ScaSqlStrsRead(&psssList, saAction);
81 + ExitOnFailure(hr, "failed to read SqlStrings table");
82 +
83 + hr = ScaSqlStrsReadScripts(&psssList, saAction);
84 + ExitOnFailure(hr, "failed to read SqlScripts table");
85 +
86 + if (SCA_ACTION_UNINSTALL == saAction)
87 + {
88 + // do uninstall actions (order is important!)
89 + hr = ScaSqlStrsUninstall(psdList, psssList);
90 + ExitOnFailure(hr, "failed to execute uninstall SQL strings");
91 +
92 + hr = ScaDbsUninstall(psdList);
93 + ExitOnFailure(hr, "failed to uninstall databases");
94 + }
95 + else
96 + {
97 + // do install actions (order is important!)
98 + hr = ScaDbsInstall(psdList);
99 + ExitOnFailure(hr, "failed to install databases");
100 +
101 + hr = ScaSqlStrsInstall(psdList, psssList);
102 + ExitOnFailure(hr, "failed to execute install SQL strings, length may be too long, try add GO to break up");
103 + }
104 +
105 +LExit:
106 + if (psssList)
107 + ScaSqlStrsFreeList(psssList);
108 +
109 + if (psdList)
110 + ScaDbsFreeList(psdList);
111 +
112 + return hr;
113 +}
src/ca/scasqlstr.cpp new
+728
@@ -0,0 +1,728 @@
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 +// sql queries
6 +LPCWSTR vcsSqlStringQuery = L"SELECT `String`, `SqlDb_`, `Component_`,`SQL`,`User_`,`Attributes`,`Sequence` "
7 +L"FROM `SqlString` ORDER BY `SqlDb_`,`Sequence`";
8 +enum eSqlStringQuery { ssqSqlString = 1, ssqSqlDb, ssqComponent, ssqSQL, ssqUser, ssqAttributes, ssqSequence };
9 +
10 +LPCWSTR vcsSqlScriptQuery = L"SELECT `ScriptBinary_`,`Script`, `SqlDb_`, `Component_`,`User_`,`Attributes`,`Sequence` "
11 +L"FROM `SqlScript` ORDER BY `SqlDb_`,`Sequence`";
12 +enum eSqlScriptQuery { sscrqScriptBinary=1, sscrqSqlScript, sscrqSqlDb, sscrqComponent, sscrqUser, sscrqAttributes, sscrqSequence };
13 +
14 +LPCWSTR vcsSqlBinaryScriptQuery = L"SELECT `Data` FROM `Binary` WHERE `Name`=?";
15 +enum eSqlBinaryScriptQuery { ssbsqData = 1 };
16 +
17 +
18 +// prototypes for private helper functions
19 +static HRESULT NewSqlStr(
20 + __out SCA_SQLSTR** ppsss
21 + );
22 +static SCA_SQLSTR* AddSqlStrToList(
23 + __in SCA_SQLSTR* psssList,
24 + __in SCA_SQLSTR* psss
25 + );
26 +static HRESULT ExecuteStrings(
27 + __in SCA_DB* psdList,
28 + __in SCA_SQLSTR* psssList,
29 + __in BOOL fInstall
30 + );
31 +
32 +HRESULT ScaSqlStrsRead(
33 + __inout SCA_SQLSTR** ppsssList,
34 + __in SCA_ACTION saAction
35 + )
36 +{
37 + HRESULT hr = S_OK;
38 + UINT er = ERROR_SUCCESS;
39 + PMSIHANDLE hView, hRec;
40 + PMSIHANDLE hViewUser, hRecUser;
41 +
42 + LPWSTR pwzComponent = NULL;
43 + LPWSTR pwzData = NULL;
44 +
45 + SCA_SQLSTR* psss = NULL;
46 +
47 + if (S_OK != WcaTableExists(L"SqlString") || S_OK != WcaTableExists(L"SqlDatabase"))
48 + {
49 + WcaLog(LOGMSG_VERBOSE, "Skipping ScaSqlStrsRead() - SqlString and/or SqlDatabase table not present");
50 + ExitFunction1(hr = S_FALSE);
51 + }
52 +
53 + // loop through all the sql strings
54 + hr = WcaOpenExecuteView(vcsSqlStringQuery, &hView);
55 + ExitOnFailure(hr, "Failed to open view on SqlString table");
56 + while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
57 + {
58 + INSTALLSTATE isInstalled = INSTALLSTATE_UNKNOWN;
59 + INSTALLSTATE isAction = INSTALLSTATE_UNKNOWN;
60 +
61 + hr = WcaGetRecordString(hRec, ssqComponent, &pwzComponent);
62 + ExitOnFailure(hr, "Failed to get Component for SQL String.");
63 +
64 + er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzComponent, &isInstalled, &isAction);
65 + hr = HRESULT_FROM_WIN32(er);
66 + ExitOnFailure(hr, "Failed to get state for component: %ls", pwzComponent);
67 +
68 + // If we're doing install but the Component is not being installed or we're doing
69 + // uninstall but the Component is not being uninstalled, skip it.
70 + if ((WcaIsInstalling(isInstalled, isAction) && SCA_ACTION_INSTALL != saAction) ||
71 + (WcaIsUninstalling(isInstalled, isAction) && SCA_ACTION_UNINSTALL != saAction))
72 + {
73 + continue;
74 + }
75 +
76 + hr = NewSqlStr(&psss);
77 + ExitOnFailure(hr, "failed to allocation new sql string element");
78 +
79 + psss->isInstalled = isInstalled;
80 + psss->isAction = isAction;
81 +
82 + hr = WcaGetRecordString(hRec, ssqSqlString, &pwzData);
83 + ExitOnFailure(hr, "Failed to get SqlString.String");
84 + hr = ::StringCchCopyW(psss->wzKey, countof(psss->wzKey), pwzData);
85 + ExitOnFailure(hr, "Failed to copy SqlString.String: %ls", pwzData);
86 +
87 + // find the database information for this string
88 + hr = WcaGetRecordString(hRec, ssqSqlDb, &pwzData);
89 + ExitOnFailure(hr, "Failed to get SqlString.SqlDb_ for SqlString '%ls'", psss->wzKey);
90 + hr = ::StringCchCopyW(psss->wzSqlDb, countof(psss->wzSqlDb), pwzData);
91 + ExitOnFailure(hr, "Failed to copy SqlString.SqlDb_: %ls", pwzData);
92 +
93 + hr = WcaGetRecordInteger(hRec, ssqAttributes, &psss->iAttributes);
94 + ExitOnFailure(hr, "Failed to get SqlString.Attributes for SqlString '%ls'", psss->wzKey);
95 +
96 + //get the sequence number for the string (note that this will be sequenced with scripts too)
97 + hr = WcaGetRecordInteger(hRec, ssqSequence, &psss->iSequence);
98 + ExitOnFailure(hr, "Failed to get SqlString.Sequence for SqlString '%ls'", psss->wzKey);
99 +
100 + // execute SQL
101 + hr = WcaGetRecordFormattedString(hRec, ssqSQL, &pwzData);
102 + ExitOnFailure(hr, "Failed to get SqlString.SQL for SqlString '%ls'", psss->wzKey);
103 +
104 + Assert(!psss->pwzSql);
105 + hr = StrAllocString(&psss->pwzSql, pwzData, 0);
106 + ExitOnFailure(hr, "Failed to alloc string for SqlString '%ls'", psss->wzKey);
107 +
108 + *ppsssList = AddSqlStrToList(*ppsssList, psss);
109 + psss = NULL; // set the sss to NULL so it doesn't get freed below
110 + }
111 +
112 + if (E_NOMOREITEMS == hr)
113 + {
114 + hr = S_OK;
115 + }
116 + ExitOnFailure(hr, "Failure occured while reading SqlString table");
117 +
118 +LExit:
119 + // if anything was left over after an error clean it all up
120 + if (psss)
121 + {
122 + ScaSqlStrsFreeList(psss);
123 + }
124 +
125 + ReleaseStr(pwzData);
126 + ReleaseStr(pwzComponent);
127 +
128 + return hr;
129 +}
130 +
131 +
132 +HRESULT ScaSqlStrsReadScripts(
133 + __inout SCA_SQLSTR** ppsssList,
134 + __in SCA_ACTION saAction
135 + )
136 +{
137 + HRESULT hr = S_OK;
138 + UINT er = ERROR_SUCCESS;
139 +
140 + PMSIHANDLE hView, hRec;
141 + PMSIHANDLE hViewBinary, hRecBinary;
142 + PMSIHANDLE hViewUser, hRecUser;
143 +
144 + LPWSTR pwzComponent = NULL;
145 + LPWSTR pwzData = NULL;
146 +
147 + BYTE* pbScript = NULL;
148 + DWORD cbRead = 0;
149 + DWORD cbScript = 0;
150 + DWORD cchScript = 0;
151 +
152 + LPWSTR pwzScriptBuffer = NULL;
153 + WCHAR* pwzScript = NULL;
154 + WCHAR* pwz;
155 + DWORD cch = 0;
156 +
157 + SCA_SQLSTR sss;
158 + SCA_SQLSTR* psss = NULL;
159 +
160 + if (S_OK != WcaTableExists(L"SqlScript") || S_OK != WcaTableExists(L"SqlDatabase") || S_OK != WcaTableExists(L"Binary"))
161 + {
162 + WcaLog(LOGMSG_VERBOSE, "Skipping ScaSqlStrsReadScripts() - SqlScripts and/or SqlDatabase table not present");
163 + ExitFunction1(hr = S_FALSE);
164 + }
165 +
166 + // open a view on the binary table
167 + hr = WcaOpenView(vcsSqlBinaryScriptQuery, &hViewBinary);
168 + ExitOnFailure(hr, "Failed to open view on Binary table for SqlScripts");
169 +
170 + // loop through all the sql scripts
171 + hr = WcaOpenExecuteView(vcsSqlScriptQuery, &hView);
172 + ExitOnFailure(hr, "Failed to open view on SqlScript table");
173 + while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
174 + {
175 + INSTALLSTATE isInstalled = INSTALLSTATE_UNKNOWN;
176 + INSTALLSTATE isAction = INSTALLSTATE_UNKNOWN;
177 +
178 + hr = WcaGetRecordString(hRec, sscrqComponent, &pwzComponent);
179 + ExitOnFailure(hr, "Failed to get Component for SQL Script.");
180 +
181 + er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzComponent, &isInstalled, &isAction);
182 + hr = HRESULT_FROM_WIN32(er);
183 + ExitOnFailure(hr, "Failed to get state for component: %ls", pwzComponent);
184 +
185 + // If we're doing install but the Component is not being installed or we're doing
186 + // uninstall but the Component is not being uninstalled, skip it.
187 + if ((WcaIsInstalling(isInstalled, isAction) && SCA_ACTION_INSTALL != saAction) ||
188 + (WcaIsUninstalling(isInstalled, isAction) && SCA_ACTION_UNINSTALL != saAction))
189 + {
190 + continue;
191 + }
192 +
193 + ::ZeroMemory(&sss, sizeof(sss));
194 +
195 + sss.isInstalled = isInstalled;
196 + sss.isAction = isAction;
197 +
198 + hr = WcaGetRecordString(hRec, sscrqSqlScript, &pwzData);
199 + ExitOnFailure(hr, "Failed to get SqlScript.Script");
200 + hr = ::StringCchCopyW(sss.wzKey, countof(sss.wzKey), pwzData);
201 + ExitOnFailure(hr, "Failed to copy SqlScript.Script: %ls", pwzData);
202 +
203 + // find the database information for this string
204 + hr = WcaGetRecordString(hRec, sscrqSqlDb, &pwzData);
205 + ExitOnFailure(hr, "Failed to get SqlScript.SqlDb_ for SqlScript '%ls'", sss.wzKey);
206 + hr = ::StringCchCopyW(sss.wzSqlDb, countof(sss.wzSqlDb), pwzData);
207 + ExitOnFailure(hr, "Failed to copy SqlScritp.SqlDbb: %ls", pwzData);
208 +
209 + hr = WcaGetRecordInteger(hRec, sscrqAttributes, &sss.iAttributes);
210 + ExitOnFailure(hr, "Failed to get SqlScript.Attributes for SqlScript '%ls'", sss.wzKey);
211 +
212 + hr = WcaGetRecordInteger(hRec, sscrqSequence, &sss.iSequence);
213 + ExitOnFailure(hr, "Failed to get SqlScript.Sequence for SqlScript '%ls'", sss.wzKey);
214 +
215 + // get the sql script out of the binary stream
216 + hr = WcaExecuteView(hViewBinary, hRec);
217 + ExitOnFailure(hr, "Failed to open SqlScript.BinaryScript_ for SqlScript '%ls'", sss.wzKey);
218 + hr = WcaFetchSingleRecord(hViewBinary, &hRecBinary);
219 + ExitOnFailure(hr, "Failed to fetch SqlScript.BinaryScript_ for SqlScript '%ls'", sss.wzKey);
220 +
221 + // Note: We need to allocate an extra character on the stream to NULL terminate the SQL script.
222 + // The WcaGetRecordStream() function won't let us add extra space on the end of the stream
223 + // so we'll read the stream "the old fashioned way".
224 + //hr = WcaGetRecordStream(hRecBinary, ssbsqData, (BYTE**)&pbScript, &cbScript);
225 + //ExitOnFailure(hr, "Failed to read SqlScript.BinaryScript_ for SqlScript '%ls'", sss.wzKey);
226 + er = ::MsiRecordReadStream(hRecBinary, ssbsqData, NULL, &cbRead);
227 + hr = HRESULT_FROM_WIN32(er);
228 + ExitOnFailure(hr, "failed to get size of stream");
229 +
230 + cbScript = cbRead + sizeof(WCHAR); // we may have an ANSI SQL script but leave enough to even NULL terminate a WCHAR string
231 + hr = WcaAllocStream(&pbScript, cbScript); // this will allocate a fully zeroed out buffer so our string will be NULL terminated
232 + ExitOnFailure(hr, "failed to allocate data for stream");
233 +
234 + er = ::MsiRecordReadStream(hRecBinary, ssbsqData, reinterpret_cast<char*>(pbScript), &cbRead); //read the buffer but leave the space for the NULL terminator
235 + hr = HRESULT_FROM_WIN32(er);
236 + ExitOnFailure(hr, "failed to read from stream");
237 +
238 + Assert(cbRead + sizeof(WCHAR) == cbScript);
239 +
240 + // Check for the UNICODE BOM file marker.
241 + if ((0xFF == *pbScript) && (0xFE == *(pbScript + 1)))
242 + {
243 + // Copy the UNICODE string after the BOM marker (subtract one because we'll skip the BOM marker).
244 + cchScript = (cbScript / sizeof(WCHAR)) - 1;
245 +
246 + hr = StrAllocString(&pwzScriptBuffer, reinterpret_cast<LPWSTR>(pbScript) + 1, 0);
247 + ExitOnFailure(hr, "Failed to allocate WCHAR string of size '%d'", cchScript);
248 + }
249 + else
250 + {
251 + // We have an ANSI string so convert it to UNICODE.
252 + cchScript = cbScript;
253 +
254 + hr = StrAllocStringAnsi(&pwzScriptBuffer, reinterpret_cast<LPCSTR>(pbScript), 0, CP_ACP);
255 + ExitOnFailure(hr, "Failed to allocate WCHAR string of size '%d'", cchScript);
256 + }
257 +
258 + // Free the byte buffer since it has been converted to a new UNICODE string, one way or another.
259 + if (pbScript)
260 + {
261 + WcaFreeStream(pbScript);
262 + pbScript = NULL;
263 + }
264 +
265 + // Process the SQL script stripping out unnecessary stuff (like comments) and looking for "GO" statements.
266 + pwzScript = pwzScriptBuffer;
267 + while (cchScript && pwzScript && *pwzScript)
268 + {
269 + // strip off leading whitespace
270 + while (cchScript && *pwzScript && iswspace(*pwzScript))
271 + {
272 + ++pwzScript;
273 + --cchScript;
274 + }
275 +
276 + Assert(0 <= cchScript);
277 +
278 + // if there is a SQL comment remove it
279 + while (cchScript && L'/' == *pwzScript && L'*' == *(pwzScript + 1))
280 + {
281 + // go until end of comment
282 + while (cchScript && *pwzScript && *(pwzScript + 1) && !(L'*' == *pwzScript && L'/' == *(pwzScript + 1)))
283 + {
284 + ++pwzScript;
285 + --cchScript;
286 + }
287 +
288 + Assert(2 <= cchScript);
289 +
290 + if (2 <= cchScript)
291 + {
292 + // to account for */ at end
293 + pwzScript+=2;
294 + cchScript-=2;
295 + }
296 +
297 + Assert(0 <= cchScript);
298 +
299 + // strip off any new leading whitespace
300 + while (cchScript && *pwzScript && iswspace(*pwzScript))
301 + {
302 + ++pwzScript;
303 + --cchScript;
304 + }
305 + }
306 +
307 + while (cchScript && L'-' == *pwzScript && L'-' == *(pwzScript + 1))
308 + {
309 + // go past the new line character
310 + while (cchScript && *pwzScript && L'\n' != *pwzScript)
311 + {
312 + ++pwzScript;
313 + --cchScript;
314 + }
315 +
316 + Assert(0 <= cchScript);
317 +
318 + if (cchScript && L'\n' == *pwzScript)
319 + {
320 + ++pwzScript;
321 + --cchScript;
322 + }
323 +
324 + Assert(0 <= cchScript);
325 +
326 + // strip off any new leading whitespace
327 + while (cchScript && *pwzScript && iswspace(*pwzScript))
328 + {
329 + ++pwzScript;
330 + --cchScript;
331 + }
332 + }
333 +
334 + Assert(0 <= cchScript);
335 +
336 + // try to isolate a "GO" keyword and count the characters in the SQL string
337 + pwz = pwzScript;
338 + cch = 0;
339 + while (cchScript && *pwz)
340 + {
341 + //skip past comment lines that might have "go" in them
342 + //note that these comments are "in the middle" of our function,
343 + //or possibly at the end of a line
344 + if (cchScript && L'-' == *pwz && L'-' == *(pwz + 1))
345 + {
346 + // skip past chars until the new line character
347 + while (cchScript && *pwz && (L'\n' != *pwz))
348 + {
349 + ++pwz;
350 + ++cch;
351 + --cchScript;
352 + }
353 + }
354 +
355 + //skip past comment lines of form /* to */ that might have "go" in them
356 + //note that these comments are "in the middle" of our function,
357 + //or possibly at the end of a line
358 + if (cchScript && L'/' == *pwz && L'*' == *(pwz + 1))
359 + {
360 + // skip past chars until the new line character
361 + while (cchScript && *pwz && *(pwz + 1) && !((L'*' == *pwz) && (L'/' == *(pwz + 1))))
362 + {
363 + ++pwz;
364 + ++cch;
365 + --cchScript;
366 + }
367 +
368 + if (2 <= cchScript)
369 + {
370 + // to account for */ at end
371 + pwz+=2;
372 + cch+=2;
373 + cchScript-=2;
374 + }
375 + }
376 +
377 + // Skip past strings that may be part of the SQL statement that might have a "go" in them
378 + if ( cchScript && L'\'' == *pwz )
379 + {
380 + ++pwz;
381 + ++cch;
382 + --cchScript;
383 +
384 + // Skip past chars until the end of the string
385 + while ( cchScript && *pwz && !(L'\'' == *pwz) )
386 + {
387 + ++pwz;
388 + ++cch;
389 + --cchScript;
390 + }
391 + }
392 +
393 + // Skip past strings that may be part of the SQL statement that might have a "go" in them
394 + if ( cchScript && L'\"' == *pwz )
395 + {
396 + ++pwz;
397 + ++cch;
398 + --cchScript;
399 +
400 + // Skip past chars until the end of the string
401 + while ( cchScript && *pwz && !(L'\"' == *pwz) )
402 + {
403 + ++pwz;
404 + ++cch;
405 + --cchScript;
406 + }
407 + }
408 +
409 + // if "GO" is isolated
410 + if ((pwzScript == pwz || iswspace(*(pwz - 1))) &&
411 + (L'G' == *pwz || L'g' == *pwz) &&
412 + (L'O' == *(pwz + 1) || L'o' == *(pwz + 1)) &&
413 + (0 == *(pwz + 2) || iswspace(*(pwz + 2))))
414 + {
415 + *pwz = 0; // null terminate the SQL string on the "G"
416 + pwz += 2;
417 + cchScript -= 2;
418 + break; // found "GO" now add SQL string to list
419 + }
420 +
421 + ++pwz;
422 + ++cch;
423 + --cchScript;
424 + }
425 +
426 + Assert(0 <= cchScript);
427 +
428 + if (0 < cch) //don't process if there's nothing to process
429 + {
430 + // replace tabs with spaces
431 + for (LPWSTR pwzTab = wcsstr(pwzScript, L"\t"); pwzTab; pwzTab = wcsstr(pwzTab, L"\t"))
432 + *pwzTab = ' ';
433 +
434 + // strip off whitespace at the end of the script string
435 + for (LPWSTR pwzErase = pwzScript + cch - 1; pwzScript < pwzErase && iswspace(*pwzErase); pwzErase--)
436 + {
437 + *(pwzErase) = 0;
438 + cch--;
439 + }
440 + }
441 +
442 + if (0 < cch)
443 + {
444 + hr = NewSqlStr(&psss);
445 + ExitOnFailure(hr, "failed to allocate new sql string element");
446 +
447 + // copy everything over
448 + hr = ::StringCchCopyW(psss->wzKey, countof(psss->wzKey), sss.wzKey);
449 + ExitOnFailure(hr, "Failed to copy key string to sqlstr object");
450 + hr = ::StringCchCopyW(psss->wzSqlDb, countof(psss->wzSqlDb), sss.wzSqlDb);
451 + ExitOnFailure(hr, "Failed to copy DB string to sqlstr object");
452 + hr = ::StringCchCopyW(psss->wzComponent, countof(psss->wzComponent), sss.wzComponent);
453 + ExitOnFailure(hr, "Failed to copy component string to sqlstr object");
454 + psss->isInstalled = sss.isInstalled;
455 + psss->isAction = sss.isAction;
456 + psss->iAttributes = sss.iAttributes;
457 + psss->iSequence = sss.iSequence;
458 +
459 + // cchRequired includes the NULL terminating char
460 + hr = StrAllocString(&psss->pwzSql, pwzScript, 0);
461 + ExitOnFailure(hr, "Failed to allocate string for SQL script: '%ls'", psss->wzKey);
462 +
463 + *ppsssList = AddSqlStrToList(*ppsssList, psss);
464 + psss = NULL; // set the db NULL so it doesn't accidentally get freed below
465 + }
466 +
467 + pwzScript = pwz;
468 + }
469 + }
470 +
471 + if (E_NOMOREITEMS == hr)
472 + {
473 + hr = S_OK;
474 + }
475 + ExitOnFailure(hr, "Failure occured while reading SqlString table");
476 +
477 +LExit:
478 + // if anything was left over after an error clean it all up
479 + if (psss)
480 + {
481 + ScaSqlStrsFreeList(psss);
482 + }
483 +
484 + if (pbScript)
485 + {
486 + WcaFreeStream(pbScript);
487 + }
488 +
489 + ReleaseStr(pwzScriptBuffer);
490 + ReleaseStr(pwzData);
491 + ReleaseStr(pwzComponent);
492 +
493 + return hr;
494 +}
495 +
496 +
497 +HRESULT ScaSqlStrsInstall(
498 + __in SCA_DB* psdList,
499 + __in SCA_SQLSTR* psssList
500 + )
501 +{
502 + HRESULT hr = ExecuteStrings(psdList, psssList, TRUE);
503 +
504 + return hr;
505 +}
506 +
507 +
508 +HRESULT ScaSqlStrsUninstall(
509 + __in SCA_DB* psdList,
510 + __in SCA_SQLSTR* psssList
511 + )
512 +{
513 + HRESULT hr = ExecuteStrings(psdList, psssList, FALSE);
514 +
515 + return hr;
516 +}
517 +
518 +
519 +void ScaSqlStrsFreeList(
520 + __in SCA_SQLSTR* psssList
521 + )
522 +{
523 + SCA_SQLSTR* psssDelete = psssList;
524 + while (psssList)
525 + {
526 + psssDelete = psssList;
527 + psssList = psssList->psssNext;
528 +
529 + if (psssDelete->pwzSql)
530 + {
531 + ReleaseStr(psssDelete->pwzSql);
532 + }
533 +
534 + MemFree(psssDelete);
535 + }
536 +}
537 +
538 +
539 +// private helper functions
540 +
541 +static HRESULT NewSqlStr(
542 + __out SCA_SQLSTR** ppsss
543 + )
544 +{
545 + HRESULT hr = S_OK;
546 + SCA_SQLSTR* psss = static_cast<SCA_SQLSTR*>(MemAlloc(sizeof(SCA_SQLSTR), TRUE));
547 + ExitOnNull(psss, hr, E_OUTOFMEMORY, "failed to allocate memory for new sql string element");
548 +
549 + *ppsss = psss;
550 +
551 +LExit:
552 + return hr;
553 +}
554 +
555 +
556 +static SCA_SQLSTR* AddSqlStrToList(
557 + __in SCA_SQLSTR* psssList,
558 + __in SCA_SQLSTR* psss
559 + )
560 +{
561 + Assert(psss); //just checking
562 +
563 + //make certain we have a valid sequence number; note that negatives are technically valid
564 + if (MSI_NULL_INTEGER == psss->iSequence)
565 + {
566 + psss->iSequence = 0;
567 + }
568 +
569 + if (psssList)
570 + {
571 + //list already exists, so insert psss into the list in Sequence order
572 +
573 + //see if we need to change the head, otherwise figure out where in the order it fits
574 + if (psss->iSequence < psssList->iSequence)
575 + {
576 + psss->psssNext = psssList;
577 + psssList = psss;
578 + }
579 + else
580 + {
581 + SCA_SQLSTR* psssT = psssList;
582 + //note that if Sequence numbers are duplicated, as in the case of a sqlscript,
583 + //we need to insert them "at the end" of the group so the sqlfile stays in order
584 + while (psssT->psssNext && (psssT->psssNext->iSequence <= psss->iSequence))
585 + {
586 + psssT = psssT->psssNext;
587 + }
588 +
589 + //insert our new psss AFTER psssT
590 + psss->psssNext = psssT->psssNext;
591 + psssT->psssNext = psss;
592 + }
593 + }
594 + else
595 + {
596 + psssList = psss;
597 + }
598 +
599 + return psssList;
600 +}
601 +
602 +
603 +static HRESULT ExecuteStrings(
604 + __in SCA_DB* psdList,
605 + __in SCA_SQLSTR* psssList,
606 + __in BOOL fInstall
607 + )
608 +{
609 + HRESULT hr = S_FALSE; // assume nothing will be done
610 +
611 + int iRollback = -1;
612 + int iOldRollback = iRollback;
613 +
614 + LPCWSTR wzOldDb = NULL;
615 + UINT uiCost = 0;
616 + WCHAR* pwzCustomActionData = NULL;
617 + WCHAR wzNumber[64];
618 +
619 + // loop through all sql strings
620 + for (SCA_SQLSTR* psss = psssList; psss; psss = psss->psssNext)
621 + {
622 + // if installing this component
623 + if ((fInstall && (psss->iAttributes & SCASQL_EXECUTE_ON_INSTALL) && WcaIsInstalling(psss->isInstalled, psss->isAction) && !WcaIsReInstalling(psss->isInstalled, psss->isAction)) ||
624 + (fInstall && (psss->iAttributes & SCASQL_EXECUTE_ON_REINSTALL) && WcaIsReInstalling(psss->isInstalled, psss->isAction)) ||
625 + (!fInstall && (psss->iAttributes & SCASQL_EXECUTE_ON_UNINSTALL) && WcaIsUninstalling(psss->isInstalled, psss->isAction)))
626 + {
627 + // determine if this is a rollback scheduling or normal deferred scheduling
628 + if (psss->iAttributes & SCASQL_ROLLBACK)
629 + {
630 + iRollback = 1;
631 + }
632 + else
633 + {
634 + iRollback = 0;
635 + }
636 +
637 + // if we need to create a connection to a new server\database
638 + if (!wzOldDb || 0 != lstrcmpW(wzOldDb, psss->wzSqlDb) || iOldRollback != iRollback)
639 + {
640 + const SCA_DB* psd = ScaDbsFindDatabase(psss->wzSqlDb, psdList);
641 + if (!psd)
642 + {
643 + ExitOnFailure(hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND), "failed to find data for Database: %ls", psss->wzSqlDb);
644 + }
645 +
646 + if (-1 == iOldRollback)
647 + {
648 + iOldRollback = iRollback;
649 + }
650 + Assert(0 == iOldRollback || 1 == iOldRollback);
651 +
652 + // if there was custom action data before, schedule the action to write it
653 + if (pwzCustomActionData && *pwzCustomActionData)
654 + {
655 + Assert(pwzCustomActionData && *pwzCustomActionData && uiCost);
656 +
657 + hr = WcaDoDeferredAction(1 == iOldRollback ? L"RollbackExecuteSqlStrings" : L"ExecuteSqlStrings", pwzCustomActionData, uiCost);
658 + ExitOnFailure(hr, "failed to schedule ExecuteSqlStrings action, rollback: %d", iOldRollback);
659 + iOldRollback = iRollback;
660 +
661 + *pwzCustomActionData = L'\0';
662 + uiCost = 0;
663 + }
664 +
665 + Assert(!pwzCustomActionData || (pwzCustomActionData && 0 == *pwzCustomActionData) && 0 == uiCost);
666 +
667 + hr = WcaWriteStringToCaData(psd->wzKey, &pwzCustomActionData);
668 + ExitOnFailure(hr, "Failed to add SQL Server Database String to CustomActionData for Database String: %ls", psd->wzKey);
669 +
670 + hr = WcaWriteStringToCaData(psd->wzServer, &pwzCustomActionData);
671 + ExitOnFailure(hr, "Failed to add SQL Server to CustomActionData for Database String: %ls", psd->wzKey);
672 +
673 + hr = WcaWriteStringToCaData(psd->wzInstance, &pwzCustomActionData);
674 + ExitOnFailure(hr, "Failed to add SQL Instance to CustomActionData for Database String: %ls", psd->wzKey);
675 +
676 + hr = WcaWriteStringToCaData(psd->wzDatabase, &pwzCustomActionData);
677 + ExitOnFailure(hr, "Failed to add SQL Database to CustomActionData for Database String: %ls", psd->wzKey);
678 +
679 + hr = ::StringCchPrintfW(wzNumber, countof(wzNumber), L"%d", psd->iAttributes);
680 + ExitOnFailure(hr, "Failed to format attributes integer value to string");
681 + hr = WcaWriteStringToCaData(wzNumber, &pwzCustomActionData);
682 + ExitOnFailure(hr, "Failed to add SQL Attributes to CustomActionData for Database String: %ls", psd->wzKey);
683 +
684 + hr = ::StringCchPrintfW(wzNumber, countof(wzNumber), L"%d", psd->fUseIntegratedAuth);
685 + ExitOnFailure(hr, "Failed to format UseIntegratedAuth integer value to string");
686 + hr = WcaWriteStringToCaData(wzNumber, &pwzCustomActionData);
687 + ExitOnFailure(hr, "Failed to add SQL IntegratedAuth flag to CustomActionData for Database String: %ls", psd->wzKey);
688 +
689 + hr = WcaWriteStringToCaData(psd->scau.wzName, &pwzCustomActionData);
690 + ExitOnFailure(hr, "Failed to add SQL UserName to CustomActionData for Database String: %ls", psd->wzKey);
691 +
692 + hr = WcaWriteStringToCaData(psd->scau.wzPassword, &pwzCustomActionData);
693 + ExitOnFailure(hr, "Failed to add SQL Password to CustomActionData for Database String: %ls", psd->wzKey);
694 +
695 + uiCost += COST_SQL_CONNECTDB;
696 +
697 + wzOldDb = psss->wzSqlDb;
698 + }
699 +
700 + WcaLog(LOGMSG_VERBOSE, "Scheduling SQL string: %ls", psss->pwzSql);
701 +
702 + hr = WcaWriteStringToCaData(psss->wzKey, &pwzCustomActionData);
703 + ExitOnFailure(hr, "Failed to add SQL Key to CustomActionData for SQL string: %ls", psss->wzKey);
704 +
705 + hr = WcaWriteIntegerToCaData(psss->iAttributes, &pwzCustomActionData);
706 + ExitOnFailure(hr, "failed to add attributes to CustomActionData for SQL string: %ls", psss->wzKey);
707 +
708 + hr = WcaWriteStringToCaData(psss->pwzSql, &pwzCustomActionData);
709 + ExitOnFailure(hr, "Failed to to add SQL Query to CustomActionData for SQL string: %ls", psss->wzKey);
710 + uiCost += COST_SQL_STRING;
711 + }
712 + }
713 +
714 + if (pwzCustomActionData && *pwzCustomActionData)
715 + {
716 + Assert(pwzCustomActionData && *pwzCustomActionData && uiCost);
717 + hr = WcaDoDeferredAction(1 == iRollback ? L"RollbackExecuteSqlStrings" : L"ExecuteSqlStrings", pwzCustomActionData, uiCost);
718 + ExitOnFailure(hr, "Failed to schedule ExecuteSqlStrings action");
719 +
720 + *pwzCustomActionData = L'\0';
721 + uiCost = 0;
722 + }
723 +
724 +LExit:
725 + ReleaseStr(pwzCustomActionData);
726 +
727 + return hr;
728 +}
src/ca/scasqlstr.h new
+51
@@ -0,0 +1,51 @@
1 +#pragma once
2 +// 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.
3 +
4 +
5 +#include "scadb.h"
6 +
7 +struct SCA_SQLSTR
8 +{
9 + // darwin information
10 + WCHAR wzKey[MAX_DARWIN_KEY + 1];
11 + WCHAR wzComponent[MAX_DARWIN_KEY + 1];
12 + INSTALLSTATE isInstalled, isAction;
13 +
14 + WCHAR wzSqlDb[MAX_DARWIN_COLUMN + 1];
15 +
16 + BOOL fHasUser;
17 + SCA_USER scau;
18 +
19 + LPWSTR pwzSql;
20 + int iAttributes;
21 + int iSequence; //used to sequence SqlString and SqlScript tables together
22 +
23 + SCA_SQLSTR* psssNext;
24 +};
25 +
26 +
27 +// prototypes
28 +HRESULT ScaSqlStrsRead(
29 + __inout SCA_SQLSTR** ppsssList,
30 + __in SCA_ACTION saAction
31 + );
32 +
33 +HRESULT ScaSqlStrsReadScripts(
34 + __inout SCA_SQLSTR** ppsssList,
35 + __in SCA_ACTION saAction
36 + );
37 +
38 +HRESULT ScaSqlStrsInstall(
39 + __in SCA_DB* psdList,
40 + __in SCA_SQLSTR* psssList
41 + );
42 +
43 +HRESULT ScaSqlStrsUninstall(
44 + __in SCA_DB* psdList,
45 + __in SCA_SQLSTR* psssList
46 + );
47 +
48 +void ScaSqlStrsFreeList(
49 + __in SCA_SQLSTR* psssList
50 + );
51 +
src/ca/scauser.cpp new
+82
@@ -0,0 +1,82 @@
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 +LPCWSTR vcsUserQuery = L"SELECT `User`, `Component_`, `Name`, `Domain`, `Password` FROM `User` WHERE `User`=?";
6 +enum eUserQuery { vuqUser = 1, vuqComponent, vuqName, vuqDomain, vuqPassword };
7 +
8 +
9 +HRESULT __stdcall ScaGetUser(
10 + __in LPCWSTR wzUser,
11 + __out SCA_USER* pscau
12 + )
13 +{
14 + if (!wzUser || !pscau)
15 + {
16 + return E_INVALIDARG;
17 + }
18 +
19 + HRESULT hr = S_OK;
20 + PMSIHANDLE hView, hRec;
21 +
22 + LPWSTR pwzData = NULL;
23 +
24 + // clear struct and bail right away if no user key was passed to search for
25 + ::ZeroMemory(pscau, sizeof(*pscau));
26 + if (!*wzUser)
27 + {
28 + ExitFunction1(hr = S_OK);
29 + }
30 +
31 + hRec = ::MsiCreateRecord(1);
32 + hr = WcaSetRecordString(hRec, 1, wzUser);
33 + ExitOnFailure(hr, "Failed to look up User");
34 +
35 + hr = WcaOpenView(vcsUserQuery, &hView);
36 + ExitOnFailure(hr, "Failed to open view on User table");
37 + hr = WcaExecuteView(hView, hRec);
38 + ExitOnFailure(hr, "Failed to execute view on User table");
39 +
40 + hr = WcaFetchSingleRecord(hView, &hRec);
41 + if (S_OK == hr)
42 + {
43 + hr = WcaGetRecordString(hRec, vuqUser, &pwzData);
44 + ExitOnFailure(hr, "Failed to get User.User");
45 + hr = ::StringCchCopyW(pscau->wzKey, countof(pscau->wzKey), pwzData);
46 + ExitOnFailure(hr, "Failed to copy key string to user object");
47 +
48 + hr = WcaGetRecordString(hRec, vuqComponent, &pwzData);
49 + ExitOnFailure(hr, "Failed to get User.Component_");
50 + hr = ::StringCchCopyW(pscau->wzComponent, countof(pscau->wzComponent), pwzData);
51 + ExitOnFailure(hr, "Failed to copy component string to user object");
52 +
53 + hr = WcaGetRecordFormattedString(hRec, vuqName, &pwzData);
54 + ExitOnFailure(hr, "Failed to get User.Name");
55 + hr = ::StringCchCopyW(pscau->wzName, countof(pscau->wzName), pwzData);
56 + ExitOnFailure(hr, "Failed to copy name string to user object");
57 +
58 + hr = WcaGetRecordFormattedString(hRec, vuqDomain, &pwzData);
59 + ExitOnFailure(hr, "Failed to get User.Domain");
60 + hr = ::StringCchCopyW(pscau->wzDomain, countof(pscau->wzDomain), pwzData);
61 + ExitOnFailure(hr, "Failed to copy domain string to user object");
62 +
63 + hr = WcaGetRecordFormattedString(hRec, vuqPassword, &pwzData);
64 + ExitOnFailure(hr, "Failed to get User.Password");
65 + hr = ::StringCchCopyW(pscau->wzPassword, countof(pscau->wzPassword), pwzData);
66 + ExitOnFailure(hr, "Failed to copy password string to user object");
67 + }
68 + else if (E_NOMOREITEMS == hr)
69 + {
70 + WcaLog(LOGMSG_STANDARD, "Error: Cannot locate User.User='%ls'", wzUser);
71 + hr = E_FAIL;
72 + }
73 + else
74 + {
75 + ExitOnFailure(hr, "Error or found multiple matching User rows");
76 + }
77 +
78 +LExit:
79 + ReleaseStr(pwzData);
80 +
81 + return hr;
82 +}
src/ca/scauser.h new
+40
@@ -0,0 +1,40 @@
1 +#pragma once
2 +// 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.
3 +
4 +
5 +
6 +// structs
7 +struct SCA_GROUP
8 +{
9 + WCHAR wzKey[MAX_DARWIN_KEY + 1];
10 + WCHAR wzComponent[MAX_DARWIN_KEY + 1];
11 +
12 + WCHAR wzDomain[MAX_DARWIN_COLUMN + 1];
13 + WCHAR wzName[MAX_DARWIN_COLUMN + 1];
14 +
15 + SCA_GROUP *psgNext;
16 +};
17 +
18 +struct SCA_USER
19 +{
20 + WCHAR wzKey[MAX_DARWIN_KEY + 1];
21 + WCHAR wzComponent[MAX_DARWIN_KEY + 1];
22 + INSTALLSTATE isInstalled;
23 + INSTALLSTATE isAction;
24 +
25 + WCHAR wzDomain[MAX_DARWIN_COLUMN + 1];
26 + WCHAR wzName[MAX_DARWIN_COLUMN + 1];
27 + WCHAR wzPassword[MAX_DARWIN_COLUMN + 1];
28 + INT iAttributes;
29 +
30 + SCA_GROUP *psgGroups;
31 +
32 + SCA_USER *psuNext;
33 +};
34 +
35 +
36 +// prototypes
37 +HRESULT __stdcall ScaGetUser(
38 + __in LPCWSTR wzUser,
39 + __out SCA_USER* pscau
40 + );
src/ca/sqlca.def
+7 -1
@@ -4,4 +4,10 @@
4 LIBRARY "sqlca"
5
6 EXPORTS
7 -
7 +;scaexec.cpp
8 + CreateDatabase
9 + DropDatabase
10 + ExecuteSqlStrings
11 +;scasql.cpp
12 + InstallSqlData
13 + UninstallSqlData
src/ca/sqlca.vcxproj
+11
@@ -45,11 +45,22 @@
45 <ClCompile Include="dllmain.cpp">
46 <PrecompiledHeader>Create</PrecompiledHeader>
47 </ClCompile>
48 + <ClCompile Include="scadb.cpp" />
49 + <ClCompile Include="scaexec.cpp" />
50 + <ClCompile Include="scasql.cpp" />
51 + <ClCompile Include="scasqlstr.cpp" />
52 + <ClCompile Include="scauser.cpp" />
53 <ClCompile Include="sqlca.cpp" />
54 </ItemGroup>
55
56 <ItemGroup>
57 + <ClInclude Include="CustomMsiErrors.h" />
58 <ClInclude Include="precomp.h" />
59 + <ClInclude Include="sca.h" />
60 + <ClInclude Include="scacost.h" />
61 + <ClInclude Include="scadb.h" />
62 + <ClInclude Include="scasqlstr.h" />
63 + <ClInclude Include="scauser.h" />
64 </ItemGroup>
65
66 <ItemGroup>