aboutsummaryrefslogtreecommitdiff
path: root/src/ca
diff options
context:
space:
mode:
Diffstat (limited to 'src/ca')
-rw-r--r--src/ca/DriveCheck.cpp126
-rw-r--r--src/ca/PrintEula.cpp544
-rw-r--r--src/ca/cost.h9
-rw-r--r--src/ca/dllmain.cpp26
-rw-r--r--src/ca/precomp.h19
-rw-r--r--src/ca/uica.def8
-rw-r--r--src/ca/uica.vcxproj59
7 files changed, 791 insertions, 0 deletions
diff --git a/src/ca/DriveCheck.cpp b/src/ca/DriveCheck.cpp
new file mode 100644
index 00000000..fafd73c2
--- /dev/null
+++ b/src/ca/DriveCheck.cpp
@@ -0,0 +1,126 @@
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
5static HRESULT PathIsRemote(__in LPCWSTR pTargetFolder, __inout BOOL* fPathRemote);
6static HRESULT PathIsRemovable(__in LPCWSTR pTargetFolder, __inout BOOL* fPathRemovable);
7
8/********************************************************************
9 ValidatePath - Custom Action entry point
10
11********************************************************************/
12UINT __stdcall ValidatePath(MSIHANDLE hInstall)
13{
14 HRESULT hr = S_OK;
15
16 LPWSTR pwszWixUIDir = NULL;
17 LPWSTR pwszInstallPath = NULL;
18 BOOL fInstallPathIsRemote = TRUE;
19 BOOL fInstallPathIsRemoveable = TRUE;
20
21 hr = WcaInitialize(hInstall, "ValidatePath");
22 ExitOnFailure(hr, "failed to initialize");
23
24 hr = WcaGetProperty(L"WIXUI_INSTALLDIR", &pwszWixUIDir);
25 ExitOnFailure(hr, "failed to get WixUI Installation Directory");
26
27 hr = WcaGetProperty(pwszWixUIDir, &pwszInstallPath);
28 ExitOnFailure(hr, "failed to get Installation Directory");
29
30 hr = PathIsRemote(pwszInstallPath, &fInstallPathIsRemote);
31 if (FAILED(hr))
32 {
33 TraceError(hr, "Unable to determine if path is remote");
34 //reset HR, as we need to continue and find out if is a UNC path
35 hr = S_OK;
36 }
37
38 hr = PathIsRemovable(pwszInstallPath, &fInstallPathIsRemoveable);
39 if (FAILED(hr))
40 {
41 TraceError(hr, "Unable to determine if path is removable");
42 //reset HR, as we need to continue and find out if is a UNC path
43 hr = S_OK;
44 }
45
46 // If the path does not point to a network drive, mapped drive, or removable drive,
47 // then set WIXUI_INSTALLDIR_VALID to "1" otherwise set it to 0
48 BOOL fInstallPathIsUnc = PathIsUNCW(pwszInstallPath);
49 if (!fInstallPathIsUnc && !fInstallPathIsRemote && !fInstallPathIsRemoveable)
50 {
51 // path is valid
52 hr = WcaSetProperty(L"WIXUI_INSTALLDIR_VALID", L"1");
53 ExitOnFailure(hr, "failed to set WIXUI_INSTALLDIR_VALID");
54 }
55 else
56 {
57 // path is invalid; we can't log it because we're being called from a DoAction control event
58 // but we can at least call WcaLog to get it to write to the debugger from a debug build
59 WcaLog(LOGMSG_STANDARD, "Installation path %ls is invalid: it is %s UNC path, %s remote path, or %s path on a removable drive, and must be none of these.",
60 pwszInstallPath, fInstallPathIsUnc ? "a" : "not a", fInstallPathIsRemote ? "a" : "not a", fInstallPathIsRemoveable ? "a" : "not a");
61 hr = WcaSetProperty(L"WIXUI_INSTALLDIR_VALID", L"0");
62 ExitOnFailure(hr, "failed to set WIXUI_INSTALLDIR_VALID");
63 }
64
65LExit:
66 ReleaseStr(pwszInstallPath);
67 ReleaseStr(pwszWixUIDir);
68
69 return WcaFinalize(SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE);
70}
71
72/********************************************************************
73 PathIsRemote - helper function for ValidatePath
74
75********************************************************************/
76static HRESULT PathIsRemote(__in LPCWSTR pTargetFolder, __inout BOOL* fPathRemote)
77{
78 HRESULT hr = S_OK;
79 LPWSTR pStrippedTargetFolder = NULL;
80
81 hr = StrAllocString(&pStrippedTargetFolder, pTargetFolder, 0);
82
83 // Terminate the path at the root
84 if(!::PathStripToRootW(pStrippedTargetFolder))
85 {
86 hr = HRESULT_FROM_WIN32(ERROR_INVALID_DRIVE);
87 ExitOnFailure(hr, "failed to parse target folder");
88 }
89
90 UINT uResult = GetDriveTypeW(pStrippedTargetFolder);
91
92 *fPathRemote = (DRIVE_REMOTE == uResult) ;
93
94LExit:
95 ReleaseStr(pStrippedTargetFolder);
96
97 return hr;
98}
99
100/********************************************************************
101 PathIsRemovable - helper function for ValidatePath
102
103********************************************************************/
104static HRESULT PathIsRemovable(__in LPCWSTR pTargetFolder, __inout BOOL* fPathRemovable)
105{
106 HRESULT hr = S_OK;
107 LPWSTR pStrippedTargetFolder = NULL;
108
109 hr = StrAllocString(&pStrippedTargetFolder, pTargetFolder, 0);
110
111 // Terminate the path at the root
112 if(!::PathStripToRootW(pStrippedTargetFolder))
113 {
114 hr = HRESULT_FROM_WIN32(ERROR_INVALID_DRIVE);
115 ExitOnFailure(hr, "failed to parse target folder");
116 }
117
118 UINT uResult = GetDriveTypeW(pStrippedTargetFolder);
119
120 *fPathRemovable = ((DRIVE_CDROM == uResult) || (DRIVE_REMOVABLE == uResult) || (DRIVE_RAMDISK == uResult) || (DRIVE_UNKNOWN == uResult));
121
122LExit:
123 ReleaseStr(pStrippedTargetFolder);
124
125 return hr;
126}
diff --git a/src/ca/PrintEula.cpp b/src/ca/PrintEula.cpp
new file mode 100644
index 00000000..770a082c
--- /dev/null
+++ b/src/ca/PrintEula.cpp
@@ -0,0 +1,544 @@
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// Constants
6LPCWSTR vcsEulaQuery = L"SELECT `Text` FROM `Control` WHERE `Control`='LicenseText'";
7
8
9enum eEulaQuery { eqText = 1};
10const int IDM_POPULATE = 100;
11const int IDM_PRINT = 101;
12const int CONTROL_X_COORDINATE = 0;
13const int CONTROL_Y_COORDINATE = 0;
14const int CONTROL_WIDTH = 500;
15const int CONTROL_HEIGHT = 500;
16const int ONE_INCH = 1440; // 1440 TWIPS = 1 inch.
17const int TEXT_RECORD_POS = 1;
18const int STRING_CAPACITY = 512;
19const int NO_OF_COPIES = 1;
20const LPWSTR WINDOW_CLASS = L"PrintEulaRichText";
21
22//Forward declarations of functions, check the function definitions for the comments
23static LRESULT CALLBACK WndProc(__in HWND hWnd, __in UINT message, __in WPARAM wParam, __in LPARAM lParam);
24static HRESULT ReadEulaText(__in MSIHANDLE hInstall, __out LPSTR* ppszEulaText);
25static DWORD CALLBACK ReadStreamCallback(__in DWORD Cookie, __out LPBYTE pbBuff, __in LONG cb, __out LONG FAR *pcb);
26static HRESULT CreateRichTextWindow(__out HWND* phWndMain, __out BOOL* pfRegisteredClass);
27static HRESULT PrintRichText(__in HWND hWndMain);
28static void Print(__in_opt HWND hWnd);
29static void LoadEulaText(__in_opt HWND hWnd);
30static void ShowErrorMessage(__in HRESULT hr);
31
32//Global variables
33PRINTDLGEXW* vpPrintDlg = NULL; //Parameters for print (needed on both sides of WndProc callbacks)
34LPSTR vpszEulaText = NULL;
35HRESULT vhr = S_OK; //Global hr, used by the functions called from WndProc to set errorcode
36
37
38/********************************************************************
39 PrintEula - Custom Action entry point
40
41********************************************************************/
42extern "C" UINT __stdcall PrintEula(MSIHANDLE hInstall)
43{
44 //AssertSz(FALSE, "Debug PrintEula");
45
46 HRESULT hr = S_OK;
47 HWND hWndMain = NULL;
48 HMODULE hRichEdit = NULL;
49 BOOL fRegisteredClass = FALSE;
50
51 hr = WcaInitialize(hInstall, "PrintEula");
52 ExitOnFailure(hr, "failed to initialize");
53
54 // Initialize then display print dialog.
55 vpPrintDlg = (PRINTDLGEXW*)GlobalAlloc(GPTR, sizeof(PRINTDLGEXW)); // MSDN says to allocate on heap.
56 ExitOnNullWithLastError(vpPrintDlg, hr, "Failed to allocate memory for print dialog struct.");
57
58 vpPrintDlg->lStructSize = sizeof(PRINTDLGEX);
59 vpPrintDlg->hwndOwner = ::FindWindowW(L"MsiDialogCloseClass", NULL);
60 vpPrintDlg->Flags = PD_RETURNDC | PD_COLLATE | PD_NOCURRENTPAGE | PD_ALLPAGES | PD_NOPAGENUMS | PD_NOSELECTION;
61 vpPrintDlg->nCopies = NO_OF_COPIES;
62 vpPrintDlg->nStartPage = START_PAGE_GENERAL;
63
64 hr = ::PrintDlgExW(vpPrintDlg);
65 ExitOnFailure(hr, "Failed to show print dialog");
66
67 // If user said they want to print.
68 if (PD_RESULT_PRINT == vpPrintDlg->dwResultAction)
69 {
70 // Get the stream for Eula
71 hr = ReadEulaText(hInstall, &vpszEulaText);
72 ExitOnFailure(hr, "failed to read Eula text from MSI database");
73
74 // Have to load Rich Edit since we'll be creating a Rich Edit control in the window
75 hr = LoadSystemLibrary(L"Riched20.dll", &hRichEdit);
76 ExitOnFailure(hr, "failed to load rich edit 2.0 library");
77
78 hr = CreateRichTextWindow(&hWndMain, &fRegisteredClass);
79 ExitOnFailure(hr, "failed to create rich text window for printing");
80
81 hr = PrintRichText(hWndMain);
82 if (FAILED(hr)) // Since we've already shown the print dialog, we better show them a dialog explaining why it didn't print
83 {
84 ShowErrorMessage(hr);
85 }
86 }
87
88LExit:
89 ReleaseNullStr(vpszEulaText);
90 if (vpPrintDlg)
91 {
92 if (vpPrintDlg->hDevMode)
93 {
94 ::GlobalFree(vpPrintDlg->hDevMode);
95 }
96
97 if (vpPrintDlg->hDevNames)
98 {
99 ::GlobalFree(vpPrintDlg->hDevNames);
100 }
101
102 if (vpPrintDlg->hDC)
103 {
104 ::DeleteDC(vpPrintDlg->hDC);
105 }
106
107 ::GlobalFree(vpPrintDlg);
108 vpPrintDlg = NULL;
109 }
110
111 if (fRegisteredClass)
112 {
113 ::UnregisterClassW(WINDOW_CLASS, NULL);
114 }
115
116 if (NULL != hRichEdit)
117 {
118 ::FreeLibrary(hRichEdit);
119 }
120
121 // Always return success since we dont want to stop the
122 // installation even if the Eula printing fails.
123 return WcaFinalize(ERROR_SUCCESS);
124}
125
126
127
128/********************************************************************
129CreateRichTextWindow - Creates Window and Child RichText control.
130
131********************************************************************/
132HRESULT CreateRichTextWindow(
133 __out HWND* phWndMain,
134 __out BOOL* pfRegisteredClass
135 )
136{
137 HRESULT hr = S_OK;
138 HWND hWndMain = NULL;
139 WNDCLASSEXW wcex;
140
141 //
142 // Register the window class
143 //
144 wcex.cbSize = sizeof(WNDCLASSEXW);
145 wcex.style = CS_HREDRAW | CS_VREDRAW;
146 wcex.lpfnWndProc = (WNDPROC)WndProc;
147 wcex.cbClsExtra = 0;
148 wcex.cbWndExtra = 0;
149 wcex.hInstance = NULL;
150 wcex.hIcon = NULL;
151 wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
152 wcex.hbrBackground = (HBRUSH)(COLOR_BACKGROUND+1);
153 wcex.lpszMenuName = NULL;
154 wcex.lpszClassName = WINDOW_CLASS;
155 wcex.hIconSm = NULL;
156
157 if (0 == ::RegisterClassExW(&wcex))
158 {
159 DWORD dwResult = ::GetLastError();
160
161 // If we get "Class already exists" error ignore it. We might
162 // encounter this when the user tries to print more than once
163 // in the same setup instance and we are unable to clean up fully.
164 if (dwResult != ERROR_CLASS_ALREADY_EXISTS)
165 {
166 ExitOnFailure(hr = HRESULT_FROM_WIN32(dwResult), "failed to register window class");
167 }
168 }
169
170 *pfRegisteredClass = TRUE;
171
172 // Perform application initialization:
173 hWndMain = ::CreateWindowW(WINDOW_CLASS, NULL, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, NULL, NULL);
174 ExitOnNullWithLastError(hWndMain, hr, "failed to create window for printing");
175
176 ::ShowWindow(hWndMain, SW_HIDE);
177 if (!::UpdateWindow(hWndMain))
178 {
179 ExitWithLastError(hr, "failed to update window");
180 }
181
182 *phWndMain = hWndMain;
183
184LExit:
185 return hr;
186}
187
188
189/********************************************************************
190 PrintRichText - Sends messages to load the Eula text, print it, and
191 close the window.
192
193 NOTE: Returns errors that have occured while attempting to print,
194 which were saved in vhr by the print callbacks.
195********************************************************************/
196HRESULT PrintRichText(
197 __in HWND hWndMain
198 )
199{
200 MSG msg;
201
202 // Populate the RichEdit control
203 ::SendMessageW(hWndMain, WM_COMMAND, IDM_POPULATE, 0);
204
205 // Print Eula
206 ::SendMessageW(hWndMain, WM_COMMAND, IDM_PRINT, 0);
207
208 // Done! Lets close the Window
209 ::SendMessage(hWndMain, WM_CLOSE, 0, 0);
210 // Main message loop:
211 while (::GetMessageW(&msg, NULL, 0, 0))
212 {
213// if (!::TranslateAcceleratorW(msg.hwnd, NULL, &msg))
214// {
215// ::TranslateMessage(&msg);
216// ::DispatchMessageW(&msg);
217// }
218 }
219
220
221 // return any errors encountered in the print callbacks
222 return vhr;
223}
224
225
226/********************************************************************
227 WndProc - Windows callback procedure
228
229********************************************************************/
230LRESULT CALLBACK WndProc(
231 __in HWND hWnd,
232 __in UINT message,
233 __in WPARAM wParam,
234 __in LPARAM lParam
235 )
236{
237 static HWND hWndRichEdit = NULL;
238 int wmId, wmEvent;
239 PAINTSTRUCT ps;
240 HDC hdc;
241
242 switch (message)
243 {
244 case WM_CREATE:
245 hWndRichEdit = ::CreateWindowExW(WS_EX_CLIENTEDGE, RICHEDIT_CLASSW, L"", ES_MULTILINE | WS_CHILD | WS_VISIBLE | WS_VSCROLL, CONTROL_X_COORDINATE, CONTROL_Y_COORDINATE, CONTROL_WIDTH, CONTROL_HEIGHT, hWnd, NULL, NULL, NULL);
246 break;
247 case WM_COMMAND:
248 wmId = LOWORD(wParam);
249 wmEvent = HIWORD(wParam);
250 switch (wmId)
251 {
252 case IDM_POPULATE:
253 LoadEulaText(hWndRichEdit);
254 break;
255 case IDM_PRINT:
256 Print(hWndRichEdit);
257 break;
258 default:
259 return ::DefWindowProcW(hWnd, message, wParam, lParam);
260 break;
261 }
262 break;
263 case WM_PAINT:
264 hdc = ::BeginPaint(hWnd, &ps);
265 ::EndPaint(hWnd, &ps);
266 break;
267 case WM_DESTROY:
268 ::PostQuitMessage(0);
269 break;
270 default:
271 return ::DefWindowProcW(hWnd, message, wParam, lParam);
272 }
273
274 return 0;
275}
276
277
278/********************************************************************
279 ReadStreamCallback - Callback function to read data to the RichText control
280
281 NOTE: Richtext control uses this function to read data from the buffer
282********************************************************************/
283DWORD CALLBACK ReadStreamCallback(
284 __in DWORD /*Cookie*/,
285 __out LPBYTE pbBuff,
286 __in LONG cb,
287 __out LONG FAR *pcb
288 )
289{
290 static LPCSTR pszTextBuf = NULL;
291 DWORD er = ERROR_SUCCESS;
292
293 // If it's null set it to the beginning of the EULA buffer
294 if (pszTextBuf == NULL)
295 {
296 pszTextBuf = vpszEulaText;
297 }
298
299 LONG lTextLength = (LONG)lstrlen(pszTextBuf);
300
301 if (cb < 0)
302 {
303 *pcb = 0;
304 er = 1;
305 }
306 else if (lTextLength < cb ) // If the size to be written is less than then length of the buffer, write the rest
307 {
308 *pcb = lTextLength;
309 memcpy(pbBuff, pszTextBuf, *pcb);
310 pszTextBuf = NULL;
311 }
312 else // Only write the amount being asked for and move the pointer along
313 {
314 *pcb = cb;
315 memcpy(pbBuff, pszTextBuf, *pcb);
316 pszTextBuf = pszTextBuf + cb;
317 }
318
319 return er;
320}
321
322
323/********************************************************************
324 LoadEulaText - Reads data for Richedit control
325
326********************************************************************/
327void LoadEulaText(
328 __in HWND hWnd
329 )
330{
331 HRESULT hr = S_OK;
332
333 ExitOnNull(hWnd, hr, ERROR_INVALID_HANDLE, "Invalid Handle passed to LoadEulaText");
334
335 // Docs say this doesn't return any value
336 ::SendMessageW(hWnd, EM_LIMITTEXT, static_cast<WPARAM>(lstrlen(vpszEulaText)), 0);
337
338 EDITSTREAM es;
339 ::ZeroMemory(&es, sizeof(es));
340 es.pfnCallback = (EDITSTREAMCALLBACK)ReadStreamCallback;
341 es.dwCookie = (DWORD)0;
342 ::SendMessageW(hWnd, EM_STREAMIN, SF_RTF, (LPARAM)&es);
343
344 if (0 != es.dwError)
345 {
346 ExitOnLastError(hr, "failed to load the EULA into the control");
347 }
348
349LExit:
350 vhr = hr;
351}
352
353
354/********************************************************************
355 ReadEulaText - Reads Eula text from the MSI
356
357********************************************************************/
358HRESULT ReadEulaText(
359 __in MSIHANDLE /*hInstall*/,
360 __out LPSTR* ppszEulaText
361 )
362{
363 HRESULT hr = S_OK;
364 PMSIHANDLE hDB;
365 PMSIHANDLE hView;
366 PMSIHANDLE hRec;
367 LPWSTR pwzEula = NULL;
368
369 hr = WcaOpenExecuteView(vcsEulaQuery, &hView);
370 ExitOnFailure(hr, "failed to open and execute view for PrintEula query");
371
372 hr = WcaFetchSingleRecord(hView, &hRec);
373 ExitOnFailure(hr, "failed to fetch the row containing the LicenseText");
374
375 hr = WcaGetRecordString(hRec, 1, &pwzEula);
376 ExitOnFailure(hr, "failed to get LicenseText in PrintEula");
377
378 hr = StrAnsiAllocString(ppszEulaText, pwzEula, 0, CP_ACP);
379 ExitOnFailure(hr, "failed to convert LicenseText to ANSI code page");
380
381LExit:
382 return hr;
383}
384
385
386/********************************************************************
387 Print - Function that sends the data from richedit control to the printer
388
389 NOTE: Any errors encountered are saved to the vhr variable
390********************************************************************/
391void Print(
392 __in_opt HWND hRtfWnd
393 )
394{
395 HRESULT hr = S_OK;
396 FORMATRANGE fRange;
397 RECT rcPage;
398 RECT rcPrintablePage;
399 GETTEXTLENGTHEX gTxex;
400 HDC hPrinterDC = vpPrintDlg->hDC;
401 int nHorizRes = ::GetDeviceCaps(hPrinterDC, HORZRES);
402 int nVertRes = ::GetDeviceCaps(hPrinterDC, VERTRES);
403 int nLogPixelsX = ::GetDeviceCaps(hPrinterDC, LOGPIXELSX);
404 //int nLogPixelsY = ::GetDeviceCaps(hPrinterDC, LOGPIXELSY);
405 LONG_PTR lTextLength = 0; // Length of document.
406 LONG_PTR lTextPrinted = 0; // Amount of document printed.
407 DOCINFOW dInfo;
408 LPDEVNAMES pDevnames;
409 LPWSTR sczProductName = NULL;
410 BOOL fStartedDoc = FALSE;
411 BOOL fPrintedSomething = FALSE;
412
413 // Ensure the printer DC is in MM_TEXT mode.
414 if (0 == ::SetMapMode(hPrinterDC, MM_TEXT))
415 {
416 ExitWithLastError(hr, "failed to set map mode");
417 }
418
419 // Rendering to the same DC we are measuring.
420 ::ZeroMemory(&fRange, sizeof(fRange));
421 fRange.hdc = fRange.hdcTarget = hPrinterDC;
422
423 // Set up the page.
424 rcPage.left = rcPage.top = 0;
425 rcPage.right = MulDiv(nHorizRes, ONE_INCH, nLogPixelsX);
426 rcPage.bottom = MulDiv(nVertRes, ONE_INCH, nLogPixelsX);
427
428 // Set up 1" margins all around.
429 rcPrintablePage.left = rcPage.left + ONE_INCH;
430 rcPrintablePage.top = rcPage.top + ONE_INCH;
431 rcPrintablePage.right = rcPage.right - ONE_INCH;
432 rcPrintablePage.bottom = rcPage.bottom - ONE_INCH;
433
434 // Set up the print job (standard printing stuff here).
435 ::ZeroMemory(&dInfo, sizeof(dInfo));
436 dInfo.cbSize = sizeof(DOCINFO);
437 hr = WcaGetProperty(L"ProductName", &sczProductName);
438 if (FAILED(hr))
439 {
440 // If we fail to get the product name, don't fail, just leave it blank;
441 dInfo.lpszDocName = L"";
442 hr = S_OK;
443 }
444 else
445 {
446 dInfo.lpszDocName = sczProductName;
447 }
448
449 pDevnames = (LPDEVNAMES)::GlobalLock(vpPrintDlg->hDevNames);
450 ExitOnNullWithLastError(pDevnames, hr, "failed to get global lock");
451
452 dInfo.lpszOutput = (LPWSTR)pDevnames + pDevnames->wOutputOffset;
453
454 if (0 == ::GlobalUnlock(pDevnames))
455 {
456 ExitWithLastError(hr, "failed to release global lock");
457 }
458
459 // Start the document.
460 if (0 >= ::StartDocW(hPrinterDC, &dInfo))
461 {
462 ExitWithLastError(hr, "failed to start print document");
463 }
464
465 fStartedDoc = TRUE;
466
467 ::ZeroMemory(&gTxex, sizeof(gTxex));
468 gTxex.flags = GTL_NUMCHARS | GTL_PRECISE;
469 lTextLength = ::SendMessageW(hRtfWnd, EM_GETTEXTLENGTHEX, (LONG_PTR)&gTxex, 0);
470
471 while (lTextPrinted < lTextLength)
472 {
473 // Start the page.
474 if (0 >= ::StartPage(hPrinterDC))
475 {
476 ExitWithLastError(hr, "failed to start print page");
477 }
478
479 // Always reset to the full printable page and start where the
480 // last text left off (or zero at the beginning).
481 fRange.rc = rcPrintablePage;
482 fRange.rcPage = rcPage;
483 fRange.chrg.cpMin = (LONG)lTextPrinted;
484 fRange.chrg.cpMax = -1;
485
486 // Print as much text as can fit on a page. The return value is
487 // the index of the first character on the next page. Using TRUE
488 // for the wParam parameter causes the text to be printed.
489 lTextPrinted = ::SendMessageW(hRtfWnd, EM_FORMATRANGE, TRUE, (LPARAM)&fRange);
490 fPrintedSomething = TRUE;
491
492 // If text wasn't printed (i.e. we didn't move past the point we started) then
493 // something must have gone wrong.
494 if (lTextPrinted <= fRange.chrg.cpMin)
495 {
496 hr = E_FAIL;
497 ExitOnFailure(hr, "failed to print some text");
498 }
499
500 // Print last page.
501 if (0 >= ::EndPage(hPrinterDC))
502 {
503 ExitWithLastError(hr, "failed to end print page");
504 }
505 }
506
507LExit:
508 // Tell the control to release cached information, if we actually tried to
509 // print something.
510 if (fPrintedSomething)
511 {
512 ::SendMessageW(hRtfWnd, EM_FORMATRANGE, 0, (LPARAM)NULL);
513 }
514
515 if (fStartedDoc)
516 {
517 ::EndDoc(hPrinterDC);
518 }
519
520 ReleaseStr(sczProductName);
521
522 vhr = hr;
523}
524
525
526/********************************************************************
527 ShowErrorMessage - Display MessageBox showing the message for hr.
528
529********************************************************************/
530void ShowErrorMessage(
531 __in HRESULT hr
532 )
533{
534 WCHAR wzMsg[STRING_CAPACITY];
535
536#pragma prefast(push)
537#pragma prefast(disable:25028)
538 if (0 != ::FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, 0, hr, 0, wzMsg, countof(wzMsg), 0))
539#pragma prefast(pop)
540 {
541 HWND hWnd = ::GetForegroundWindow();
542 ::MessageBoxW(hWnd, wzMsg, L"PrintEULA", MB_OK | MB_ICONWARNING);
543 }
544}
diff --git a/src/ca/cost.h b/src/ca/cost.h
new file mode 100644
index 00000000..8b8e8874
--- /dev/null
+++ b/src/ca/cost.h
@@ -0,0 +1,9 @@
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
5const UINT COST_SECUREOBJECT = 1000;
6const UINT COST_SERVICECONFIG = 1000;
7const UINT COST_XMLFILE = 1000;
8const UINT COST_CLOSEAPP = 500;
9
diff --git a/src/ca/dllmain.cpp b/src/ca/dllmain.cpp
new file mode 100644
index 00000000..df53f872
--- /dev/null
+++ b/src/ca/dllmain.cpp
@@ -0,0 +1,26 @@
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/********************************************************************
6DllMain - standard entry point for all WiX CustomActions
7
8********************************************************************/
9extern "C" BOOL WINAPI DllMain(
10 IN HINSTANCE hInst,
11 IN ULONG ulReason,
12 IN LPVOID)
13{
14 switch(ulReason)
15 {
16 case DLL_PROCESS_ATTACH:
17 WcaGlobalInitialize(hInst);
18 break;
19
20 case DLL_PROCESS_DETACH:
21 WcaGlobalFinalize();
22 break;
23 }
24
25 return TRUE;
26}
diff --git a/src/ca/precomp.h b/src/ca/precomp.h
new file mode 100644
index 00000000..dcdf2653
--- /dev/null
+++ b/src/ca/precomp.h
@@ -0,0 +1,19 @@
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 <windows.h>
6#include <msiquery.h>
7#include <richedit.h>
8#include <shlwapi.h>
9
10#include "wixstrsafe.h"
11#include "wcautil.h"
12#include "aclutil.h"
13#include "fileutil.h"
14#include "memutil.h"
15#include "strutil.h"
16#include "xmlutil.h"
17
18#include "CustomMsiErrors.h"
19#include "cost.h"
diff --git a/src/ca/uica.def b/src/ca/uica.def
new file mode 100644
index 00000000..62ce8135
--- /dev/null
+++ b/src/ca/uica.def
@@ -0,0 +1,8 @@
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
4LIBRARY "uica"
5
6EXPORTS
7 PrintEula
8 ValidatePath
diff --git a/src/ca/uica.vcxproj b/src/ca/uica.vcxproj
new file mode 100644
index 00000000..92e20e1a
--- /dev/null
+++ b/src/ca/uica.vcxproj
@@ -0,0 +1,59 @@
1<?xml version="1.0" encoding="utf-8"?>
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<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
6 <ItemGroup Label="ProjectConfigurations">
7 <ProjectConfiguration Include="Debug|Win32">
8 <Configuration>Debug</Configuration>
9 <Platform>Win32</Platform>
10 </ProjectConfiguration>
11 <ProjectConfiguration Include="Release|Win32">
12 <Configuration>Release</Configuration>
13 <Platform>Win32</Platform>
14 </ProjectConfiguration>
15 </ItemGroup>
16 <ItemGroup Label="ProjectConfigurations">
17 <ProjectConfiguration Include="Debug|ARM">
18 <Configuration>Debug</Configuration>
19 <Platform>ARM</Platform>
20 </ProjectConfiguration>
21 <ProjectConfiguration Include="Release|ARM">
22 <Configuration>Release</Configuration>
23 <Platform>ARM</Platform>
24 </ProjectConfiguration>
25 </ItemGroup>
26
27 <PropertyGroup Label="Globals">
28 <ProjectGuid>{F72D34CA-48DA-4DFD-91A9-A0C78BEF6981}</ProjectGuid>
29 <ConfigurationType>DynamicLibrary</ConfigurationType>
30 <CharacterSet>MultiByte</CharacterSet>
31 <TargetName>uica</TargetName>
32 <ProjectModuleDefinitionFile>uica.def</ProjectModuleDefinitionFile>
33 </PropertyGroup>
34
35 <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), wix.proj))\tools\WixBuild.props" />
36
37 <PropertyGroup>
38 <ProjectAdditionalIncludeDirectories>$(WixRoot)src\libs\dutil\inc;$(WixRoot)src\libs\wcautil</ProjectAdditionalIncludeDirectories>
39 <ProjectAdditionalLinkLibraries>msi.lib;shlwapi.lib;dutil.lib;wcautil.lib</ProjectAdditionalLinkLibraries>
40 </PropertyGroup>
41
42 <ItemGroup>
43 <ClCompile Include="dllmain.cpp" />
44 <ClCompile Include="DriveCheck.cpp" />
45 <ClCompile Include="PrintEula.cpp" />
46 </ItemGroup>
47 <ItemGroup>
48 <ClInclude Include="cost.h" />
49 <ClInclude Include="precomp.h" />
50 </ItemGroup>
51 <ItemGroup>
52 <None Include="uica.def" />
53 </ItemGroup>
54 <ItemGroup>
55 <ResourceCompile Include="uica.rc" />
56 </ItemGroup>
57
58 <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), wix.proj))\tools\WixBuild.targets" />
59</Project>