Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Side by Side Diff: src/installer-ca/wcawrap.cpp

Issue 11521026: initial custom action library, "hello, world" quality (Closed)
Patch Set: Created Sept. 3, 2013, 12:48 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 //------------------------------------------------------------------------------ -------------------
2 // <copyright file="wcawrap.cpp" company="Outercurve Foundation">
3 // Copyright (c) 2004, Outercurve Foundation.
4 // This software is released under Microsoft Reciprocal License (MS-RL).
5 // The license and further copyright text can be found in the file
6 // LICENSE.TXT at the root directory of the distribution.
7 // </copyright>
8 //
9 // <summary>
10 // Windows Installer XML CustomAction utility library wrappers for MSI API
11 // </summary>
12 //------------------------------------------------------------------------------ -------------------
13
14 #include "precomp.h"
15
16
17 /********************************************************************
18 WcaProcessMessage() - sends a message from the CustomAction
19
20 ********************************************************************/
21 extern "C" UINT WIXAPI WcaProcessMessage(
22 __in INSTALLMESSAGE eMessageType,
23 __in MSIHANDLE hRecord
24 )
25 {
26 UINT er = ::MsiProcessMessage(WcaGetInstallHandle(), eMessageType, hRecord);
27 if (ERROR_INSTALL_USEREXIT == er || IDCANCEL == er)
28 {
29 WcaSetReturnValue(ERROR_INSTALL_USEREXIT);
30 }
31
32 return er;
33 }
34
35
36 /********************************************************************
37 WcaErrorMessage() - sends an error message from the CustomAction using
38 the Error table
39
40 NOTE: Any and all var_args (...) must be WCHAR*
41 ********************************************************************/
42 extern "C" UINT __cdecl WcaErrorMessage(
43 __in int iError,
44 __in HRESULT hrError,
45 __in UINT uiType,
46 __in DWORD cArgs,
47 ...
48 )
49 {
50 UINT er;
51 MSIHANDLE hRec = NULL;
52 va_list args;
53
54 uiType |= INSTALLMESSAGE_ERROR; // ensure error type is set
55 hRec = ::MsiCreateRecord(cArgs + 2);
56 if (!hRec)
57 {
58 er = ERROR_OUTOFMEMORY;
59 ExitOnFailure(HRESULT_FROM_WIN32(er), "failed to create record when send ing error message");
60 }
61
62 er = ::MsiRecordSetInteger(hRec, 1, iError);
63 ExitOnFailure(HRESULT_FROM_WIN32(er), "failed to set error code into error m essage");
64
65 er = ::MsiRecordSetInteger(hRec, 2, hrError);
66 ExitOnFailure(HRESULT_FROM_WIN32(er), "failed to set hresult code into error message");
67
68 va_start(args, cArgs);
69 for (DWORD i = 0; i < cArgs; i++)
70 {
71 er = ::MsiRecordSetStringW(hRec, i + 3, va_arg(args, WCHAR*));
72 ExitOnFailure(HRESULT_FROM_WIN32(er), "failed to set string string into error message");
73 }
74 va_end(args);
75
76 er = WcaProcessMessage(static_cast<INSTALLMESSAGE>(uiType), hRec);
77 LExit:
78 if (hRec)
79 {
80 ::MsiCloseHandle(hRec);
81 }
82
83 return er;
84 }
85
86
87 /********************************************************************
88 WcaProgressMessage() - extends the progress bar or sends a progress
89 update from the CustomAction
90
91 ********************************************************************/
92 extern "C" HRESULT WIXAPI WcaProgressMessage(
93 __in UINT uiCost,
94 __in BOOL fExtendProgressBar
95 )
96 {
97 static BOOL fExplicitProgressMessages = FALSE;
98
99 HRESULT hr = S_OK;
100 UINT er = ERROR_SUCCESS;
101 MSIHANDLE hRec = ::MsiCreateRecord(3);
102
103 // if aren't extending the progress bar and we haven't switched into explici t message mode
104 if (!fExtendProgressBar && !fExplicitProgressMessages)
105 {
106 AssertSz(::MsiGetMode(WcaGetInstallHandle(), MSIRUNMODE_SCHEDULED) ||
107 ::MsiGetMode(WcaGetInstallHandle(), MSIRUNMODE_COMMIT) ||
108 ::MsiGetMode(WcaGetInstallHandle(), MSIRUNMODE_ROLLBACK), "can only send progress bar messages in a deferred CustomAction");
109
110 // tell Darwin to use explicit progress messages
111 ::MsiRecordSetInteger(hRec, 1, 1);
112 ::MsiRecordSetInteger(hRec, 2, 1);
113 ::MsiRecordSetInteger(hRec, 3, 0);
114
115 er = WcaProcessMessage(INSTALLMESSAGE_PROGRESS, hRec);
116 if (0 == er || IDOK == er || IDYES == er)
117 {
118 hr = S_OK;
119 }
120 else if (IDABORT == er || IDCANCEL == er)
121 {
122 WcaSetReturnValue(ERROR_INSTALL_USEREXIT); // note that the user sai d exit
123 ExitFunction1(hr = S_FALSE);
124 }
125 else
126 {
127 hr = E_UNEXPECTED;
128 }
129 ExitOnFailure(hr, "failed to tell Darwin to use explicit progress messag es");
130
131 fExplicitProgressMessages = TRUE;
132 }
133 #if DEBUG
134 else if (fExtendProgressBar) // if we are extending the progress bar, make sure we're not deferred
135 {
136 AssertSz(!::MsiGetMode(WcaGetInstallHandle(), MSIRUNMODE_SCHEDULED), "ca nnot add ticks to progress bar length from deferred CustomAction");
137 }
138 #endif
139
140 // send the progress message
141 ::MsiRecordSetInteger(hRec, 1, (fExtendProgressBar) ? 3 : 2);
142 ::MsiRecordSetInteger(hRec, 2, uiCost);
143 ::MsiRecordSetInteger(hRec, 3, 0);
144
145 er = WcaProcessMessage(INSTALLMESSAGE_PROGRESS, hRec);
146 if (0 == er || IDOK == er || IDYES == er)
147 {
148 hr = S_OK;
149 }
150 else if (IDABORT == er || IDCANCEL == er)
151 {
152 WcaSetReturnValue(ERROR_INSTALL_USEREXIT); // note that the user said ex it
153 hr = S_FALSE;
154 }
155 else
156 {
157 hr = E_UNEXPECTED;
158 }
159
160 LExit:
161 if (hRec)
162 {
163 ::MsiCloseHandle(hRec);
164 }
165
166 return hr;
167 }
168
169
170 /********************************************************************
171 WcaIsInstalling() - determines if a pair of installstates means install
172
173 ********************************************************************/
174 extern "C" BOOL WIXAPI WcaIsInstalling(
175 __in INSTALLSTATE isInstalled,
176 __in INSTALLSTATE isAction
177 )
178 {
179 return (INSTALLSTATE_LOCAL == isAction ||
180 INSTALLSTATE_SOURCE == isAction ||
181 (INSTALLSTATE_DEFAULT == isAction &&
182 (INSTALLSTATE_LOCAL == isInstalled ||
183 INSTALLSTATE_SOURCE == isInstalled)));
184 }
185
186 /********************************************************************
187 WcaIsReInstalling() - determines if a pair of installstates means reinstall
188
189 ********************************************************************/
190 extern "C" BOOL WIXAPI WcaIsReInstalling(
191 __in INSTALLSTATE isInstalled,
192 __in INSTALLSTATE isAction
193 )
194 {
195 return ((INSTALLSTATE_LOCAL == isAction ||
196 INSTALLSTATE_SOURCE == isAction ||
197 INSTALLSTATE_DEFAULT == isAction) &&
198 (INSTALLSTATE_LOCAL == isInstalled ||
199 INSTALLSTATE_SOURCE == isInstalled));
200 }
201
202
203 /********************************************************************
204 WcaIsUninstalling() - determines if a pair of installstates means uninstall
205
206 ********************************************************************/
207 extern "C" BOOL WIXAPI WcaIsUninstalling(
208 __in INSTALLSTATE isInstalled,
209 __in INSTALLSTATE isAction
210 )
211 {
212 return ((INSTALLSTATE_ABSENT == isAction ||
213 INSTALLSTATE_REMOVED == isAction) &&
214 (INSTALLSTATE_LOCAL == isInstalled ||
215 INSTALLSTATE_SOURCE == isInstalled));
216 }
217
218
219 /********************************************************************
220 WcaGetComponentToDo() - gets a component's install states and
221 determines if they mean install, uninstall, or reinstall.
222 ********************************************************************/
223 extern "C" WCA_TODO WIXAPI WcaGetComponentToDo(
224 __in_z LPCWSTR wzComponentId
225 )
226 {
227 INSTALLSTATE isInstalled = INSTALLSTATE_UNKNOWN;
228 INSTALLSTATE isAction = INSTALLSTATE_UNKNOWN;
229 if (ERROR_SUCCESS != ::MsiGetComponentStateW(WcaGetInstallHandle(), wzCompon entId, &isInstalled, &isAction))
230 {
231 return WCA_TODO_UNKNOWN;
232 }
233
234 if (WcaIsReInstalling(isInstalled, isAction))
235 {
236 return WCA_TODO_REINSTALL;
237 }
238 else if (WcaIsUninstalling(isInstalled, isAction))
239 {
240 return WCA_TODO_UNINSTALL;
241 }
242 else if (WcaIsInstalling(isInstalled, isAction))
243 {
244 return WCA_TODO_INSTALL;
245 }
246 else
247 {
248 return WCA_TODO_UNKNOWN;
249 }
250 }
251
252
253 /********************************************************************
254 WcaSetComponentState() - sets the install state of a Component
255
256 ********************************************************************/
257 extern "C" HRESULT WIXAPI WcaSetComponentState(
258 __in_z LPCWSTR wzComponent,
259 __in INSTALLSTATE isState
260 )
261 {
262 UINT er = ::MsiSetComponentStateW(WcaGetInstallHandle(), wzComponent, isStat e);
263 if (ERROR_INSTALL_USEREXIT == er)
264 {
265 WcaSetReturnValue(er);
266 }
267
268 return HRESULT_FROM_WIN32(er);
269 }
270
271
272 /********************************************************************
273 WcaTableExists() - determines if installing database contains a table
274
275 ********************************************************************/
276 extern "C" HRESULT WIXAPI WcaTableExists(
277 __in_z LPCWSTR wzTable
278 )
279 {
280 HRESULT hr = S_OK;
281 UINT er = ERROR_SUCCESS;
282
283 // NOTE: The following line of commented out code should work in a
284 // CustomAction but does not in Windows Installer v1.1
285 // er = ::MsiDatabaseIsTablePersistentW(hDatabase, wzTable);
286
287 // a "most elegant" workaround a Darwin v1.1 bug
288 PMSIHANDLE hRec;
289 er = ::MsiDatabaseGetPrimaryKeysW(WcaGetDatabaseHandle(), wzTable, &hRec);
290
291 if (ERROR_SUCCESS == er)
292 {
293 hr = S_OK;
294 }
295 else if (ERROR_INVALID_TABLE == er)
296 {
297 hr = S_FALSE;
298 }
299 else
300 {
301 hr = E_FAIL;
302 }
303 Assert(SUCCEEDED(hr));
304
305 return hr;
306 }
307
308
309 /********************************************************************
310 WcaOpenView() - opens a view on the installing database
311
312 ********************************************************************/
313 extern "C" HRESULT WIXAPI WcaOpenView(
314 __in_z LPCWSTR wzSql,
315 __out MSIHANDLE* phView
316 )
317 {
318 if (!wzSql || !*wzSql|| !phView)
319 {
320 return E_INVALIDARG;
321 }
322
323 HRESULT hr = S_OK;
324 UINT er = ::MsiDatabaseOpenViewW(WcaGetDatabaseHandle(), wzSql, phView);
325 ExitOnWin32Error1(er, hr, "failed to open view on database with SQL: %ls", w zSql);
326
327 LExit:
328 return hr;
329 }
330
331
332 /********************************************************************
333 WcaExecuteView() - executes a parameterized open view on the installing database
334
335 ********************************************************************/
336 extern "C" HRESULT WIXAPI WcaExecuteView(
337 __in MSIHANDLE hView,
338 __in MSIHANDLE hRec
339 )
340 {
341 if (!hView)
342 {
343 return E_INVALIDARG;
344 }
345 AssertSz(hRec, "Use WcaOpenExecuteView() if you don't need to pass in a reco rd");
346
347 HRESULT hr = S_OK;
348 UINT er = ::MsiViewExecute(hView, hRec);
349 ExitOnWin32Error(er, hr, "failed to execute view");
350
351 LExit:
352 return hr;
353 }
354
355
356 /********************************************************************
357 WcaOpenExecuteView() - opens and executes a view on the installing database
358
359 ********************************************************************/
360 extern "C" HRESULT WIXAPI WcaOpenExecuteView(
361 __in_z LPCWSTR wzSql,
362 __out MSIHANDLE* phView
363 )
364 {
365 if (!wzSql || !*wzSql|| !phView)
366 {
367 return E_INVALIDARG;
368 }
369
370 HRESULT hr = S_OK;
371 UINT er = ::MsiDatabaseOpenViewW(WcaGetDatabaseHandle(), wzSql, phView);
372 ExitOnWin32Error(er, hr, "failed to open view on database");
373
374 er = ::MsiViewExecute(*phView, NULL);
375 ExitOnWin32Error(er, hr, "failed to execute view");
376
377 LExit:
378 return hr;
379 }
380
381
382 /********************************************************************
383 WcaFetchRecord() - gets the next record from a view on the installing database
384
385 ********************************************************************/
386 extern "C" HRESULT WIXAPI WcaFetchRecord(
387 __in MSIHANDLE hView,
388 __out MSIHANDLE* phRec
389 )
390 {
391 if (!hView|| !phRec)
392 {
393 return E_INVALIDARG;
394 }
395
396 HRESULT hr = S_OK;
397 UINT er = ::MsiViewFetch(hView, phRec);
398 hr = HRESULT_FROM_WIN32(er);
399 if (FAILED(hr) && E_NOMOREITEMS != hr)
400 {
401 ExitOnFailure(hr, "failed to fetch record from view");
402 }
403
404 LExit:
405 return hr;
406 }
407
408
409 /********************************************************************
410 WcaFetchSingleRecord() - gets a single record from a view on the installing data base
411
412 ********************************************************************/
413 extern "C" HRESULT WIXAPI WcaFetchSingleRecord(
414 __in MSIHANDLE hView,
415 __out MSIHANDLE* phRec
416 )
417 {
418 if (!hView|| !phRec)
419 {
420 return E_INVALIDARG;
421 }
422
423 HRESULT hr = S_OK;
424 UINT er = ::MsiViewFetch(hView, phRec);
425 if (ERROR_NO_MORE_ITEMS == er)
426 {
427 hr = S_FALSE;
428 }
429 else
430 {
431 hr = HRESULT_FROM_WIN32(er);
432 }
433 ExitOnFailure(hr, "failed to fetch single record from view");
434
435 #ifdef DEBUG // only do this in debug to verify that a single record was returne d
436 MSIHANDLE hRecTest;
437 er = ::MsiViewFetch(hView, &hRecTest);
438 AssertSz(ERROR_NO_MORE_ITEMS == er && NULL == hRecTest, "WcaSingleFetch() di d not fetch a single record");
439 ::MsiCloseHandle(hRecTest);
440 #endif
441
442 LExit:
443 return hr;
444 }
445
446
447 /********************************************************************
448 WcaGetProperty - gets a string property value from the active install
449
450 ********************************************************************/
451 extern "C" HRESULT WIXAPI WcaGetProperty(
452 __in_z LPCWSTR wzProperty,
453 __inout LPWSTR* ppwzData
454 )
455 {
456 if (!wzProperty || !*wzProperty || !ppwzData)
457 {
458 return E_INVALIDARG;
459 }
460
461 HRESULT hr = S_OK;
462 UINT er = ERROR_SUCCESS;
463 DWORD_PTR cch = 0;
464
465 if (!*ppwzData)
466 {
467 WCHAR szEmpty[1] = L"";
468 er = ::MsiGetPropertyW(WcaGetInstallHandle(), wzProperty, szEmpty, (DWOR D *)&cch);
469 if (ERROR_MORE_DATA == er || ERROR_SUCCESS == er)
470 {
471 hr = StrAlloc(ppwzData, ++cch);
472 }
473 else
474 {
475 hr = HRESULT_FROM_WIN32(er);
476 }
477 ExitOnFailure1(hr, "Failed to allocate string for Property '%ls'", wzPro perty);
478 }
479 else
480 {
481 hr = StrMaxLength(*ppwzData, &cch);
482 ExitOnFailure(hr, "Failed to get previous size of property data string." );
483 }
484
485 er = ::MsiGetPropertyW(WcaGetInstallHandle(), wzProperty, *ppwzData, (DWORD *)&cch);
486 if (ERROR_MORE_DATA == er)
487 {
488 Assert(*ppwzData);
489 hr = StrAlloc(ppwzData, ++cch);
490 ExitOnFailure1(hr, "Failed to allocate string for Property '%ls'", wzPro perty);
491
492 er = ::MsiGetPropertyW(WcaGetInstallHandle(), wzProperty, *ppwzData, (DW ORD *)&cch);
493 }
494 ExitOnWin32Error1(er, hr, "Failed to get data for property '%ls'", wzPropert y);
495
496 LExit:
497 return hr;
498 }
499
500
501 /********************************************************************
502 WcaGetFormattedProperty - gets a formatted string property value from
503 the active install
504
505 ********************************************************************/
506 extern "C" HRESULT WIXAPI WcaGetFormattedProperty(
507 __in_z LPCWSTR wzProperty,
508 __out LPWSTR* ppwzData
509 )
510 {
511 if (!wzProperty || !*wzProperty || !ppwzData)
512 {
513 return E_INVALIDARG;
514 }
515
516 HRESULT hr = S_OK;
517 LPWSTR pwzPropertyValue = NULL;
518
519 hr = WcaGetProperty(wzProperty, &pwzPropertyValue);
520 ExitOnFailure1(hr, "failed to get %ls", wzProperty);
521
522 hr = WcaGetFormattedString(pwzPropertyValue, ppwzData);
523 ExitOnFailure2(hr, "failed to get formatted value for property: '%ls' with v alue: '%ls'", wzProperty, pwzPropertyValue);
524
525 LExit:
526 ReleaseStr(pwzPropertyValue);
527
528 return hr;
529 }
530
531
532 /********************************************************************
533 WcaGetFormattedString - gets a formatted string value from
534 the active install
535
536 ********************************************************************/
537 extern "C" HRESULT WIXAPI WcaGetFormattedString(
538 __in_z LPCWSTR wzString,
539 __out LPWSTR* ppwzData
540 )
541 {
542 if (!wzString || !*wzString || !ppwzData)
543 {
544 return E_INVALIDARG;
545 }
546
547 HRESULT hr = S_OK;
548 UINT er = ERROR_SUCCESS;
549 PMSIHANDLE hRecord = ::MsiCreateRecord(1);
550 DWORD_PTR cch = 0;
551
552 er = ::MsiRecordSetStringW(hRecord, 0, wzString);
553 ExitOnWin32Error1(er, hr, "Failed to set record field 0 with '%ls'", wzStrin g);
554
555 if (!*ppwzData)
556 {
557 WCHAR szEmpty[1] = L"";
558 er = ::MsiFormatRecordW(WcaGetInstallHandle(), hRecord, szEmpty, (DWORD *)&cch);
559 if (ERROR_MORE_DATA == er || ERROR_SUCCESS == er)
560 {
561 hr = StrAlloc(ppwzData, ++cch);
562 }
563 else
564 {
565 hr = HRESULT_FROM_WIN32(er);
566 }
567 ExitOnFailure1(hr, "Failed to allocate string for formatted string: '%ls '", wzString);
568 }
569 else
570 {
571 hr = StrMaxLength(*ppwzData, &cch);
572 ExitOnFailure(hr, "Failed to get previous size of property data string") ;
573 }
574
575 er = ::MsiFormatRecordW(WcaGetInstallHandle(), hRecord, *ppwzData, (DWORD *) &cch);
576 if (ERROR_MORE_DATA == er)
577 {
578 hr = StrAlloc(ppwzData, ++cch);
579 ExitOnFailure1(hr, "Failed to allocate string for formatted string: '%ls '", wzString);
580
581 er = ::MsiFormatRecordW(WcaGetInstallHandle(), hRecord, *ppwzData, (DWOR D *)&cch);
582 }
583 ExitOnWin32Error1(er, hr, "Failed to get formatted string: '%ls'", wzString) ;
584
585 LExit:
586 return hr;
587 }
588
589
590 /********************************************************************
591 WcaGetIntProperty - gets an integer property value from the active install
592
593 ********************************************************************/
594 extern "C" HRESULT WIXAPI WcaGetIntProperty(
595 __in_z LPCWSTR wzProperty,
596 __inout int* piData
597 )
598 {
599 if (!piData)
600 return E_INVALIDARG;
601
602 HRESULT hr = S_OK;
603 UINT er;
604
605 WCHAR wzValue[32];
606 DWORD cch = countof(wzValue) - 1;
607
608 er = ::MsiGetPropertyW(WcaGetInstallHandle(), wzProperty, wzValue, &cch);
609 ExitOnWin32Error1(er, hr, "Failed to get data for property '%ls'", wzPropert y);
610
611 *piData = wcstol(wzValue, NULL, 10);
612
613 LExit:
614 return hr;
615 }
616
617
618 /********************************************************************
619 WcaGetTargetPath - gets the target path for a specified folder
620
621 ********************************************************************/
622 extern "C" HRESULT WIXAPI WcaGetTargetPath(
623 __in_z LPCWSTR wzFolder,
624 __out LPWSTR* ppwzData
625 )
626 {
627 if (!wzFolder || !*wzFolder || !ppwzData)
628 return E_INVALIDARG;
629
630 HRESULT hr = S_OK;
631
632 UINT er = ERROR_SUCCESS;
633 DWORD_PTR cch = 0;
634
635 if (!*ppwzData)
636 {
637 WCHAR szEmpty[1] = L"";
638 er = ::MsiGetTargetPathW(WcaGetInstallHandle(), wzFolder, szEmpty, (DWOR D*)&cch);
639 if (ERROR_MORE_DATA == er || ERROR_SUCCESS == er)
640 {
641 ++cch; //Add one for the null terminator
642 hr = StrAlloc(ppwzData, cch);
643 }
644 else
645 {
646 hr = HRESULT_FROM_WIN32(er);
647 }
648 ExitOnFailure1(hr, "Failed to allocate string for target path of folder: '%ls'", wzFolder);
649 }
650 else
651 {
652 hr = StrMaxLength(*ppwzData, &cch);
653 ExitOnFailure(hr, "Failed to get previous size of string");
654 }
655
656 er = ::MsiGetTargetPathW(WcaGetInstallHandle(), wzFolder, *ppwzData, (DWORD* )&cch);
657 if (ERROR_MORE_DATA == er)
658 {
659 ++cch;
660 hr = StrAlloc(ppwzData, cch);
661 ExitOnFailure1(hr, "Failed to allocate string for target path of folder: '%ls'", wzFolder);
662
663 er = ::MsiGetTargetPathW(WcaGetInstallHandle(), wzFolder, *ppwzData, (DW ORD*)&cch);
664 }
665 ExitOnWin32Error1(er, hr, "Failed to get target path for folder '%ls'", wzFo lder);
666
667 LExit:
668 return hr;
669 }
670
671
672 /********************************************************************
673 WcaSetProperty - sets a string property value in the active install
674
675 ********************************************************************/
676 extern "C" HRESULT WIXAPI WcaSetProperty(
677 __in_z LPCWSTR wzPropertyName,
678 __in_z LPCWSTR wzPropertyValue
679 )
680 {
681 HRESULT hr = S_OK;
682
683 if (!wzPropertyName || !*wzPropertyName || !wzPropertyValue)
684 return E_INVALIDARG;
685
686 UINT er = ::MsiSetPropertyW(WcaGetInstallHandle(), wzPropertyName, wzPropert yValue);
687 ExitOnWin32Error1(er, hr, "failed to set property: %ls", wzPropertyName);
688
689 LExit:
690 return hr;
691 }
692
693
694 /********************************************************************
695 WcaSetIntProperty - sets a integer property value in the active install
696
697 ********************************************************************/
698 extern "C" HRESULT WIXAPI WcaSetIntProperty(
699 __in_z LPCWSTR wzPropertyName,
700 __in int nPropertyValue
701 )
702 {
703 if (!wzPropertyName || !*wzPropertyName)
704 return E_INVALIDARG;
705
706 // 12 characters should be enough for a 32-bit int: 10 digits, 1 sign, 1 nul l
707 WCHAR wzPropertyValue[13];
708 HRESULT hr = StringCchPrintfW(wzPropertyValue, countof(wzPropertyValue), L"% d", nPropertyValue);
709 ExitOnFailure1(hr, "failed to convert into string property value: %d", nProp ertyValue);
710
711 UINT er = ::MsiSetPropertyW(WcaGetInstallHandle(), wzPropertyName, wzPropert yValue);
712 ExitOnWin32Error1(er, hr, "failed to set property: %ls", wzPropertyName);
713
714 LExit:
715 return hr;
716 }
717
718
719 /********************************************************************
720 WcaIsPropertySet() - returns TRUE if property is set
721
722 ********************************************************************/
723 extern "C" BOOL WIXAPI WcaIsPropertySet(
724 __in LPCSTR szProperty
725 )
726 {
727 DWORD cchProperty = 0;
728 char szEmpty[1] = "";
729 #ifdef DEBUG
730 UINT er =
731 #endif
732 ::MsiGetPropertyA(WcaGetInstallHandle(), szProperty, szEmpty, &cchProper ty);
733 AssertSz(ERROR_INVALID_PARAMETER != er && ERROR_INVALID_HANDLE != er, "Unexp ected return value from ::MsiGetProperty()");
734
735 return 0 < cchProperty; // property is set if the length is greater than zer o
736 }
737
738
739 /********************************************************************
740 WcaIsUnicodePropertySet() - returns TRUE if property is set
741
742 ********************************************************************/
743 extern "C" BOOL WIXAPI WcaIsUnicodePropertySet(
744 __in LPCWSTR wzProperty
745 )
746 {
747 DWORD cchProperty = 0;
748 wchar_t wzEmpty[1] = L"";
749 #ifdef DEBUG
750 UINT er =
751 #endif
752 ::MsiGetPropertyW(WcaGetInstallHandle(), wzProperty, wzEmpty, &cchProper ty);
753 AssertSz(ERROR_INVALID_PARAMETER != er && ERROR_INVALID_HANDLE != er, "Unexp ected return value from ::MsiGetProperty()");
754
755 return 0 < cchProperty; // property is set if the length is greater than zer o
756 }
757
758
759 /********************************************************************
760 WcaGetRecordInteger() - gets an integer field out of a record
761
762 NOTE: returns S_FALSE if the field was null
763 ********************************************************************/
764 extern "C" HRESULT WIXAPI WcaGetRecordInteger(
765 __in MSIHANDLE hRec,
766 __in UINT uiField,
767 __inout int* piData
768 )
769 {
770 if (!hRec || !piData)
771 return E_INVALIDARG;
772
773 HRESULT hr = S_OK;
774 *piData = ::MsiRecordGetInteger(hRec, uiField);
775 if (MSI_NULL_INTEGER == *piData)
776 hr = S_FALSE;
777
778 //LExit:
779 return hr;
780 }
781
782
783 /********************************************************************
784 WcaGetRecordString() - gets a string field out of a record
785
786 ********************************************************************/
787 extern "C" HRESULT WIXAPI WcaGetRecordString(
788 __in MSIHANDLE hRec,
789 __in UINT uiField,
790 __inout LPWSTR* ppwzData
791 )
792 {
793 if (!hRec || !ppwzData)
794 return E_INVALIDARG;
795
796 HRESULT hr = S_OK;
797 UINT er;
798 DWORD_PTR cch = 0;
799
800 if (!*ppwzData)
801 {
802 WCHAR szEmpty[1] = L"";
803 er = ::MsiRecordGetStringW(hRec, uiField, szEmpty, (DWORD*)&cch);
804 if (ERROR_MORE_DATA == er || ERROR_SUCCESS == er)
805 {
806 hr = StrAlloc(ppwzData, ++cch);
807 }
808 else
809 {
810 hr = HRESULT_FROM_WIN32(er);
811 }
812 ExitOnFailure(hr, "Failed to allocate memory for record string");
813 }
814 else
815 {
816 hr = StrMaxLength(*ppwzData, &cch);
817 ExitOnFailure(hr, "Failed to get previous size of string");
818 }
819
820 er = ::MsiRecordGetStringW(hRec, uiField, *ppwzData, (DWORD*)&cch);
821 if (ERROR_MORE_DATA == er)
822 {
823 hr = StrAlloc(ppwzData, ++cch);
824 ExitOnFailure(hr, "Failed to allocate memory for record string");
825
826 er = ::MsiRecordGetStringW(hRec, uiField, *ppwzData, (DWORD*)&cch);
827 }
828 ExitOnWin32Error(er, hr, "Failed to get string from record");
829
830 LExit:
831 return hr;
832 }
833
834
835 /********************************************************************
836 HideNulls() - internal helper function to escape [~] in formatted strings
837
838 ********************************************************************/
839 static void HideNulls(
840 __inout_z LPWSTR wzData
841 )
842 {
843 LPWSTR pwz = wzData;
844
845 while(*pwz)
846 {
847 if (pwz[0] == L'[' && pwz[1] == L'~' && pwz[2] == L']') // found a null [~]
848 {
849 pwz[0] = L'!'; // turn it into !$!
850 pwz[1] = L'$';
851 pwz[2] = L'!';
852 pwz += 3;
853 }
854 else
855 {
856 ++pwz;
857 }
858 }
859 }
860
861
862 /********************************************************************
863 RevealNulls() - internal helper function to unescape !$! in formatted strings
864
865 ********************************************************************/
866 static void RevealNulls(
867 __inout_z LPWSTR wzData
868 )
869 {
870 LPWSTR pwz = wzData;
871
872 while(*pwz)
873 {
874 if (pwz[0] == L'!' && pwz[1] == L'$' && pwz[2] == L'!') // found the fak e null !$!
875 {
876 pwz[0] = L'['; // turn it back into [~]
877 pwz[1] = L'~';
878 pwz[2] = L']';
879 pwz += 3;
880 }
881 else
882 {
883 ++pwz;
884 }
885 }
886 }
887
888
889 /********************************************************************
890 WcaGetRecordFormattedString() - gets formatted string filed from record
891
892 ********************************************************************/
893 extern "C" HRESULT WIXAPI WcaGetRecordFormattedString(
894 __in MSIHANDLE hRec,
895 __in UINT uiField,
896 __inout LPWSTR* ppwzData
897 )
898 {
899 if (!hRec || !ppwzData)
900 {
901 return E_INVALIDARG;
902 }
903
904 HRESULT hr = S_OK;
905 UINT er;
906 DWORD_PTR cch = 0;
907 PMSIHANDLE hRecFormat;
908
909 // get the format string
910 hr = WcaGetRecordString(hRec, uiField, ppwzData);
911 ExitOnFailure(hr, "failed to get string from record");
912
913 if (!**ppwzData)
914 {
915 ExitFunction();
916 }
917
918 // hide the nulls '[~]' so we can get them back after formatting
919 HideNulls(*ppwzData);
920
921 // set up the format record
922 hRecFormat = ::MsiCreateRecord(1);
923 ExitOnNull(hRecFormat, hr, E_UNEXPECTED, "Failed to create record to format string");
924 hr = WcaSetRecordString(hRecFormat, 0, *ppwzData);
925 ExitOnFailure(hr, "failed to set string to format record");
926
927 // format the string
928 hr = StrMaxLength(*ppwzData, &cch);
929 ExitOnFailure(hr, "failed to get max length of string");
930
931 er = ::MsiFormatRecordW(WcaGetInstallHandle(), hRecFormat, *ppwzData, (DWORD *)&cch);
932 if (ERROR_MORE_DATA == er)
933 {
934 hr = StrAlloc(ppwzData, ++cch);
935 ExitOnFailure(hr, "Failed to allocate memory for record string");
936
937 er = ::MsiFormatRecordW(WcaGetInstallHandle(), hRecFormat, *ppwzData, (D WORD*)&cch);
938 }
939 ExitOnWin32Error(er, hr, "Failed to format string");
940
941 // put the nulls back
942 RevealNulls(*ppwzData);
943
944 LExit:
945 return hr;
946 }
947
948
949 /********************************************************************
950 WcaGetRecordFormattedInteger() - gets formatted integer from record
951
952 ********************************************************************/
953 extern "C" HRESULT WIXAPI WcaGetRecordFormattedInteger(
954 __in MSIHANDLE hRec,
955 __in UINT uiField,
956 __out int* piData
957 )
958 {
959 if (!hRec || !piData)
960 {
961 return E_INVALIDARG;
962 }
963
964 HRESULT hr = S_OK;
965 LPWSTR pwzData = NULL;
966
967 hr = WcaGetRecordFormattedString(hRec, uiField, &pwzData);
968 ExitOnFailure1(hr, "failed to get record field: %u", uiField);
969 if (pwzData && *pwzData)
970 {
971 LPWSTR wz = NULL;
972 *piData = wcstol(pwzData, &wz, 10);
973 if (wz && *wz)
974 {
975 hr = E_INVALIDARG;
976 ExitOnFailure2(hr, "failed to parse record field: %u as number: %ls" , uiField, pwzData);
977 }
978 }
979 else
980 {
981 *piData = MSI_NULL_INTEGER;
982 }
983
984 LExit:
985 return hr;
986 }
987
988
989 /********************************************************************
990 WcaAllocStream() - creates a byte stream of the specified size
991
992 NOTE: Use WcaFreeStream() to release the byte stream
993 ********************************************************************/
994 extern "C" HRESULT WIXAPI WcaAllocStream(
995 __deref_out_bcount_part(cbData, 0) BYTE** ppbData,
996 __in DWORD cbData
997 )
998 {
999 Assert(ppbData);
1000 HRESULT hr;
1001 BYTE* pbNewData;
1002
1003 if (*ppbData)
1004 pbNewData = static_cast<BYTE*>(MemReAlloc(*ppbData, cbData, TRUE));
1005 else
1006 pbNewData = static_cast<BYTE*>(MemAlloc(cbData, TRUE));
1007
1008 if (!pbNewData)
1009 {
1010 ExitOnLastError(hr, "Failed to allocate string");
1011 }
1012
1013 *ppbData = pbNewData;
1014 pbNewData = NULL;
1015
1016 hr = S_OK;
1017 LExit:
1018 ReleaseMem(pbNewData);
1019
1020 return hr;
1021 }
1022
1023
1024 /********************************************************************
1025 WcaFreeStream() - frees a byte stream
1026
1027 ********************************************************************/
1028 extern "C" HRESULT WIXAPI WcaFreeStream(
1029 __in BYTE* pbData
1030 )
1031 {
1032 if (!pbData)
1033 return E_INVALIDARG;
1034
1035 HRESULT hr = MemFree(pbData);
1036 return hr;
1037 }
1038
1039
1040 /********************************************************************
1041 WcaGetRecordStream() - gets a byte stream field from record
1042
1043 ********************************************************************/
1044 extern "C" HRESULT WIXAPI WcaGetRecordStream(
1045 __in MSIHANDLE hRecBinary,
1046 __in UINT uiField,
1047 __deref_out_bcount_full(*pcbData) BYTE** ppbData,
1048 __out DWORD* pcbData
1049 )
1050 {
1051 HRESULT hr = S_OK;
1052 UINT er = ERROR_SUCCESS;
1053
1054 if (!hRecBinary || !ppbData || !pcbData)
1055 return E_INVALIDARG;
1056
1057 *pcbData = 0;
1058 er = ::MsiRecordReadStream(hRecBinary, uiField, NULL, pcbData);
1059 ExitOnWin32Error(er, hr, "failed to get size of stream");
1060
1061 hr = WcaAllocStream(ppbData, *pcbData);
1062 ExitOnFailure(hr, "failed to allocate data for stream");
1063
1064 er = ::MsiRecordReadStream(hRecBinary, uiField, (char*)*ppbData, pcbData);
1065 ExitOnWin32Error(er, hr, "failed to read from stream");
1066
1067 LExit:
1068 return hr;
1069 }
1070
1071
1072 /********************************************************************
1073 WcaSetRecordString() - set a string field in record
1074
1075 ********************************************************************/
1076 extern "C" HRESULT WIXAPI WcaSetRecordString(
1077 __in MSIHANDLE hRec,
1078 __in UINT uiField,
1079 __in_z LPCWSTR wzData
1080 )
1081 {
1082 if (!hRec || !wzData)
1083 return E_INVALIDARG;
1084
1085 HRESULT hr = S_OK;
1086 UINT er = ::MsiRecordSetStringW(hRec, uiField, wzData);
1087 ExitOnWin32Error(er, hr, "failed to set string in record");
1088
1089 LExit:
1090 return hr;
1091 }
1092
1093
1094 /********************************************************************
1095 WcaSetRecordInteger() - set a integer field in record
1096
1097 ********************************************************************/
1098 extern "C" HRESULT WIXAPI WcaSetRecordInteger(
1099 __in MSIHANDLE hRec,
1100 __in UINT uiField,
1101 __in int iValue
1102 )
1103 {
1104 if (!hRec)
1105 return E_INVALIDARG;
1106
1107 HRESULT hr = S_OK;
1108 UINT er = ::MsiRecordSetInteger(hRec, uiField, iValue);
1109 ExitOnWin32Error(er, hr, "failed to set integer in record");
1110
1111 LExit:
1112 return hr;
1113 }
1114
1115
1116 /********************************************************************
1117
1118 WcaDoDeferredAction() - schedules an action at this point in the script
1119
1120 ********************************************************************/
1121 extern "C" HRESULT WIXAPI WcaDoDeferredAction(
1122 __in_z LPCWSTR wzAction,
1123 __in_z LPCWSTR wzCustomActionData,
1124 __in UINT uiCost
1125 )
1126 {
1127 HRESULT hr = S_OK;
1128 UINT er;
1129
1130 if (wzCustomActionData && *wzCustomActionData)
1131 {
1132 er = ::MsiSetPropertyW(WcaGetInstallHandle(), wzAction, wzCustomActionDa ta);
1133 ExitOnWin32Error(er, hr, "Failed to set CustomActionData for deferred ac tion");
1134 }
1135
1136 if (0 < uiCost)
1137 {
1138 hr = WcaProgressMessage(uiCost, TRUE); // add ticks to the progress bar
1139 // TODO: handle the return codes correctly
1140 }
1141
1142 er = ::MsiDoActionW(WcaGetInstallHandle(), wzAction);
1143 if (ERROR_INSTALL_USEREXIT == er)
1144 {
1145 WcaSetReturnValue(er);
1146 }
1147 ExitOnWin32Error(er, hr, "Failed MsiDoAction on deferred action");
1148
1149 LExit:
1150 return hr;
1151 }
1152
1153
1154 /********************************************************************
1155 WcaCountOfCustomActionDataRecords() - counts the number of records
1156 passed to a deferred CustomAction
1157
1158 ********************************************************************/
1159 extern "C" DWORD WIXAPI WcaCountOfCustomActionDataRecords(
1160 __in_z LPCWSTR wzData
1161 )
1162 {
1163 WCHAR delim[] = {MAGIC_MULTISZ_DELIM, 0}; // magic char followed by NULL ter minator
1164 DWORD dwCount = 0;
1165
1166 // Loop through until there are no delimiters, we are at the end of the stri ng, or the delimiter is the last character in the string
1167 for (LPCWSTR pwzCurrent = wzData; pwzCurrent && *pwzCurrent && *(pwzCurrent + 1); pwzCurrent = wcsstr(pwzCurrent, delim))
1168 {
1169 ++dwCount;
1170 ++pwzCurrent;
1171 }
1172
1173 return dwCount;
1174 }
1175
1176
1177 /********************************************************************
1178 BreakDownCustomActionData() - internal helper to chop up CustomActionData
1179
1180 NOTE: this modifies the passed in data
1181 ********************************************************************/
1182 static LPWSTR BreakDownCustomActionData(
1183 __inout LPWSTR* ppwzData
1184 )
1185 {
1186 if (!ppwzData)
1187 return NULL;
1188 if (0 == *ppwzData)
1189 return NULL;
1190
1191 WCHAR delim[] = {MAGIC_MULTISZ_DELIM, 0}; // magic char followed by Null ter minator
1192
1193 LPWSTR pwzReturn = *ppwzData;
1194 LPWSTR pwz = wcsstr(pwzReturn, delim);
1195 if (pwz)
1196 {
1197 *pwz = 0;
1198 *ppwzData = pwz + 1;
1199 }
1200 else
1201 *ppwzData = 0;
1202
1203 return pwzReturn;
1204 }
1205
1206
1207 /********************************************************************
1208 RevertCustomActionData() - Reverts custom action data changes made
1209 by BreakDownCustomActionData;
1210
1211 NOTE: this modifies the passed in data
1212 ********************************************************************/
1213 extern "C" void WIXAPI RevertCustomActionData(
1214 __in LPWSTR wzRevertTo,
1215 __in LPCWSTR wzRevertFrom
1216 )
1217 {
1218 if (!wzRevertTo)
1219 return;
1220 if (!wzRevertFrom)
1221 return;
1222 // start at the revert point and replace all \0 with MAGIC_MULTISZ_DELIM
1223 for(LPWSTR wzIndex = wzRevertTo; wzIndex < wzRevertFrom; wzIndex++)
1224 {
1225 if (0 == *wzIndex)
1226 {
1227 *wzIndex = MAGIC_MULTISZ_DELIM;
1228 }
1229 }
1230 return;
1231 }
1232
1233 /********************************************************************
1234 WcaReadStringFromCaData() - reads a string out of the CustomActionData
1235
1236 NOTE: this modifies the passed in ppwzCustomActionData variable
1237 ********************************************************************/
1238 extern "C" HRESULT WIXAPI WcaReadStringFromCaData(
1239 __deref_in LPWSTR* ppwzCustomActionData,
1240 __deref_out_z LPWSTR* ppwzString
1241 )
1242 {
1243 HRESULT hr = S_OK;
1244
1245 LPCWSTR pwz = BreakDownCustomActionData(ppwzCustomActionData);
1246 if (!pwz)
1247 return E_NOMOREITEMS;
1248
1249 hr = StrAllocString(ppwzString, pwz, 0);
1250 ExitOnFailure(hr, "failed to allocate memory for string");
1251
1252 hr = S_OK;
1253 LExit:
1254 return hr;
1255 }
1256
1257
1258 /********************************************************************
1259 WcaReadIntegerFromCaData() - reads an integer out of the CustomActionData
1260
1261 NOTE: this modifies the passed in ppwzCustomActionData variable
1262 ********************************************************************/
1263 extern "C" HRESULT WIXAPI WcaReadIntegerFromCaData(
1264 __deref_in LPWSTR* ppwzCustomActionData,
1265 __out int* piResult
1266 )
1267 {
1268 LPCWSTR pwz = BreakDownCustomActionData(ppwzCustomActionData);
1269 if (!pwz || 0 == wcslen(pwz))
1270 return E_NOMOREITEMS;
1271
1272 *piResult = wcstol(pwz, NULL, 10);
1273 return S_OK;
1274 }
1275
1276
1277
1278
1279 /********************************************************************
1280 WcaWriteStringToCaData() - adds a string to the CustomActionData to
1281 feed a deferred CustomAction
1282
1283 ********************************************************************/
1284 extern "C" HRESULT WIXAPI WcaWriteStringToCaData(
1285 __in_z LPCWSTR wzString,
1286 __deref_inout_z_opt LPWSTR* ppwzCustomActionData
1287 )
1288 {
1289 HRESULT hr = S_OK;
1290 WCHAR delim[] = {MAGIC_MULTISZ_DELIM, 0}; // magic char followed by NULL ter minator
1291
1292 if (!ppwzCustomActionData)
1293 {
1294 ExitFunction1(hr = E_INVALIDARG);
1295 }
1296
1297 DWORD cchString = lstrlenW(wzString) + 1; // assume we'll be adding the deli m
1298 DWORD_PTR cchCustomActionData = 0;
1299
1300 if (*ppwzCustomActionData)
1301 {
1302 hr = StrMaxLength(*ppwzCustomActionData, &cchCustomActionData);
1303 ExitOnFailure(hr, "failed to get length of custom action data");
1304 }
1305
1306 if ((cchCustomActionData - lstrlenW(*ppwzCustomActionData)) < cchString + 1)
1307 {
1308 cchCustomActionData += cchString + 1 + 255; // add 255 for good measure
1309 hr = StrAlloc(ppwzCustomActionData, cchCustomActionData);
1310 ExitOnFailure(hr, "Failed to allocate memory for CustomActionData string ");
1311 }
1312
1313 if (**ppwzCustomActionData) // if data exists toss the delimiter on before a dding more to the end
1314 {
1315 hr = ::StringCchCatW(*ppwzCustomActionData, cchCustomActionData, delim);
1316 ExitOnFailure(hr, "Failed to concatenate CustomActionData string");
1317 }
1318
1319 hr = ::StringCchCatW(*ppwzCustomActionData, cchCustomActionData, wzString);
1320 ExitOnFailure(hr, "Failed to concatenate CustomActionData string");
1321
1322 LExit:
1323 return hr;
1324 }
1325
1326
1327 /********************************************************************
1328 WcaWriteIntegerToCaData() - adds an integer to the CustomActionData to
1329 feed a deferred CustomAction
1330
1331 ********************************************************************/
1332 extern "C" HRESULT WIXAPI WcaWriteIntegerToCaData(
1333 __in int i,
1334 __deref_out_z_opt LPWSTR* ppwzCustomActionData
1335 )
1336 {
1337 WCHAR wzBuffer[13];
1338 StringCchPrintfW(wzBuffer, countof(wzBuffer), L"%d", i);
1339
1340 return WcaWriteStringToCaData(wzBuffer, ppwzCustomActionData);
1341 }
1342
1343
1344
1345 /********************************************************************
1346 WcaAddTempRecord - adds a temporary record to the active database
1347
1348 NOTE: you cannot use PMSIHANDLEs for the __in/__out parameters
1349 NOTE: uiUniquifyColumn can be 0 if no column needs to be made unique
1350 ********************************************************************/
1351 extern "C" HRESULT __cdecl WcaAddTempRecord(
1352 __inout MSIHANDLE* phTableView,
1353 __inout MSIHANDLE* phColumns,
1354 __in_z LPCWSTR wzTable,
1355 __out_opt MSIDBERROR* pdbError,
1356 __in UINT uiUniquifyColumn,
1357 __in UINT cColumns,
1358 ...
1359 )
1360 {
1361 Assert(phTableView && phColumns);
1362
1363 static DWORD dwUniquifyValue = ::GetTickCount();
1364
1365 HRESULT hr = S_OK;
1366 UINT er = ERROR_SUCCESS;
1367
1368 LPWSTR pwzQuery = NULL;
1369 PMSIHANDLE hTempRec;
1370 DWORD i;
1371 va_list args;
1372
1373 LPWSTR pwzData = NULL;
1374 LPWSTR pwzUniquify = NULL;
1375
1376 //
1377 // if we don't have a table and its columns already
1378 //
1379 if (NULL == *phTableView)
1380 {
1381 // set the query
1382 hr = StrAllocFormatted(&pwzQuery, L"SELECT * FROM `%s`",wzTable);
1383 ExitOnFailure(hr, "failed to allocate string for query");
1384
1385 // Open and Execute the temp View
1386 hr = WcaOpenExecuteView(pwzQuery, phTableView);
1387 ExitOnFailure1(hr, "failed to openexecute temp view with query %ls", pwz Query);
1388 }
1389
1390 if (NULL == *phColumns)
1391 {
1392 // use GetColumnInfo to populate the datatype record
1393 er = ::MsiViewGetColumnInfo(*phTableView, MSICOLINFO_TYPES, phColumns);
1394 ExitOnWin32Error1(er, hr, "failed to columns for table: %ls", wzTable);
1395 }
1396 AssertSz(::MsiRecordGetFieldCount(*phColumns) == cColumns, "passed in argume nt does not match number of columns in table");
1397
1398 //
1399 // create the temp record
1400 //
1401 hTempRec = ::MsiCreateRecord(cColumns);
1402 ExitOnNull1(hTempRec, hr, E_UNEXPECTED, "could not create temp record for ta ble: %ls", wzTable);
1403
1404 //
1405 // loop through all the columns filling in the data
1406 //
1407 va_start(args, cColumns);
1408 for (i = 1; i <= cColumns; i++)
1409 {
1410 hr = WcaGetRecordString(*phColumns, i, &pwzData);
1411 ExitOnFailure1(hr, "failed to get the data type for %d", i);
1412
1413 // if data type is string write string
1414 if (L's' == *pwzData || L'S' == *pwzData || L'g' == *pwzData || L'G' == *pwzData || L'l' == *pwzData || L'L' == *pwzData)
1415 {
1416 LPCWSTR wz = va_arg(args, WCHAR*);
1417
1418 // if this is the column that is supposed to be unique add the time stamp on the end
1419 if (uiUniquifyColumn == i)
1420 {
1421 hr = StrAllocFormatted(&pwzUniquify, L"%s%u", wz, ++dwUniquifyVa lue); // up the count so we have no collisions on the unique name
1422 ExitOnFailure1(hr, "failed to allocate string for unique column: %d", uiUniquifyColumn);
1423
1424 wz = pwzUniquify;
1425 }
1426
1427 er = ::MsiRecordSetStringW(hTempRec, i, wz);
1428 ExitOnWin32Error1(er, hr, "failed to set string value at position %d ", i);
1429 }
1430 // if data type is integer write integer
1431 else if (L'i' == *pwzData || L'I' == *pwzData || L'j' == *pwzData || L'J ' == *pwzData)
1432 {
1433 AssertSz(uiUniquifyColumn != i, "Cannot uniquify an integer column") ;
1434 int iData = va_arg(args, int);
1435
1436 er = ::MsiRecordSetInteger(hTempRec, i, iData);
1437 ExitOnWin32Error1(er, hr, "failed to set integer value at position % d", i);
1438 }
1439 else
1440 {
1441 // not supporting binary streams so error out
1442 hr = HRESULT_FROM_WIN32(ERROR_DATATYPE_MISMATCH);
1443 ExitOnRootFailure2(hr, "unsupported data type '%ls' in column: %d", pwzData, i);
1444 }
1445 }
1446 va_end(args);
1447
1448 //
1449 // add the temporary record to the MSI
1450 //
1451 er = ::MsiViewModify(*phTableView, MSIMODIFY_INSERT_TEMPORARY, hTempRec);
1452 hr = HRESULT_FROM_WIN32(er);
1453 if (FAILED(hr))
1454 {
1455 if (pdbError)
1456 {
1457 // MSI provides only a generic ERROR_FUNCTION_FAILED if a temporary row
1458 // can't be inserted; if we're being asked to provide the detailed e rror,
1459 // get it using the MSIMODIFY_VALIDATE_NEW flag
1460 er = ::MsiViewModify(*phTableView, MSIMODIFY_VALIDATE_NEW, hTempRec) ;
1461 hr = HRESULT_FROM_WIN32(er);
1462 }
1463
1464 WCHAR wzBuf[MAX_PATH];
1465 DWORD cchBuf = countof(wzBuf);
1466 MSIDBERROR dbErr = ::MsiViewGetErrorW(*phTableView, wzBuf, &cchBuf);
1467 if (pdbError)
1468 {
1469 *pdbError = dbErr;
1470 }
1471 ExitOnFailure2(hr, "failed to add temporary row, dberr: %d, err: %ls", d bErr, wzBuf);
1472 }
1473
1474 LExit:
1475 ReleaseStr(pwzUniquify);
1476 ReleaseStr(pwzData);
1477 ReleaseStr(pwzQuery);
1478
1479 return hr;
1480 }
1481
1482
1483 /********************************************************************
1484 WcaDumpTable - dumps a table to the log file
1485
1486 ********************************************************************/
1487 extern "C" HRESULT WIXAPI WcaDumpTable(
1488 __in_z LPCWSTR wzTable
1489 )
1490 {
1491 HRESULT hr = S_OK;
1492 UINT er = ERROR_SUCCESS;
1493
1494 LPWSTR pwzQuery = NULL;
1495 PMSIHANDLE hView;
1496 PMSIHANDLE hColumns;
1497 DWORD cColumns = 0;
1498 PMSIHANDLE hRec;
1499
1500 LPWSTR pwzData = NULL;
1501 LPWSTR pwzPrint = NULL;
1502
1503 hr = StrAllocFormatted(&pwzQuery, L"SELECT * FROM `%s`",wzTable);
1504 ExitOnFailure(hr, "failed to allocate string for query");
1505
1506 // Open and Execute the temp View
1507 hr = WcaOpenExecuteView(pwzQuery, &hView);
1508 ExitOnFailure1(hr, "failed to openexecute temp view with query %ls", pwzQuer y);
1509
1510 // Use GetColumnInfo to populate the names of the columns.
1511 er = ::MsiViewGetColumnInfo(hView, MSICOLINFO_NAMES, &hColumns);
1512 hr = HRESULT_FROM_WIN32(er);
1513 ExitOnFailure1(hr, "failed to get column info for table: %ls", wzTable);
1514
1515 cColumns = ::MsiRecordGetFieldCount(hColumns);
1516
1517 WcaLog(LOGMSG_STANDARD, "--- Begin Table Dump %ls ---", wzTable);
1518
1519 // Loop through all the columns filling in the data.
1520 for (DWORD i = 1; i <= cColumns; i++)
1521 {
1522 hr = WcaGetRecordString(hColumns, i, &pwzData);
1523 ExitOnFailure1(hr, "failed to get the column name for %d", i);
1524
1525 hr = StrAllocConcat(&pwzPrint, pwzData, 0);
1526 ExitOnFailure(hr, "Failed to add column name.");
1527
1528 hr = StrAllocConcat(&pwzPrint, L"\t", 1);
1529 ExitOnFailure(hr, "Failed to add column name.");
1530 }
1531
1532 WcaLog(LOGMSG_STANDARD, "%ls", pwzPrint);
1533
1534 // Now dump the actual rows.
1535 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
1536 {
1537 if (pwzPrint && *pwzPrint)
1538 {
1539 *pwzPrint = L'\0';
1540 }
1541
1542 for (DWORD i = 1; i <= cColumns; i++)
1543 {
1544 hr = WcaGetRecordString(hRec, i, &pwzData);
1545 ExitOnFailure1(hr, "failed to get the column name for %d", i);
1546
1547 hr = StrAllocConcat(&pwzPrint, pwzData, 0);
1548 ExitOnFailure(hr, "Failed to add column name.");
1549
1550 hr = StrAllocConcat(&pwzPrint, L"\t", 1);
1551 ExitOnFailure(hr, "Failed to add column name.");
1552 }
1553
1554 WcaLog(LOGMSG_STANDARD, "%ls", pwzPrint);
1555 }
1556
1557 WcaLog(LOGMSG_STANDARD, "--- End Table Dump %ls ---", wzTable);
1558
1559 LExit:
1560 ReleaseStr(pwzPrint);
1561 ReleaseStr(pwzData);
1562 ReleaseStr(pwzQuery);
1563
1564 return hr;
1565 }
1566
1567
1568 HRESULT WIXAPI WcaDeferredActionRequiresReboot()
1569 {
1570 HRESULT hr = S_OK;
1571 ATOM atomReboot = 0;
1572
1573 atomReboot = ::GlobalAddAtomW(L"WcaDeferredActionRequiresReboot");
1574 ExitOnNullWithLastError(atomReboot, hr, "Failed to create WcaDeferredActionR equiresReboot global atom.");
1575
1576 LExit:
1577 return hr;
1578 }
1579
1580
1581 BOOL WIXAPI WcaDidDeferredActionRequireReboot()
1582 {
1583 // NOTE: This function does not delete the global atom. That is done
1584 // purposefully so that any other installs that occur after this point also
1585 // require a reboot.
1586 ATOM atomReboot = ::GlobalFindAtomW(L"WcaDeferredActionRequiresReboot");
1587 return 0 != atomReboot;
1588 }
OLDNEW

Powered by Google App Engine
This is Rietveld