Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4453 lines
116 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. wizard.c
  5. Abstract:
  6. Send fax wizard dialogs
  7. Environment:
  8. Fax driver user interface
  9. Revision History:
  10. 01/19/96 -davidx-
  11. Created it.
  12. mm/dd/yy -author-
  13. description
  14. --*/
  15. #include "faxui.h"
  16. #include "tapiutil.h"
  17. #include "prtcovpg.h"
  18. #include "tiff.h"
  19. #include "cwabutil.h"
  20. #include <shellapi.h>
  21. #include <imm.h>
  22. #ifdef FAX_SCAN_ENABLED
  23. #define TWRESMIN 0
  24. #define TWRESMAX 1
  25. #define TWRESSCAL 2
  26. #define TWRESCUR 3
  27. #define TWRESDEFAULT 4
  28. #define TWRESCLOSEST 5
  29. #define AUTOSCANPREV 0
  30. #define AUTOSCANFINAL 1
  31. #define CUSTOMSCAN 2
  32. #define CANCELLED 3
  33. #define FINALCANCELLED 4
  34. #define AUTOSCANSHEETFED 5
  35. #define CUSTOMDIGITALCAMERA 6
  36. #define DCCANCELLED 7
  37. #define Align(p, x) (((x) & ((p)-1)) ? (((x) & ~((p)-1)) + p) : (x))
  38. #define WM_PAGE_COMPLETE (WM_USER+1000)
  39. #define NUM_IFD_ENTRIES 18
  40. #define IFD_SUBFILETYPE 0 // 254
  41. #define IFD_IMAGEWIDTH 1 // 256
  42. #define IFD_IMAGELENGTH 2 // 257
  43. #define IFD_BITSPERSAMPLE 3 // 258
  44. #define IFD_COMPRESSION 4 // 259
  45. #define IFD_PHOTOMETRIC 5 // 262
  46. #define IFD_FILLORDER 6 // 266
  47. #define IFD_STRIPOFFSETS 7 // 273
  48. #define IFD_SAMPLESPERPIXEL 8 // 277
  49. #define IFD_ROWSPERSTRIP 9 // 278
  50. #define IFD_STRIPBYTECOUNTS 10 // 279
  51. #define IFD_XRESOLUTION 11 // 281
  52. #define IFD_YRESOLUTION 12 // 282
  53. #define IFD_GROUP3OPTIONS 13 // 292
  54. #define IFD_RESOLUTIONUNIT 14 // 296
  55. #define IFD_PAGENUMBER 15 // 297
  56. #define IFD_SOFTWARE 16 // 305
  57. #define IFD_CLEANFAXDATA 17 // 327
  58. typedef struct {
  59. WORD wIFDEntries;
  60. TIFF_TAG ifd[NUM_IFD_ENTRIES];
  61. DWORD nextIFDOffset;
  62. DWORD filler;
  63. DWORD xresNum;
  64. DWORD xresDenom;
  65. DWORD yresNum;
  66. DWORD yresDenom;
  67. CHAR software[32];
  68. } FAXIFD, *PFAXIFD;
  69. #define SoftwareStr "Windows NT Fax Driver"
  70. #define DRIVER_SIGNATURE 'xafD'
  71. FAXIFD FaxIFDTemplate = {
  72. NUM_IFD_ENTRIES,
  73. {
  74. { TIFFTAG_SUBFILETYPE, TIFF_LONG, 1, 0 },
  75. { TIFFTAG_IMAGEWIDTH, TIFF_LONG, 1, 0 },
  76. { TIFFTAG_IMAGELENGTH, TIFF_LONG, 1, 0 },
  77. { TIFFTAG_BITSPERSAMPLE, TIFF_SHORT, 1, 1 },
  78. { TIFFTAG_COMPRESSION, TIFF_SHORT, 1, COMPRESSION_NONE },
  79. { TIFFTAG_PHOTOMETRIC, TIFF_SHORT, 1, PHOTOMETRIC_MINISWHITE },
  80. { TIFFTAG_FILLORDER, TIFF_SHORT, 1, FILLORDER_MSB2LSB },
  81. { TIFFTAG_STRIPOFFSETS, TIFF_LONG, 1, 0 },
  82. { TIFFTAG_SAMPLESPERPIXEL, TIFF_SHORT, 1, 1 },
  83. { TIFFTAG_ROWSPERSTRIP, TIFF_LONG, 1, 0 },
  84. { TIFFTAG_STRIPBYTECOUNTS, TIFF_LONG, 1, 0 },
  85. { TIFFTAG_XRESOLUTION, TIFF_RATIONAL, 1, 0 },
  86. { TIFFTAG_YRESOLUTION, TIFF_RATIONAL, 1, 0 },
  87. { TIFFTAG_GROUP3OPTIONS, TIFF_LONG, 1, 0 },
  88. { TIFFTAG_RESOLUTIONUNIT, TIFF_SHORT, 1, RESUNIT_INCH },
  89. { TIFFTAG_PAGENUMBER, TIFF_SHORT, 2, 0 },
  90. { TIFFTAG_SOFTWARE, TIFF_ASCII, sizeof(SoftwareStr)+1, 0 },
  91. { TIFFTAG_CLEANFAXDATA, TIFF_SHORT, 1, 0 },
  92. },
  93. 0,
  94. DRIVER_SIGNATURE,
  95. 0,
  96. 1,
  97. 0,
  98. 1,
  99. SoftwareStr
  100. };
  101. #endif
  102. VOID
  103. FillInPropertyPage(
  104. PROPSHEETPAGE *psp,
  105. INT dlgId,
  106. DLGPROC dlgProc,
  107. PUSERMEM pUserMem,
  108. INT TitleId,
  109. INT SubTitleId
  110. )
  111. /*++
  112. Routine Description:
  113. Fill out a PROPSHEETPAGE structure with the supplied parameters
  114. Arguments:
  115. psp - Points to the PROPSHEETPAGE structure to be filled out
  116. dlgId - Dialog template resource ID
  117. dlgProc - Dialog procedure
  118. pUserMem - Pointer to the user mode memory structure
  119. TitleId - resource id for wizard subtitle
  120. SubTitleId - resource id for wizard subtitle
  121. Return Value:
  122. NONE
  123. --*/
  124. {
  125. LPTSTR WizardTitle;
  126. LPTSTR WizardSubTitle;
  127. psp->dwSize = sizeof(PROPSHEETPAGE);
  128. //
  129. // Don't show titles if it's the first or last page
  130. //
  131. if (TitleId==0 && SubTitleId ==0) {
  132. psp->dwFlags = PSP_DEFAULT | PSP_HIDEHEADER;;
  133. } else {
  134. psp->dwFlags = PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
  135. }
  136. psp->hInstance = ghInstance;
  137. psp->pszTemplate = MAKEINTRESOURCE(dlgId);
  138. psp->pfnDlgProc = dlgProc;
  139. psp->lParam = (LPARAM) pUserMem;
  140. WizardTitle = MemAlloc(200* sizeof(TCHAR) );
  141. WizardSubTitle = MemAlloc(200* sizeof(TCHAR) );
  142. LoadString(ghInstance,TitleId,WizardTitle,200);
  143. LoadString(ghInstance,SubTitleId,WizardSubTitle,200);
  144. psp->pszHeaderTitle = WizardTitle;
  145. psp->pszHeaderSubTitle = WizardSubTitle;
  146. }
  147. LPTSTR
  148. GetTextStringValue(
  149. HWND hwnd
  150. )
  151. /*++
  152. Routine Description:
  153. Retrieve the string value in a text field
  154. Arguments:
  155. hwnd - Handle to a text window
  156. Return Value:
  157. Pointer to a string representing the current content of the text field
  158. NULL if the text field is empty or if there is an error
  159. --*/
  160. {
  161. INT length;
  162. LPTSTR pString;
  163. //
  164. // Find out how many characters are in the text field
  165. // and allocate enough memory to hold the string value
  166. //
  167. if ((length = GetWindowTextLength(hwnd)) == 0 ||
  168. (pString = MemAlloc(sizeof(TCHAR) * (length + 1))) == NULL)
  169. {
  170. return NULL;
  171. }
  172. //
  173. // Actually retrieve the string value
  174. //
  175. if (GetWindowText(hwnd, pString, length + 1) == 0) {
  176. MemFree(pString);
  177. return NULL;
  178. }
  179. return pString;
  180. }
  181. VOID
  182. LimitTextFields(
  183. HWND hDlg,
  184. INT *pLimitInfo
  185. )
  186. /*++
  187. Routine Description:
  188. Limit the maximum length for a number of text fields
  189. Arguments:
  190. hDlg - Specifies the handle to the dialog window
  191. pLimitInfo - Array of text field control IDs and their maximum length
  192. ID for the 1st text field, maximum length for the 1st text field
  193. ID for the 2nd text field, maximum length for the 2nd text field
  194. ...
  195. 0
  196. Note: The maximum length counts the NUL-terminator.
  197. Return Value:
  198. NONE
  199. --*/
  200. {
  201. while (*pLimitInfo != 0) {
  202. SendDlgItemMessage(hDlg, pLimitInfo[0], EM_SETLIMITTEXT, pLimitInfo[1]-1, 0);
  203. pLimitInfo += 2;
  204. }
  205. }
  206. VOID
  207. SaveLastRecipientInfo(
  208. LPTSTR pName,
  209. LPTSTR pAreaCode,
  210. LPTSTR pPhoneNumber,
  211. DWORD countryId,
  212. BOOL useDialingRules
  213. )
  214. /*++
  215. Routine Description:
  216. Save the information about the last recipient in the registry
  217. Arguments:
  218. pName - Specifies the recipient name
  219. pAreaCode - Specifies the recipient area code
  220. pPhoneNumber - Specifies the recipient phone number
  221. countryId - Specifies the recipient country ID
  222. useDialingRules - Whether use dialing rules is checked
  223. Return Value:
  224. NONE
  225. --*/
  226. {
  227. HKEY hRegKey;
  228. if (hRegKey = GetUserInfoRegKey(REGKEY_FAX_USERINFO, REG_READWRITE)) {
  229. SetRegistryString(hRegKey, REGVAL_LAST_RECNAME, pName);
  230. SetRegistryString(hRegKey, REGVAL_LAST_RECNUMBER, pPhoneNumber);
  231. SetRegistryDword(hRegKey, REGVAL_USE_DIALING_RULES, useDialingRules);
  232. if (useDialingRules) {
  233. SetRegistryString(hRegKey, REGVAL_LAST_RECAREACODE, pAreaCode);
  234. SetRegistryDword(hRegKey, REGVAL_LAST_COUNTRYID, countryId);
  235. }
  236. RegCloseKey(hRegKey);
  237. }
  238. }
  239. VOID
  240. RestoreLastRecipientInfo(
  241. HWND hDlg,
  242. PDWORD pCountryId
  243. )
  244. /*++
  245. Routine Description:
  246. Restore the information about the last recipient from the registry
  247. Arguments:
  248. hDlg - Specifies a handle to the fax recipient wizard page
  249. pCountryId - Returns the last selected country ID
  250. Return Value:
  251. NONE
  252. --*/
  253. {
  254. HKEY hRegKey;
  255. LPTSTR buffer;
  256. //TCHAR buffer[MAX_STRING_LEN];
  257. *pCountryId = GetDefaultCountryID();
  258. if (hRegKey = GetUserInfoRegKey(REGKEY_FAX_USERINFO, REG_READONLY)) {
  259. buffer = GetRegistryString(hRegKey, REGVAL_LAST_RECNAME, TEXT(""));
  260. if (buffer) {
  261. SetDlgItemText(hDlg, IDC_CHOOSE_NAME_EDIT, buffer);
  262. MemFree(buffer);
  263. }
  264. buffer = GetRegistryString(hRegKey, REGVAL_LAST_RECAREACODE, TEXT(""));
  265. if (buffer) {
  266. SetDlgItemText(hDlg, IDC_CHOOSE_AREA_CODE_EDIT, buffer);
  267. MemFree(buffer);
  268. }
  269. buffer = GetRegistryString(hRegKey, REGVAL_LAST_RECNUMBER, TEXT(""));
  270. if (buffer) {
  271. SetDlgItemText(hDlg, IDC_CHOOSE_NUMBER_EDIT, buffer);
  272. MemFree(buffer);
  273. }
  274. CheckDlgButton(hDlg,
  275. IDC_USE_DIALING_RULES,
  276. GetRegistryDword(hRegKey, REGVAL_USE_DIALING_RULES));
  277. *pCountryId = GetRegistryDword(hRegKey, REGVAL_LAST_COUNTRYID);
  278. RegCloseKey(hRegKey);
  279. }
  280. }
  281. PUSERMEM
  282. CommonWizardProc(
  283. HWND hDlg,
  284. UINT message,
  285. WPARAM wParam,
  286. LPARAM lParam,
  287. DWORD buttonFlags
  288. )
  289. /*++
  290. Routine Description:
  291. Common procedure for handling wizard pages:
  292. Arguments:
  293. hDlg - Identifies the wizard page
  294. message - Specifies the message
  295. wParam - Specifies additional message-specific information
  296. lParam - Specifies additional message-specific information
  297. buttonFlags - Indicate which buttons should be enabled
  298. Return Value:
  299. NULL - Message is processed and the dialog procedure should return FALSE
  300. Otherwise - Message is not completely processed and
  301. The return value is a pointer to the user mode memory structure
  302. --*/
  303. {
  304. PUSERMEM pUserMem;
  305. switch (message) {
  306. case WM_INITDIALOG:
  307. //
  308. // Store the pointer to user mode memory structure
  309. //
  310. lParam = ((PROPSHEETPAGE *) lParam)->lParam;
  311. pUserMem = (PUSERMEM) lParam;
  312. Assert(ValidPDEVUserMem(pUserMem));
  313. SetWindowLongPtr(hDlg, DWLP_USER, lParam);
  314. break;
  315. case WM_NOTIFY:
  316. pUserMem = (PUSERMEM) GetWindowLongPtr(hDlg, DWLP_USER);
  317. Assert(ValidPDEVUserMem(pUserMem));
  318. switch (((NMHDR *) lParam)->code) {
  319. case PSN_WIZFINISH:
  320. pUserMem->finishPressed = TRUE;
  321. break;
  322. case PSN_SETACTIVE:
  323. PropSheet_SetWizButtons(GetParent(hDlg), buttonFlags);
  324. break;
  325. case PSN_RESET:
  326. case PSN_WIZBACK:
  327. case PSN_WIZNEXT:
  328. case PSN_KILLACTIVE:
  329. case LVN_KEYDOWN:
  330. break;
  331. default:
  332. return NULL;
  333. }
  334. break;
  335. case WM_COMMAND:
  336. pUserMem = (PUSERMEM) GetWindowLongPtr(hDlg, DWLP_USER);
  337. Assert(ValidPDEVUserMem(pUserMem));
  338. break;
  339. default:
  340. return NULL;
  341. }
  342. return pUserMem;
  343. }
  344. /*
  345. * IsStringACSII
  346. *
  347. * Purpose:
  348. * This function determines whether a string contains ONLY ASCII characters.
  349. *
  350. * Arguments:
  351. * ptszString - points to the string to test.
  352. *
  353. * Returns:
  354. * TRUE - indicates that the string contains only ASCII characters.
  355. *
  356. */
  357. BOOL IsStringASCII( LPTSTR ptszString )
  358. {
  359. BOOL fReturnValue = (BOOL) TRUE;
  360. // Determine whether the contents of the edit control are legal.
  361. while ( (*ptszString != (TCHAR) TEXT('\0')) &&
  362. ( fReturnValue == (BOOL) TRUE) )
  363. {
  364. if ( (*ptszString < (TCHAR) 0x0020) || (*ptszString > (TCHAR) MAXCHAR) )
  365. {
  366. // The string contains at least one non-ASCII character.
  367. fReturnValue = (BOOL) FALSE;
  368. }
  369. ptszString = _tcsinc( ptszString );
  370. } // end of while loop
  371. return ( fReturnValue );
  372. }
  373. INT
  374. GetCurrentRecipient(
  375. HWND hDlg,
  376. PRECIPIENT *ppRecipient
  377. )
  378. /*++
  379. Routine Description:
  380. Extract the current recipient information in the dialog
  381. Arguments:
  382. hDlg - Handle to the fax recipient wizard page
  383. ppRecipient - Buffer to receive a pointer to a newly created RECIPIENT structure
  384. NULL if caller is only interested in the validity of recipient info
  385. Return Value:
  386. = 0 if successful
  387. > 0 error message string resource ID otherwise
  388. < 0 other error conditions
  389. --*/
  390. {
  391. LPLINECOUNTRYENTRY pLineCountryEntry;
  392. DWORD countryId, countryCode;
  393. PRECIPIENT pRecipient;
  394. TCHAR areaCode[MAX_RECIPIENT_NUMBER];
  395. TCHAR phoneNumber[MAX_RECIPIENT_NUMBER];
  396. INT nameLen, areaCodeLen, numberLen;
  397. LPTSTR pName, pAddress;
  398. INT useDialingRules;
  399. //
  400. // Default value in case of error
  401. //
  402. if (ppRecipient)
  403. *ppRecipient = NULL;
  404. //
  405. // Find the current country code
  406. //
  407. countryCode = 0;
  408. pLineCountryEntry = NULL;
  409. countryId = GetCountryListBoxSel(GetDlgItem(hDlg, IDC_CHOOSE_COUNTRY_COMBO));
  410. useDialingRules = IsDlgButtonChecked(hDlg, IDC_USE_DIALING_RULES);
  411. if ((useDialingRules == BST_CHECKED) &&
  412. (pLineCountryEntry = FindCountry(countryId)))
  413. {
  414. countryCode = pLineCountryEntry->dwCountryCode;
  415. }
  416. nameLen = GetWindowTextLength(GetDlgItem(hDlg, IDC_CHOOSE_NAME_EDIT));
  417. areaCodeLen = GetWindowTextLength(GetDlgItem(hDlg, IDC_CHOOSE_AREA_CODE_EDIT));
  418. numberLen = GetWindowTextLength(GetDlgItem(hDlg, IDC_CHOOSE_NUMBER_EDIT));
  419. //
  420. // Validate the edit text fields
  421. //
  422. if (nameLen <= 0)
  423. return IDS_BAD_RECIPIENT_NAME;
  424. if (numberLen <= 0 || numberLen >= MAX_RECIPIENT_NUMBER)
  425. return IDS_BAD_RECIPIENT_NUMBER;
  426. if ((areaCodeLen <= 0 && AreaCodeRules(pLineCountryEntry) == AREACODE_REQUIRED) ||
  427. (areaCodeLen >= MAX_RECIPIENT_NUMBER))
  428. {
  429. return IDS_BAD_RECIPIENT_AREACODE;
  430. }
  431. if (ppRecipient == NULL)
  432. return 0;
  433. //
  434. // Calculate the amount of memory space we need and allocate it
  435. //
  436. pRecipient = MemAllocZ(sizeof(RECIPIENT));
  437. pName = MemAllocZ((nameLen + 1) * sizeof(TCHAR));
  438. pAddress = MemAllocZ((areaCodeLen + numberLen + 20) * sizeof(TCHAR));
  439. if (!pRecipient || !pName || !pAddress) {
  440. MemFree(pRecipient);
  441. MemFree(pName);
  442. MemFree(pAddress);
  443. return -1;
  444. }
  445. *ppRecipient = pRecipient;
  446. pRecipient->pName = pName;
  447. pRecipient->pAddress = pAddress;
  448. //
  449. // Get the recipient's name
  450. //
  451. GetWindowText(GetDlgItem(hDlg, IDC_CHOOSE_NAME_EDIT), pName, nameLen+1);
  452. //
  453. // Get the recipient's number
  454. // AddressType
  455. // [+ CountryCode Space]
  456. // [( AreaCode ) Space]
  457. // SubscriberNumber
  458. //
  459. GetWindowText(GetDlgItem(hDlg, IDC_CHOOSE_AREA_CODE_EDIT), areaCode, MAX_RECIPIENT_NUMBER);
  460. if ( IsStringASCII( areaCode ) == (BOOL) FALSE )
  461. {
  462. return ( (INT) IDS_ERROR_AREA_CODE );
  463. }
  464. GetWindowText(GetDlgItem(hDlg, IDC_CHOOSE_NUMBER_EDIT), phoneNumber, MAX_RECIPIENT_NUMBER);
  465. if ( IsStringASCII( phoneNumber ) == (BOOL) FALSE )
  466. {
  467. return ( (INT) IDS_ERROR_FAX_NUMBER );
  468. }
  469. AssemblePhoneNumber(pAddress,
  470. countryCode,
  471. areaCode,
  472. phoneNumber);
  473. //
  474. // Save the information about the last recipient as a convenience
  475. //
  476. SaveLastRecipientInfo(pName,
  477. areaCode,
  478. phoneNumber,
  479. countryId,
  480. useDialingRules == BST_CHECKED);
  481. return 0;
  482. }
  483. VOID
  484. InitRecipientListView(
  485. HWND hwndLV
  486. )
  487. /*++
  488. Routine Description:
  489. Initialize the recipient list view on the first page of Send Fax wizard
  490. Arguments:
  491. hwndLV - Window handle to the list view control
  492. Return Value:
  493. NONE
  494. --*/
  495. {
  496. LV_COLUMN lvc;
  497. RECT rect;
  498. TCHAR buffer[MAX_TITLE_LEN];
  499. if (hwndLV == NULL)
  500. return;
  501. GetClientRect(hwndLV, &rect);
  502. ZeroMemory(&lvc, sizeof(lvc));
  503. lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
  504. lvc.fmt = LVCFMT_LEFT;
  505. lvc.pszText = buffer;
  506. lvc.cx = (rect.right - rect.left) / 2;
  507. lvc.iSubItem = 0;
  508. LoadString(ghInstance, IDS_COLUMN_RECIPIENT_NAME, buffer, MAX_TITLE_LEN);
  509. if (ListView_InsertColumn(hwndLV, 0, &lvc) == -1)
  510. Error(("ListView_InsertColumn failed\n"));
  511. lvc.cx -= GetSystemMetrics(SM_CXVSCROLL);
  512. lvc.iSubItem = 1;
  513. LoadString(ghInstance, IDS_COLUMN_RECIPIENT_NUMBER, buffer, MAX_TITLE_LEN);
  514. if (ListView_InsertColumn(hwndLV, 1, &lvc) == -1)
  515. Error(("ListView_InsertColumn failed\n"));
  516. }
  517. BOOL
  518. InsertRecipientListItem(
  519. HWND hwndLV,
  520. PRECIPIENT pRecipient
  521. )
  522. /*++
  523. Routine Description:
  524. Insert an item into the recipient list view
  525. Arguments:
  526. hwndLV - Window handle to the recipient list view
  527. pRecipient - Specifies the recipient to be inserted
  528. Return Value:
  529. TRUE if successful, FALSE if there is an error
  530. --*/
  531. {
  532. LV_ITEM lvi;
  533. INT index;
  534. ZeroMemory(&lvi, sizeof(lvi));
  535. lvi.mask = LVIF_PARAM | LVIF_TEXT | LVIF_STATE;
  536. lvi.lParam = (LPARAM) pRecipient;
  537. lvi.pszText = pRecipient->pName;
  538. lvi.state = lvi.stateMask = LVIS_SELECTED;
  539. if ((index = ListView_InsertItem(hwndLV, &lvi)) == -1) {
  540. Error(("ListView_InsertItem failed\n"));
  541. return FALSE;
  542. }
  543. lvi.mask = LVIF_TEXT;
  544. lvi.iItem = index;
  545. lvi.iSubItem = 1;
  546. lvi.pszText = pRecipient->pAddress;
  547. if (! ListView_SetItem(hwndLV, &lvi))
  548. Error(("ListView_SetItem failed\n"));
  549. return TRUE;
  550. }
  551. PRECIPIENT
  552. GetRecipientListItem(
  553. HWND hwndLV,
  554. INT index
  555. )
  556. /*++
  557. Routine Description:
  558. Retrieve the recipient associated with an item in the list view
  559. Arguments:
  560. hwndLV - Window handle to the recipient list view
  561. index - Specifies the index of the interested item
  562. Return Value:
  563. Pointer to the requested recipient information
  564. NULL if there is an error
  565. --*/
  566. {
  567. LV_ITEM lvi;
  568. ZeroMemory(&lvi, sizeof(lvi));
  569. lvi.mask = LVIF_PARAM;
  570. lvi.iItem = index;
  571. if (ListView_GetItem(hwndLV, &lvi))
  572. return (PRECIPIENT) lvi.lParam;
  573. Error(("ListView_GetItem failed\n"));
  574. return NULL;
  575. }
  576. INT
  577. AddRecipient(
  578. HWND hDlg,
  579. PUSERMEM pUserMem
  580. )
  581. /*++
  582. Routine Description:
  583. Add the current recipient information entered by the user
  584. into the recipient list
  585. Arguments:
  586. hDlg - Handle to the fax recipient wizard page
  587. pUserMem - Points to user mode memory structure
  588. Return Value:
  589. Same meaning as return value from GetCurrentRecipient, i.e.
  590. = 0 if successful
  591. > 0 error message string resource ID otherwise
  592. < 0 other error conditions
  593. --*/
  594. {
  595. PRECIPIENT pRecipient;
  596. INT errId;
  597. HWND hwndLV;
  598. //
  599. // Collect information about the current recipient
  600. //
  601. if ((errId = GetCurrentRecipient(hDlg, &pRecipient)) != 0)
  602. return errId;
  603. //
  604. // Insert the current recipient to the recipient list
  605. //
  606. if ((hwndLV = GetDlgItem(hDlg, IDC_CHOOSE_RECIPIENT_LIST)) &&
  607. InsertRecipientListItem(hwndLV, pRecipient))
  608. {
  609. errId = 0;
  610. pRecipient->pNext = pUserMem->pRecipients;
  611. pUserMem->pRecipients = pRecipient;
  612. //
  613. // Clear the name and number fields after successfully
  614. // adding the recipient to the internal list
  615. //
  616. SetWindowText(GetDlgItem(hDlg, IDC_CHOOSE_NAME_EDIT), TEXT(""));
  617. SetWindowText(GetDlgItem(hDlg, IDC_CHOOSE_AREA_CODE_EDIT), TEXT(""));
  618. SetWindowText(GetDlgItem(hDlg, IDC_CHOOSE_NUMBER_EDIT), TEXT(""));
  619. //CheckDlgButton(hDlg, IDC_USE_DIALING_RULES, FALSE);
  620. } else {
  621. FreeRecipient(pRecipient);
  622. errId = -1;
  623. }
  624. return errId;
  625. }
  626. BOOL
  627. DoAddressBook(
  628. HWND hDlg,
  629. PUSERMEM pUserMem
  630. )
  631. /*++
  632. Routine Description:
  633. Display the MAPI address book dialog
  634. Arguments:
  635. hDlg - Handle to the fax recipient wizard page
  636. pUserMem - Points to user mode memory structure
  637. Return Value:
  638. TRUE if successful, FALSE otherwise
  639. --*/
  640. {
  641. HWND hwndLV;
  642. BOOL result;
  643. PRECIPIENT pNewRecip = NULL;
  644. PRECIPIENT tmpRecip;
  645. if (! pUserMem->lpWabInit &&
  646. ! (pUserMem->lpWabInit = InitializeWAB(ghInstance)))
  647. {
  648. EnableWindow(GetDlgItem(hDlg, IDC_CHOOSE_ADDRBOOK), FALSE);
  649. return FALSE;
  650. }
  651. //
  652. // Get a handle to the recipient list window
  653. //
  654. if (! (hwndLV = GetDlgItem(hDlg, IDC_CHOOSE_RECIPIENT_LIST)))
  655. return FALSE;
  656. //
  657. // Add current recipient to the list if necessary
  658. //
  659. AddRecipient(hDlg, pUserMem);
  660. result = CallWabAddress(
  661. hDlg,
  662. pUserMem,
  663. &pNewRecip
  664. );
  665. FreeRecipientList(pUserMem);
  666. pUserMem->pRecipients = pNewRecip;
  667. ListView_DeleteAllItems(hwndLV);
  668. for (tmpRecip = pNewRecip; tmpRecip; tmpRecip = tmpRecip->pNext) {
  669. InsertRecipientListItem(hwndLV, tmpRecip);
  670. }
  671. if (!result) {
  672. DisplayMessageDialog( hDlg, MB_OK, 0, IDS_BAD_ADDRESS_TYPE );
  673. }
  674. return result;
  675. }
  676. BOOL
  677. ValidateRecipients(
  678. HWND hDlg,
  679. PUSERMEM pUserMem
  680. )
  681. /*++
  682. Routine Description:
  683. Validate the list of fax recipients entered by the user
  684. Arguments:
  685. hDlg - Handle to the fax recipient wizard page
  686. pUserMem - Points to user mode memory structure
  687. Return Value:
  688. TRUE if successful, FALSE otherwise
  689. --*/
  690. {
  691. INT errId;
  692. //
  693. // Add current recipient to the list if necessary
  694. //
  695. errId = AddRecipient(hDlg, pUserMem);
  696. //
  697. // There must be at least one recipient
  698. //
  699. if (pUserMem->pRecipients)
  700. return TRUE;
  701. //
  702. // Display an error message
  703. //
  704. if (errId > 0)
  705. DisplayMessageDialog(hDlg, 0, 0, errId);
  706. else
  707. MessageBeep(MB_OK);
  708. //
  709. // Set current focus to the appropriate text field as a convenience
  710. //
  711. switch (errId) {
  712. case IDS_ERROR_FAX_NUMBER:
  713. SetDlgItemText(hDlg, IDC_CHOOSE_NUMBER_EDIT, L"");
  714. case IDS_BAD_RECIPIENT_NUMBER:
  715. errId = IDC_CHOOSE_NUMBER_EDIT;
  716. break;
  717. case IDS_ERROR_AREA_CODE:
  718. SetDlgItemText(hDlg, IDC_CHOOSE_AREA_CODE_EDIT, L"");
  719. case IDS_BAD_RECIPIENT_AREACODE:
  720. errId = IDC_CHOOSE_AREA_CODE_EDIT;
  721. break;
  722. case IDS_BAD_RECIPIENT_NAME:
  723. default:
  724. errId = IDC_CHOOSE_NAME_EDIT;
  725. break;
  726. }
  727. SetFocus(GetDlgItem(hDlg, errId));
  728. return FALSE;
  729. }
  730. PRECIPIENT *
  731. FindRecipient(
  732. PUSERMEM pUserMem,
  733. PRECIPIENT pRecipient
  734. )
  735. /*++
  736. Routine Description:
  737. Check if the specified recipient is in the list of recipients
  738. Arguments:
  739. pUserMem - Points to user mode memory structure
  740. pRecipient - Specifies the recipient to be found
  741. Return Value:
  742. Address of the link pointer to the specified recipient
  743. NULL if the specified recipient is not found
  744. --*/
  745. {
  746. PRECIPIENT pCurrent, *ppPrevNext;
  747. //
  748. // Search for the specified recipient in the list
  749. //
  750. ppPrevNext = (PRECIPIENT *) &pUserMem->pRecipients;
  751. pCurrent = pUserMem->pRecipients;
  752. while (pCurrent && pCurrent != pRecipient) {
  753. ppPrevNext = (PRECIPIENT *) &pCurrent->pNext;
  754. pCurrent = pCurrent->pNext;
  755. }
  756. //
  757. // Return the address of the link pointer to the specified recipient
  758. // or NULL if the specified recipient is not found
  759. //
  760. return pCurrent ? ppPrevNext : NULL;
  761. }
  762. BOOL
  763. RemoveRecipient(
  764. HWND hDlg,
  765. PUSERMEM pUserMem
  766. )
  767. /*++
  768. Routine Description:
  769. Remove the currently selected recipient from the recipient list
  770. Arguments:
  771. hDlg - Handle to the fax recipient wizard page
  772. pUserMem - Points to user mode memory structure
  773. Return Value:
  774. TRUE if successful, FALSE otherwise
  775. --*/
  776. {
  777. PRECIPIENT pRecipient, *ppPrevNext;
  778. INT selIndex;
  779. HWND hwndLV;
  780. //
  781. // Get the currently selected recipient, and
  782. // Find the current recipient in the list, then
  783. // Delete the current recipient and select the next one below it
  784. //
  785. if ((hwndLV = GetDlgItem(hDlg, IDC_CHOOSE_RECIPIENT_LIST)) &&
  786. (selIndex = ListView_GetNextItem(hwndLV, -1, LVNI_ALL|LVNI_SELECTED)) != -1 &&
  787. (pRecipient = GetRecipientListItem(hwndLV, selIndex)) &&
  788. (ppPrevNext = FindRecipient(pUserMem, pRecipient)) &&
  789. ListView_DeleteItem(hwndLV, selIndex))
  790. {
  791. ListView_SetItemState(hwndLV,
  792. selIndex,
  793. LVIS_SELECTED|LVIS_FOCUSED,
  794. LVIS_SELECTED|LVIS_FOCUSED);
  795. //
  796. // Delete the recipient from the internal list
  797. //
  798. *ppPrevNext = pRecipient->pNext;
  799. FreeRecipient(pRecipient);
  800. return TRUE;
  801. }
  802. MessageBeep(MB_ICONHAND);
  803. return FALSE;
  804. }
  805. VOID
  806. LocationListInit(
  807. HWND hDlg,
  808. PUSERMEM pUserMem
  809. )
  810. /*++
  811. Routine Description:
  812. Initialize the list of TAPI locations
  813. Arguments:
  814. hDlg - Handle to "Compose New Fax" wizard window
  815. pUserMem - Pointer to user mode memory structure
  816. Return Value:
  817. NONE
  818. --*/
  819. {
  820. HWND hwndList;
  821. DWORD index;
  822. LRESULT listIdx;
  823. LPTSTR pLocationName, pSelectedName = NULL;
  824. LPLINETRANSLATECAPS pTranslateCaps = NULL;
  825. LPLINELOCATIONENTRY pLocationEntry;
  826. //
  827. // For remote printers, hide the location combo-box
  828. //
  829. if (! pUserMem->isLocalPrinter) {
  830. ShowWindow(GetDlgItem(hDlg, IDC_LOCATION_PROMPT), SW_HIDE);
  831. ShowWindow(GetDlgItem(hDlg, IDC_LOCATION_LIST), SW_HIDE);
  832. ShowWindow(GetDlgItem(hDlg, IDC_TAPI_PROPS), SW_HIDE);
  833. return;
  834. }
  835. //
  836. // Get the list of locations from TAPI and use it
  837. // to initialize the location combo-box.
  838. //
  839. if ((hwndList = GetDlgItem(hDlg, IDC_LOCATION_LIST)) &&
  840. (pTranslateCaps = GetTapiLocationInfo(hDlg)))
  841. {
  842. SendMessage(hwndList, CB_RESETCONTENT, 0, 0);
  843. pLocationEntry = (LPLINELOCATIONENTRY)
  844. ((PBYTE) pTranslateCaps + pTranslateCaps->dwLocationListOffset);
  845. for (index=0; index < pTranslateCaps->dwNumLocations; index++) {
  846. pLocationName = (LPTSTR)
  847. ((PBYTE) pTranslateCaps + pLocationEntry->dwLocationNameOffset);
  848. if (pLocationEntry->dwPermanentLocationID == pTranslateCaps->dwCurrentLocationID)
  849. pSelectedName = pLocationName;
  850. listIdx = SendMessage(hwndList, CB_INSERTSTRING, 0, (LPARAM) pLocationName);
  851. if (listIdx != CB_ERR) {
  852. SendMessage(hwndList,
  853. CB_SETITEMDATA,
  854. listIdx,
  855. pLocationEntry->dwPermanentLocationID);
  856. }
  857. pLocationEntry++;
  858. }
  859. if (pSelectedName != NULL)
  860. SendMessage(hwndList, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) pSelectedName);
  861. }
  862. MemFree(pTranslateCaps);
  863. }
  864. VOID
  865. LocationListSelChange(
  866. HWND hDlg
  867. )
  868. /*++
  869. Routine Description:
  870. Change the default TAPI location
  871. Arguments:
  872. hDlg - Handle to "Compose New Fax" wizard window
  873. Return Value:
  874. NONE
  875. --*/
  876. {
  877. HWND hwndList;
  878. LRESULT selIndex;
  879. DWORD locationID;
  880. if ((hwndList = GetDlgItem(hDlg, IDC_LOCATION_LIST)) &&
  881. (selIndex = SendMessage(hwndList, CB_GETCURSEL, 0, 0)) != CB_ERR &&
  882. (locationID = (DWORD)SendMessage(hwndList, CB_GETITEMDATA, selIndex, 0)) != CB_ERR)
  883. {
  884. SetCurrentLocation(locationID);
  885. }
  886. }
  887. VOID
  888. UpdateCountryCombobox(
  889. HWND hDlg,
  890. DWORD countryId
  891. )
  892. /*++
  893. Routine Description:
  894. Update the country/region combobox
  895. Arguments:
  896. hDlg - Handle to recipient wizard page
  897. countryId - country id
  898. Return Value:
  899. NONE
  900. --*/
  901. {
  902. HWND hwndUseDialingRultes = GetDlgItem(hDlg, IDC_USE_DIALING_RULES);
  903. HWND hwndDialingLocation = GetDlgItem(hDlg, IDC_LOCATION_LIST);
  904. HWND hwndDialingLocationStatic = GetDlgItem(hDlg, IDC_LOCATION_PROMPT);
  905. HWND hwndLocation = GetDlgItem(hDlg, IDC_CHOOSE_COUNTRY_COMBO);
  906. HWND hwndLocationStatic = GetDlgItem(hDlg, IDC_STATIC_CHOOSE_COUNTRY_COMBO);
  907. HWND hwndProp = GetDlgItem(hDlg, IDC_TAPI_PROPS);
  908. static int OldCountryCode = 0;
  909. if (IsDlgButtonChecked(hDlg, IDC_USE_DIALING_RULES) != BST_CHECKED) {
  910. //
  911. // user unchecked use dialing rules
  912. // remember the old country code and area code and clear out the UI
  913. //
  914. OldCountryCode = GetCountryListBoxSel(hwndLocation);
  915. if (OldCountryCode == -1) {
  916. OldCountryCode = countryId != -1 ? countryId : 0;
  917. }
  918. SendMessage(hwndLocation, CB_RESETCONTENT, FALSE, 0);
  919. EnableWindow(hwndLocation, FALSE);
  920. EnableWindow(hwndLocationStatic, FALSE);
  921. EnableWindow(hwndDialingLocation, FALSE);
  922. EnableWindow(hwndDialingLocationStatic, FALSE);
  923. EnableWindow(hwndProp, FALSE);
  924. }
  925. else {
  926. //
  927. // user checked use dialing rules
  928. // enable country combo, restore settings
  929. //
  930. EnableWindow(hwndLocation, TRUE);
  931. EnableWindow(hwndLocationStatic, TRUE);
  932. InitCountryListBox(GetDlgItem(hDlg, IDC_CHOOSE_COUNTRY_COMBO),
  933. GetDlgItem(hDlg, IDC_CHOOSE_AREA_CODE_EDIT),
  934. countryId != -1 ? countryId : OldCountryCode);
  935. EnableWindow(hwndDialingLocation, TRUE);
  936. EnableWindow(hwndDialingLocationStatic, TRUE);
  937. EnableWindow(hwndProp, TRUE);
  938. }
  939. SelChangeCountryListBox(GetDlgItem(hDlg, IDC_CHOOSE_COUNTRY_COMBO),
  940. GetDlgItem(hDlg, IDC_CHOOSE_AREA_CODE_EDIT));
  941. }
  942. INT_PTR
  943. CALLBACK
  944. firstdlgproc(
  945. HWND hDlg,
  946. UINT iMsg,
  947. WPARAM wParam,
  948. LPARAM lParam
  949. )
  950. {
  951. switch(iMsg) {
  952. case WM_INITDIALOG:
  953. CheckDlgButton(hDlg, IDC_EDIT_USERINFO_NOW, TRUE);
  954. return TRUE;
  955. case WM_COMMAND:
  956. switch(LOWORD( wParam )) {
  957. case IDOK:
  958. if (IsDlgButtonChecked(hDlg, IDC_EDIT_USERINFO_NOW) == BST_CHECKED) {
  959. EndDialog( hDlg, IDYES );
  960. }
  961. else {
  962. EndDialog( hDlg, IDNO );
  963. }
  964. return TRUE;
  965. }
  966. break;
  967. }
  968. return FALSE;
  969. }
  970. INT_PTR
  971. CALLBACK
  972. firstprintdlgproc(
  973. HWND hDlg,
  974. UINT iMsg,
  975. WPARAM wParam,
  976. LPARAM lParam
  977. )
  978. {
  979. switch(iMsg) {
  980. case WM_COMMAND:
  981. EndDialog( hDlg, LOWORD( wParam ));
  982. break;
  983. }
  984. return FALSE;
  985. }
  986. BOOL
  987. DoFirstTimeInitStuff(
  988. HWND hDlg,
  989. BOOL bWelcomePage
  990. )
  991. {
  992. BOOL bInitialized = TRUE;
  993. HKEY hRegKey;
  994. // TCHAR MessageBuffer[1024],TitleBuffer[100];
  995. SHELLEXECUTEINFO shellExeInfo = {
  996. sizeof(SHELLEXECUTEINFO),
  997. SEE_MASK_NOCLOSEPROCESS,
  998. hDlg,
  999. L"Open",
  1000. L"rundll32",
  1001. L"shell32.dll,Control_RunDLL fax.cpl",
  1002. NULL,
  1003. SW_SHOWNORMAL,
  1004. };
  1005. TCHAR ScratchCmdLine[MAX_PATH];
  1006. PCTSTR PrinterCmdLine = TEXT("rundll32.exe printui.dll,PrintUIEntry /il");
  1007. STARTUPINFO si;
  1008. PROCESS_INFORMATION pi;
  1009. //
  1010. // print or fax first time?
  1011. //
  1012. if (bWelcomePage && !GetEnvironmentVariable(TEXT("NTFaxSendNote"), NULL, 0)) {
  1013. DWORD PrinterCount = 1;
  1014. PRINTER_INFO_4 *pPrinterInfo4;
  1015. if (hRegKey = GetUserInfoRegKey(REGKEY_FAX_USERINFO, REG_READONLY)) {
  1016. bInitialized = GetRegistryDword(hRegKey, REGVAL_PRINTER_INITIALIZED);
  1017. RegCloseKey(hRegKey);
  1018. }
  1019. if (bInitialized) {
  1020. return TRUE;
  1021. }
  1022. //
  1023. // if there is more than one printer don't confuse the user by asking
  1024. // to add a printer since one is already installed.
  1025. //
  1026. pPrinterInfo4 = MyEnumPrinters(
  1027. NULL,
  1028. 4,
  1029. &PrinterCount,
  1030. PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS);
  1031. if (pPrinterInfo4) {
  1032. MemFree(pPrinterInfo4);
  1033. if (PrinterCount > 1) {
  1034. if (hRegKey = GetUserInfoRegKey(REGKEY_FAX_USERINFO, REG_READWRITE)) {
  1035. SetRegistryDword(hRegKey, REGVAL_PRINTER_INITIALIZED , 1);
  1036. RegCloseKey(hRegKey);
  1037. }
  1038. return(TRUE);
  1039. }
  1040. }
  1041. if (DialogBoxParam(ghInstance,
  1042. MAKEINTRESOURCE( IDD_WIZFIRSTTIMEPRINT ),
  1043. hDlg,
  1044. firstprintdlgproc,
  1045. (LPARAM)NULL) != IDOK) {
  1046. //
  1047. // if they said "print", then launch the add/remove printer wizard
  1048. //
  1049. ZeroMemory(&si,sizeof(si));
  1050. GetStartupInfo(&si);
  1051. lstrcpy(ScratchCmdLine,PrinterCmdLine);
  1052. if (CreateProcess(
  1053. NULL,
  1054. ScratchCmdLine,
  1055. NULL,
  1056. NULL,
  1057. FALSE,
  1058. DETACHED_PROCESS,
  1059. NULL,
  1060. NULL,
  1061. &si,
  1062. &pi
  1063. )) {
  1064. CloseHandle( pi.hThread );
  1065. CloseHandle( pi.hProcess );
  1066. }
  1067. return(FALSE);
  1068. } else {
  1069. if (hRegKey = GetUserInfoRegKey(REGKEY_FAX_USERINFO, REG_READWRITE)) {
  1070. SetRegistryDword(hRegKey, REGVAL_PRINTER_INITIALIZED , 1);
  1071. RegCloseKey(hRegKey);
  1072. }
  1073. return(TRUE);
  1074. }
  1075. } else if (!bWelcomePage) {
  1076. if (hRegKey = GetUserInfoRegKey(REGKEY_FAX_USERINFO, REG_READONLY)) {
  1077. bInitialized = GetRegistryDword(hRegKey, REGVAL_WIZARD_INITIALIZED);
  1078. RegCloseKey(hRegKey);
  1079. }
  1080. if (bInitialized) {
  1081. return TRUE;
  1082. }
  1083. //
  1084. // show the user a dialog
  1085. //
  1086. if (DialogBoxParam(ghInstance,
  1087. MAKEINTRESOURCE( IDD_WIZFIRSTTIME ),
  1088. hDlg,
  1089. firstdlgproc,
  1090. (LPARAM)NULL) == IDYES) {
  1091. //
  1092. // if they said yes, then launch the control panel applet
  1093. //
  1094. if (!ShellExecuteEx(&shellExeInfo)) {
  1095. DisplayMessageDialog(hDlg, 0, 0, IDS_ERR_CPL_LAUNCH);
  1096. return FALSE;
  1097. }
  1098. WaitForSingleObject( shellExeInfo.hProcess, INFINITE );
  1099. CloseHandle( shellExeInfo.hProcess ) ;
  1100. }
  1101. //
  1102. // set the reg key so this doesn't come up again
  1103. //
  1104. if (hRegKey = GetUserInfoRegKey(REGKEY_FAX_USERINFO, REG_READWRITE)) {
  1105. SetRegistryDword(hRegKey, REGVAL_WIZARD_INITIALIZED , 1 );
  1106. RegCloseKey(hRegKey);
  1107. }
  1108. }
  1109. return(TRUE);
  1110. }
  1111. INT_PTR
  1112. RecipientWizProc(
  1113. HWND hDlg,
  1114. UINT message,
  1115. WPARAM wParam,
  1116. LPARAM lParam
  1117. )
  1118. /*++
  1119. Routine Description:
  1120. Dialog procedure for the first wizard page: selecting the fax recipient
  1121. Arguments:
  1122. hDlg - Identifies the wizard page
  1123. message - Specifies the message
  1124. wParam - Specifies additional message-specific information
  1125. lParam - Specifies additional message-specific information
  1126. Return Value:
  1127. Depends on the message parameter
  1128. --*/
  1129. #define UpdateAddToListButton() \
  1130. EnableWindow(GetDlgItem(hDlg, IDC_CHOOSE_ADD), GetCurrentRecipient(hDlg, NULL) == 0)
  1131. #define UpdateRemoveFromListButton(__BoolFlag) \
  1132. EnableWindow(GetDlgItem(hDlg, IDC_CHOOSE_REMOVE),__BoolFlag)
  1133. {
  1134. PUSERMEM pUserMem;
  1135. DWORD countryId;
  1136. INT cmd;
  1137. NMHDR *pNMHdr;
  1138. DWORD dwErrorCode;
  1139. HANDLE hEditControl;
  1140. TCHAR tszBuffer[MAX_STRING_LEN];
  1141. //
  1142. // Maximum length for various text fields
  1143. //
  1144. static INT textLimits[] = {
  1145. IDC_CHOOSE_NAME_EDIT, 64,
  1146. IDC_CHOOSE_AREA_CODE_EDIT, 11,
  1147. IDC_CHOOSE_NUMBER_EDIT, 51,
  1148. 0
  1149. };
  1150. //
  1151. // Handle common messages shared by all wizard pages
  1152. //
  1153. if (! (pUserMem = CommonWizardProc(hDlg, message, wParam, lParam, PSWIZB_BACK | PSWIZB_NEXT)))
  1154. return FALSE;
  1155. switch (message) {
  1156. case WM_INITDIALOG:
  1157. //
  1158. // check if the user has run the wizard before so they can fill in the coverpage info.
  1159. //
  1160. DoFirstTimeInitStuff(hDlg, FALSE);
  1161. //
  1162. // tapi is asynchronously initialized, wait for it to finish spinning up.
  1163. //
  1164. WaitForSingleObject( pUserMem->hTapiEvent, INFINITE );
  1165. //
  1166. // Restore the last recipient information as a convenience
  1167. //
  1168. RestoreLastRecipientInfo(hDlg, &countryId);
  1169. //
  1170. // Initialize the list of countries
  1171. //
  1172. UpdateCountryCombobox(hDlg, countryId);
  1173. //
  1174. // Check if MAPI is installed - we need it for address book features
  1175. //
  1176. // if (! IsMapiAvailable())
  1177. // EnableWindow(GetDlgItem(hDlg, IDC_CHOOSE_ADDRBOOK), FALSE);
  1178. LimitTextFields(hDlg, textLimits);
  1179. //
  1180. // Initialize the recipient list view
  1181. //
  1182. InitRecipientListView(GetDlgItem(hDlg, IDC_CHOOSE_RECIPIENT_LIST));
  1183. //
  1184. // Initialize the location combo-box
  1185. //
  1186. LocationListInit(hDlg, pUserMem);
  1187. // Disable the IME for the area code edit control.
  1188. hEditControl = GetDlgItem( hDlg, IDC_CHOOSE_AREA_CODE_EDIT );
  1189. if ( hEditControl != (HWND) INVALID_HANDLE_VALUE )
  1190. {
  1191. ImmAssociateContext( hEditControl, (HIMC) NULL );
  1192. }
  1193. // Disable the IME for the fax phone number edit control.
  1194. hEditControl = GetDlgItem( hDlg, IDC_CHOOSE_NUMBER_EDIT );
  1195. if ( hEditControl != (HWND) INVALID_HANDLE_VALUE )
  1196. {
  1197. ImmAssociateContext( hEditControl, (HIMC) NULL );
  1198. }
  1199. break;
  1200. case WM_NOTIFY:
  1201. pNMHdr = (NMHDR *) lParam;
  1202. switch (pNMHdr->code) {
  1203. case LVN_KEYDOWN:
  1204. if (pNMHdr->hwndFrom == GetDlgItem(hDlg, IDC_CHOOSE_RECIPIENT_LIST) &&
  1205. ((LV_KEYDOWN *) pNMHdr)->wVKey == VK_DELETE)
  1206. {
  1207. RemoveRecipient(hDlg, pUserMem);
  1208. }
  1209. break;
  1210. case PSN_WIZNEXT:
  1211. if (! ValidateRecipients(hDlg, pUserMem)) {
  1212. //
  1213. // Validate the list of recipients and prevent the user
  1214. // from advancing to the next page if there is a problem
  1215. //
  1216. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, -1);
  1217. return TRUE;
  1218. }
  1219. break;
  1220. case PSN_SETACTIVE:
  1221. //
  1222. // make sure the remove button has the correct state
  1223. //
  1224. UpdateRemoveFromListButton(pUserMem->pRecipients ? TRUE : FALSE);
  1225. break;
  1226. }
  1227. return FALSE;
  1228. case WM_COMMAND:
  1229. cmd = GET_WM_COMMAND_CMD(wParam, lParam);
  1230. switch (GET_WM_COMMAND_ID(wParam, lParam)) {
  1231. case IDC_CHOOSE_COUNTRY_COMBO:
  1232. if (cmd == CBN_SELCHANGE) {
  1233. //
  1234. // Update the area code edit box if necessary
  1235. //
  1236. SelChangeCountryListBox(GetDlgItem(hDlg, IDC_CHOOSE_COUNTRY_COMBO),
  1237. GetDlgItem(hDlg, IDC_CHOOSE_AREA_CODE_EDIT));
  1238. UpdateAddToListButton();
  1239. }
  1240. break;
  1241. case IDC_CHOOSE_NAME_EDIT:
  1242. if (cmd == EN_CHANGE)
  1243. {
  1244. UpdateAddToListButton();
  1245. }
  1246. break;
  1247. case IDC_CHOOSE_AREA_CODE_EDIT:
  1248. if (cmd == EN_CHANGE)
  1249. {
  1250. UpdateAddToListButton();
  1251. // Look for DBCS in the edit control.
  1252. // Read the text from the edit control.
  1253. if ( GetDlgItemText( hDlg, IDC_CHOOSE_AREA_CODE_EDIT, tszBuffer,
  1254. MAX_STRING_LEN ) != 0 )
  1255. {
  1256. // Determine whether the contents of the edit control are legal.
  1257. if ( IsStringASCII( tszBuffer ) != (BOOL) TRUE )
  1258. {
  1259. LoadString(ghInstance, IDS_ERROR_AREA_CODE,
  1260. tszBuffer, MAX_STRING_LEN);
  1261. MessageBox( hDlg, tszBuffer, NULL,
  1262. (UINT) (MB_ICONSTOP | MB_OK) );
  1263. SetDlgItemText(hDlg, IDC_CHOOSE_AREA_CODE_EDIT, L"");
  1264. }
  1265. }
  1266. else
  1267. {
  1268. dwErrorCode = GetLastError();
  1269. if ( dwErrorCode != (DWORD) ERROR_SUCCESS )
  1270. {
  1271. // Error reading the edit control.
  1272. }
  1273. }
  1274. }
  1275. break;
  1276. case IDC_CHOOSE_NUMBER_EDIT:
  1277. if (cmd == EN_CHANGE)
  1278. {
  1279. UpdateAddToListButton();
  1280. // Look for DBCS in the edit control.
  1281. // Read the text from the edit control.
  1282. if ( GetDlgItemText( hDlg, IDC_CHOOSE_NUMBER_EDIT, tszBuffer,
  1283. MAX_STRING_LEN ) != 0 )
  1284. {
  1285. // Determine whether the contents of the edit control are legal.
  1286. if ( IsStringASCII( tszBuffer ) != (BOOL) TRUE )
  1287. {
  1288. LoadString(ghInstance, IDS_ERROR_FAX_NUMBER,
  1289. tszBuffer, MAX_STRING_LEN);
  1290. MessageBox( hDlg, tszBuffer, NULL,
  1291. (UINT) (MB_ICONSTOP | MB_OK) );
  1292. SetDlgItemText(hDlg, IDC_CHOOSE_NUMBER_EDIT, L"");
  1293. }
  1294. }
  1295. else
  1296. {
  1297. dwErrorCode = GetLastError();
  1298. if ( dwErrorCode != (DWORD) ERROR_SUCCESS )
  1299. {
  1300. // Error reading the edit control.
  1301. }
  1302. }
  1303. }
  1304. break;
  1305. case IDC_USE_DIALING_RULES:
  1306. UpdateCountryCombobox(hDlg, -1);
  1307. UpdateAddToListButton();
  1308. break;
  1309. case IDC_CHOOSE_ADDRBOOK:
  1310. DoAddressBook(hDlg, pUserMem);
  1311. UpdateRemoveFromListButton(pUserMem->pRecipients ? TRUE : FALSE);
  1312. break;
  1313. case IDC_TAPI_PROPS:
  1314. DoTapiProps(hDlg);
  1315. LocationListInit(hDlg, pUserMem);
  1316. break;
  1317. case IDC_LOCATION_LIST:
  1318. if (cmd == CBN_SELCHANGE)
  1319. LocationListSelChange(hDlg);
  1320. break;
  1321. case IDC_CHOOSE_ADD:
  1322. if ((cmd = AddRecipient(hDlg, pUserMem)) != 0) {
  1323. if (cmd > 0)
  1324. DisplayMessageDialog(hDlg, 0, 0, cmd);
  1325. else
  1326. MessageBeep(MB_OK);
  1327. } else {
  1328. SetFocus(GetDlgItem(hDlg, IDC_CHOOSE_NAME_EDIT));
  1329. //
  1330. // enable the remove button
  1331. //
  1332. UpdateRemoveFromListButton(TRUE);
  1333. }
  1334. break;
  1335. case IDC_CHOOSE_REMOVE:
  1336. RemoveRecipient(hDlg, pUserMem);
  1337. //
  1338. // disable the remove button if there are no more recipients
  1339. //
  1340. if (!pUserMem->pRecipients) {
  1341. UpdateRemoveFromListButton(FALSE);
  1342. }
  1343. }
  1344. break;
  1345. }
  1346. return TRUE;
  1347. }
  1348. VOID
  1349. ValidateSelectedCoverPage(
  1350. PUSERMEM pUserMem
  1351. )
  1352. /*++
  1353. Routine Description:
  1354. If a cover page is selected, then do the following:
  1355. if the cover page file is a link resolve it
  1356. check if the cover page file contains note/subject fields
  1357. Arguments:
  1358. pUserMem - Points to user mode memory structure
  1359. Return Value:
  1360. NONE
  1361. --*/
  1362. {
  1363. TCHAR filename[MAX_PATH];
  1364. COVDOCINFO covDocInfo;
  1365. DWORD ec;
  1366. if (ResolveShortcut(pUserMem->coverPage, filename))
  1367. _tcscpy(pUserMem->coverPage, filename);
  1368. Verbose(("Cover page selected: %ws\n", pUserMem->coverPage));
  1369. ec = PrintCoverPage(NULL, NULL, pUserMem->coverPage, &covDocInfo);
  1370. if (!ec) {
  1371. pUserMem->noteSubjectFlag = covDocInfo.Flags;
  1372. pUserMem->cpPaperSize = covDocInfo.PaperSize;
  1373. pUserMem->cpOrientation = covDocInfo.Orientation;
  1374. } else {
  1375. Error(("Cannot examine cover page file '%ws': %d\n",
  1376. pUserMem->coverPage,
  1377. ec));
  1378. }
  1379. }
  1380. INT_PTR
  1381. CoverPageWizProc(
  1382. HWND hDlg,
  1383. UINT message,
  1384. WPARAM wParam,
  1385. LPARAM lParam
  1386. )
  1387. /*++
  1388. Routine Description:
  1389. Dialog procedure for the second wizard page:
  1390. selecting cover page and setting other fax options
  1391. Arguments:
  1392. hDlg - Identifies the wizard page
  1393. message - Specifies the message
  1394. wParam - Specifies additional message-specific information
  1395. lParam - Specifies additional message-specific information
  1396. Return Value:
  1397. Depends on the message parameter
  1398. --*/
  1399. {
  1400. static INT textLimits[] = {
  1401. IDC_CHOOSE_CP_SUBJECT, 256,
  1402. IDC_CHOOSE_CP_NOTE, 8192,
  1403. 0
  1404. };
  1405. PUSERMEM pUserMem;
  1406. PDMPRIVATE pdmPrivate;
  1407. WORD cmdId;
  1408. HKEY hRegKey;
  1409. //
  1410. // Handle common messages shared by all wizard pages
  1411. //
  1412. if (! (pUserMem = CommonWizardProc(hDlg, message, wParam, lParam, PSWIZB_BACK|PSWIZB_NEXT)))
  1413. return FALSE;
  1414. //
  1415. // Handle anything specific to the current wizard page
  1416. //
  1417. pdmPrivate = &pUserMem->devmode.dmPrivate;
  1418. switch (message) {
  1419. case WM_INITDIALOG:
  1420. //
  1421. // Retrieve the most recently used cover page settings
  1422. //
  1423. if (hRegKey = GetUserInfoRegKey(REGKEY_FAX_USERINFO, REG_READONLY)) {
  1424. LPTSTR tmp;
  1425. pdmPrivate->sendCoverPage =
  1426. GetRegistryDword(hRegKey, REGVAL_SEND_COVERPG);
  1427. tmp = GetRegistryString(hRegKey, REGVAL_COVERPG, TEXT("") );
  1428. if (tmp) {
  1429. lstrcpy(pUserMem->coverPage, tmp );
  1430. MemFree(tmp);
  1431. }
  1432. RegCloseKey(hRegKey);
  1433. }
  1434. //
  1435. // Initialize the list of cover pages
  1436. //
  1437. WaitForSingleObject( pUserMem->hFaxSvcEvent, INFINITE );
  1438. if (pUserMem->pCPInfo = AllocCoverPageInfo(pUserMem->hPrinter, pUserMem->ServerCPOnly)) {
  1439. InitCoverPageList(pUserMem->pCPInfo,
  1440. GetDlgItem(hDlg, IDC_CHOOSE_CP_LIST),
  1441. pUserMem->coverPage);
  1442. }
  1443. //
  1444. // Indicate whether cover page should be sent
  1445. //
  1446. if (SendDlgItemMessage(hDlg, IDC_CHOOSE_CP_LIST, CB_GETCOUNT, 0, 0) <= 0) {
  1447. pdmPrivate->sendCoverPage = FALSE;
  1448. EnableWindow(GetDlgItem(hDlg, IDC_CHOOSE_CP_CHECK), FALSE);
  1449. }
  1450. CheckDlgButton(hDlg, IDC_CHOOSE_CP_CHECK, pdmPrivate->sendCoverPage);
  1451. EnableWindow(GetDlgItem(hDlg, IDC_CHOOSE_CP_LIST), pdmPrivate->sendCoverPage);
  1452. EnableWindow(GetDlgItem(hDlg, IDC_STATIC_CHOOSE_CP_SUBJECT), pdmPrivate->sendCoverPage);
  1453. EnableWindow(GetDlgItem(hDlg, IDC_CHOOSE_CP_SUBJECT), pdmPrivate->sendCoverPage);
  1454. EnableWindow(GetDlgItem(hDlg, IDC_STATIC_CHOOSE_CP_NOTE), pdmPrivate->sendCoverPage);
  1455. EnableWindow(GetDlgItem(hDlg, IDC_CHOOSE_CP_NOTE), pdmPrivate->sendCoverPage);
  1456. //
  1457. // make sure the user selects a coverpage if this is the fax send utility
  1458. //
  1459. if (GetEnvironmentVariable(TEXT("NTFaxSendNote"), NULL, 0)) {
  1460. pdmPrivate->sendCoverPage = TRUE;
  1461. CheckDlgButton(hDlg, IDC_CHOOSE_CP_CHECK, TRUE);
  1462. // hide the checkbox
  1463. MyHideWindow(GetDlgItem(hDlg,IDC_CHOOSE_CP_CHECK) );
  1464. EnableWindow(GetDlgItem(hDlg, IDC_CHOOSE_CP_LIST), TRUE);
  1465. EnableWindow(GetDlgItem(hDlg, IDC_STATIC_CHOOSE_CP_SUBJECT), TRUE);
  1466. EnableWindow(GetDlgItem(hDlg, IDC_CHOOSE_CP_SUBJECT), TRUE);
  1467. EnableWindow(GetDlgItem(hDlg, IDC_STATIC_CHOOSE_CP_NOTE), TRUE);
  1468. EnableWindow(GetDlgItem(hDlg, IDC_CHOOSE_CP_NOTE), TRUE);
  1469. } else {
  1470. MyHideWindow(GetDlgItem(hDlg, IDC_STATIC_CHOOSE_CP_NOCHECK) );
  1471. }
  1472. LimitTextFields(hDlg, textLimits);
  1473. break;
  1474. case WM_COMMAND:
  1475. switch (cmdId = GET_WM_COMMAND_ID(wParam, lParam)) {
  1476. case IDC_CHOOSE_CP_CHECK:
  1477. EnableWindow(GetDlgItem(hDlg, IDC_STATIC_CHOOSE_CP), IsDlgButtonChecked(hDlg, cmdId) );
  1478. EnableWindow(GetDlgItem(hDlg, IDC_CHOOSE_CP_LIST), IsDlgButtonChecked(hDlg, cmdId) );
  1479. EnableWindow(GetDlgItem(hDlg, IDC_STATIC_CHOOSE_CP_SUBJECT), IsDlgButtonChecked(hDlg, cmdId) );
  1480. EnableWindow(GetDlgItem(hDlg, IDC_CHOOSE_CP_SUBJECT), IsDlgButtonChecked(hDlg, cmdId) );
  1481. EnableWindow(GetDlgItem(hDlg, IDC_STATIC_CHOOSE_CP_NOTE), IsDlgButtonChecked(hDlg, cmdId) );
  1482. EnableWindow(GetDlgItem(hDlg, IDC_CHOOSE_CP_NOTE), IsDlgButtonChecked(hDlg, cmdId) );
  1483. break;
  1484. };
  1485. break;
  1486. case WM_NOTIFY:
  1487. if (((NMHDR *) lParam)->code == PSN_WIZNEXT) {
  1488. //
  1489. // Remember the cover page settings selected
  1490. //
  1491. pUserMem->noteSubjectFlag = 0;
  1492. pUserMem->cpPaperSize = 0;
  1493. pUserMem->cpOrientation = 0;
  1494. pdmPrivate->sendCoverPage = IsDlgButtonChecked(hDlg, IDC_CHOOSE_CP_CHECK);
  1495. GetSelectedCoverPage(pUserMem->pCPInfo,
  1496. GetDlgItem(hDlg, IDC_CHOOSE_CP_LIST),
  1497. pUserMem->coverPage);
  1498. if (hRegKey = GetUserInfoRegKey(REGKEY_FAX_USERINFO, REG_READWRITE)) {
  1499. SetRegistryDword(hRegKey, REGVAL_SEND_COVERPG, pdmPrivate->sendCoverPage);
  1500. SetRegistryString(hRegKey, REGVAL_COVERPG, pUserMem->coverPage);
  1501. RegCloseKey(hRegKey);
  1502. }
  1503. //
  1504. // If a cover page is selected, then do the following:
  1505. // if the cover page file is a link resolve it
  1506. // check if the cover page file contains note/subject fields
  1507. //
  1508. if (pdmPrivate->sendCoverPage)
  1509. ValidateSelectedCoverPage(pUserMem);
  1510. //
  1511. // Collect the current values of other dialog controls
  1512. //
  1513. if (pUserMem->pSubject) MemFree(pUserMem->pSubject);
  1514. if (pUserMem->pNoteMessage) MemFree(pUserMem->pNoteMessage);
  1515. pUserMem->pSubject = GetTextStringValue(GetDlgItem(hDlg, IDC_CHOOSE_CP_SUBJECT));
  1516. pUserMem->pNoteMessage = GetTextStringValue(GetDlgItem(hDlg, IDC_CHOOSE_CP_NOTE));
  1517. //
  1518. // If the current application is "Send Note" utility, then
  1519. // the note field must not be empty.
  1520. //
  1521. if (pUserMem->pSubject == NULL &&
  1522. pUserMem->pNoteMessage == NULL &&
  1523. GetEnvironmentVariable(TEXT("NTFaxSendNote"), NULL, 0))
  1524. {
  1525. DisplayMessageDialog(hDlg, 0, 0, IDS_NOTE_SUBJECT_EMPTY);
  1526. SetFocus(GetDlgItem(hDlg, IDC_CHOOSE_CP_SUBJECT));
  1527. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, -1);
  1528. return TRUE;
  1529. }
  1530. }
  1531. return FALSE;
  1532. }
  1533. return TRUE;
  1534. }
  1535. INT_PTR
  1536. FaxOptsWizProc(
  1537. HWND hDlg,
  1538. UINT message,
  1539. WPARAM wParam,
  1540. LPARAM lParam
  1541. )
  1542. /*++
  1543. Routine Description:
  1544. Dialog procedure for the first wizard page: entering subject and note information
  1545. Arguments:
  1546. hDlg - Identifies the wizard page
  1547. message - Specifies the message
  1548. wParam - Specifies additional message-specific information
  1549. lParam - Specifies additional message-specific information
  1550. Return Value:
  1551. Depends on the message parameter
  1552. --*/
  1553. {
  1554. //
  1555. // Maximum length for various text fields
  1556. //
  1557. static INT textLimits[] = {
  1558. IDC_WIZ_FAXOPTS_BILLING, 16,
  1559. 0
  1560. };
  1561. PUSERMEM pUserMem;
  1562. PDMPRIVATE pdmPrivate;
  1563. WORD cmdId;
  1564. // TCHAR TimeFormat[32];
  1565. TCHAR Is24H[2], IsRTL[2], *pszTimeFormat = TEXT("h : mm tt");
  1566. static HWND hTimeControl;
  1567. SYSTEMTIME st;
  1568. if (! (pUserMem = CommonWizardProc(hDlg, message, wParam, lParam, PSWIZB_BACK|PSWIZB_NEXT)))
  1569. return FALSE;
  1570. pdmPrivate = &pUserMem->devmode.dmPrivate;
  1571. switch (message) {
  1572. case WM_INITDIALOG:
  1573. //LoadString(ghInstance,IDS_WIZ_TIME_FORMAT,TimeFormat,sizeof(TimeFormat));
  1574. hTimeControl = GetDlgItem(hDlg, IDC_WIZ_FAXOPTS_SENDTIME);
  1575. if (GetLocaleInfo( LOCALE_USER_DEFAULT,LOCALE_ITIME, Is24H,sizeof(Is24H) ) && Is24H[0] == TEXT('1')) {
  1576. pszTimeFormat = TEXT("H : mm");
  1577. }
  1578. else if (GetLocaleInfo( LOCALE_USER_DEFAULT,LOCALE_ITIMEMARKPOSN, IsRTL,sizeof(IsRTL) ) && IsRTL[0] == TEXT('1')) {
  1579. pszTimeFormat = TEXT("tt h : mm");
  1580. }
  1581. LimitTextFields(hDlg, textLimits);
  1582. DateTime_SetFormat( hTimeControl,pszTimeFormat );
  1583. //
  1584. // restore time to send controls
  1585. //
  1586. cmdId = (pdmPrivate->whenToSend == SENDFAX_AT_CHEAP) ? IDC_WIZ_FAXOPTS_DISCOUNT :
  1587. (pdmPrivate->whenToSend == SENDFAX_AT_TIME) ? IDC_WIZ_FAXOPTS_SPECIFIC :
  1588. IDC_WIZ_FAXOPTS_ASAP;
  1589. CheckDlgButton(hDlg, cmdId, TRUE);
  1590. EnableWindow(hTimeControl, (cmdId == IDC_WIZ_FAXOPTS_SPECIFIC) );
  1591. EnableWindow(GetDlgItem(hDlg, IDC_STATIC_FAXOPTS_DATE), (cmdId == IDC_WIZ_FAXOPTS_SPECIFIC) );
  1592. GetLocalTime(&st);
  1593. st.wHour = pdmPrivate->sendAtTime.Hour;
  1594. st.wMinute = pdmPrivate->sendAtTime.Minute;
  1595. DateTime_SetSystemtime( hTimeControl, GDT_VALID, &st );
  1596. SetDlgItemText(hDlg, IDC_WIZ_FAXOPTS_BILLING, pdmPrivate->billingCode);
  1597. return TRUE;
  1598. case WM_NOTIFY:
  1599. if (((NMHDR *) lParam)->code == PSN_WIZNEXT) {
  1600. //
  1601. // retrieve the billing code
  1602. //
  1603. if (! GetDlgItemText(hDlg, IDC_WIZ_FAXOPTS_BILLING, pdmPrivate->billingCode, MAX_BILLING_CODE)) {
  1604. pdmPrivate->billingCode[0] = NUL;
  1605. }
  1606. //
  1607. // retrieve the sending time
  1608. //
  1609. pdmPrivate->whenToSend = IsDlgButtonChecked(hDlg,IDC_WIZ_FAXOPTS_DISCOUNT) ? SENDFAX_AT_CHEAP :
  1610. IsDlgButtonChecked(hDlg,IDC_WIZ_FAXOPTS_SPECIFIC) ? SENDFAX_AT_TIME :
  1611. SENDFAX_ASAP;
  1612. if (pdmPrivate->whenToSend == SENDFAX_AT_TIME) {
  1613. DWORD rVal;
  1614. SYSTEMTIME SendTime;
  1615. TCHAR TimeBuffer[128];
  1616. //
  1617. // get specific time
  1618. //
  1619. rVal = DateTime_GetSystemtime(hTimeControl, &SendTime);
  1620. pdmPrivate->sendAtTime.Hour = SendTime.wHour;
  1621. pdmPrivate->sendAtTime.Minute = SendTime.wMinute;
  1622. rVal = GetDateFormat(
  1623. LOCALE_SYSTEM_DEFAULT,
  1624. 0,
  1625. &SendTime,
  1626. NULL,
  1627. TimeBuffer,
  1628. sizeof(TimeBuffer)
  1629. );
  1630. TimeBuffer[rVal - 1] = TEXT(' ');
  1631. GetTimeFormat(
  1632. LOCALE_SYSTEM_DEFAULT,
  1633. 0,
  1634. &SendTime,
  1635. NULL,
  1636. &TimeBuffer[rVal],
  1637. sizeof(TimeBuffer)
  1638. );
  1639. Verbose(("faxui - Fax Send time %ws", TimeBuffer));
  1640. }
  1641. }
  1642. break;
  1643. case WM_COMMAND:
  1644. switch (cmdId = GET_WM_COMMAND_ID(wParam, lParam)) {
  1645. case IDC_WIZ_FAXOPTS_SPECIFIC:
  1646. case IDC_WIZ_FAXOPTS_DISCOUNT:
  1647. case IDC_WIZ_FAXOPTS_ASAP:
  1648. EnableWindow(hTimeControl, (cmdId == IDC_WIZ_FAXOPTS_SPECIFIC) );
  1649. EnableWindow(GetDlgItem(hDlg, IDC_STATIC_FAXOPTS_DATE), (cmdId == IDC_WIZ_FAXOPTS_SPECIFIC) );
  1650. break;
  1651. };
  1652. break;
  1653. default:
  1654. return FALSE;
  1655. } ;
  1656. return TRUE;
  1657. }
  1658. #ifdef FAX_SCAN_ENABLED
  1659. BOOL
  1660. CloseDataSource(
  1661. PUSERMEM pUserMem,
  1662. TW_IDENTITY * TwIdentity
  1663. );
  1664. BOOL
  1665. OpenDataSource(
  1666. PUSERMEM pUserMem,
  1667. TW_IDENTITY * TwIdentity
  1668. );
  1669. BOOL
  1670. DisableDataSource(
  1671. PUSERMEM pUserMem,
  1672. TW_USERINTERFACE * TwUserInterface
  1673. );
  1674. BOOL
  1675. EnableDataSource(
  1676. PUSERMEM pUserMem,
  1677. TW_USERINTERFACE * TwUserInterface
  1678. );
  1679. BOOL
  1680. SetCapability(
  1681. PUSERMEM pUserMem,
  1682. USHORT Capability,
  1683. USHORT Type,
  1684. LPVOID Value
  1685. );
  1686. BOOL
  1687. Scan_SetCapabilities(
  1688. PUSERMEM pUserMem
  1689. );
  1690. #define WM_SCAN_INIT WM_APP
  1691. #define WM_SCAN_OPENDSM WM_APP+1
  1692. #define WM_SCAN_CLOSEDSM WM_APP+2
  1693. #define WM_SCAN_GETDEFAULT WM_APP+3
  1694. #define WM_SCAN_GETFIRST WM_APP+4
  1695. #define WM_SCAN_GETNEXT WM_APP+5
  1696. #define WM_SCAN_OPENDS WM_APP+10
  1697. #define WM_SCAN_CLOSEDS WM_APP+11
  1698. #define WM_SCAN_ENABLEDS WM_APP+12
  1699. #define WM_SCAN_DISABLEDS WM_APP+13
  1700. #define WM_SCAN_CONTROLGET WM_APP+20
  1701. #define WM_SCAN_CONTROLGETDEF WM_APP+21
  1702. #define WM_SCAN_CONTROLRESET WM_APP+22
  1703. #define WM_SCAN_CONTROLSET WM_APP+23
  1704. #define WM_SCAN_CONTROLENDXFER WM_APP+24
  1705. #define WM_SCAN_IMAGEGET WM_APP+30
  1706. #define Scan_Init(_pUserMem) (SendMessage(_pUserMem->hWndTwain, WM_SCAN_INIT,0,(LPARAM)_pUserMem))
  1707. #define Scan_OpenDSM(_pUserMem) ((DWORD)SendMessage(_pUserMem->hWndTwain, WM_SCAN_OPENDSM,0,(LPARAM)&_pUserMem->hWndTwain))
  1708. #define Scan_CloseDSM(_pUserMem) ((DWORD)SendMessage(_pUserMem->hWndTwain, WM_SCAN_CLOSEDSM,0,(LPARAM)&_pUserMem->hWndTwain))
  1709. #define Scan_GetDefault(_pUserMem,_TwIdentity) ((DWORD)SendMessage(_pUserMem->hWndTwain, WM_SCAN_GETDEFAULT,0,(LPARAM)_TwIdentity))
  1710. #define Scan_GetFirst(_pUserMem,_TwIdentity) ((DWORD)SendMessage(_pUserMem->hWndTwain, WM_SCAN_GETFIRST,0,(LPARAM)_TwIdentity))
  1711. #define Scan_GetNext(_pUserMem,_TwIdentity) ((DWORD)SendMessage(_pUserMem->hWndTwain, WM_SCAN_GETNEXT,0,(LPARAM)_TwIdentity))
  1712. #define Scan_OpenDS(_pUserMem,_TwIdentity) (SendMessage(_pUserMem->hWndTwain, WM_SCAN_OPENDS,0,(LPARAM)_TwIdentity))
  1713. #define Scan_CloseDS(_pUserMem,_TwIdentity) ((DWORD)SendMessage(_pUserMem->hWndTwain, WM_SCAN_CLOSEDS,0,(LPARAM)_TwIdentity))
  1714. #define Scan_EnableDS(_pUserMem,_TwUi) (SendMessage(_pUserMem->hWndTwain, WM_SCAN_ENABLEDS,0,(LPARAM)_TwUi))
  1715. #define Scan_DisableDS(_pUserMem,_TwUi) (SendMessage(_pUserMem->hWndTwain, WM_SCAN_DISABLEDS,0,(LPARAM)_TwUi))
  1716. #define Scan_ControlGet(_pUserMem,_What,_Data) ((DWORD)SendMessage(_pUserMem->hWndTwain, WM_SCAN_CONTROLGET,(WPARAM)_What,(LPARAM)_Data))
  1717. #define Scan_ControlGetDef(_pUserMem,_What,_Data) (SendMessage(_pUserMem->hWndTwain, WM_SCAN_CONTROLGETDEF,(WPARAM)_What,(LPARAM)_Data))
  1718. #define Scan_ControlReset(_pUserMem,_What,_Data) ((DWORD)SendMessage(_pUserMem->hWndTwain, WM_SCAN_CONTROLRESET,(WPARAM)_What,(LPARAM)_Data))
  1719. #define Scan_ControlSet(_pUserMem,_What,_Data) ((DWORD)SendMessage(_pUserMem->hWndTwain, WM_SCAN_CONTROLSET,(WPARAM)_What,(LPARAM)_Data))
  1720. #define Scan_ControlEndXfer(_pUserMem,_What,_Data) ((DWORD)SendMessage(_pUserMem->hWndTwain, WM_SCAN_CONTROLENDXFER,(WPARAM)_What,(LPARAM)_Data))
  1721. #define Scan_ImageGet(_pUserMem,_What,_Data) ((DWORD)SendMessage(_pUserMem->hWndTwain, WM_SCAN_IMAGEGET,(WPARAM)_What,(LPARAM)_Data))
  1722. //#define WM_SCAN_GETEVENT WM_APP+7
  1723. DWORD
  1724. CallTwain(
  1725. PUSERMEM pUserMem,
  1726. TW_UINT32 DG,
  1727. TW_UINT16 DAT,
  1728. TW_UINT16 MSG,
  1729. TW_MEMREF pData
  1730. )
  1731. {
  1732. DWORD TwResult = 0;
  1733. TW_STATUS TwStatus = {0};
  1734. __try {
  1735. TwResult = pUserMem->pDsmEntry(
  1736. &pUserMem->AppId,
  1737. NULL,
  1738. DG,
  1739. DAT,
  1740. MSG,
  1741. pData
  1742. );
  1743. if (TwResult) {
  1744. pUserMem->pDsmEntry(
  1745. &pUserMem->AppId,
  1746. NULL,
  1747. DG_CONTROL,
  1748. DAT_STATUS,
  1749. MSG_GET,
  1750. (TW_MEMREF) &TwStatus
  1751. );
  1752. if (TwStatus.ConditionCode) {
  1753. TwResult = TwStatus.ConditionCode;
  1754. }
  1755. Verbose(( "CallTwain failed, ec=%d\n", TwResult ));
  1756. }
  1757. } __except (EXCEPTION_EXECUTE_HANDLER) {
  1758. //
  1759. // for some reason we crashed, so return the exception code
  1760. //
  1761. TwResult = GetExceptionCode();
  1762. Verbose(( "CallTwain crashed, ec=0x%08x\n", TwResult ));
  1763. }
  1764. return TwResult;
  1765. }
  1766. DWORD
  1767. CallTwainDataSource(
  1768. PUSERMEM pUserMem,
  1769. TW_UINT32 DG,
  1770. TW_UINT16 DAT,
  1771. TW_UINT16 MSG,
  1772. TW_MEMREF pData
  1773. )
  1774. {
  1775. DWORD TwResult = 0;
  1776. TW_STATUS TwStatus = {0};
  1777. __try {
  1778. TwResult = pUserMem->pDsmEntry(
  1779. &pUserMem->AppId,
  1780. &pUserMem->DataSource,
  1781. DG,
  1782. DAT,
  1783. MSG,
  1784. pData
  1785. );
  1786. if (TwResult) {
  1787. pUserMem->pDsmEntry(
  1788. &pUserMem->AppId,
  1789. &pUserMem->DataSource,
  1790. DG_CONTROL,
  1791. DAT_STATUS,
  1792. MSG_GET,
  1793. (TW_MEMREF) &TwStatus
  1794. );
  1795. if (TwStatus.ConditionCode) {
  1796. TwResult = TwStatus.ConditionCode;
  1797. }
  1798. //Verbose(( "CallTwainDataSource failed, ec=%d\n", TwResult ));
  1799. }
  1800. } __except (EXCEPTION_EXECUTE_HANDLER) {
  1801. //
  1802. // for some reason we crashed, so return the exception code
  1803. //
  1804. TwResult = GetExceptionCode();
  1805. Verbose(( "CallTwainDataSource crashed, ec=0x%08x\n", TwResult ));
  1806. }
  1807. return TwResult;
  1808. }
  1809. LRESULT
  1810. WINAPI
  1811. TwainWndProc(
  1812. HWND hwnd,
  1813. UINT uMsg,
  1814. WPARAM wParam,
  1815. LPARAM lParam
  1816. )
  1817. {
  1818. DWORD TwResult = 0;
  1819. static PUSERMEM pUserMem = NULL;
  1820. switch (uMsg) {
  1821. case WM_SCAN_INIT:
  1822. pUserMem = (PUSERMEM)lParam;
  1823. return(TRUE);
  1824. break;
  1825. case WM_SCAN_OPENDSM :
  1826. TwResult = CallTwain(
  1827. pUserMem,
  1828. DG_CONTROL,
  1829. DAT_PARENT,
  1830. MSG_OPENDSM,
  1831. (TW_MEMREF) lParam
  1832. );
  1833. if (TwResult != TWRC_SUCCESS) {
  1834. Verbose(( "MSG_OPENDSM (DAT_PARENT) failed, ec = %d\n", TwResult ));
  1835. }
  1836. return(TwResult);
  1837. break;
  1838. case WM_SCAN_CLOSEDSM:
  1839. TwResult = CallTwain(
  1840. pUserMem,
  1841. DG_CONTROL,
  1842. DAT_PARENT,
  1843. MSG_CLOSEDSM,
  1844. (TW_MEMREF) lParam
  1845. );
  1846. if (TwResult != TWRC_SUCCESS) {
  1847. Verbose(( "MSG_CLOSEDSM (DAT_PARENT) failed, ec = %d\n", TwResult ));
  1848. }
  1849. return(TwResult);
  1850. break;
  1851. case WM_SCAN_GETDEFAULT:
  1852. TwResult = CallTwain(
  1853. pUserMem,
  1854. DG_CONTROL,
  1855. DAT_IDENTITY,
  1856. MSG_GETDEFAULT,
  1857. (TW_MEMREF) lParam
  1858. );
  1859. if (TwResult != TWRC_SUCCESS) {
  1860. Verbose(( "MSG_GETDEFAULT (DAT_IDENTITY) failed, ec = %d\n", TwResult ));
  1861. }
  1862. return(TwResult);
  1863. break;
  1864. case WM_SCAN_GETFIRST:
  1865. TwResult = CallTwain(
  1866. pUserMem,
  1867. DG_CONTROL,
  1868. DAT_IDENTITY,
  1869. MSG_GETFIRST,
  1870. (TW_MEMREF) lParam
  1871. );
  1872. if (TwResult != TWRC_SUCCESS) {
  1873. Verbose(( "MSG_GETFIRST (DAT_IDENTITY) failed, ec = %d\n", TwResult ));
  1874. }
  1875. return(TwResult);
  1876. break;
  1877. case WM_SCAN_GETNEXT:
  1878. TwResult = CallTwain(
  1879. pUserMem,
  1880. DG_CONTROL,
  1881. DAT_IDENTITY,
  1882. MSG_GETNEXT,
  1883. (TW_MEMREF) lParam
  1884. );
  1885. if (TwResult != TWRC_SUCCESS && TwResult != TWRC_ENDOFLIST) {
  1886. Verbose(( "MSG_GETNEXT (DAT_IDENTITY) failed, ec = %d\n", TwResult ));
  1887. }
  1888. return(TwResult);
  1889. break;
  1890. case WM_SCAN_OPENDS:
  1891. if (OpenDataSource( pUserMem, (TW_IDENTITY *)lParam ) &&
  1892. Scan_SetCapabilities( pUserMem )) {
  1893. return TRUE;
  1894. }
  1895. return(FALSE);
  1896. case WM_SCAN_CLOSEDS:
  1897. return (CloseDataSource( pUserMem, (TW_IDENTITY *)lParam ));
  1898. case WM_SCAN_ENABLEDS:
  1899. return (EnableDataSource( pUserMem, (TW_USERINTERFACE *)lParam ));
  1900. case WM_SCAN_DISABLEDS:
  1901. return (DisableDataSource( pUserMem, (TW_USERINTERFACE *)lParam ));
  1902. case WM_SCAN_CONTROLGET:
  1903. TwResult = CallTwainDataSource(
  1904. pUserMem,
  1905. DG_CONTROL,
  1906. (TW_UINT16)wParam,
  1907. MSG_GET,
  1908. (TW_MEMREF) lParam
  1909. );
  1910. if (TwResult != TWRC_SUCCESS) {
  1911. Verbose(( "MSG_GET (%d)failed, ec = %d\n", wParam, TwResult ));
  1912. }
  1913. return(TwResult);
  1914. break;
  1915. case WM_SCAN_CONTROLGETDEF:
  1916. TwResult = CallTwainDataSource(
  1917. pUserMem,
  1918. DG_CONTROL,
  1919. (TW_UINT16)wParam,
  1920. MSG_GETDEFAULT,
  1921. (TW_MEMREF) lParam
  1922. );
  1923. if (TwResult != TWRC_SUCCESS) {
  1924. Verbose(( "MSG_GETDEFAULT (%d)failed, ec = %d\n", wParam, TwResult ));
  1925. }
  1926. return(TwResult);
  1927. break;
  1928. case WM_SCAN_CONTROLRESET:
  1929. TwResult = CallTwainDataSource(
  1930. pUserMem,
  1931. DG_CONTROL,
  1932. (TW_UINT16)wParam,
  1933. MSG_RESET,
  1934. (TW_MEMREF) lParam
  1935. );
  1936. if (TwResult != TWRC_SUCCESS) {
  1937. Verbose(( "MSG_RESET (%d)failed, ec = %d\n", wParam, TwResult ));
  1938. }
  1939. return(TwResult);
  1940. break;
  1941. case WM_SCAN_CONTROLSET:
  1942. TwResult = CallTwainDataSource(
  1943. pUserMem,
  1944. DG_CONTROL,
  1945. (TW_UINT16)wParam,
  1946. MSG_SET,
  1947. (TW_MEMREF) lParam
  1948. );
  1949. if (TwResult != TWRC_SUCCESS) {
  1950. Verbose(( "MSG_SET (%d)failed, ec = %d\n", wParam, TwResult ));
  1951. }
  1952. return(TwResult);
  1953. break;
  1954. case WM_SCAN_CONTROLENDXFER:
  1955. TwResult = CallTwainDataSource(
  1956. pUserMem,
  1957. DG_CONTROL,
  1958. (TW_UINT16)wParam,
  1959. MSG_ENDXFER,
  1960. (TW_MEMREF) lParam
  1961. );
  1962. if (TwResult != TWRC_SUCCESS) {
  1963. Verbose(( "MSG_ENDXFER (%d)failed, ec = %d\n", wParam, TwResult ));
  1964. }
  1965. return(TwResult);
  1966. break;
  1967. case WM_SCAN_IMAGEGET:
  1968. TwResult = CallTwainDataSource(
  1969. pUserMem,
  1970. DG_IMAGE,
  1971. (TW_UINT16)wParam,
  1972. MSG_GET,
  1973. (TW_MEMREF) lParam
  1974. );
  1975. if (TwResult != TWRC_SUCCESS) {
  1976. Verbose(( "MSG_GET (DAT_IMAGEINFO) failed, ec = %d\n", TwResult ));
  1977. }
  1978. return(TwResult);
  1979. break;
  1980. default:
  1981. return DefWindowProc( hwnd, uMsg, wParam, lParam );
  1982. };
  1983. Assert(FALSE);
  1984. return FALSE;
  1985. }
  1986. DWORD
  1987. TwainMessagePumpThread(
  1988. PUSERMEM pUserMem
  1989. )
  1990. {
  1991. WNDCLASS wc;
  1992. MSG msg;
  1993. HWND hWnd;
  1994. DWORD WaitObj;
  1995. TW_EVENT TwEvent;
  1996. DWORD TwResult;
  1997. wc.style = CS_OWNDC;
  1998. wc.lpfnWndProc = (WNDPROC)TwainWndProc;
  1999. wc.cbClsExtra = 0;
  2000. wc.cbWndExtra = 0;
  2001. wc.hInstance = ghInstance;
  2002. wc.hIcon = NULL;
  2003. wc.hCursor = NULL;
  2004. wc.hbrBackground = NULL;
  2005. wc.lpszMenuName = NULL;
  2006. wc.lpszClassName = L"FaxWizTwainWindow";
  2007. if (RegisterClass( &wc ) == 0) {
  2008. SetEvent( pUserMem->hEvent );
  2009. return 0;
  2010. }
  2011. hWnd = CreateWindow(
  2012. L"FaxWizTwainWindow",
  2013. L"FaxWizTwainWindow",
  2014. WS_DISABLED,
  2015. 0,
  2016. 0,
  2017. 0,
  2018. 0,
  2019. NULL,
  2020. NULL,
  2021. ghInstance,
  2022. NULL
  2023. );
  2024. if (hWnd == NULL) {
  2025. SetEvent( pUserMem->hEvent );
  2026. return 0;
  2027. }
  2028. pUserMem->hWndTwain = hWnd;
  2029. Scan_Init(pUserMem);
  2030. SetEvent( pUserMem->hEvent );
  2031. while (TRUE) {
  2032. WaitObj = MsgWaitForMultipleObjectsEx( 1, &pUserMem->hEventQuit, INFINITE, QS_ALLINPUT, 0 );
  2033. if (WaitObj == WAIT_OBJECT_0) {
  2034. return 0;
  2035. }
  2036. // PeekMessage instead of GetMessage so we drain the message queue
  2037. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE )) {
  2038. if (msg.message == WM_QUIT) {
  2039. return 0;
  2040. }
  2041. if (pUserMem->TwainAvail) {
  2042. TwEvent.pEvent = (TW_MEMREF) &msg;
  2043. TwEvent.TWMessage = MSG_NULL;
  2044. TwResult = CallTwainDataSource(
  2045. pUserMem,
  2046. DG_CONTROL,
  2047. DAT_EVENT,
  2048. MSG_PROCESSEVENT,
  2049. (TW_MEMREF) &TwEvent
  2050. );
  2051. //if (TwResult != TWRC_SUCCESS && TwResult != TWRC_NOTDSEVENT) {
  2052. // Verbose(( "MSG_PROCESSEVENT (DAT_EVENT) failed, ec=%d\n", TwResult ));
  2053. //}
  2054. switch (TwEvent.TWMessage) {
  2055. case MSG_XFERREADY:
  2056. //
  2057. // transition from state 5 to state 6
  2058. //
  2059. Verbose(( "received MSG_XFERREADY, setting hEventXfer\n" ));
  2060. SetEvent( pUserMem->hEventXfer );
  2061. break;
  2062. case MSG_CLOSEDSREQ:
  2063. //
  2064. // transition from state 5 to 4 to 3
  2065. //
  2066. pUserMem->TwainCancelled = TRUE;
  2067. Verbose(( "received MSG_CLOSEDSREQ, setting hEventXfer\n" ));
  2068. SetEvent( pUserMem->hEventXfer );
  2069. break;
  2070. case MSG_NULL:
  2071. break;
  2072. }
  2073. if (TwResult == TWRC_NOTDSEVENT) {
  2074. TranslateMessage( &msg );
  2075. DispatchMessage( &msg );
  2076. }
  2077. }
  2078. }
  2079. }
  2080. return 0;
  2081. }
  2082. VOID
  2083. TerminateTwain(
  2084. PUSERMEM pUserMem
  2085. )
  2086. {
  2087. DWORD TwResult;
  2088. Verbose(( "entering TerminateTwain, state = %d\n", pUserMem->State ));
  2089. //Scan_CloseDS( pUserMem, &pUserMem->DataSource );
  2090. CloseDataSource( pUserMem, &pUserMem->DataSource );
  2091. if (pUserMem->State == 3) {
  2092. TwResult = Scan_CloseDSM( pUserMem );
  2093. if (TwResult == TWRC_SUCCESS) {
  2094. pUserMem->State = 2;
  2095. Verbose(( "entering state 2\n" ));
  2096. }
  2097. }
  2098. if (pUserMem->hWndTwain) {
  2099. DestroyWindow( pUserMem->hWndTwain );
  2100. }
  2101. SetEvent( pUserMem->hEventQuit );
  2102. WaitForSingleObject( pUserMem->hThread, INFINITE );
  2103. if (pUserMem->hTwain) {
  2104. FreeLibrary( pUserMem->hTwain );
  2105. }
  2106. CloseHandle( pUserMem->hThread );
  2107. }
  2108. #if 0
  2109. BOOL
  2110. SetCapability(
  2111. PUSERMEM pUserMem,
  2112. USHORT Capability,
  2113. USHORT Type,
  2114. LPVOID Value
  2115. )
  2116. {
  2117. DWORD TwResult;
  2118. TW_CAPABILITY TwCapability;
  2119. TW_ONEVALUE *TwOneValue;
  2120. TW_FIX32 *TwFix32;
  2121. TwCapability.Cap = Capability;
  2122. TwCapability.ConType = TWON_ONEVALUE;
  2123. TwCapability.hContainer = GlobalAlloc( GHND, sizeof(TW_ONEVALUE) );
  2124. TwOneValue = (TW_ONEVALUE*) GlobalLock( TwCapability.hContainer );
  2125. TwOneValue->ItemType = Type;
  2126. if (Type == TWTY_FIX32) {
  2127. TwFix32 = (TW_FIX32*)Value;
  2128. CopyMemory( &TwOneValue->Item, TwFix32, sizeof(TW_FIX32) );
  2129. } else {
  2130. TwOneValue->Item = (DWORD)Value;
  2131. }
  2132. GlobalUnlock( TwCapability.hContainer );
  2133. //
  2134. // bugbug called in opendatasource
  2135. //
  2136. TwResult = CallTwainDataSource(
  2137. pUserMem,
  2138. DG_CONTROL,
  2139. DAT_CAPABILITY,
  2140. MSG_SET,
  2141. (TW_MEMREF) &TwCapability
  2142. );
  2143. GlobalFree( TwCapability.hContainer );
  2144. if (TwResult != TWRC_SUCCESS) {
  2145. Verbose(( "Could not set capability 0x%04x\n", Capability ));
  2146. return FALSE;
  2147. }
  2148. return TRUE;
  2149. }
  2150. #else
  2151. BOOL
  2152. SetCapability(
  2153. PUSERMEM pUserMem,
  2154. USHORT Capability,
  2155. USHORT Type,
  2156. LPVOID Value
  2157. )
  2158. {
  2159. DWORD TwResult;
  2160. TW_CAPABILITY TwCapability;
  2161. TW_ONEVALUE *TwOneValue;
  2162. TW_FIX32 *TwFix32;
  2163. TwCapability.Cap = Capability;
  2164. TwCapability.ConType = TWON_ONEVALUE;
  2165. TwCapability.hContainer = GlobalAlloc( GHND, sizeof(TW_ONEVALUE) );
  2166. TwOneValue = (TW_ONEVALUE*) GlobalLock( TwCapability.hContainer );
  2167. TwOneValue->ItemType = Type;
  2168. if (Type == TWTY_FIX32) {
  2169. TwFix32 = (TW_FIX32*)Value;
  2170. CopyMemory( &TwOneValue->Item, TwFix32, sizeof(TW_FIX32) );
  2171. } else {
  2172. TwOneValue->Item = PtrToUlong(Value);
  2173. }
  2174. GlobalUnlock( TwCapability.hContainer );
  2175. //
  2176. // bugbug called in opendatasource
  2177. //
  2178. TwResult = Scan_ControlSet(pUserMem, DAT_CAPABILITY, &TwCapability);
  2179. GlobalFree( TwCapability.hContainer );
  2180. if (TwResult != TWRC_SUCCESS) {
  2181. Verbose(( "Could not set capability 0x%04x\n", Capability ));
  2182. return FALSE;
  2183. }
  2184. return TRUE;
  2185. }
  2186. #endif
  2187. float
  2188. FIX32ToFloat(
  2189. TW_FIX32 fix32
  2190. )
  2191. {
  2192. float floater;
  2193. floater = (float) fix32.Whole + (float) fix32.Frac / (float) 65536.0;
  2194. return floater;
  2195. }
  2196. BOOL
  2197. OpenDataSource(
  2198. PUSERMEM pUserMem,
  2199. TW_IDENTITY * TwIdentity
  2200. )
  2201. {
  2202. DWORD TwResult;
  2203. Verbose(( "entering OpenDataSource, state = %d\n", pUserMem->State ));
  2204. if (pUserMem->State == 3) {
  2205. //
  2206. // open the data source
  2207. //
  2208. TwResult = CallTwain(
  2209. pUserMem,
  2210. DG_CONTROL,
  2211. DAT_IDENTITY,
  2212. MSG_OPENDS,
  2213. (TW_MEMREF) TwIdentity
  2214. );
  2215. if (TwResult != TWRC_SUCCESS) {
  2216. return FALSE;
  2217. }
  2218. pUserMem->State = 4;
  2219. Verbose(( "entering state 4\n" ));
  2220. }
  2221. return TRUE;
  2222. }
  2223. BOOL
  2224. Scan_SetCapabilities(
  2225. PUSERMEM pUserMem
  2226. )
  2227. {
  2228. //
  2229. // set the capabilities
  2230. //
  2231. SetCapability( pUserMem, CAP_XFERCOUNT, TWTY_INT16, (LPVOID)1 );
  2232. SetCapability( pUserMem, ICAP_PIXELTYPE, TWTY_INT16, (LPVOID)TWPT_BW );
  2233. SetCapability( pUserMem, ICAP_BITDEPTH, TWTY_INT16, (LPVOID)1 );
  2234. SetCapability( pUserMem, ICAP_BITORDER, TWTY_INT16, (LPVOID)TWBO_MSBFIRST );
  2235. SetCapability( pUserMem, ICAP_PIXELFLAVOR, TWTY_INT16, (LPVOID)TWPF_VANILLA );
  2236. SetCapability( pUserMem, ICAP_XFERMECH, TWTY_INT16, (LPVOID)TWSX_MEMORY );
  2237. return TRUE;
  2238. }
  2239. BOOL
  2240. EnableDataSource(
  2241. PUSERMEM pUserMem,
  2242. TW_USERINTERFACE *TwUserInterface
  2243. )
  2244. {
  2245. DWORD TwResult;
  2246. if (pUserMem->State == 4) {
  2247. ResetEvent( pUserMem->hEventXfer );
  2248. //
  2249. // enable the data source's user interface
  2250. //
  2251. pUserMem->TwainCancelled = FALSE;
  2252. TwResult = CallTwainDataSource(
  2253. pUserMem,
  2254. DG_CONTROL,
  2255. DAT_USERINTERFACE,
  2256. MSG_ENABLEDS,
  2257. (TW_MEMREF) TwUserInterface
  2258. );
  2259. if (TwResult != TWRC_SUCCESS) {
  2260. Verbose(( "MSG_ENABLEDS (DAT_USERINTERFACE) failed, ec=%d\n",TwResult ));
  2261. return FALSE;
  2262. }
  2263. pUserMem->State = 5;
  2264. Verbose(( "entering state 5\n" ));
  2265. }
  2266. return TRUE;
  2267. }
  2268. BOOL
  2269. DisableDataSource(
  2270. PUSERMEM pUserMem,
  2271. TW_USERINTERFACE * TwUserInterface
  2272. )
  2273. {
  2274. DWORD TwResult;
  2275. Verbose(( "entering DisableDataSource, state = %d\n",pUserMem->State ));
  2276. if (pUserMem->State == 5) {
  2277. //
  2278. // disable the data source
  2279. //
  2280. TwResult = CallTwainDataSource(
  2281. pUserMem,
  2282. DG_CONTROL,
  2283. DAT_USERINTERFACE,
  2284. MSG_DISABLEDS,
  2285. (TW_MEMREF) TwUserInterface
  2286. );
  2287. if (TwResult != TWRC_SUCCESS) {
  2288. Verbose(( "MSG_DISABLEDS (DAT_USERINTERFACE) failed, ec = %d\n", TwResult ));
  2289. return FALSE;
  2290. }
  2291. pUserMem->State = 4;
  2292. Verbose(( "entering state 4\n" ));
  2293. }
  2294. return TRUE;
  2295. }
  2296. BOOL
  2297. CloseDataSource(
  2298. PUSERMEM pUserMem,
  2299. TW_IDENTITY * TwIdentity
  2300. )
  2301. {
  2302. DWORD TwResult;
  2303. Verbose(( "entering CloseDataSource, state = %d\n",pUserMem->State ));
  2304. if (pUserMem->State == 4) {
  2305. //
  2306. // close the data source
  2307. //
  2308. TwResult = CallTwain(
  2309. pUserMem,
  2310. DG_CONTROL,
  2311. DAT_IDENTITY,
  2312. MSG_CLOSEDS,
  2313. (TW_MEMREF) TwIdentity
  2314. );
  2315. if (TwResult != TWRC_SUCCESS) {
  2316. Verbose(( "MSG_CLOSEDS (DAT_IDENTIFY) failed, ec = %d\n", TwResult ));
  2317. return FALSE;
  2318. }
  2319. pUserMem->State = 3;
  2320. Verbose(( "entering state 3\n" ));
  2321. }
  2322. Verbose(( "leaving CloseDataSource, state = %d\n",pUserMem->State ));
  2323. return TRUE;
  2324. }
  2325. BOOL
  2326. InitializeTwain(
  2327. PUSERMEM pUserMem
  2328. )
  2329. {
  2330. BOOL Rval = FALSE;
  2331. DWORD TwResult;
  2332. DWORD ThreadId;
  2333. HKEY hKey;
  2334. hKey = OpenRegistryKey( HKEY_LOCAL_MACHINE, REGKEY_SOFTWARE, FALSE, REG_READONLY );
  2335. if (hKey) {
  2336. if (GetRegistryDword( hKey, REGVAL_SCANNER_SUPPORT ) != 0) {
  2337. RegCloseKey( hKey );
  2338. return FALSE;
  2339. }
  2340. RegCloseKey( hKey );
  2341. }
  2342. pUserMem->State = 1;
  2343. Verbose(( "entering state 1\n" ));
  2344. pUserMem->hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
  2345. pUserMem->hEventQuit = CreateEvent( NULL, TRUE, FALSE, NULL );
  2346. pUserMem->hEventXfer = CreateEvent( NULL, TRUE, FALSE, NULL );
  2347. pUserMem->hThread = CreateThread(
  2348. NULL,
  2349. 0,
  2350. (LPTHREAD_START_ROUTINE)TwainMessagePumpThread,
  2351. pUserMem,
  2352. 0,
  2353. &ThreadId
  2354. );
  2355. if (!pUserMem->hThread) {
  2356. goto exit;
  2357. }
  2358. WaitForSingleObject( pUserMem->hEvent, INFINITE );
  2359. if (pUserMem->hWndTwain == NULL) {
  2360. goto exit;
  2361. }
  2362. pUserMem->hTwain = LoadLibrary( L"twain_32.dll" );
  2363. if (pUserMem->hTwain) {
  2364. pUserMem->pDsmEntry = (DSMENTRYPROC) GetProcAddress( pUserMem->hTwain, "DSM_Entry" );
  2365. }
  2366. if (pUserMem->pDsmEntry == NULL) {
  2367. goto exit;
  2368. }
  2369. pUserMem->State = 2;
  2370. Verbose(( "entering state 2\n" ));
  2371. //
  2372. // open the data source manager
  2373. //
  2374. pUserMem->AppId.Id = 0;
  2375. pUserMem->AppId.Version.MajorNum = 1;
  2376. pUserMem->AppId.Version.MinorNum = 0;
  2377. pUserMem->AppId.Version.Language = TWLG_USA;
  2378. pUserMem->AppId.Version.Country = TWCY_USA;
  2379. strcpy( pUserMem->AppId.Version.Info, "Fax Print Wizard" );
  2380. pUserMem->AppId.ProtocolMajor = TWON_PROTOCOLMAJOR;
  2381. pUserMem->AppId.ProtocolMinor = TWON_PROTOCOLMINOR;
  2382. pUserMem->AppId.SupportedGroups = DG_IMAGE | DG_CONTROL;
  2383. strcpy( pUserMem->AppId.Manufacturer, "Microsoft" );
  2384. strcpy( pUserMem->AppId.ProductFamily, "Windows" );
  2385. strcpy( pUserMem->AppId.ProductName, "Windows" );
  2386. TwResult = Scan_OpenDSM( pUserMem );
  2387. if (TwResult != TWRC_SUCCESS) {
  2388. Verbose(( "MSG_OPENDSM (DAT_PARENT) failed, ec = %d\n", TwResult ));
  2389. goto exit;
  2390. }
  2391. pUserMem->State = 3;
  2392. Verbose(( "entering state 3\n" ));
  2393. //
  2394. // select the default data source
  2395. //
  2396. TwResult = Scan_GetDefault(pUserMem, &pUserMem->DataSource);
  2397. if (TwResult != TWRC_SUCCESS) {
  2398. Verbose(( "MSG_GETDEFAULT (DAT_IDENTITY) failed, ec = %d\n", TwResult ));
  2399. goto exit;
  2400. }
  2401. //
  2402. // return success
  2403. //
  2404. Rval = TRUE;
  2405. pUserMem->TwainAvail = TRUE;
  2406. exit:
  2407. if (!Rval) {
  2408. //
  2409. // part of the initialization failed
  2410. // so lets clean everything up before exiting
  2411. //
  2412. TerminateTwain( pUserMem );
  2413. }
  2414. return Rval;
  2415. }
  2416. DWORD
  2417. ScanningThread(
  2418. PUSERMEM pUserMem
  2419. )
  2420. {
  2421. DWORD TwResult;
  2422. TW_SETUPMEMXFER TwSetupMemXfer;
  2423. TW_IMAGEMEMXFER TwImageMemXfer;
  2424. TW_PENDINGXFERS TwPendingXfers;
  2425. TW_USERINTERFACE TwUserInterface;
  2426. TW_IMAGEINFO TwImageInfo;
  2427. HANDLE hFile = INVALID_HANDLE_VALUE;
  2428. TIFF_HEADER TiffHdr;
  2429. DWORD FileBytes = 0;
  2430. DWORD BytesWritten;
  2431. LPBYTE Buffer1 = NULL;
  2432. LPBYTE CurrBuffer;
  2433. LPBYTE p = NULL;
  2434. DWORD LineSize;
  2435. DWORD i;
  2436. DWORD Lines;
  2437. LPBYTE ScanBuffer = NULL;
  2438. DWORD IfdOffset;
  2439. DWORD NextIfdSeekPoint;
  2440. WORD NumDirEntries;
  2441. DWORD DataOffset;
  2442. BOOL FirstTime = TRUE;
  2443. Verbose(( "Entering ScanningThread, state = %d\n", pUserMem->State ));
  2444. pUserMem->TwainActive = TRUE;
  2445. if (pUserMem->State == 5) {
  2446. while (pUserMem->State == 5) {
  2447. //
  2448. // wait for the MSG_XFERREADY message to be
  2449. // delivered to the message pump. this moves
  2450. // us to state 6
  2451. //
  2452. WaitForSingleObject( pUserMem->hEventXfer, INFINITE );
  2453. ResetEvent( pUserMem->hEventXfer );
  2454. Verbose(( "hEventXfer signalled\n" ));
  2455. if (pUserMem->TwainCancelled) {
  2456. Verbose(( "twain cancelled\n" ));
  2457. TwUserInterface.ShowUI = FALSE;
  2458. TwUserInterface.ModalUI = FALSE;
  2459. TwUserInterface.hParent = NULL;
  2460. Scan_DisableDS(pUserMem, &TwUserInterface);
  2461. goto exit;
  2462. }
  2463. //
  2464. // get the image info
  2465. //
  2466. TwResult = Scan_ImageGet(pUserMem,DAT_IMAGEINFO,&TwImageInfo);
  2467. if (TwResult != TWRC_SUCCESS) {
  2468. Verbose(( "MSG_GET (DAT_IMAGEINFO) failed, ec=%d\n", TwResult ));
  2469. goto exit;
  2470. }
  2471. //
  2472. // we only allow monochrome images
  2473. //
  2474. if (TwImageInfo.BitsPerPixel > 1) {
  2475. DisplayMessageDialog( NULL,
  2476. MB_ICONASTERISK | MB_OK | MB_SETFOREGROUND,
  2477. IDS_SCAN_ERROR_TITLE,
  2478. IDS_SCAN_ERROR_BW );
  2479. //
  2480. // go back to state 5
  2481. //
  2482. TwResult = Scan_ControlReset(pUserMem,DAT_PENDINGXFERS,&TwPendingXfers);
  2483. if (TwResult != TWRC_SUCCESS) {
  2484. Verbose(( "MSG_RESET (DAT_PENDINGXFERS) failed, ec=%d\n", TwResult ));
  2485. goto exit;
  2486. }
  2487. } else {
  2488. pUserMem->State = 6;
  2489. Verbose(( "entering state 6\n" ));
  2490. }
  2491. }
  2492. //
  2493. // setup the memory buffer sizes
  2494. //
  2495. TwResult = Scan_ControlGet(pUserMem,DAT_SETUPMEMXFER, &TwSetupMemXfer);
  2496. if (TwResult != TWRC_SUCCESS) {
  2497. Verbose(( "MSG_GET (DAT_SETUPMEMXFER) failed, ec=%d\n", TwResult ));
  2498. goto exit;
  2499. }
  2500. Buffer1 = (LPBYTE) MemAlloc( TwSetupMemXfer.Preferred );
  2501. TwImageMemXfer.Compression = TWON_DONTCARE16;
  2502. TwImageMemXfer.BytesPerRow = TWON_DONTCARE32;
  2503. TwImageMemXfer.Columns = TWON_DONTCARE32;
  2504. TwImageMemXfer.Rows = TWON_DONTCARE32;
  2505. TwImageMemXfer.XOffset = TWON_DONTCARE32;
  2506. TwImageMemXfer.YOffset = TWON_DONTCARE32;
  2507. TwImageMemXfer.BytesWritten = TWON_DONTCARE32;
  2508. TwImageMemXfer.Memory.Flags = TWMF_APPOWNS | TWMF_POINTER;
  2509. TwImageMemXfer.Memory.Length = TwSetupMemXfer.Preferred;
  2510. TwImageMemXfer.Memory.TheMem = Buffer1;
  2511. }
  2512. Verbose(( "begin transferring image... " ));
  2513. Verbose(( "entering state 7, TwResult = %d\n", TwResult ));
  2514. while (TwResult != TWRC_XFERDONE) {
  2515. try_again:
  2516. pUserMem->State = 7;
  2517. TwResult = Scan_ImageGet(pUserMem,DAT_IMAGEMEMXFER,&TwImageMemXfer);
  2518. if (TwResult == 0) {
  2519. if (ScanBuffer == NULL) {
  2520. ScanBuffer = VirtualAlloc(
  2521. NULL,
  2522. TwImageMemXfer.BytesPerRow * (TwImageInfo.ImageLength + 16),
  2523. MEM_COMMIT,
  2524. PAGE_READWRITE
  2525. );
  2526. if (ScanBuffer == NULL) {
  2527. goto exit;
  2528. }
  2529. p = ScanBuffer;
  2530. }
  2531. CopyMemory( p, Buffer1, TwImageMemXfer.BytesWritten );
  2532. p += TwImageMemXfer.BytesWritten;
  2533. FileBytes += TwImageMemXfer.BytesWritten;
  2534. } else if ( TwResult != TWRC_XFERDONE) {
  2535. Verbose(( "MGS_GET (DAT_IMAGEMEMXFER) failed, ec = %d ", TwResult ));
  2536. goto exit;
  2537. }
  2538. }
  2539. Assert( TwResult == TWRC_XFERDONE );
  2540. if (!ScanBuffer || !FileBytes) {
  2541. //
  2542. // we didn't really scan anything...
  2543. //
  2544. Verbose(( "asked for tranfer, but nothing was transferred\n" ));
  2545. if (FirstTime) {
  2546. FirstTime = FALSE;
  2547. goto try_again;
  2548. }
  2549. TwResult = Scan_ControlEndXfer(pUserMem,DAT_PENDINGXFERS, &TwPendingXfers);
  2550. pUserMem->State = 5;
  2551. //
  2552. // disable the data source's user interface
  2553. //
  2554. TwUserInterface.ShowUI = FALSE;
  2555. TwUserInterface.ModalUI = FALSE;
  2556. TwUserInterface.hParent = NULL;
  2557. Scan_DisableDS(pUserMem, &TwUserInterface);
  2558. pUserMem->State = 4;
  2559. Verbose(( "entering state 4\n" ));
  2560. goto exit;
  2561. }
  2562. pUserMem->PageCount += 1;
  2563. Verbose(( "...finished transferring image\n" ));
  2564. hFile = CreateFile(
  2565. pUserMem->FileName,
  2566. GENERIC_READ | GENERIC_WRITE,
  2567. 0,
  2568. NULL,
  2569. OPEN_EXISTING,
  2570. 0,
  2571. NULL
  2572. );
  2573. if (hFile == INVALID_HANDLE_VALUE) {
  2574. Verbose(( "CreateFile failed, ec=%d\n", GetLastError() ));
  2575. goto exit;
  2576. }
  2577. if (pUserMem->PageCount == 1) {
  2578. TiffHdr.Identifier = TIFF_LITTLEENDIAN;
  2579. TiffHdr.Version = TIFF_VERSION;
  2580. TiffHdr.IFDOffset = 0;
  2581. WriteFile( hFile, &TiffHdr, sizeof(TiffHdr), &BytesWritten, NULL );
  2582. } else {
  2583. ReadFile( hFile, &TiffHdr, sizeof(TiffHdr), &BytesWritten, NULL );
  2584. NextIfdSeekPoint = TiffHdr.IFDOffset;
  2585. while (NextIfdSeekPoint) {
  2586. SetFilePointer( hFile, NextIfdSeekPoint, NULL, FILE_BEGIN );
  2587. ReadFile( hFile, &NumDirEntries, sizeof(NumDirEntries), &BytesWritten, NULL );
  2588. SetFilePointer( hFile, NumDirEntries*sizeof(TIFF_TAG), NULL, FILE_CURRENT );
  2589. ReadFile( hFile, &NextIfdSeekPoint, sizeof(NextIfdSeekPoint), &BytesWritten, NULL );
  2590. }
  2591. }
  2592. NextIfdSeekPoint = SetFilePointer( hFile, 0, NULL, FILE_CURRENT ) - sizeof(NextIfdSeekPoint);
  2593. SetFilePointer( hFile, 0, NULL, FILE_END );
  2594. DataOffset = SetFilePointer( hFile, 0, NULL, FILE_CURRENT );
  2595. LineSize = TwImageInfo.ImageWidth / 8;
  2596. LineSize += (TwImageInfo.ImageWidth % 8) ? 1 : 0;
  2597. Lines = FileBytes / TwImageMemXfer.BytesPerRow;
  2598. CurrBuffer = ScanBuffer;
  2599. for (i=0; i<Lines; i++) {
  2600. WriteFile( hFile, CurrBuffer, LineSize, &BytesWritten, NULL );
  2601. CurrBuffer += TwImageMemXfer.BytesPerRow;
  2602. }
  2603. IfdOffset = SetFilePointer( hFile, 0, NULL, FILE_CURRENT );
  2604. FaxIFDTemplate.xresNum = (DWORD) FIX32ToFloat( TwImageInfo.XResolution );
  2605. FaxIFDTemplate.yresNum = (DWORD) FIX32ToFloat( TwImageInfo.YResolution );
  2606. FaxIFDTemplate.ifd[IFD_PAGENUMBER].DataOffset = MAKELONG( pUserMem->PageCount-1, 0);
  2607. FaxIFDTemplate.ifd[IFD_IMAGEWIDTH].DataOffset = TwImageInfo.ImageWidth;
  2608. FaxIFDTemplate.ifd[IFD_IMAGELENGTH].DataOffset = Lines;
  2609. FaxIFDTemplate.ifd[IFD_ROWSPERSTRIP].DataOffset = Lines;
  2610. FaxIFDTemplate.ifd[IFD_STRIPBYTECOUNTS].DataOffset = Lines * LineSize;
  2611. FaxIFDTemplate.ifd[IFD_STRIPOFFSETS].DataOffset = DataOffset;
  2612. FaxIFDTemplate.ifd[IFD_XRESOLUTION].DataOffset = IfdOffset + FIELD_OFFSET( FAXIFD, xresNum );
  2613. FaxIFDTemplate.ifd[IFD_YRESOLUTION].DataOffset = IfdOffset + FIELD_OFFSET( FAXIFD, yresNum );
  2614. FaxIFDTemplate.ifd[IFD_SOFTWARE].DataOffset = IfdOffset + FIELD_OFFSET( FAXIFD, software );
  2615. WriteFile( hFile, &FaxIFDTemplate, sizeof(FaxIFDTemplate), &BytesWritten, NULL );
  2616. SetFilePointer( hFile, NextIfdSeekPoint, NULL, FILE_BEGIN );
  2617. WriteFile( hFile, &IfdOffset, sizeof(DWORD), &BytesWritten, NULL );
  2618. //
  2619. // end the transfer
  2620. //
  2621. TwResult = Scan_ControlEndXfer(pUserMem,DAT_PENDINGXFERS, &TwPendingXfers);
  2622. if (TwResult != TWRC_SUCCESS) {
  2623. Verbose(( "MSG_ENDXFER (DAT_PENDINGXFERS) failed, ec=%d\n", TwResult ));
  2624. goto exit;
  2625. }
  2626. pUserMem->State = 5;
  2627. Verbose(( "entering state 5\n" ));
  2628. //
  2629. // disable the data source's user interface
  2630. //
  2631. TwUserInterface.ShowUI = FALSE;
  2632. TwUserInterface.ModalUI = FALSE;
  2633. TwUserInterface.hParent = NULL;
  2634. Scan_DisableDS(pUserMem, &TwUserInterface);
  2635. pUserMem->State = 4;
  2636. Verbose(( "entering state 4\n" ));
  2637. PostMessage( pUserMem->hDlgScan, WM_PAGE_COMPLETE, 0, 0 );
  2638. exit:
  2639. if (ScanBuffer) {
  2640. VirtualFree( ScanBuffer, 0, MEM_RELEASE);
  2641. }
  2642. if (hFile != INVALID_HANDLE_VALUE) {
  2643. CloseHandle( hFile );
  2644. }
  2645. MemFree( Buffer1 );
  2646. Verbose(( "leaving scanning thread, state = %d\n", pUserMem->State ));
  2647. pUserMem->TwainActive = FALSE;
  2648. return 0;
  2649. }
  2650. BOOL
  2651. EnumerateDataSources(
  2652. PUSERMEM pUserMem,
  2653. HWND ComboBox,
  2654. HWND StaticText
  2655. )
  2656. {
  2657. DWORD TwResult;
  2658. TW_IDENTITY TwIdentity;
  2659. TW_IDENTITY *pDataSource;
  2660. DWORD i;
  2661. DWORD Count = 0;
  2662. TwResult = Scan_GetFirst( pUserMem, &TwIdentity );
  2663. if (TwResult != TWRC_SUCCESS) {
  2664. return FALSE;
  2665. }
  2666. do {
  2667. i = (DWORD)SendMessageA( ComboBox, CB_ADDSTRING, 0, (LPARAM)TwIdentity.ProductName );
  2668. pDataSource = (TW_IDENTITY*) MemAlloc( sizeof(TW_IDENTITY) );
  2669. if (pDataSource) {
  2670. CopyMemory( pDataSource, &TwIdentity, sizeof(TW_IDENTITY) );
  2671. SendMessageA( ComboBox, CB_SETITEMDATA, i, (LPARAM)pDataSource );
  2672. }
  2673. Count += 1;
  2674. TwResult = Scan_GetNext( pUserMem, &TwIdentity );
  2675. } while (TwResult == 0);
  2676. i = (DWORD)SendMessageA( ComboBox, CB_FINDSTRINGEXACT, 0, (LPARAM)pUserMem->DataSource.ProductName );
  2677. if (i == CB_ERR) {
  2678. i = 0;
  2679. }
  2680. SendMessageA( ComboBox, CB_SETCURSEL, i, 0 );
  2681. if (Count == 1) {
  2682. EnableWindow( StaticText, FALSE );
  2683. EnableWindow( ComboBox, FALSE );
  2684. }
  2685. return TRUE;
  2686. }
  2687. INT_PTR
  2688. ScanWizProc(
  2689. HWND hDlg,
  2690. UINT message,
  2691. WPARAM wParam,
  2692. LPARAM lParam
  2693. )
  2694. /*++
  2695. Routine Description:
  2696. Dialog procedure for the first wizard page: entering subject and note information
  2697. Arguments:
  2698. hDlg - Identifies the wizard page
  2699. message - Specifies the message
  2700. wParam - Specifies additional message-specific information
  2701. lParam - Specifies additional message-specific information
  2702. Return Value:
  2703. Depends on the message parameter
  2704. --*/
  2705. {
  2706. PUSERMEM pUserMem;
  2707. HANDLE hThread;
  2708. DWORD ThreadId;
  2709. WCHAR TempPath[MAX_PATH];
  2710. //TW_PENDINGXFERS TwPendingXfers;
  2711. TW_USERINTERFACE TwUserInterface;
  2712. pUserMem = (PUSERMEM) GetWindowLongPtr(hDlg, DWLP_USER);
  2713. switch (message) {
  2714. case WM_INITDIALOG:
  2715. lParam = ((PROPSHEETPAGE *) lParam)->lParam;
  2716. pUserMem = (PUSERMEM) lParam;
  2717. SetWindowLongPtr(hDlg, DWLP_USER, lParam);
  2718. if (GetEnvironmentVariable(L"NTFaxSendNote", TempPath, sizeof(TempPath)) == 0 || TempPath[0] != L'1') {
  2719. pUserMem->TwainAvail = FALSE;
  2720. return TRUE;
  2721. }
  2722. if (pUserMem->TwainAvail) {
  2723. EnumerateDataSources( pUserMem, GetDlgItem( hDlg, IDC_DATA_SOURCE ), GetDlgItem( hDlg, IDC_STATIC_DATA_SOURCE) );
  2724. } else {
  2725. pUserMem->TwainAvail = FALSE;
  2726. return TRUE;
  2727. }
  2728. if (GetTempPath( sizeof(TempPath)/sizeof(WCHAR), TempPath )) {
  2729. if (GetTempFileName( TempPath, L"fax", 0, pUserMem->FileName )) {
  2730. SetEnvironmentVariable( L"ScanTifName", pUserMem->FileName );
  2731. }
  2732. }
  2733. pUserMem->hDlgScan = hDlg;
  2734. return TRUE;
  2735. case WM_NOTIFY:
  2736. switch ( ((NMHDR *) lParam)->code) {
  2737. case PSN_SETACTIVE:
  2738. PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK|PSWIZB_NEXT);
  2739. if (!pUserMem->TwainAvail) {
  2740. //
  2741. // jump to next page
  2742. //
  2743. SetWindowLongPtr( hDlg, DWLP_MSGRESULT, -1 );
  2744. return TRUE;
  2745. }
  2746. return FALSE;
  2747. break;
  2748. case PSN_WIZNEXT:
  2749. if (!pUserMem->PageCount) {
  2750. //
  2751. // we didn't actually scan any pages
  2752. //
  2753. DeleteFile( pUserMem->FileName ) ;
  2754. SetEnvironmentVariable( L"ScanTifName", NULL );
  2755. }
  2756. //Scan_CloseDS( pUserMem, &pUserMem->DataSource );
  2757. CloseDataSource( pUserMem, &pUserMem->DataSource );
  2758. Assert(pUserMem->State == 3);
  2759. pUserMem->State = 3;
  2760. SetWindowLongPtr( hDlg, DWLP_MSGRESULT, IDD_WIZARD_FAXOPTS );
  2761. return TRUE;
  2762. break;
  2763. case PSN_QUERYCANCEL:
  2764. //
  2765. // we didn't actually scan any pages
  2766. //
  2767. DeleteFile( pUserMem->FileName ) ;
  2768. if (pUserMem->TwainActive) {
  2769. TwUserInterface.ShowUI = FALSE;
  2770. TwUserInterface.ModalUI = FALSE;
  2771. TwUserInterface.hParent = NULL;
  2772. DisableDataSource( pUserMem, &TwUserInterface );
  2773. }
  2774. CloseDataSource( pUserMem, &pUserMem->DataSource );
  2775. break;
  2776. default:
  2777. break;
  2778. }
  2779. break;
  2780. case WM_PAGE_COMPLETE:
  2781. SetDlgItemInt( hDlg, IDC_PAGE_COUNT, pUserMem->PageCount, FALSE );
  2782. break;
  2783. case WM_COMMAND:
  2784. if (HIWORD(wParam) == CBN_SELCHANGE) {
  2785. TW_IDENTITY *pDataSource;
  2786. DWORD i;
  2787. i = (DWORD)SendDlgItemMessage( hDlg, IDC_DATA_SOURCE, CB_GETCURSEL, 0, 0 );
  2788. pDataSource = (TW_IDENTITY *) SendDlgItemMessage( hDlg, IDC_DATA_SOURCE, CB_GETITEMDATA, i, 0 );
  2789. CopyMemory( &pUserMem->DataSource, pDataSource, sizeof(TW_IDENTITY) );
  2790. }
  2791. if (HIWORD(wParam) == BN_CLICKED) {
  2792. //
  2793. // scan a page
  2794. //
  2795. TW_USERINTERFACE TwUserInterface;
  2796. TwUserInterface.ShowUI = TRUE;
  2797. TwUserInterface.ModalUI = TRUE;
  2798. TwUserInterface.hParent = GetParent(pUserMem->hDlgScan);
  2799. if ( !pUserMem->TwainActive
  2800. && Scan_OpenDS( pUserMem, &pUserMem->DataSource)
  2801. //&& Scan_SetCapabilities( pUserMem )
  2802. && Scan_EnableDS( pUserMem, &TwUserInterface )) {
  2803. EnableWindow( GetDlgItem( hDlg, IDC_DATA_SOURCE ), FALSE );
  2804. hThread = CreateThread(
  2805. NULL,
  2806. 0,
  2807. (LPTHREAD_START_ROUTINE)ScanningThread,
  2808. pUserMem,
  2809. 0,
  2810. &ThreadId
  2811. );
  2812. if (hThread) {
  2813. CloseHandle( hThread );
  2814. }
  2815. }
  2816. }
  2817. break;
  2818. case WM_DESTROY:
  2819. if (pUserMem->TwainAvail) {
  2820. TerminateTwain( pUserMem );
  2821. }
  2822. break;
  2823. /* case WM_ACTIVATE:
  2824. if (LOWORD(wParam) == WA_ACTIVE) {
  2825. if (!pUserMem->TwainActive) {
  2826. EnableWindow( hDlg, TRUE );
  2827. return TRUE;
  2828. }
  2829. } */
  2830. }
  2831. return FALSE;
  2832. }
  2833. #endif
  2834. LPTSTR
  2835. FormatTime(
  2836. WORD Hour,
  2837. WORD Minute,
  2838. LPTSTR Buffer,
  2839. DWORD BufferSize)
  2840. {
  2841. SYSTEMTIME SystemTime;
  2842. ZeroMemory(&SystemTime,sizeof(SystemTime));
  2843. SystemTime.wHour = Hour;
  2844. SystemTime.wMinute = Minute;
  2845. GetTimeFormat(LOCALE_USER_DEFAULT,
  2846. TIME_NOSECONDS,
  2847. &SystemTime,
  2848. NULL,
  2849. Buffer,
  2850. BufferSize
  2851. );
  2852. return Buffer;
  2853. }
  2854. INT_PTR
  2855. FinishWizProc(
  2856. HWND hDlg,
  2857. UINT message,
  2858. WPARAM wParam,
  2859. LPARAM lParam
  2860. )
  2861. /*++
  2862. Routine Description:
  2863. Dialog procedure for the last wizard page:
  2864. give user a chance to confirm or cancel the dialog.
  2865. Arguments:
  2866. hDlg - Identifies the wizard page
  2867. message - Specifies the message
  2868. wParam - Specifies additional message-specific information
  2869. lParam - Specifies additional message-specific information
  2870. Return Value:
  2871. Depends on the message parameter
  2872. --*/
  2873. {
  2874. PUSERMEM pUserMem;
  2875. TCHAR RecipientNameBuffer[64];
  2876. TCHAR RecipientNumberBuffer[64];
  2877. TCHAR TmpTimeBuffer[64];
  2878. TCHAR TimeBuffer[64];
  2879. TCHAR SendTimeBuffer[64];
  2880. TCHAR NoneBuffer[64];
  2881. LPTSTR SenderName;
  2882. TCHAR CoverpageBuffer[64];
  2883. LPTSTR Coverpage;
  2884. HKEY hKey;
  2885. if (! (pUserMem = CommonWizardProc(hDlg, message, wParam, lParam, PSWIZB_BACK|PSWIZB_FINISH)) )
  2886. return FALSE;
  2887. switch (message) {
  2888. case WM_NOTIFY:
  2889. if (((NMHDR *) lParam)->code != PSN_SETACTIVE) break;
  2890. case WM_INITDIALOG:
  2891. LoadString(ghInstance,IDS_NONE,NoneBuffer,sizeof(NoneBuffer)/sizeof(TCHAR) );
  2892. //
  2893. // large title font on last page
  2894. //
  2895. SetWindowFont(GetDlgItem(hDlg,IDC_STATIC_WIZ_CONGRATS_READY), pUserMem->hLargeFont, TRUE);
  2896. //
  2897. // set the sender name if it exists
  2898. //
  2899. if ( (hKey = GetUserInfoRegKey(REGKEY_FAX_USERINFO,TRUE) ) &&
  2900. (SenderName = GetRegistryString(hKey,REGVAL_FULLNAME,TEXT("")) )
  2901. ) {
  2902. SetDlgItemText(hDlg, IDC_WIZ_CONGRATS_FROM, SenderName );
  2903. EnableWindow(GetDlgItem(hDlg,IDC_STATIC_WIZ_CONGRATS_FROM),TRUE);
  2904. EnableWindow(GetDlgItem(hDlg,IDC_WIZ_CONGRATS_FROM),TRUE);
  2905. MemFree(SenderName);
  2906. } else {
  2907. SetDlgItemText(hDlg, IDC_WIZ_CONGRATS_FROM, NoneBuffer );
  2908. EnableWindow(GetDlgItem(hDlg,IDC_STATIC_WIZ_CONGRATS_FROM),FALSE);
  2909. EnableWindow(GetDlgItem(hDlg,IDC_WIZ_CONGRATS_FROM),FALSE);
  2910. }
  2911. //
  2912. // set the recipient name
  2913. //
  2914. if (pUserMem->pRecipients && pUserMem->pRecipients->pNext) {
  2915. //
  2916. // more than one user, just put "Multiple" in the text
  2917. //
  2918. LoadString(ghInstance,IDS_MULTIPLE_RECIPIENTS,RecipientNameBuffer,sizeof(RecipientNameBuffer)/sizeof(TCHAR) );
  2919. LoadString(ghInstance,IDS_MULTIPLE_RECIPIENTS,RecipientNumberBuffer,sizeof(RecipientNumberBuffer)/sizeof(TCHAR) );
  2920. SetDlgItemText(hDlg, IDC_WIZ_CONGRATS_TO, RecipientNameBuffer );
  2921. SetDlgItemText(hDlg, IDC_WIZ_CONGRATS_NUMBER, RecipientNumberBuffer );
  2922. EnableWindow(GetDlgItem(hDlg,IDC_STATIC_WIZ_CONGRATS_TO),FALSE);
  2923. EnableWindow(GetDlgItem(hDlg,IDC_WIZ_CONGRATS_TO),FALSE);
  2924. EnableWindow(GetDlgItem(hDlg,IDC_STATIC_WIZ_CONGRATS_NUMBER),FALSE);
  2925. EnableWindow(GetDlgItem(hDlg,IDC_WIZ_CONGRATS_NUMBER),FALSE);
  2926. } else {
  2927. SetDlgItemText(hDlg, IDC_WIZ_CONGRATS_TO, pUserMem->pRecipients->pName );
  2928. SetDlgItemText(hDlg, IDC_WIZ_CONGRATS_NUMBER, pUserMem->pRecipients->pAddress );
  2929. EnableWindow(GetDlgItem(hDlg,IDC_STATIC_WIZ_CONGRATS_TO),TRUE);
  2930. EnableWindow(GetDlgItem(hDlg,IDC_WIZ_CONGRATS_TO),TRUE);
  2931. EnableWindow(GetDlgItem(hDlg,IDC_STATIC_WIZ_CONGRATS_NUMBER),TRUE);
  2932. EnableWindow(GetDlgItem(hDlg,IDC_WIZ_CONGRATS_NUMBER),TRUE);
  2933. }
  2934. //
  2935. // when to send
  2936. //
  2937. switch (pUserMem->devmode.dmPrivate.whenToSend) {
  2938. case SENDFAX_AT_TIME:
  2939. LoadString(ghInstance,IDS_SEND_SPECIFIC,TmpTimeBuffer,sizeof(TmpTimeBuffer)/sizeof(TCHAR) );
  2940. wsprintf(SendTimeBuffer,
  2941. TmpTimeBuffer,
  2942. FormatTime(pUserMem->devmode.dmPrivate.sendAtTime.Hour,
  2943. pUserMem->devmode.dmPrivate.sendAtTime.Minute,
  2944. TimeBuffer,
  2945. sizeof(TimeBuffer)) );
  2946. break;
  2947. case SENDFAX_AT_CHEAP:
  2948. LoadString(ghInstance,IDS_SEND_DISCOUNT,SendTimeBuffer,sizeof(SendTimeBuffer)/sizeof(TCHAR) );
  2949. break;
  2950. case SENDFAX_ASAP:
  2951. LoadString(ghInstance,IDS_SEND_ASAP,SendTimeBuffer,sizeof(SendTimeBuffer)/sizeof(TCHAR) );
  2952. };
  2953. SetDlgItemText(hDlg, IDC_WIZ_CONGRATS_TIME, SendTimeBuffer );
  2954. //
  2955. // Coverpage
  2956. //
  2957. if (pUserMem->devmode.dmPrivate.sendCoverPage) {
  2958. EnableWindow(GetDlgItem(hDlg,IDC_STATIC_WIZ_CONGRATS_COVERPG),TRUE);
  2959. EnableWindow(GetDlgItem(hDlg,IDC_STATIC_WIZ_CONGRATS_SUBJECT),TRUE);
  2960. EnableWindow(GetDlgItem(hDlg,IDC_WIZ_CONGRATS_COVERPG),TRUE);
  2961. EnableWindow(GetDlgItem(hDlg,IDC_WIZ_CONGRATS_SUBJECT),TRUE);
  2962. //
  2963. // format the coverpage for display to the user
  2964. //
  2965. // drop path
  2966. Coverpage = _tcsrchr(pUserMem->coverPage,TEXT(PATH_SEPARATOR));
  2967. if (!Coverpage) {
  2968. Coverpage = pUserMem->coverPage;
  2969. } else {
  2970. Coverpage++;
  2971. }
  2972. _tcscpy(CoverpageBuffer,Coverpage);
  2973. // crop file extension
  2974. Coverpage = _tcschr(CoverpageBuffer,TEXT(FILENAME_EXT));
  2975. if (Coverpage && *Coverpage) {
  2976. *Coverpage = (TCHAR) NUL;
  2977. }
  2978. SetDlgItemText(hDlg, IDC_WIZ_CONGRATS_COVERPG, CoverpageBuffer );
  2979. if (pUserMem->pSubject) {
  2980. SetDlgItemText(hDlg, IDC_WIZ_CONGRATS_SUBJECT, pUserMem->pSubject );
  2981. } else {
  2982. EnableWindow(GetDlgItem(hDlg,IDC_WIZ_CONGRATS_SUBJECT),FALSE);
  2983. EnableWindow(GetDlgItem(hDlg,IDC_STATIC_WIZ_CONGRATS_SUBJECT),FALSE);
  2984. SetDlgItemText(hDlg, IDC_WIZ_CONGRATS_SUBJECT, NoneBuffer );
  2985. }
  2986. } else {
  2987. SetDlgItemText(hDlg, IDC_WIZ_CONGRATS_COVERPG, NoneBuffer );
  2988. SetDlgItemText(hDlg, IDC_WIZ_CONGRATS_SUBJECT, NoneBuffer );
  2989. EnableWindow(GetDlgItem(hDlg,IDC_STATIC_WIZ_CONGRATS_COVERPG),FALSE);
  2990. EnableWindow(GetDlgItem(hDlg,IDC_STATIC_WIZ_CONGRATS_SUBJECT),FALSE);
  2991. EnableWindow(GetDlgItem(hDlg,IDC_WIZ_CONGRATS_COVERPG),FALSE);
  2992. EnableWindow(GetDlgItem(hDlg,IDC_WIZ_CONGRATS_SUBJECT),FALSE);
  2993. }
  2994. //
  2995. // Billing Code
  2996. //
  2997. if (pUserMem->devmode.dmPrivate.billingCode[0]) {
  2998. EnableWindow(GetDlgItem(hDlg,IDC_STATIC_WIZ_CONGRATS_BILLING), TRUE);
  2999. EnableWindow(GetDlgItem(hDlg,IDC_WIZ_CONGRATS_BILLING),TRUE);
  3000. SetDlgItemText(hDlg, IDC_WIZ_CONGRATS_BILLING, pUserMem->devmode.dmPrivate.billingCode );
  3001. } else {
  3002. EnableWindow(GetDlgItem(hDlg,IDC_STATIC_WIZ_CONGRATS_BILLING), FALSE);
  3003. EnableWindow(GetDlgItem(hDlg,IDC_WIZ_CONGRATS_BILLING), FALSE);
  3004. SetDlgItemText(hDlg, IDC_WIZ_CONGRATS_BILLING, NoneBuffer );
  3005. }
  3006. return TRUE;
  3007. default:
  3008. return FALSE;
  3009. } ;
  3010. return TRUE;
  3011. }
  3012. INT_PTR
  3013. WelcomeWizProc(
  3014. HWND hDlg,
  3015. UINT message,
  3016. WPARAM wParam,
  3017. LPARAM lParam
  3018. )
  3019. /*++
  3020. Routine Description:
  3021. Dialog procedure for the last wizard page:
  3022. give user a chance to confirm or cancel the dialog.
  3023. Arguments:
  3024. hDlg - Identifies the wizard page
  3025. message - Specifies the message
  3026. wParam - Specifies additional message-specific information
  3027. lParam - Specifies additional message-specific information
  3028. Return Value:
  3029. Depends on the message parameter
  3030. --*/
  3031. {
  3032. PUSERMEM pUserMem;
  3033. if (! (pUserMem = CommonWizardProc(hDlg, message, wParam, lParam, PSWIZB_NEXT)))
  3034. return FALSE;
  3035. switch (message) {
  3036. case WM_INITDIALOG:
  3037. //
  3038. // set the large fonts
  3039. //
  3040. SetWindowFont(GetDlgItem(hDlg,IDC_WIZ_WELCOME_TITLE), pUserMem->hLargeFont, TRUE);
  3041. //
  3042. // show this text only if we're running the send wizard
  3043. //
  3044. if (!GetEnvironmentVariable(TEXT("NTFaxSendNote"), NULL, 0)) {
  3045. MyHideWindow(GetDlgItem(hDlg,IDC_WIZ_WELCOME_FAXSEND) );
  3046. MyHideWindow(GetDlgItem(hDlg,IDC_WIZ_WELCOME_FAXSEND_CONT) );
  3047. }
  3048. return TRUE;
  3049. } ;
  3050. return FALSE;
  3051. }
  3052. BOOL
  3053. GetFakeRecipientInfo(
  3054. PUSERMEM pUserMem,
  3055. DWORD nRecipients
  3056. )
  3057. /*++
  3058. Routine Description:
  3059. Skip send fax wizard and get faked recipient information from the registry
  3060. Arguments:
  3061. pUserMem - Points to the user mode memory structure
  3062. nRecipients - Total number of faked recipient entries
  3063. Return Value:
  3064. TRUE if successful, FALSE if there is an error
  3065. --*/
  3066. {
  3067. LPTSTR pRecipientEntry;
  3068. DWORD index;
  3069. TCHAR buffer[MAX_STRING_LEN];
  3070. BOOL success = FALSE;
  3071. HKEY hRegKey;
  3072. //
  3073. // Retrieve information about the next fake recipient entry
  3074. //
  3075. Verbose(("Send Fax Wizard skipped...\n"));
  3076. if (hRegKey = GetUserInfoRegKey(REGKEY_FAX_USERINFO, REG_READWRITE))
  3077. index = GetRegistryDword(hRegKey, REGVAL_STRESS_INDEX);
  3078. else
  3079. index = 0;
  3080. if (index >= nRecipients)
  3081. index = 0;
  3082. wsprintf(buffer, TEXT("FakeRecipient%d"), index);
  3083. pRecipientEntry = GetPrinterDataStr(pUserMem->hPrinter, buffer);
  3084. if (hRegKey) {
  3085. //
  3086. // Update an index so that next time around we'll pick a different fake recipient
  3087. //
  3088. if (++index >= nRecipients)
  3089. index = 0;
  3090. SetRegistryDword(hRegKey, REGVAL_STRESS_INDEX, index);
  3091. RegCloseKey(hRegKey);
  3092. }
  3093. //
  3094. // Each fake recipient entry is a REG_MULTI_SZ of the following format:
  3095. // recipient name #1
  3096. // recipient fax number #1
  3097. // recipient name #2
  3098. // recipient fax number #2
  3099. // ...
  3100. //
  3101. if (pRecipientEntry) {
  3102. __try {
  3103. PRECIPIENT pRecipient;
  3104. LPTSTR pName, pAddress, p = pRecipientEntry;
  3105. while (*p) {
  3106. pName = p;
  3107. pAddress = pName + _tcslen(pName) + 1;
  3108. p = pAddress + _tcslen(pAddress) + 1;
  3109. pRecipient = MemAllocZ(sizeof(RECIPIENT));
  3110. pName = DuplicateString(pName);
  3111. pAddress = DuplicateString(pAddress);
  3112. if (!pRecipient || !pName || !pAddress) {
  3113. Error(("Invalid fake recipient information\n"));
  3114. MemFree(pRecipient);
  3115. MemFree(pName);
  3116. MemFree(pAddress);
  3117. break;
  3118. }
  3119. pRecipient->pNext = pUserMem->pRecipients;
  3120. pUserMem->pRecipients = pRecipient;
  3121. pRecipient->pName = pName;
  3122. pRecipient->pAddress = pAddress;
  3123. }
  3124. } __finally {
  3125. if (success = (pUserMem->pRecipients != NULL)) {
  3126. //
  3127. // Determine whether a cover page should be used
  3128. //
  3129. LPTSTR pCoverPage;
  3130. pCoverPage = GetPrinterDataStr(pUserMem->hPrinter, TEXT("FakeCoverPage"));
  3131. if (pUserMem->devmode.dmPrivate.sendCoverPage = (pCoverPage != NULL))
  3132. CopyString(pUserMem->coverPage, pCoverPage, MAX_PATH);
  3133. MemFree(pCoverPage);
  3134. }
  3135. }
  3136. }
  3137. MemFree(pRecipientEntry);
  3138. return success;
  3139. }
  3140. BOOL
  3141. SendFaxWizard(
  3142. PUSERMEM pUserMem
  3143. )
  3144. /*++
  3145. Routine Description:
  3146. Present the Send Fax Wizard to the user. This is invoked
  3147. during CREATEDCPRE document event.
  3148. Arguments:
  3149. pUserMem - Points to the user mode memory structure
  3150. Return Value:
  3151. TRUE if successful, FALSE if there is an error or the user pressed Cancel.
  3152. --*/
  3153. #ifdef FAX_SCAN_ENABLED
  3154. #define NUM_PAGES 6 // Number of wizard pages
  3155. #else
  3156. #define NUM_PAGES 5 // Number of wizard pages
  3157. #endif
  3158. {
  3159. PROPSHEETPAGE *ppsp;
  3160. PROPSHEETHEADER psh;
  3161. INT result;
  3162. DWORD nRecipients;
  3163. HDC hdc;
  3164. int i;
  3165. LOGFONT LargeFont;
  3166. NONCLIENTMETRICS ncm = {0};
  3167. TCHAR FontName[100];
  3168. TCHAR FontSize[30];
  3169. int iFontSize;
  3170. DWORD ThreadId;
  3171. HANDLE hThread;
  3172. Assert(pUserMem->pRecipients == NULL);
  3173. //
  3174. // A shortcut to skip fax wizard for debugging/testing purposes
  3175. //
  3176. if (nRecipients = GetPrinterDataDWord(pUserMem->hPrinter, TEXT("FakeRecipientCount"), 0))
  3177. return GetFakeRecipientInfo(pUserMem, nRecipients);
  3178. Verbose(("Presenting Send Fax Wizard...\n"));
  3179. if (! (ppsp = MemAllocZ(sizeof(PROPSHEETPAGE) * NUM_PAGES))) {
  3180. Error(("Memory allocation failed\n"));
  3181. return FALSE;
  3182. }
  3183. //
  3184. // fire off a thread to do some slow stuff later on in the wizard.
  3185. //
  3186. pUserMem->hFaxSvcEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
  3187. pUserMem->hTapiEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
  3188. #ifdef FAX_SCAN_ENABLED
  3189. pUserMem->hTwainEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
  3190. if (!pUserMem->hFaxSvcEvent || !pUserMem->hTapiEvent || !pUserMem->hTwainEvent) {
  3191. Error(("CreateEvent for async events failed\n"));
  3192. return FALSE;
  3193. }
  3194. #else
  3195. if (!pUserMem->hFaxSvcEvent || !pUserMem->hTapiEvent) {
  3196. Error(("CreateEvent for async events failed\n"));
  3197. return FALSE;
  3198. }
  3199. #endif
  3200. hThread = CreateThread(NULL,0,AsyncWizardThread,pUserMem,0,&ThreadId);
  3201. if (hThread) {
  3202. CloseHandle(hThread);
  3203. } else {
  3204. return FALSE;
  3205. }
  3206. //
  3207. // Fill out one PROPSHEETPAGE structure for every page:
  3208. // The first page is a welcome page
  3209. // The first page is for choose the fax recipient
  3210. // The second page is for choosing cover page, subject and note
  3211. // The third page is for entering time to send and other options
  3212. // The fourth page is for scanning pages
  3213. // The last page gives the user a chance to confirm or cancel the dialog
  3214. //
  3215. FillInPropertyPage( ppsp, IDD_WIZARD_WELCOME, WelcomeWizProc, pUserMem ,0,0);
  3216. FillInPropertyPage( ppsp+1, IDD_WIZARD_CHOOSE_WHO, RecipientWizProc, pUserMem ,IDS_WIZ_RECIPIENT_TITLE,IDS_WIZ_RECIPIENT_SUB);
  3217. //
  3218. // set second page title correctly if we're running as faxsend or from file print
  3219. if (!GetEnvironmentVariable(TEXT("NTFaxSendNote"), NULL, 0)) {
  3220. FillInPropertyPage( ppsp+2, IDD_WIZARD_CHOOSE_CP, CoverPageWizProc, pUserMem ,IDS_WIZ_COVERPAGE_TITLE_2,IDS_WIZ_COVERPAGE_SUB_2 );
  3221. }
  3222. else {
  3223. FillInPropertyPage( ppsp+2, IDD_WIZARD_CHOOSE_CP, CoverPageWizProc, pUserMem ,IDS_WIZ_COVERPAGE_TITLE_1,IDS_WIZ_COVERPAGE_SUB_1 );
  3224. }
  3225. #ifdef FAX_SCAN_ENABLED
  3226. FillInPropertyPage( ppsp+3, IDD_WIZARD_SCAN, ScanWizProc, pUserMem ,IDS_WIZ_SCAN_TITLE,IDS_WIZ_SCAN_SUB);
  3227. FillInPropertyPage( ppsp+4, IDD_WIZARD_FAXOPTS, FaxOptsWizProc, pUserMem ,IDS_WIZ_FAXOPTS_TITLE,IDS_WIZ_FAXOPTS_SUB);
  3228. FillInPropertyPage( ppsp+5, IDD_WIZARD_CONGRATS, FinishWizProc, pUserMem ,0,0);
  3229. #else
  3230. FillInPropertyPage( ppsp+3, IDD_WIZARD_FAXOPTS, FaxOptsWizProc, pUserMem ,IDS_WIZ_FAXOPTS_TITLE,IDS_WIZ_FAXOPTS_SUB);
  3231. FillInPropertyPage( ppsp+4, IDD_WIZARD_CONGRATS, FinishWizProc, pUserMem ,0,0);
  3232. #endif
  3233. //
  3234. // Fill out the PROPSHEETHEADER structure
  3235. //
  3236. ZeroMemory(&psh, sizeof(psh));
  3237. psh.dwSize = sizeof(PROPSHEETHEADER);
  3238. psh.dwFlags = PSH_PROPSHEETPAGE | PSH_WIZARD | PSH_WIZARD97 | PSH_WATERMARK | PSH_HEADER;
  3239. psh.hwndParent = GetActiveWindow();
  3240. psh.hInstance = ghInstance;
  3241. psh.hIcon = NULL;
  3242. psh.pszCaption = TEXT("");
  3243. psh.nPages = NUM_PAGES;
  3244. psh.nStartPage = 0;
  3245. psh.ppsp = ppsp;
  3246. psh.pszbmHeader = MAKEINTRESOURCE(IDB_FAXWIZ_WATERMARK);
  3247. psh.pszbmWatermark = MAKEINTRESOURCE(IDB_WATERMARK_16);
  3248. if(hdc = GetDC(NULL)) {
  3249. if(GetDeviceCaps(hdc,BITSPIXEL) >= 8) {
  3250. psh.pszbmWatermark = MAKEINTRESOURCE(IDB_WATERMARK_256);
  3251. }
  3252. ReleaseDC(NULL,hdc);
  3253. }
  3254. //
  3255. // get the large fonts for wizard97
  3256. //
  3257. ncm.cbSize = sizeof(ncm);
  3258. SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0);
  3259. CopyMemory((LPVOID* )&LargeFont,(LPVOID *) &ncm.lfMessageFont,sizeof(LargeFont) );
  3260. LoadString(ghInstance,IDS_LARGEFONT_NAME,FontName,sizeof(FontName)/sizeof(TCHAR) );
  3261. LoadString(ghInstance,IDS_LARGEFONT_SIZE,FontSize,sizeof(FontSize)/sizeof(TCHAR) );
  3262. iFontSize = _tcstoul( FontSize, NULL, 10 );
  3263. // make sure we at least have some basic font
  3264. if (*FontName == 0 || iFontSize == 0) {
  3265. lstrcpy(FontName,TEXT("MS Shell Dlg") );
  3266. iFontSize = 18;
  3267. }
  3268. lstrcpy(LargeFont.lfFaceName, FontName);
  3269. LargeFont.lfWeight = FW_BOLD;
  3270. if (hdc = GetDC(NULL)) {
  3271. LargeFont.lfHeight = 0 - (GetDeviceCaps(hdc,LOGPIXELSY) * iFontSize / 72);
  3272. pUserMem->hLargeFont = CreateFontIndirect(&LargeFont);
  3273. ReleaseDC( NULL, hdc);
  3274. }
  3275. //
  3276. // Display the wizard pages
  3277. //
  3278. if (PropertySheet(&psh) > 0)
  3279. result = pUserMem->finishPressed;
  3280. else
  3281. result = FALSE;
  3282. //
  3283. // Cleanup properly before exiting
  3284. //
  3285. //
  3286. // free headings
  3287. //
  3288. for (i = 0; i< NUM_PAGES; i++) {
  3289. MemFree( (PVOID)(ppsp+i)->pszHeaderTitle );
  3290. MemFree( (PVOID)(ppsp+i)->pszHeaderSubTitle );
  3291. }
  3292. if (pUserMem->lpWabInit) {
  3293. UnInitializeWAB( pUserMem->lpWabInit);
  3294. }
  3295. DeinitTapiService();
  3296. MemFree(ppsp);
  3297. DeleteObject(pUserMem->hLargeFont);
  3298. FreeCoverPageInfo(pUserMem->pCPInfo);
  3299. pUserMem->pCPInfo = NULL;
  3300. #ifdef FAX_SCAN_ENABLED
  3301. //
  3302. // if the user pressed cancel, cleanup leftover scanned file.
  3303. //
  3304. if (!pUserMem->finishPressed && pUserMem->TwainAvail && pUserMem->FileName) {
  3305. DeleteFile( pUserMem->FileName ) ;
  3306. SetEnvironmentVariable( L"ScanTifName", NULL );
  3307. }
  3308. #endif
  3309. Verbose(("Wizard finished...\n"));
  3310. return result;
  3311. }