aboutsummaryrefslogtreecommitdiff
path: root/src/libs/wcautil/WixToolset.WcaUtil/wcawrapquery.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/wcautil/WixToolset.WcaUtil/wcawrapquery.cpp')
-rw-r--r--src/libs/wcautil/WixToolset.WcaUtil/wcawrapquery.cpp717
1 files changed, 717 insertions, 0 deletions
diff --git a/src/libs/wcautil/WixToolset.WcaUtil/wcawrapquery.cpp b/src/libs/wcautil/WixToolset.WcaUtil/wcawrapquery.cpp
new file mode 100644
index 00000000..a3b593fd
--- /dev/null
+++ b/src/libs/wcautil/WixToolset.WcaUtil/wcawrapquery.cpp
@@ -0,0 +1,717 @@
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#include "wcawrapquery.h"
5
6static const LPWSTR ISINSTALLEDCOLUMNNAME = L"ISInstalled";
7static const LPWSTR ISACTIONCOLUMNNAME = L"ISAction";
8static const LPWSTR SOURCEPATHCOLUMNNAME = L"SourcePath";
9static const LPWSTR TARGETPATHCOLUMNNAME = L"TargetPath";
10
11// This instantiates a new query object in the deferred CA, and returns the handle to the query
12WCA_WRAPQUERY_HANDLE WIXAPI GetNewQueryInstance(
13 DWORD dwInColumns,
14 DWORD dwInRows
15 )
16{
17 HRESULT hr = S_OK;
18
19 WCA_WRAPQUERY_HANDLE hNewHandle = NULL;
20
21 hNewHandle = static_cast<WCA_WRAPQUERY_HANDLE>(MemAlloc(sizeof(WCA_WRAPQUERY_STRUCT), TRUE));
22 if (NULL == hNewHandle)
23 {
24 hr = E_OUTOFMEMORY;
25 ExitOnFailure(hr, "Failed to allocate Query Instance");
26 }
27
28 // Initialize non-array members
29 hNewHandle->dwColumns = dwInColumns;
30 hNewHandle->dwRows = dwInRows;
31 hNewHandle->dwNextIndex = 0;
32
33 // Initialize arrays
34 if (0 != hNewHandle->dwColumns)
35 {
36 hNewHandle->pcdtColumnType = static_cast<eColumnDataType *>(MemAlloc(hNewHandle->dwColumns * sizeof(eColumnDataType), TRUE));
37 if (NULL == hNewHandle->pcdtColumnType)
38 {
39 hr = E_OUTOFMEMORY;
40 ExitOnFailure(hr, "Failed to allocate column type array");
41 }
42
43 hNewHandle->ppwzColumnNames = static_cast<LPWSTR *>(MemAlloc(hNewHandle->dwColumns * sizeof(LPWSTR), TRUE));
44 if (NULL == hNewHandle->ppwzColumnNames)
45 {
46 hr = E_OUTOFMEMORY;
47 ExitOnFailure(hr, "Failed to allocate column names array");
48 }
49 }
50
51 for (DWORD i=0;i<hNewHandle->dwColumns;i++)
52 {
53 hNewHandle->pcdtColumnType[i] = cdtUnknown;
54 hNewHandle->ppwzColumnNames[i] = NULL;
55 }
56
57 if (0 != hNewHandle->dwRows)
58 {
59 hNewHandle->phRecords = static_cast<MSIHANDLE *>(MemAlloc(hNewHandle->dwRows * sizeof(MSIHANDLE), TRUE));
60 if (NULL == hNewHandle->phRecords)
61 {
62 hr = E_OUTOFMEMORY;
63 ExitOnFailure(hr, "Failed to allocate records array");
64 }
65 }
66
67 for (DWORD i=0;i<hNewHandle->dwRows;i++)
68 {
69 hNewHandle->phRecords[i] = NULL;
70 }
71
72 return hNewHandle;
73
74LExit:
75 // The handle isn't complete, so destroy any memory it allocated before returning NULL
76 if (NULL != hNewHandle)
77 {
78 WcaFinishUnwrapQuery(hNewHandle);
79 }
80
81 return NULL;
82}
83
84// This function takes in the column type string from MsiViewGetColumnInfo, and returns
85// whether the column stores strings, ints, binary streams, or
86// cdtUnknown if this information couldn't be determined.
87eColumnDataType WIXAPI GetDataTypeFromString(
88 LPCWSTR pwzTypeString
89 )
90{
91 if (!pwzTypeString || !*pwzTypeString)
92 {
93 return cdtUnknown;
94 }
95
96 switch (pwzTypeString[0])
97 {
98 case 'v':
99 case 'V':
100 case 'o':
101 case 'O':
102 return cdtStream;
103
104 case 'g':
105 case 'G':
106 case 's':
107 case 'S':
108 case 'l':
109 case 'L':
110 return cdtString;
111
112 case 'i':
113 case 'I':
114 case 'j':
115 case 'J':
116 return cdtInt;
117
118 default:
119 return cdtUnknown;
120 }
121}
122
123HRESULT WIXAPI WcaWrapEmptyQuery(
124 __inout LPWSTR * ppwzCustomActionData
125 )
126{
127 HRESULT hr = S_OK;
128
129 WcaLog(LOGMSG_TRACEONLY, "Wrapping result of empty query");
130
131 hr = WcaWriteIntegerToCaData(static_cast<int>(wqaTableBegin), ppwzCustomActionData);
132 ExitOnFailure(hr, "Failed to write table begin marker to custom action data");
133
134 hr = WcaWriteIntegerToCaData(0, ppwzCustomActionData);
135 ExitOnFailure(hr, "Failed to write number of columns to custom action data");
136
137 hr = WcaWriteIntegerToCaData(0, ppwzCustomActionData);
138 ExitOnFailure(hr, "Failed to write number of rows to custom action data");
139
140 hr = WcaWriteIntegerToCaData(static_cast<int>(wqaTableFinish), ppwzCustomActionData);
141 ExitOnFailure(hr, "Failed to write table finish marker to custom action data");
142
143// WcaLog(LOGMSG_TRACEONLY, "Finished wrapping result of empty query");
144
145LExit:
146 return hr;
147}
148
149/********************************************************************
150WcaWrapQuery() - wraps a view and transmits it through the
151 CustomActionData property
152
153********************************************************************/
154HRESULT WIXAPI WcaWrapQuery(
155 __in_z LPCWSTR pwzQuery,
156 __inout LPWSTR * ppwzCustomActionData,
157 __in_opt DWORD dwFormatMask,
158 __in_opt DWORD dwComponentColumn,
159 __in_opt DWORD dwDirectoryColumn
160 )
161{
162 HRESULT hr = S_OK;
163 HRESULT hrTemp = S_OK;
164 UINT er = ERROR_SUCCESS;
165 UINT cViewColumns;
166 eColumnDataType *pcdtColumnTypeList = NULL;
167 LPWSTR pwzData = NULL;
168 LPWSTR pwzColumnData = NULL;
169 LPWSTR pwzRecordData = NULL;
170 BYTE* pbData = NULL;
171 DWORD dwNumRecords = 0;
172 BOOL fAddComponentState = FALSE; // Add two integer columns to the right side of the query - ISInstalled, and ISAction
173 BOOL fAddDirectoryPath = FALSE; // Add two string columns to the right side of the query - SourcePath, and TargetPath
174 int iTempInteger = 0;
175
176 WCHAR wzPath[MAX_PATH + 1];
177 DWORD dwLen;
178 INSTALLSTATE isInstalled = INSTALLSTATE_UNKNOWN;
179 INSTALLSTATE isAction = INSTALLSTATE_UNKNOWN;
180
181 PMSIHANDLE hColumnTypes, hColumnNames;
182 PMSIHANDLE hView, hRec;
183
184 WcaLog(LOGMSG_TRACEONLY, "Wrapping result of query: \"%ls\"", pwzQuery);
185
186 // open the view
187 hr = WcaOpenExecuteView(pwzQuery, &hView);
188 ExitOnFailure(hr, "Failed to execute view");
189
190 hr = WcaWriteIntegerToCaData(static_cast<int>(wqaTableBegin), ppwzCustomActionData);
191 ExitOnFailure(hr, "Failed to write table begin marker to custom action data");
192
193// WcaLog(LOGMSG_TRACEONLY, "Starting to wrap table's column information", pwzQuery);
194
195 // Use GetColumnInfo to populate the names of the columns.
196 er = ::MsiViewGetColumnInfo(hView, MSICOLINFO_TYPES, &hColumnTypes);
197 ExitOnWin32Error(er, hr, "Failed to get column types");
198
199 er = ::MsiViewGetColumnInfo(hView, MSICOLINFO_NAMES, &hColumnNames);
200 ExitOnWin32Error(er, hr, "Failed to get column names");
201
202 cViewColumns = ::MsiRecordGetFieldCount(hColumnTypes);
203
204 if (0xFFFFFFFF == cViewColumns)
205 {
206 // According to MSDN, this return value only happens when the handle is invalid
207 hr = E_HANDLE;
208 ExitOnFailure(hr, "Failed to get number of fields in record");
209 }
210
211 if (cViewColumns >= dwComponentColumn)
212 {
213 fAddComponentState = TRUE;
214 }
215 else if (0xFFFFFFFF != dwComponentColumn)
216 {
217 hr = E_INVALIDARG;
218 ExitOnFailure(hr, "Component column %d out of range", dwComponentColumn);
219 }
220
221 if (cViewColumns >= dwDirectoryColumn)
222 {
223 fAddDirectoryPath = TRUE;
224 }
225 else if (0xFFFFFFFF != dwDirectoryColumn)
226 {
227 hr = E_INVALIDARG;
228 ExitOnFailure(hr, "Directory column %d out of range", dwDirectoryColumn);
229 }
230
231 hr = WcaWriteIntegerToCaData(static_cast<int>(cViewColumns) + 2 * static_cast<int>(fAddComponentState) + 2 * static_cast<int>(fAddDirectoryPath), ppwzCustomActionData);
232 ExitOnFailure(hr, "Failed to write number of columns to custom action data");
233
234 pcdtColumnTypeList = new eColumnDataType[cViewColumns];
235 ExitOnNull(pcdtColumnTypeList, hr, E_OUTOFMEMORY, "Failed to allocate memory to store column info types");
236
237 // Loop through all the columns reporting information about each one
238 for (DWORD i = 0; i < cViewColumns; i++)
239 {
240 hr = WcaGetRecordString(hColumnNames, i+1, &pwzData);
241 ExitOnFailure(hr, "Failed to get the column %d name", i+1);
242
243 hr = WcaWriteStringToCaData(pwzData, &pwzColumnData);
244 ExitOnFailure(hr, "Failed to write column %d name %ls to custom action data", i+1, pwzData);
245
246 hr = WcaGetRecordString(hColumnTypes, i+1, &pwzData);
247 ExitOnFailure(hr, "Failed to get the column type string for column %d", i+1);
248
249 pcdtColumnTypeList[i] = GetDataTypeFromString(pwzData);
250
251 if (cdtUnknown == pcdtColumnTypeList[i])
252 {
253 hr = E_INVALIDARG;
254 ExitOnFailure(hr, "Failed to recognize column %d type string: %ls", i+1, pwzData);
255 }
256
257 hr = WcaWriteIntegerToCaData(pcdtColumnTypeList[i], &pwzColumnData);
258 ExitOnFailure(hr, "Failed to write column %d type enumeration to custom action data", i+1);
259 }
260
261 // Add two integer columns to the right side of the query - ISInstalled, and ISAction
262 if (fAddComponentState)
263 {
264 hr = WcaWriteStringToCaData(ISINSTALLEDCOLUMNNAME, &pwzColumnData);
265 ExitOnFailure(hr, "Failed to write extra column %d name %ls to custom action data", cViewColumns + 1, ISINSTALLEDCOLUMNNAME);
266
267 hr = WcaWriteIntegerToCaData(cdtInt, &pwzColumnData);
268 ExitOnFailure(hr, "Failed to write extra column %d type to custom action data", cViewColumns + 1);
269
270 hr = WcaWriteStringToCaData(ISACTIONCOLUMNNAME, &pwzColumnData);
271 ExitOnFailure(hr, "Failed to write extra column %d name %ls to custom action data", cViewColumns + 1, ISACTIONCOLUMNNAME);
272
273 hr = WcaWriteIntegerToCaData(cdtInt, &pwzColumnData);
274 ExitOnFailure(hr, "Failed to write extra column %d type to custom action data", cViewColumns + 1);
275 }
276
277 if (fAddDirectoryPath)
278 {
279 hr = WcaWriteStringToCaData(SOURCEPATHCOLUMNNAME, &pwzColumnData);
280 ExitOnFailure(hr, "Failed to write extra column %d name %ls to custom action data", cViewColumns + 1, SOURCEPATHCOLUMNNAME);
281
282 hr = WcaWriteIntegerToCaData(cdtString, &pwzColumnData);
283 ExitOnFailure(hr, "Failed to write extra column %d type to custom action data", cViewColumns + 1);
284
285 hr = WcaWriteStringToCaData(TARGETPATHCOLUMNNAME, &pwzColumnData);
286 ExitOnFailure(hr, "Failed to write extra column %d name %ls to custom action data", cViewColumns + 1, TARGETPATHCOLUMNNAME);
287
288 hr = WcaWriteIntegerToCaData(cdtString, &pwzColumnData);
289 ExitOnFailure(hr, "Failed to write extra column %d type to custom action data", cViewColumns + 1);
290 }
291
292 // Begin wrapping actual table data
293 //WcaLog(LOGMSG_TRACEONLY, "Starting to wrap table data", pwzQuery);
294 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
295 {
296 hr = WcaWriteIntegerToCaData(static_cast<int>(wqaRowBegin), &pwzRecordData);
297 ExitOnFailure(hr, "Failed to write row begin marker to custom action data");
298
299 for (DWORD i = 0; i < cViewColumns; i++)
300 {
301 switch (pcdtColumnTypeList[i])
302 {
303 case cdtString:
304 // If we were given a format mask, we're not past the index, and it's set to true for this column, then format the string
305 if (i < (sizeof(dwFormatMask) * 8) && (dwFormatMask & (1 << i)))
306 {
307 hr = WcaGetRecordFormattedString(hRec, i + 1, &pwzData);
308 }
309 else
310 {
311 hr = WcaGetRecordString(hRec, i + 1, &pwzData);
312 }
313 ExitOnFailure(hr, "Failed to get string for column %d", i + 1);
314
315 hr = WcaWriteStringToCaData(pwzData, &pwzRecordData);
316 ExitOnFailure(hr, "Failed to write string to temporary record custom action data for column %d", i + 1);
317 break;
318
319 case cdtInt:
320 if (i < (sizeof(dwFormatMask) * 8) && (dwFormatMask & (1 << i)))
321 {
322 hr = WcaGetRecordFormattedInteger(hRec, i + 1, &iTempInteger);
323 }
324 else
325 {
326 hr = WcaGetRecordInteger(hRec, i + 1, &iTempInteger);
327 }
328 ExitOnFailure(hr, "Failed to get integer for column %d", i + 1);
329
330 hr = WcaWriteIntegerToCaData(iTempInteger, &pwzRecordData);
331 ExitOnFailure(hr, "Failed to write integer to temporary record custom action data for column %d", i + 1);
332 break;
333
334 case cdtStream:
335 hr = E_NOTIMPL;
336 ExitOnFailure(hr, "A query was wrapped which contained a binary stream data field in column %d - however, the ability to wrap stream data fields is not implemented at this time", i);
337 break;
338
339 case cdtUnknown:
340 default:
341 hr = E_INVALIDARG;
342 ExitOnFailure(hr, "Failed to recognize column type enumeration %d for column %d", pcdtColumnTypeList[i], i + 1);
343 }
344 }
345
346 // Add two integer columns to the right side of the query - ISInstalled, and ISAction
347 if (fAddComponentState)
348 {
349 // Get the component ID
350 hr = WcaGetRecordString(hRec, dwComponentColumn, &pwzData);
351 ExitOnFailure(hr, "Failed to get component from column %d while adding extra columns", dwComponentColumn);
352
353 if (!pwzData || !*pwzData)
354 {
355 // If no component was provided, set these both to zero as though a structure to store them were allocated with memory zero'd out
356 isInstalled = (INSTALLSTATE)0;
357 isAction = (INSTALLSTATE)0;
358 }
359 else
360 {
361 er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzData, &isInstalled, &isAction);
362 // If we don't get the component state, that may be because the component ID was invalid, but isn't necessarily an error, so write NULL's
363 if (FAILED(HRESULT_FROM_WIN32(er)))
364 {
365 ExitOnFailure(hr, "Failed to get component state for component %ls", pwzData);
366 }
367 }
368
369 hr = WcaWriteIntegerToCaData(isInstalled, &pwzRecordData);
370 ExitOnFailure(hr, "Failed to write extra ISInstalled column to custom action data");
371
372 hr = WcaWriteIntegerToCaData(isAction, &pwzRecordData);
373 ExitOnFailure(hr, "Failed to write extra ISAction column to custom action data");
374 }
375
376 // Add two string columns to the right side of the query - SourcePath, and TargetPath
377 if (fAddDirectoryPath)
378 {
379 hr = WcaGetRecordString(hRec, dwDirectoryColumn, &pwzData);
380 // If this fails, ignore it, and just leave those columns blank
381 if (SUCCEEDED(hr))
382 {
383 // Only get source path if the component state is INSTALLSTATE_SOURCE, or if we have no component to check the installstate of
384 if (INSTALLSTATE_SOURCE == isAction || !fAddComponentState)
385 {
386 dwLen = countof(wzPath);
387 er = ::MsiGetSourcePathW(WcaGetInstallHandle(), pwzData, wzPath, &dwLen);
388 hrTemp = HRESULT_FROM_WIN32(er);
389 if (dwLen > countof(wzPath))
390 {
391 hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
392 ExitOnRootFailure(hr, "Failed to record entire Source Path for Directory %ls because its length was greater than MAX_PATH.", pwzData);
393 }
394
395 if (SUCCEEDED(hrTemp))
396 {
397 hr = WcaWriteStringToCaData(wzPath, &pwzRecordData);
398 ExitOnFailure(hr, "Failed to write source path string to record data string");
399 }
400 else
401 {
402 hr = WcaWriteStringToCaData(L"", &pwzRecordData);
403 ExitOnFailure(hr, "Failed to write empty source path string to record data string");
404 }
405 }
406 else
407 {
408 hr = WcaWriteStringToCaData(L"", &pwzRecordData);
409 ExitOnFailure(hr, "Failed to write empty source path string before writing target path string to record data string");
410 }
411
412 dwLen = countof(wzPath);
413 er = ::MsiGetTargetPathW(WcaGetInstallHandle(), pwzData, wzPath, &dwLen);
414 hrTemp = HRESULT_FROM_WIN32(er);
415 if (dwLen > countof(wzPath))
416 {
417 hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
418 ExitOnRootFailure(hr, "Failed to record entire Source Path for Directory %ls because its length was greater than MAX_PATH.", pwzData);
419 }
420 if (SUCCEEDED(hrTemp))
421 {
422 hr = WcaWriteStringToCaData(wzPath, &pwzRecordData);
423 ExitOnFailure(hr, "Failed to write target path string to record data string");
424 }
425 else
426 {
427 hr = WcaWriteStringToCaData(L"", &pwzRecordData);
428 ExitOnFailure(hr, "Failed to write empty target path string to record data string");
429 }
430 }
431 else
432 {
433 // Write both fields as blank
434 hr = WcaWriteStringToCaData(L"", &pwzRecordData);
435 hr = WcaWriteStringToCaData(L"", &pwzRecordData);
436 }
437 }
438
439 hr = WcaWriteIntegerToCaData(static_cast<int>(wqaRowFinish), &pwzRecordData);
440 ExitOnFailure(hr, "Failed to write row finish marker to custom action data");
441
442 ++dwNumRecords;
443 }
444
445 hr = WcaWriteIntegerToCaData(dwNumRecords, ppwzCustomActionData);
446 ExitOnFailure(hr, "Failed to write number of records to custom action data");
447
448 if (NULL != pwzColumnData)
449 {
450 hr = WcaWriteStringToCaData(pwzColumnData, ppwzCustomActionData);
451 ExitOnFailure(hr, "Failed to write column data to custom action data");
452 }
453
454 if (NULL != pwzRecordData)
455 {
456 hr = WcaWriteStringToCaData(pwzRecordData, ppwzCustomActionData);
457 ExitOnFailure(hr, "Failed to write record data to custom action data");
458 }
459
460 hr = WcaWriteIntegerToCaData(static_cast<int>(wqaTableFinish), ppwzCustomActionData);
461 ExitOnFailure(hr, "Failed to write table finish marker to custom action data");
462
463// WcaLog(LOGMSG_TRACEONLY, "Finished wrapping result of query: \"%ls\"", pwzQuery);
464
465LExit:
466 ReleaseStr(pwzData);
467 ReleaseStr(pwzColumnData);
468 ReleaseStr(pwzRecordData);
469
470 ReleaseMem(pbData);
471
472 return hr;
473}
474
475
476/********************************************************************
477WcaBeginUnwrapQuery() - unwraps a view for direct access from the
478 CustomActionData property
479
480********************************************************************/
481HRESULT WIXAPI WcaBeginUnwrapQuery(
482 __out WCA_WRAPQUERY_HANDLE * phWrapQuery,
483 __inout LPWSTR * ppwzCustomActionData
484 )
485{
486 HRESULT hr = S_OK;
487 int iTempInteger = 0;
488 int iColumns = 0;
489 int iRows = 0;
490 BYTE* pbData = NULL;
491 LPWSTR pwzData = NULL;
492 WCA_WRAPQUERY_HANDLE hWrapQuery = NULL;
493
494 WcaLog(LOGMSG_TRACEONLY, "Unwrapping a query from custom action data");
495
496 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iTempInteger);
497 if (wqaTableBegin != iTempInteger)
498 {
499 hr = E_INVALIDARG;
500 }
501 ExitOnFailure(hr, "Failed to read table begin marker from custom action data (read %d instead)", iTempInteger);
502
503 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iColumns);
504 ExitOnFailure(hr, "Failed to read number of columns from custom action data");
505
506 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iRows);
507 ExitOnFailure(hr, "Failed to read number of rows from custom action data");
508
509 hWrapQuery = GetNewQueryInstance(iColumns, iRows);
510 if (NULL == hWrapQuery)
511 {
512 hr = E_POINTER;
513 }
514 ExitOnFailure(hr, "Failed to get a query instance with %d columns and %d rows", iColumns, iRows);
515
516 for (int i = 0; i < iColumns; i++)
517 {
518 hr = WcaReadStringFromCaData(ppwzCustomActionData, &(hWrapQuery->ppwzColumnNames[i]));
519 ExitOnFailure(hr, "Failed to read column %d's name from custom action data", i+1);
520
521 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iTempInteger);
522 if (cdtString != iTempInteger && cdtInt != iTempInteger && cdtStream != iTempInteger)
523 {
524 hr = E_INVALIDARG;
525 }
526 ExitOnFailure(hr, "Failed to read column %d's type from custom action data", i+1);
527
528 // Set the column type into the actual data structure
529 hWrapQuery->pcdtColumnType[i] = (eColumnDataType)iTempInteger;
530 }
531
532 for (int i = 0; i < iRows; i++)
533 {
534 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iTempInteger);
535 if (wqaRowBegin != iTempInteger)
536 {
537 hr = E_INVALIDARG;
538 }
539 ExitOnFailure(hr, "Failed to read begin row marker from custom action data (read %d instead)", iTempInteger);
540
541 hWrapQuery->phRecords[i] = ::MsiCreateRecord((unsigned int)iColumns);
542
543 for (int j = 0; j < iColumns; j++)
544 {
545 switch (hWrapQuery->pcdtColumnType[j])
546 {
547 case cdtString:
548 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzData);
549 ExitOnFailure(hr, "Failed to read string from custom action data");
550
551 hr = WcaSetRecordString(hWrapQuery->phRecords[i], j+1, pwzData);
552 ExitOnFailure(hr, "Failed to write string %ls to record in column %d", pwzData, j+1);
553 break;
554
555 case cdtInt:
556 WcaReadIntegerFromCaData(ppwzCustomActionData, &iTempInteger);
557 ExitOnFailure(hr, "Failed to read integer from custom action data");
558
559 WcaSetRecordInteger(hWrapQuery->phRecords[i], j+1, iTempInteger);
560 ExitOnFailure(hr, "Failed to write integer %d to record in column %d", iTempInteger, j+1);
561 break;
562
563 case cdtStream:
564 hr = E_NOTIMPL;
565 ExitOnFailure(hr, "A query was wrapped which contained a stream data field - however, the ability to wrap stream data fields is not implemented at this time");
566 break;
567
568 case cdtUnknown:
569 default:
570 hr = E_INVALIDARG;
571 ExitOnFailure(hr, "Failed to recognize column type enumeration %d for column %d", hWrapQuery->pcdtColumnType[j+1], i+1);
572 }
573 }
574
575 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iTempInteger);
576 if (wqaRowFinish != iTempInteger)
577 {
578 hr = E_INVALIDARG;
579 }
580 ExitOnFailure(hr, "Failed to read row finish marker from custom action data (read %d instead)", iTempInteger);
581 }
582
583 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iTempInteger);
584 if (wqaTableFinish != iTempInteger)
585 {
586 hr = E_INVALIDARG;
587 }
588 ExitOnFailure(hr, "Failed to read table finish marker from custom action data (read %d instead)", iTempInteger);
589
590 *phWrapQuery = hWrapQuery;
591
592// WcaLog(LOGMSG_TRACEONLY, "Successfully finished unwrapping a query from custom action data");
593
594LExit:
595 ReleaseStr(pwzData);
596 ReleaseMem(pbData);
597
598 return hr;
599}
600
601// This function returns the total number of records in a query
602DWORD WIXAPI WcaGetQueryRecords(
603 __in const WCA_WRAPQUERY_HANDLE hWrapQuery
604 )
605{
606 return hWrapQuery->dwRows;
607}
608
609// This function resets a query back to its first row, so that the next fetch returns the first record
610void WIXAPI WcaFetchWrappedReset(
611 __in WCA_WRAPQUERY_HANDLE hWrapQuery
612 )
613{
614 hWrapQuery->dwNextIndex = 0;
615}
616
617// Fetches the next record in the query
618// NOTE: the MSIHANDLE returned by this function should not be released, as it is the same handle used by the query object to maintain the item.
619// so, don't use this function with PMSIHANDLE objects!
620HRESULT WIXAPI WcaFetchWrappedRecord(
621 __in WCA_WRAPQUERY_HANDLE hWrapQuery,
622 __out MSIHANDLE* phRec
623 )
624{
625 DWORD dwNextIndex = hWrapQuery->dwNextIndex;
626
627 if (dwNextIndex >= hWrapQuery->dwRows)
628 {
629 return E_NOMOREITEMS;
630 }
631
632 if (NULL == hWrapQuery->phRecords[dwNextIndex])
633 {
634 return E_HANDLE;
635 }
636
637 *phRec = hWrapQuery->phRecords[hWrapQuery->dwNextIndex];
638
639 // Increment our next index variable
640 ++hWrapQuery->dwNextIndex;
641
642 return S_OK;
643}
644
645// Fetch the next record in the query where the string value in column dwComparisonColumn equals the value pwzExpectedValue
646// NOTE: the MSIHANDLE returned by this function should not be released, as it is the same handle used by the query object to maintain the item.
647// so, don't use this function with PMSIHANDLE objects!
648HRESULT WIXAPI WcaFetchWrappedRecordWhereString(
649 __in WCA_WRAPQUERY_HANDLE hWrapQuery,
650 __in DWORD dwComparisonColumn,
651 __in_z LPCWSTR pwzExpectedValue,
652 __out MSIHANDLE* phRec
653 )
654{
655 HRESULT hr = S_OK;
656 MSIHANDLE hRec = NULL;
657 LPWSTR pwzData = NULL;
658
659 while (S_OK == (hr = WcaFetchWrappedRecord(hWrapQuery, &hRec)))
660 {
661 ExitOnFailure(hr, "Failed to fetch a wrapped record");
662
663 hr = WcaGetRecordString(hRec, dwComparisonColumn, &pwzData);
664 ExitOnFailure(hr, "Failed to get record string in column %d", dwComparisonColumn);
665
666 if (0 == lstrcmpW(pwzData, pwzExpectedValue))
667 {
668 *phRec = hRec;
669 ExitFunction1(hr = S_OK);
670 }
671 }
672 // If we errored here but not because there were no records left, write an error to the log
673 if (hr != E_NOMOREITEMS)
674 {
675 ExitOnFailure(hr, "Failed while searching for a wrapped record where column %d is set to %ls", dwComparisonColumn, pwzExpectedValue);
676 }
677
678LExit:
679 ReleaseStr(pwzData);
680
681 return hr;
682}
683
684/********************************************************************
685WcaBeginUnwrapQuery() - Finishes unwrapping a view for direct access
686 from the CustomActionData property
687
688********************************************************************/
689void WIXAPI WcaFinishUnwrapQuery(
690 __in_opt WCA_WRAPQUERY_HANDLE hWrapQuery
691 )
692{
693 if (NULL == hWrapQuery)
694 {
695 WcaLog(LOGMSG_TRACEONLY, "Failed to finish an unwrap query - ignoring");
696 return;
697 }
698
699 ReleaseMem(hWrapQuery->pcdtColumnType);
700
701 for (DWORD i=0;i<hWrapQuery->dwColumns;i++)
702 {
703 ReleaseStr(hWrapQuery->ppwzColumnNames[i]);
704 }
705 ReleaseMem(hWrapQuery->ppwzColumnNames);
706
707 for (DWORD i=0;i<hWrapQuery->dwRows;i++)
708 {
709 if (NULL != hWrapQuery->phRecords[i])
710 {
711 ::MsiCloseHandle(hWrapQuery->phRecords[i]);
712 }
713 }
714 ReleaseMem(hWrapQuery->phRecords);
715
716 ReleaseMem(hWrapQuery);
717}