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