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>