Leaked source code of windows server 2003
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.

3145 lines
97 KiB

  1. /*
  2. * wabprint.c
  3. *
  4. * Purpose:
  5. * Print Contacts
  6. *
  7. * Owner:
  8. * vikramm.
  9. *
  10. * History:
  11. *
  12. * Ported from Athena mailnews\mail\msgprint.cpp 10/30/96
  13. *
  14. * Copyright (C) Microsoft Corp. 1993, 1994.
  15. */
  16. #include <_apipch.h>
  17. // Function prototypes
  18. extern BOOL PrintDlg(LPPRINTDLG lppd);
  19. extern HRESULT PrintDlgEx(LPPRINTDLGEX lppdex);
  20. INT_PTR CALLBACK fnPrintDialogProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
  21. HRESULT HrCreatePrintCallbackObject(LPIAB lpIAB, LPWABPRINTDIALOGCALLBACK * lppWABPCO, DWORD dwSelectedStyle);
  22. void ReleaseWABPrintCallbackObject(LPWABPRINTDIALOGCALLBACK lpWABPCO);
  23. SCODE ScInitPrintInfo( PRINTINFO * ppi, HWND hwnd, LPTSTR szHeader, RECT * prcBorder, HWND hWndRE);
  24. int GetNumberFromStringResource(int idNumString);
  25. BOOL bCheckForPrintExtensions(LPTSTR lpDLLPath, DWORD cchSize);
  26. HRESULT HrUseWABPrintExtension(HWND hWnd, LPADRBOOK lpAdrBook, HWND hWndLV);
  27. //
  28. // Some string constants used in text formatting
  29. //
  30. const LPTSTR lpszTab = TEXT("\t");
  31. const LPTSTR lpszFlatLine = TEXT("________________________________________________________________");
  32. const LPTSTR lpszSpace = TEXT(" ");
  33. //
  34. // Print options ...
  35. //
  36. enum _PrintRange
  37. {
  38. rangeAll=0,
  39. rangeSelected
  40. };
  41. enum _PrintStyles
  42. {
  43. styleMemo=0,
  44. styleBusinessCard,
  45. stylePhoneList
  46. };
  47. static DWORD rgPrintHelpIDs[] =
  48. {
  49. IDC_PRINT_FRAME_STYLE, IDH_WAB_COMM_GROUPBOX,
  50. IDC_PRINT_RADIO_MEMO, IDH_WAB_PRINT_MEMO,
  51. IDC_PRINT_RADIO_CARD, IDH_WAB_PRINT_BIZCARD,
  52. IDC_PRINT_RADIO_PHONELIST, IDH_WAB_PRINT_PHONELIST,
  53. 0,0
  54. };
  55. //
  56. // This structure contains information about a specific contact
  57. //
  58. enum _MemoStrings
  59. {
  60. memoTitleName=0, // the big name that will be displayed based on the current sort settings ..
  61. memoName,
  62. memoJobTitle,
  63. memoDepartment,
  64. memoOffice,
  65. memoCompany,
  66. memoBusinessAddress, // Don't mess with the order of home and business address tags
  67. memoBusinessAddressStreet,
  68. memoBusinessAddressCity,
  69. memoBusinessAddressState,
  70. memoBusinessAddressZip,
  71. memoBusinessAddressCountry,
  72. memoHomeAddress,
  73. memoHomeAddressStreet,
  74. memoHomeAddressCity,
  75. memoHomeAddressState,
  76. memoHomeAddressZip,
  77. memoHomeAddressCountry,
  78. memoBusinessPhone, // Dont mess with the phone numbers - they should all be together in this order
  79. memoBusinessFax,
  80. memoBusinessPager,
  81. memoHomePhone,
  82. memoHomeFax,
  83. memoHomeCellular,
  84. memoEmail,
  85. memoBusinessWebPage,
  86. memoHomeWebPage,
  87. memoNotes,
  88. memoGroupMembers,
  89. memoMAX
  90. };
  91. typedef struct _MemoInfo
  92. {
  93. LPTSTR lpszLabel[memoMAX];
  94. LPTSTR lpsz[memoMAX];
  95. } MEMOINFO, * LPMEMOINFO;
  96. TCHAR szDontDisplayInitials[16];
  97. /*
  98. * c o n s t a n t s
  99. */
  100. #define cTwipsPerInch 1440
  101. #define cPtsPerInch 72
  102. #ifndef WIN16
  103. #define INT_MAX 2147483647
  104. #endif
  105. #define cySepFontSize(_ppi) (12 * (_ppi)->sizeInch.cy / cPtsPerInch)
  106. #define CCHMAX_STRINGRES MAX_UI_STR
  107. /*
  108. * m a c r o s
  109. */
  110. #define ScPrintRestOfPage(_ppi,_fAdvance) ScGetNextBand( (_ppi), (_fAdvance))
  111. /*
  112. * g l o b a l s
  113. */
  114. static TCHAR szDefFont[] = TEXT("Arial");
  115. static TCHAR szThaiDefFont[] = TEXT("Cordia New");
  116. static BOOL s_bUse20 = TRUE;
  117. // Default margin settings
  118. static RECT g_rcBorder =
  119. {
  120. cTwipsPerInch * 1 / 2, // distance from left
  121. cTwipsPerInch * 3 / 4, // distance from top
  122. cTwipsPerInch * 1 / 2, // distance from right
  123. cTwipsPerInch * 1 / 2 // distance from bottom
  124. };
  125. /*
  126. * p r o t o t y p e s
  127. */
  128. SCODE ScGetNextBand( PRINTINFO * ppi, BOOL fAdvance );
  129. LONG LGetHeaderIndent();
  130. //$$/////////////////////////////////////////////////////////////////////////////
  131. //
  132. // CleanPrintAddressString
  133. //
  134. // The Home and Business addresses are FormatMessaged and may contain redundant
  135. // spaces and line breaks if input data is incomplete
  136. // We strip out those spaces etc
  137. //
  138. /////////////////////////////////////////////////////////////////////////////////
  139. void CleanPrintAddressString(LPTSTR szAddress)
  140. {
  141. LPTSTR lpTemp = szAddress;
  142. LPTSTR lpTemp2 = NULL;
  143. // The original template for styleMemo is
  144. // TEXT("%1\r\n\t%2 %3 %4\r\n\t%5")
  145. //
  146. // Worst case, we will get
  147. // TEXT("\r\n\t \r\n\t")
  148. //
  149. // We want to reduce double spaces to single space
  150. // We want to strip out empty line breaks
  151. // We want to strip out redundant tabs
  152. //
  153. // For style styleBusinessCard, there are no tabs and we
  154. // strip out redundancies accordingly
  155. //
  156. TrimSpaces(szAddress);
  157. // Squish multiple space blocks to a single space
  158. while (*lpTemp) {
  159. if (IsSpace(lpTemp) && IsSpace(CharNext(lpTemp))) {
  160. DWORD cchSize = lstrlen(lpTemp); // Boy I hate using this kind of logic, but it works here.
  161. // There are >= 2 spaces starting at lpTemp
  162. lpTemp2 = CharNext(lpTemp); // point to 2nd space
  163. StrCpyN(lpTemp, lpTemp2, cchSize);
  164. continue; // Cycle again with same lpTemp
  165. }
  166. lpTemp = CharNext(lpTemp);
  167. }
  168. TrimSpaces(szAddress);
  169. lpTemp = szAddress;
  170. // Dont let it start with a line break
  171. while(*lpTemp == '\r' && *(lpTemp+1) == '\n')
  172. {
  173. DWORD cchSize = lstrlen(lpTemp); // Boy I hate using this kind of logic, but it works here.
  174. lpTemp2 = lpTemp+2;
  175. if(*lpTemp2 == '\t')
  176. lpTemp2 = CharNext(lpTemp2);
  177. StrCpyN(lpTemp, lpTemp2, cchSize);
  178. TrimSpaces(lpTemp);
  179. }
  180. // Dont let it end with a line break
  181. if(lstrlen(szAddress))
  182. {
  183. int nLen = lstrlen(szAddress);
  184. lpTemp = szAddress;
  185. while( (*(lpTemp + nLen - 3)=='\r' && *(lpTemp + nLen - 2)=='\n') ||
  186. (*(lpTemp + nLen - 2)=='\r' && *(lpTemp + nLen - 1)=='\n') )
  187. {
  188. if(*(lpTemp + nLen -3) == '\r')
  189. *(lpTemp + nLen - 3)='\0';
  190. else
  191. *(lpTemp + nLen - 2)='\0';
  192. TrimSpaces(szAddress);
  193. nLen = lstrlen(szAddress);
  194. lpTemp = szAddress;
  195. }
  196. }
  197. TrimSpaces(szAddress);
  198. return;
  199. }
  200. //$$////////////////////////////////////////////////////////////////////////
  201. //
  202. // AddTabsToLineBreaks - For the memo format, our paragraph format for the
  203. // data on the right side gives each paragraph a default indentation
  204. // of 1 tab space after the first line. However if the data contains
  205. // line breaks, the paragraph format gets messed up. So we take
  206. // a data string and insert a tab after each line break. There are
  207. // only a few data values such as Address and Notes that need this
  208. // multi-line treatment.
  209. //
  210. ////////////////////////////////////////////////////////////////////////////
  211. void AddTabsToLineBreaks(LPTSTR * lppsz)
  212. {
  213. ULONG nBreaks = 0, nLen = 0;
  214. LPTSTR lpTemp,lpStart;
  215. LPTSTR lpsz;
  216. DWORD cchSize;
  217. if(!lppsz || !(*lppsz))
  218. goto out;
  219. lpTemp = *lppsz;
  220. // count the number of breaks which are not followed by tabs
  221. while(*lpTemp)
  222. {
  223. if(*lpTemp == '\n' && *(lpTemp+1) != '\t')
  224. nBreaks++;
  225. lpTemp = CharNext(lpTemp);
  226. }
  227. if(!nBreaks)
  228. goto out;
  229. // Allocate a new string
  230. cchSize = (lstrlen(*lppsz)+1+nBreaks);
  231. lpsz = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cchSize);
  232. if(!lpsz)
  233. goto out;
  234. lpTemp = *lppsz;
  235. lpStart = lpTemp;
  236. StrCpyN(lpsz, szEmpty, cchSize);
  237. // Copy over the old string into the new with appropriate breaks
  238. while(*lpTemp)
  239. {
  240. if((*lpTemp == '\n') && (*(lpTemp+1)!='\t'))
  241. {
  242. *lpTemp = '\0';
  243. StrCatBuff(lpsz, lpStart, cchSize);
  244. StrCatBuff(lpsz, TEXT("\n"), cchSize);
  245. StrCatBuff(lpsz, lpszTab, cchSize);
  246. lpStart = lpTemp+1;
  247. lpTemp = lpStart;
  248. }
  249. else
  250. lpTemp = CharNext(lpTemp);
  251. }
  252. if(lstrlen(lpStart))
  253. StrCatBuff(lpsz, lpStart, cchSize);
  254. LocalFreeAndNull(lppsz);
  255. *lppsz = lpsz;
  256. out:
  257. return;
  258. }
  259. //$$////////////////////////////////////////////////////////////////////////
  260. //
  261. // FreeMemoInfoStruct - Frees the MemoInfo struct allocated strings
  262. //
  263. ////////////////////////////////////////////////////////////////////////////
  264. void FreeMemoInfoStruct(LPMEMOINFO lpMI)
  265. {
  266. int i;
  267. for(i=0;i<memoMAX;i++)
  268. {
  269. if(lpMI->lpsz[i] && (lpMI->lpsz[i] != szEmpty))
  270. #ifdef WIN16
  271. if(i == memoBusinessAddress || i == memoHomeAddress)
  272. FormatMessageFreeMem(lpMI->lpsz[i]);
  273. else
  274. #endif
  275. LocalFree(lpMI->lpsz[i]);
  276. if(lpMI->lpszLabel[i] && (lpMI->lpszLabel[i] != szEmpty))
  277. LocalFree(lpMI->lpszLabel[i]);
  278. }
  279. }
  280. //$$////////////////////////////////////////////////////////////////////////////////////////////////
  281. //
  282. // GetMemoInfoStruct - Parses the data in a PropArray and puts it into a Memo_Info struch along with
  283. // the propert labels, bsaed on the given style
  284. //
  285. //
  286. ////////////////////////////////////////////////////////////////////////////////////////////////////
  287. void GetMemoInfoStruct(LPADRBOOK lpAdrBook,
  288. ULONG ulcPropCount,
  289. LPSPropValue lpPropArray,
  290. DWORD dwStyle,
  291. LPMEMOINFO lpMI,
  292. BOOL bCurrentSortIsByLastName)
  293. {
  294. ULONG i,j;
  295. TCHAR szBuf[MAX_UI_STR];
  296. LPTSTR lpszFirst = NULL;
  297. LPTSTR lpszMiddle = NULL;
  298. LPTSTR lpszLast = NULL;
  299. LPTSTR lpszDisplayName = NULL;
  300. LPTSTR lpszCompany = NULL;
  301. LPTSTR lpszNickName = NULL;
  302. BOOL bIsGroup = FALSE;
  303. int len = 0;
  304. if(!lpPropArray || !ulcPropCount)
  305. goto out;
  306. // special case initialization
  307. for(j=memoHomeAddressStreet;j<=memoHomeAddressCountry;j++)
  308. {
  309. lpMI->lpsz[j]=szEmpty;
  310. }
  311. for(j=memoBusinessAddressStreet;j<=memoBusinessAddressCountry;j++)
  312. {
  313. lpMI->lpsz[j]=szEmpty;
  314. }
  315. // Find out if this is a mailuser or a group
  316. for(i=0;i<ulcPropCount;i++)
  317. {
  318. if(lpPropArray[i].ulPropTag == PR_OBJECT_TYPE)
  319. {
  320. bIsGroup = (lpPropArray[i].Value.l == MAPI_DISTLIST);
  321. break;
  322. }
  323. }
  324. for(i=0;i<ulcPropCount;i++)
  325. {
  326. LPTSTR lpszData = NULL;
  327. int nIndex = -1;
  328. int nStringID = 0;
  329. switch(lpPropArray[i].ulPropTag)
  330. {
  331. case PR_DISPLAY_NAME:
  332. nIndex = memoName;
  333. if(bIsGroup)
  334. nStringID = idsPrintGroupName;
  335. else
  336. nStringID = idsPrintDisplayName;
  337. lpszDisplayName = lpPropArray[i].Value.LPSZ;
  338. break;
  339. case PR_NICKNAME:
  340. lpszNickName = lpPropArray[i].Value.LPSZ;
  341. break;
  342. case PR_GIVEN_NAME:
  343. lpszFirst = lpPropArray[i].Value.LPSZ;
  344. break;
  345. case PR_SURNAME:
  346. lpszLast = lpPropArray[i].Value.LPSZ;
  347. break;
  348. case PR_MIDDLE_NAME:
  349. lpszMiddle = lpPropArray[i].Value.LPSZ;
  350. break;
  351. case PR_TITLE:
  352. nIndex = memoJobTitle;
  353. nStringID = idsPrintTitle;
  354. break;
  355. case PR_DEPARTMENT_NAME:
  356. nIndex = memoDepartment;
  357. nStringID = idsPrintDepartment;
  358. break;
  359. case PR_OFFICE_LOCATION:
  360. nIndex = memoOffice;
  361. nStringID = idsPrintOffice;
  362. break;
  363. case PR_COMPANY_NAME:
  364. lpszCompany = lpPropArray[i].Value.LPSZ;
  365. nIndex = memoCompany;
  366. nStringID = idsPrintCompany;
  367. break;
  368. case PR_BUSINESS_ADDRESS_STREET:
  369. nIndex = memoBusinessAddressStreet;
  370. break;
  371. case PR_BUSINESS_ADDRESS_CITY:
  372. nIndex = memoBusinessAddressCity;
  373. break;
  374. case PR_BUSINESS_ADDRESS_STATE_OR_PROVINCE:
  375. nIndex = memoBusinessAddressState;
  376. break;
  377. case PR_BUSINESS_ADDRESS_POSTAL_CODE:
  378. nIndex = memoBusinessAddressZip;
  379. break;
  380. case PR_BUSINESS_ADDRESS_COUNTRY:
  381. nIndex = memoBusinessAddressCountry;
  382. break;
  383. case PR_HOME_ADDRESS_STREET:
  384. nIndex = memoHomeAddressStreet;
  385. break;
  386. case PR_HOME_ADDRESS_CITY:
  387. nIndex = memoHomeAddressCity;
  388. break;
  389. case PR_HOME_ADDRESS_STATE_OR_PROVINCE:
  390. nIndex = memoHomeAddressState;
  391. break;
  392. case PR_HOME_ADDRESS_POSTAL_CODE:
  393. nIndex = memoHomeAddressZip;
  394. break;
  395. case PR_HOME_ADDRESS_COUNTRY:
  396. nIndex = memoHomeAddressCountry;
  397. break;
  398. case PR_BUSINESS_TELEPHONE_NUMBER:
  399. nIndex = memoBusinessPhone;
  400. nStringID = (dwStyle == styleMemo) ? idsPrintBusinessPhone : idsPrintBusCardBusinessPhone;
  401. break;
  402. case PR_BUSINESS_FAX_NUMBER:
  403. nIndex = memoBusinessFax;
  404. nStringID = (dwStyle == styleMemo) ? idsPrintBusinessFax : idsPrintBusCardBusinessFax;
  405. break;
  406. case PR_PAGER_TELEPHONE_NUMBER:
  407. nIndex = memoBusinessPager;
  408. nStringID = idsPrintBusinessPager;
  409. break;
  410. case PR_HOME_TELEPHONE_NUMBER:
  411. nIndex = memoHomePhone;
  412. nStringID = (dwStyle == styleMemo) ? idsPrintHomePhone : idsPrintBusCardHomePhone;
  413. break;
  414. case PR_HOME_FAX_NUMBER:
  415. nIndex = memoHomeFax;
  416. nStringID = idsPrintHomeFax;
  417. break;
  418. case PR_CELLULAR_TELEPHONE_NUMBER:
  419. nIndex = memoHomeCellular;
  420. nStringID = idsPrintHomeCellular;
  421. break;
  422. case PR_BUSINESS_HOME_PAGE:
  423. nIndex = memoBusinessWebPage;
  424. nStringID = idsPrintBusinessWebPage;
  425. break;
  426. case PR_PERSONAL_HOME_PAGE:
  427. nIndex = memoHomeWebPage;
  428. nStringID = idsPrintHomeWebPage;
  429. break;
  430. case PR_COMMENT:
  431. nIndex = memoNotes;
  432. nStringID = idsPrintNotes;
  433. break;
  434. default:
  435. continue;
  436. break;
  437. }
  438. if(nIndex != -1)
  439. {
  440. if(nStringID != 0)
  441. {
  442. LoadString(hinstMapiX, nStringID, szBuf, ARRAYSIZE(szBuf));
  443. lpMI->lpszLabel[nIndex] = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*(lstrlen(szBuf)+1));
  444. if(!lpMI->lpszLabel[nIndex])
  445. goto out;
  446. StrCpyN(lpMI->lpszLabel[nIndex], szBuf, lstrlen(szBuf)+1);
  447. }
  448. lpMI->lpsz[nIndex] = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*(lstrlen(lpPropArray[i].Value.LPSZ)+1));
  449. if(!lpMI->lpsz[nIndex])
  450. goto out;
  451. StrCpyN(lpMI->lpsz[nIndex], lpPropArray[i].Value.LPSZ, lstrlen(lpPropArray[i].Value.LPSZ)+1);
  452. }
  453. }
  454. // Email is a special case since a contact can hace PR_EMAIL_ADDRESS or
  455. // PR_CONTACT_EMAIL_ADDRESSES or both or neither
  456. // We first look for PR_CONTACT_EMAIL_ADDRESS .. if not found, then for
  457. // PR_EMAIL_ADDRESS
  458. {
  459. BOOL bMVEmail = FALSE;
  460. LPTSTR lpszEmails = NULL;
  461. for(i=0;i<ulcPropCount;i++)
  462. {
  463. if(lpPropArray[i].ulPropTag == PR_CONTACT_EMAIL_ADDRESSES)
  464. {
  465. ULONG k,ulBufSize=0;
  466. for (k=0;k<lpPropArray[i].Value.MVSZ.cValues;k++)
  467. {
  468. ulBufSize += sizeof(TCHAR)*(lstrlen(lpPropArray[i].Value.MVSZ.LPPSZ[k])+1);
  469. ulBufSize += sizeof(TCHAR)*(lstrlen(szCRLF)+1);
  470. ulBufSize += sizeof(TCHAR)*(lstrlen(lpszTab)+1);
  471. }
  472. ulBufSize -= sizeof(TCHAR)*(lstrlen(szCRLF)+1);
  473. ulBufSize -= sizeof(TCHAR)*(lstrlen(lpszTab)+1);
  474. lpszEmails = LocalAlloc(LMEM_ZEROINIT, ulBufSize);
  475. if(!lpszEmails)
  476. {
  477. DebugPrintError(( TEXT("Local Alloc Failed\n")));
  478. goto out;
  479. }
  480. StrCpyN(lpszEmails, szEmpty, ulBufSize/sizeof(TCHAR));
  481. for (k=0;k<lpPropArray[i].Value.MVSZ.cValues;k++)
  482. {
  483. if(k>0)
  484. {
  485. StrCatBuff(lpszEmails, szCRLF,ulBufSize/sizeof(TCHAR) );
  486. StrCatBuff(lpszEmails, lpszTab, ulBufSize/sizeof(TCHAR));
  487. }
  488. StrCatBuff(lpszEmails,lpPropArray[i].Value.MVSZ.LPPSZ[k], ulBufSize/sizeof(TCHAR));
  489. }
  490. bMVEmail = TRUE;
  491. break;
  492. }
  493. }
  494. if(!bMVEmail)
  495. {
  496. // No CONTACT_EMAIL_ADDRESSES
  497. // Should look for email address
  498. for(i=0;i<ulcPropCount;i++)
  499. {
  500. if(lpPropArray[i].ulPropTag == PR_EMAIL_ADDRESS)
  501. {
  502. ULONG cchSize = lstrlen(lpPropArray[i].Value.LPSZ)+1;
  503. lpszEmails = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cchSize);
  504. if(!lpszEmails)
  505. goto out;
  506. StrCpyN(lpszEmails, lpPropArray[i].Value.LPSZ, cchSize);
  507. break;
  508. }
  509. }
  510. }
  511. if(lpszEmails)
  512. {
  513. ULONG cchSize = lstrlen(szBuf)+1;
  514. lpMI->lpsz[memoEmail] = lpszEmails;
  515. LoadString(hinstMapiX, idsPrintEmail, szBuf, ARRAYSIZE(szBuf));
  516. lpMI->lpszLabel[memoEmail] = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cchSize);
  517. if(!lpMI->lpszLabel[memoEmail])
  518. goto out;
  519. StrCpyN(lpMI->lpszLabel[memoEmail], szBuf, cchSize);
  520. }
  521. }
  522. //Now we have to format the Home and Business Addresses
  523. //
  524. {
  525. LPTSTR lpszData[5];
  526. for(i=memoHomeAddressStreet;i<=memoHomeAddressCountry;i++)
  527. {
  528. // Win9x bug FormatMessage cannot have more than 1023 chars
  529. len += lstrlen(lpMI->lpsz[i]);
  530. if(len < 1023)
  531. lpszData[i-memoHomeAddressStreet] = lpMI->lpsz[i];
  532. else
  533. lpszData[i-memoHomeAddressStreet] = NULL;
  534. }
  535. for(i=memoHomeAddressStreet;i<=memoHomeAddressCountry;i++)
  536. {
  537. if(lpMI->lpsz[i] && lpMI->lpsz[i] != szEmpty)
  538. {
  539. LPTSTR lpszHomeAddress = NULL;
  540. TCHAR szBuf[MAX_UI_STR];
  541. int nStringID = (dwStyle == styleMemo) ? idsPrintAddressTemplate : idsPrintBusCardAddressTemplate ;
  542. LoadString(hinstMapiX, nStringID, szBuf, CharSizeOf(szBuf));
  543. if (FormatMessage(FORMAT_MESSAGE_FROM_STRING |
  544. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  545. FORMAT_MESSAGE_ARGUMENT_ARRAY,
  546. szBuf,
  547. 0, // stringid
  548. 0, // dwLanguageId
  549. (LPTSTR)&lpszHomeAddress, // output buffer
  550. 0, //MAX_UI_STR
  551. (va_list *)&lpszData[0]))
  552. {
  553. CleanPrintAddressString(lpszHomeAddress);
  554. lpMI->lpsz[memoHomeAddress] = lpszHomeAddress;
  555. szBuf[0]='\0';
  556. LoadString(hinstMapiX, idsPrintHomeAddress, szBuf, CharSizeOf(szBuf));
  557. lpMI->lpszLabel[memoHomeAddress] = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*(lstrlen(szBuf)+1));
  558. if(!lpMI->lpszLabel[memoHomeAddress])
  559. goto out;
  560. StrCpyN(lpMI->lpszLabel[memoHomeAddress], szBuf, lstrlen(szBuf)+1 );
  561. break;
  562. }
  563. }
  564. }
  565. len = 0;
  566. for(i=memoBusinessAddressStreet;i<=memoBusinessAddressCountry;i++)
  567. {
  568. // Win9x bug FormatMessage cannot have more than 1023 chars
  569. len += lstrlen(lpMI->lpsz[i]);
  570. if(len < 1023)
  571. lpszData[i-memoBusinessAddressStreet] = lpMI->lpsz[i];
  572. else
  573. lpszData[i-memoBusinessAddressStreet] = NULL;
  574. }
  575. for(i=memoBusinessAddressStreet;i<=memoBusinessAddressCountry;i++)
  576. {
  577. if(lpMI->lpsz[i] && lpMI->lpsz[i] != szEmpty)
  578. {
  579. LPTSTR lpszBusinessAddress = NULL;
  580. TCHAR szBuf[MAX_UI_STR];
  581. int nStringID = (dwStyle == styleMemo) ? idsPrintAddressTemplate : idsPrintBusCardAddressTemplate ;
  582. TCHAR szTmp[MAX_PATH], *lpszTmp;
  583. LoadString(hinstMapiX, nStringID, szBuf, CharSizeOf(szBuf));
  584. if (FormatMessage(FORMAT_MESSAGE_FROM_STRING |
  585. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  586. FORMAT_MESSAGE_ARGUMENT_ARRAY,
  587. szBuf,
  588. 0, // stringid
  589. 0, // dwLanguageId
  590. (LPTSTR)&lpszBusinessAddress, // output buffer
  591. 0, //MAX_UI_STR
  592. (va_list *)&lpszData[0]))
  593. {
  594. CleanPrintAddressString(lpszBusinessAddress);
  595. lpMI->lpsz[memoBusinessAddress] = lpszBusinessAddress;
  596. szBuf[0]='\0';
  597. LoadString(hinstMapiX, idsPrintBusinessAddress, szBuf, CharSizeOf(szBuf));
  598. lpMI->lpszLabel[memoBusinessAddress] = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*(lstrlen(szBuf)+1));
  599. if(!lpMI->lpszLabel[memoBusinessAddress])
  600. goto out;
  601. StrCpyN(lpMI->lpszLabel[memoBusinessAddress], szBuf, lstrlen(szBuf)+1);
  602. break;
  603. }
  604. }
  605. }
  606. }
  607. // Set the name that will be printed out for each entry
  608. // This is dependent on the current view and on the local language setting
  609. {
  610. LPTSTR lpszTmp = NULL;
  611. if( bCurrentSortIsByLastName != bDNisByLN)
  612. {
  613. // for auto add to WABs we dont have all this info .. so
  614. // if we just have a displayname we use it as it is
  615. if(lpszFirst || lpszMiddle || lpszLast || lpszNickName || (lpszCompany && !lpszDisplayName))
  616. {
  617. if(SetLocalizedDisplayName(lpszFirst,
  618. lpszMiddle,
  619. lpszLast,
  620. lpszCompany,
  621. lpszNickName,
  622. NULL, //&szBuf,
  623. 0,
  624. bCurrentSortIsByLastName,
  625. NULL,
  626. &lpszTmp))
  627. {
  628. lpMI->lpsz[memoTitleName]=lpszTmp;
  629. }
  630. }
  631. }
  632. if(!lpMI->lpsz[memoTitleName])
  633. {
  634. // use whatever DisplayName we have
  635. lpMI->lpsz[memoTitleName] = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*(lstrlen(lpszDisplayName)+1));
  636. if(!lpMI->lpsz[memoTitleName])
  637. goto out;
  638. StrCpyN(lpMI->lpsz[memoTitleName],lpszDisplayName, lstrlen(lpszDisplayName)+1);
  639. }
  640. }
  641. if(bIsGroup)
  642. {
  643. LPTSTR lpszMembers = NULL;
  644. ULONG nLen = 0;
  645. // Get the group members
  646. for(i=0;i<ulcPropCount;i++)
  647. {
  648. if(lpPropArray[i].ulPropTag == PR_WAB_DL_ENTRIES || lpPropArray[i].ulPropTag == PR_WAB_DL_ONEOFFS )
  649. {
  650. // Look at each entry in the PR_WAB_DL_ENTRIES.
  651. for (j = 0; j < lpPropArray[i].Value.MVbin.cValues; j++)
  652. {
  653. ULONG cbEID = lpPropArray[i].Value.MVbin.lpbin[j].cb;
  654. LPENTRYID lpEID = (LPENTRYID)lpPropArray[i].Value.MVbin.lpbin[j].lpb;
  655. ULONG ulcProps=0;
  656. LPSPropValue lpProps=NULL;
  657. LPTSTR lpszName = NULL;
  658. ULONG k;
  659. if (HR_FAILED( HrGetPropArray( lpAdrBook,NULL,cbEID,lpEID,MAPI_UNICODE,&ulcProps,&lpProps)))
  660. {
  661. DebugPrintError(( TEXT("HrGetPropArray failed\n")));
  662. continue;
  663. }
  664. for(k=0;k<ulcProps;k++)
  665. {
  666. if(lpProps[k].ulPropTag == PR_DISPLAY_NAME)
  667. {
  668. lpszName = lpProps[k].Value.LPSZ;
  669. break;
  670. }
  671. }
  672. if(lpszName)
  673. {
  674. LPTSTR lpsz;
  675. if(!lpszMembers)
  676. nLen = 0;
  677. else
  678. {
  679. nLen = lstrlen(lpszMembers)+1;
  680. nLen += lstrlen(lpszTab) + lstrlen(szCRLF) + 1;
  681. }
  682. nLen += lstrlen(lpszName)+1;
  683. lpsz = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*nLen);
  684. if(!lpsz)
  685. {
  686. if(lpProps)
  687. MAPIFreeBuffer(lpProps);
  688. goto out;
  689. }
  690. *lpsz='\0';
  691. if(lpszMembers)
  692. {
  693. StrCpyN(lpsz,lpszMembers, nLen);
  694. StrCatBuff(lpsz,szCRLF, nLen);
  695. StrCatBuff(lpsz,lpszTab, nLen);
  696. }
  697. StrCatBuff(lpsz,lpszName, nLen);
  698. LocalFreeAndNull(&lpszMembers);
  699. lpszMembers = lpsz;
  700. }
  701. if(lpProps)
  702. MAPIFreeBuffer(lpProps);
  703. } // for(j...
  704. }
  705. } // for(i...
  706. if(lpszMembers)
  707. {
  708. ULONG cchSize = lstrlen(szBuf)+1;
  709. szBuf[0]='\0';
  710. LoadString(hinstMapiX, idsPrintGroupMembers, szBuf, ARRAYSIZE(szBuf));
  711. lpMI->lpszLabel[memoGroupMembers] = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cchSize);
  712. if(!lpMI->lpszLabel[memoGroupMembers])
  713. goto out;
  714. StrCpyN(lpMI->lpszLabel[memoGroupMembers], szBuf, cchSize);
  715. lpMI->lpsz[memoGroupMembers]=lpszMembers;
  716. }
  717. }
  718. //Speacial case formatting of multiline data
  719. if(dwStyle == styleMemo)
  720. {
  721. AddTabsToLineBreaks(&(lpMI->lpsz[memoNotes]));
  722. AddTabsToLineBreaks(&(lpMI->lpsz[memoHomeAddress]));
  723. AddTabsToLineBreaks(&(lpMI->lpsz[memoBusinessAddress]));
  724. }
  725. out:
  726. // special case uninitialization
  727. for(j=memoHomeAddressStreet;j<=memoHomeAddressCountry;j++)
  728. {
  729. if(lpMI->lpsz[j] && (lpMI->lpsz[j] != szEmpty))
  730. LocalFreeAndNull(&(lpMI->lpsz[j]));
  731. }
  732. for(j=memoBusinessAddressStreet;j<=memoBusinessAddressCountry;j++)
  733. {
  734. if(lpMI->lpsz[j] && (lpMI->lpsz[j] != szEmpty))
  735. LocalFreeAndNull(&(lpMI->lpsz[j]));
  736. }
  737. return;
  738. }
  739. /*
  740. * NTwipsToPixels
  741. *
  742. * Purpose:
  743. * Converts a measurement in twips into pixels
  744. *
  745. * Arguments:
  746. * nTwips the value to be converted
  747. * cPixels number of pixels per inch
  748. *
  749. * Returns:
  750. * Returns a int representing the number of pixels in nTwips
  751. */
  752. int NTwipsToPixels(int nTwips, int cPixelsPerInch)
  753. {
  754. LONG lT = (LONG) nTwips * (LONG) cPixelsPerInch / (LONG) cTwipsPerInch;
  755. return (int) lT;
  756. }
  757. /*
  758. * LPixelsToTwips
  759. *
  760. * Purpose:
  761. * Converts a measurement in pixles into twips
  762. *
  763. * Arguments:
  764. * nPixels the value to be converted
  765. * cPixels number of pixels per inch
  766. *
  767. * Returns:
  768. * Returns a int representing the number of pixels in nTwips
  769. */
  770. LONG LPixelsToTwips(int nPixels, int cPixelsPerInch)
  771. {
  772. LONG lT = (LONG) nPixels * (LONG) cTwipsPerInch / (LONG) cPixelsPerInch;
  773. return lT;
  774. }
  775. /*
  776. * PrintPageNumber
  777. *
  778. * Purpose:
  779. * To print the page number for each page
  780. *
  781. * Arguments:
  782. * ppi Pointer to the PRINTINFO structure
  783. *
  784. * Returns:
  785. * SCODE indicating success or failure.
  786. * Currently always return S_OK
  787. */
  788. void PrintPageNumber(PRINTINFO * ppi)
  789. {
  790. RECT rcExt;
  791. HFONT hfontOld;
  792. TCHAR szT[20];
  793. DebugPrintTrace(( TEXT("PrintPageNumber\n")));
  794. // Find out how much space our text take will take
  795. rcExt = ppi->rcBand;
  796. rcExt.top = ppi->yFooter;
  797. hfontOld = (HFONT)SelectObject(ppi->hdcPrn, ppi->hfontPlain);
  798. DrawText(ppi->hdcPrn, szT, wnsprintf(szT, ARRAYSIZE(szT), ppi->szPageNumber,
  799. ppi->lPageNumber), &rcExt, DT_CENTER);
  800. SelectObject(ppi->hdcPrn, hfontOld);
  801. }
  802. /*
  803. * ScGetNextBand
  804. *
  805. * Purpose:
  806. * Retrieves the next band to print on. Adjusts the band to conform
  807. * to the margins established in the PRINTINFO structure. Bumps up
  808. * the page number as appropriate.
  809. *
  810. * Arguments:
  811. * ppi print information
  812. * fAdvance flag whether to move to the next page
  813. *
  814. * Returns:
  815. * SCODE indicating the success or failure
  816. */
  817. SCODE ScGetNextBand(PRINTINFO * ppi, BOOL fAdvance)
  818. {
  819. SCODE sc = S_OK;
  820. int nCode;
  821. DebugPrintTrace(( TEXT("ScGetNextBand\n")));
  822. // Call the abort proc to see if the user wishes to stop
  823. if (!ppi->pfnAbortProc(ppi->hdcPrn, 0))
  824. {
  825. sc=E_FAIL;
  826. nCode = AbortDoc(ppi->hdcPrn);
  827. if(nCode < 0)
  828. {
  829. DebugPrintTrace(( TEXT("Abort Doc error: %d\n"),GetLastError()));
  830. ShowMessageBox(ppi->hwndDlg, idsPrintJobCannotStop, MB_OK | MB_ICONEXCLAMATION);
  831. }
  832. goto CleanUp;
  833. }
  834. // brettm:
  835. // USE_BANDING stuff removed, as we're always on Win32
  836. // End the previous page
  837. if (ppi->lPageNumber)
  838. {
  839. nCode = EndPage(ppi->hdcPrn);
  840. DebugPrintTrace(( TEXT("+++++++++EndPage\n")));
  841. if (nCode <= 0)
  842. {
  843. sc=E_FAIL;
  844. goto CleanUp;
  845. }
  846. }
  847. if (fAdvance)
  848. {
  849. nCode = StartPage(ppi->hdcPrn);
  850. DebugPrintTrace(( TEXT("+++++++++StartPage\n")));
  851. // Start a new page
  852. if (nCode <= 0)
  853. {
  854. sc=E_FAIL;
  855. goto CleanUp;
  856. }
  857. // Let the entire page be the band
  858. ppi->rcBand = ppi->rcMargin;
  859. ppi->fEndOfPage = TRUE; // end of page!
  860. // Bump up the page number and print
  861. ppi->lPrevPage = ppi->lPageNumber++;
  862. PrintPageNumber(ppi);
  863. {
  864. TCHAR szBuf[MAX_UI_STR];
  865. TCHAR szString[MAX_UI_STR];
  866. LoadString(hinstMapiX, idsPrintingPageNumber, szString, ARRAYSIZE(szString));
  867. wnsprintf(szBuf, ARRAYSIZE(szBuf), szString, ppi->lPageNumber);
  868. SetPrintDialogMsg(0, 0, szBuf);
  869. }
  870. }
  871. CleanUp:
  872. return sc;
  873. }
  874. /*
  875. * LGetHeaderIndent
  876. *
  877. * Purpose:
  878. * Retrieves from the resource file the suggested indent overhang for
  879. * headers.
  880. *
  881. * Arguments:
  882. * none.
  883. *
  884. * Returns:
  885. * LONG The suggested indent overhang in twips
  886. */
  887. LONG LGetHeaderIndent()
  888. {
  889. LONG lOver = 1440; // default
  890. //TCHAR szT[10];
  891. //if (LoadString(hinstMapiX, idsHeaderIndent, szT, CharSizeOf(szT)))
  892. // lOver = atoi(szT);
  893. return lOver;
  894. }
  895. //$$////////////////////////////////////////////////////////////////////////////////
  896. //
  897. // AppendText - Simple routine that appends a given string to the End of the text
  898. // in the given richedit control
  899. //
  900. ////////////////////////////////////////////////////////////////////////////////////
  901. void AppendText(HWND hWndRE, LPTSTR lpsz)
  902. {
  903. // Set the insertion point to the end of the current text
  904. int nLastChar = (int) SendMessage(hWndRE, WM_GETTEXTLENGTH, 0, 0);
  905. CHARRANGE charRange = {0};
  906. charRange.cpMin = charRange.cpMax = nLastChar + 1;
  907. SendMessage(hWndRE, EM_EXSETSEL, 0, (LPARAM) &charRange);
  908. // Insert the text
  909. // [PaulHi] 7/7/99 Raid 82350 RichEdit 1.0 can't handle Unicode
  910. // strings even though the window is created Unicode.
  911. if (s_bUse20)
  912. {
  913. // RichEdit 2.0
  914. SendMessage(hWndRE, EM_REPLACESEL, (WPARAM) FALSE, (LPARAM) lpsz);
  915. }
  916. else
  917. {
  918. // RichEdit 1.0
  919. LPSTR lpszTemp = ConvertWtoA(lpsz);
  920. Assert(lpszTemp);
  921. if (lpszTemp)
  922. SendMessageA(hWndRE, EM_REPLACESEL, (WPARAM) FALSE, (LPARAM) lpszTemp);
  923. LocalFreeAndNull(&lpszTemp);
  924. }
  925. return;
  926. }
  927. //$$////////////////////////////////////////////////////////////////////////
  928. //
  929. // ParaCmd - Sets/Unsets paragraph formatting in the Rich Edit Control
  930. //
  931. // We want all the information on the right side to be indented
  932. // so we will put an indent on that information and remove it when
  933. // adding labels
  934. ////////////////////////////////////////////////////////////////////////////
  935. void ParaCmd(HWND hWndRE, BOOL bIndent)
  936. {
  937. // We want no indentation on the first line and we want a
  938. // 1 tab indentation on the second line onwards
  939. PARAFORMAT pf ={0};
  940. int nTabStop = (int) (1.5 * cTwipsPerInch);
  941. pf.cbSize = sizeof(pf);
  942. pf.dwMask = PFM_OFFSET |
  943. PFM_TABSTOPS |
  944. PFM_NUMBERING;
  945. SendMessage(hWndRE, EM_GETPARAFORMAT, (WPARAM) TRUE, (LPARAM) &pf);
  946. pf.wNumbering = 0;
  947. if (bIndent)
  948. {
  949. //pf.dxStartIndent = nTabStop;
  950. pf.dxOffset = nTabStop;
  951. pf.cTabCount = 1;
  952. pf.rgxTabs[0] = nTabStop;
  953. }
  954. else
  955. {
  956. //pf.dxStartIndent = 0;
  957. pf.dxOffset = 0;
  958. pf.cTabCount = 1;
  959. pf.rgxTabs[0] = 720; //seems to be the default = 0.5 inches
  960. }
  961. SendMessage(hWndRE, EM_SETPARAFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &pf);
  962. return;
  963. }
  964. //$$////////////////////////////////////////////////////////////////////////
  965. //
  966. // BoldCmd - Sets/Unsets current font to bold in the Rich Edit Control
  967. //
  968. ////////////////////////////////////////////////////////////////////////////
  969. void BoldCmd(HWND hWndRE, BOOL bBold)
  970. {
  971. CHARFORMAT cf = {0};
  972. cf.cbSize = sizeof(cf);
  973. cf.dwMask = CFM_BOLD;
  974. SendMessage(hWndRE, EM_GETCHARFORMAT, (WPARAM) TRUE, (LPARAM) &cf);
  975. if (bBold)
  976. cf.dwEffects = cf.dwEffects | CFE_BOLD;
  977. else
  978. cf.dwEffects = cf.dwEffects & ~CFE_BOLD;
  979. SendMessage(hWndRE, EM_SETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf);
  980. return;
  981. }
  982. //$$////////////////////////////////////////////////////////////////////////
  983. //
  984. // TitleCmd - Sets/Unsets title text (BOLD, Bigger) in the Rich Edit Control
  985. //
  986. ////////////////////////////////////////////////////////////////////////////
  987. void TitleCmd(HWND hWndRE, BOOL bBold)
  988. {
  989. CHARFORMAT cf = {0};
  990. PARAFORMAT pf = {0};
  991. cf.cbSize = sizeof(cf);
  992. cf.dwMask = CFM_BOLD /*| CFM_ITALIC*/ | CFM_SIZE;
  993. pf.cbSize = sizeof(pf);
  994. pf.dwMask = PFM_NUMBERING;
  995. SendMessage(hWndRE, EM_GETPARAFORMAT, (WPARAM) TRUE, (LPARAM) &pf);
  996. SendMessage(hWndRE, EM_GETCHARFORMAT, (WPARAM) TRUE, (LPARAM) &cf);
  997. if (bBold)
  998. {
  999. cf.dwEffects = cf.dwEffects | CFE_BOLD; // | CFE_ITALIC;
  1000. cf.yHeight += 50;
  1001. pf.wNumbering = PFN_BULLET;
  1002. }
  1003. else
  1004. {
  1005. cf.dwEffects = cf.dwEffects & ~CFE_BOLD;
  1006. // cf.dwEffects = cf.dwEffects & ~CFE_ITALIC;
  1007. cf.yHeight -= 50;
  1008. pf.wNumbering = 0;
  1009. }
  1010. SendMessage(hWndRE, EM_SETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf);
  1011. SendMessage(hWndRE, EM_SETPARAFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &pf);
  1012. return;
  1013. }
  1014. //$$////////////////////////////////////////////////////////////////////////
  1015. //
  1016. // ReduceFontCmd - Reduces the displayed font in the Rich Edit Control
  1017. //
  1018. ////////////////////////////////////////////////////////////////////////////
  1019. void ReduceFontCmd(HWND hWndRE, BOOL bReduce, int nReduceBy, BOOL bSelectionOnly)
  1020. {
  1021. CHARFORMAT cf = {0};
  1022. cf.cbSize = sizeof(cf);
  1023. cf.dwMask = CFM_SIZE;
  1024. SendMessage(hWndRE, EM_GETCHARFORMAT, (WPARAM) bSelectionOnly, (LPARAM) &cf);
  1025. if (bReduce)
  1026. cf.yHeight -= nReduceBy; //40;
  1027. else
  1028. cf.yHeight += nReduceBy; //40;
  1029. SendMessage(hWndRE, EM_SETCHARFORMAT, (WPARAM) bSelectionOnly ? SCF_SELECTION : SCF_DEFAULT, (LPARAM) &cf);
  1030. return;
  1031. }
  1032. //$$////////////////////////////////////////////////////////////////////////
  1033. //
  1034. // SetTabsCmd - Sets and Unsets the Tabs in the RichEdit Control
  1035. //
  1036. ////////////////////////////////////////////////////////////////////////////
  1037. void SetTabsCmd(HWND hWndRE, BOOL bSet)
  1038. {
  1039. PARAFORMAT pf ={0};
  1040. int nTabStop = (int) (1.5 * cTwipsPerInch);
  1041. int j;
  1042. pf.cbSize = sizeof(pf);
  1043. pf.dwMask = PFM_TABSTOPS | PFM_NUMBERING;
  1044. SendMessage(hWndRE, EM_GETPARAFORMAT, (WPARAM) TRUE, (LPARAM) &pf);
  1045. pf.wNumbering = 0;
  1046. if (bSet)
  1047. {
  1048. for(j=0;j<5;j++)
  1049. pf.rgxTabs[j] = nTabStop;
  1050. }
  1051. else
  1052. {
  1053. for(j=0;j<5;j++)
  1054. pf.rgxTabs[j] = 720;
  1055. }
  1056. SendMessage(hWndRE, EM_SETPARAFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &pf);
  1057. return;
  1058. }
  1059. //$$////////////////////////////////////////////////////////////////////////////////////////////
  1060. //
  1061. // WABStylePhoneList - Fills the Rich edit control with info from MI as per the
  1062. // Phone List style
  1063. //
  1064. // hWndRE - handle to Print Formating Rich Edit Control
  1065. // MI - MEMOINFO strcuture containing the info to print
  1066. // lpszPrevEntry - the first TCHAR of the previous entry - this lets us break the list
  1067. // alphabetically - this points to a preallocated buffer
  1068. //
  1069. ////////////////////////////////////////////////////////////////////////////////////////////////
  1070. void WABStylePhoneList(HWND hWndRE, MEMOINFO MI, LPTSTR lpszPrevEntry, DWORD cchSizePrevEntry)
  1071. {
  1072. // We want an extra gap between certain groups of information
  1073. // we'll track these groups using these BOOLs
  1074. ULONG i,j,k;
  1075. TCHAR szBufChar1[16];
  1076. TCHAR szBufChar2[16];
  1077. LPTSTR lpTemp = NULL;
  1078. int nReduceFontBy = GetNumberFromStringResource(idsPhoneFontReduceBy);
  1079. // First we compare the first character of the current string with the previous
  1080. // string - if it is the same, then we do nothing - if it different, we ouput
  1081. // the lower case TCHAR as a heading for the phone directory
  1082. //
  1083. // If the character is not alphanumeric, we ignore it as a heading (e.g. ' )
  1084. // Bug: 25710
  1085. // We ignore these initialls totally if localizers have set idsDontDisplayInitials
  1086. // these initials to anything other than 0 because in some FE languages
  1087. // names have double characters in them and they look strange with a single
  1088. // character up front
  1089. if(szDontDisplayInitials[0] == '0')
  1090. {
  1091. StrCpyN(szBufChar1, lpszPrevEntry, ARRAYSIZE(szBufChar1));
  1092. if(lstrlen(MI.lpsz[memoTitleName]) > 16)
  1093. {
  1094. ULONG iLen = TruncatePos(MI.lpsz[memoTitleName], 16-1);
  1095. CopyMemory(szBufChar2, MI.lpsz[memoTitleName], sizeof(TCHAR)*iLen);
  1096. szBufChar2[iLen]='\0';
  1097. }
  1098. else
  1099. StrCpyN(szBufChar2, MI.lpsz[memoTitleName], ARRAYSIZE(szBufChar2));
  1100. /***********
  1101. // Bug 14615 - this alphanumeric filtering doesnt work for DBCS and FE names
  1102. //
  1103. // Ignore all non-alpha numeric characters
  1104. lpTemp = szBufChar2;
  1105. {
  1106. //Temp Hack
  1107. TCHAR szTemp[16];
  1108. LPTSTR lpTemp2 = NULL;
  1109. StrCpyN(szTemp, lpTemp, ARRAYSIZE(szTemp));
  1110. lpTemp2 = CharNext(szTemp);
  1111. *lpTemp2 = '\0';
  1112. while(lpTemp && lstrlen(lpTemp))
  1113. {
  1114. if(IsCharAlphaNumeric(szTemp[0]))
  1115. break;
  1116. lpTemp = CharNext(lpTemp);
  1117. StrCpyN(szTemp, lpTemp, ARRAYSIZE(szTemp));
  1118. lpTemp2 = CharNext(szTemp);
  1119. *lpTemp2 = '\0';
  1120. }
  1121. }
  1122. if(lpTemp != szBufChar2)
  1123. StrCpyN(szBufChar2, lpTemp, ARRAYSIZE(szBufChar2));
  1124. ***************/
  1125. // Isolate the first TCHAR of the above strings
  1126. lpTemp = CharNext(szBufChar1);
  1127. *lpTemp = '\0';
  1128. lpTemp = CharNext(szBufChar2);
  1129. *lpTemp = '\0';
  1130. // Compare these two characters
  1131. CharLower(szBufChar1);
  1132. CharLower(szBufChar2);
  1133. if(lstrcmp(szBufChar1, szBufChar2))
  1134. {
  1135. // They are different
  1136. // Add the TCHAR as a title string
  1137. AppendText(hWndRE, szCRLF);
  1138. TitleCmd(hWndRE, TRUE);
  1139. BoldCmd(hWndRE, TRUE);
  1140. AppendText(hWndRE, lpszSpace);
  1141. AppendText(hWndRE, szBufChar2);
  1142. AppendText(hWndRE, szCRLF);
  1143. TitleCmd(hWndRE, FALSE);
  1144. BoldCmd(hWndRE, FALSE);
  1145. ParaCmd(hWndRE, TRUE);
  1146. AppendText(hWndRE, lpszFlatLine);
  1147. AppendText(hWndRE, szCRLF);
  1148. AppendText(hWndRE, szCRLF);
  1149. ParaCmd(hWndRE, FALSE);
  1150. StrCpyN(lpszPrevEntry, szBufChar2, cchSizePrevEntry);
  1151. }
  1152. } //dontdisplayinitials
  1153. ReduceFontCmd(hWndRE, TRUE, nReduceFontBy, TRUE);
  1154. SetTabsCmd(hWndRE, TRUE);
  1155. // Figure out how much space the name will take up ...
  1156. {
  1157. TCHAR szBuf[MAX_PATH];
  1158. int nMaxTabs = 2;
  1159. int nTabStop = (int)(1.5 * cTwipsPerInch);
  1160. int MaxWidth = nMaxTabs * nTabStop;
  1161. int sizeCxTwips;
  1162. int PixelsPerInch;
  1163. int nLen = lstrlen(MI.lpsz[memoTitleName]);
  1164. SIZE size = {0};
  1165. HDC hdc = GetDC(hWndRE);
  1166. {
  1167. HDC hDC = GetDC(NULL);
  1168. PixelsPerInch = GetDeviceCaps(hDC, LOGPIXELSX);
  1169. ReleaseDC(NULL, hDC);
  1170. }
  1171. if (nLen >= MAX_PATH)
  1172. {
  1173. ULONG iLen = TruncatePos(MI.lpsz[memoTitleName], MAX_PATH-1);
  1174. CopyMemory(szBuf, MI.lpsz[memoTitleName], sizeof(TCHAR)*iLen);
  1175. szBuf[iLen]='\0';
  1176. }
  1177. else
  1178. StrCpyN(szBuf, MI.lpsz[memoTitleName], ARRAYSIZE(szBuf));
  1179. nLen = lstrlen(szBuf);
  1180. GetTextExtentPoint32(hdc, szBuf, nLen, &size);
  1181. sizeCxTwips = (int)((size.cx * cTwipsPerInch)/PixelsPerInch);
  1182. // We dont want our displayed name to be more than 2 tabstops
  1183. // so we decide where to truncate the name to fit it on screen
  1184. if(sizeCxTwips > MaxWidth)
  1185. {
  1186. while(sizeCxTwips > MaxWidth)
  1187. {
  1188. nLen--;
  1189. nLen = TruncatePos(szBuf, nLen);
  1190. szBuf[nLen]='\0';
  1191. nLen = lstrlen(szBuf);
  1192. GetTextExtentPoint32(hdc, szBuf, nLen, &size);
  1193. sizeCxTwips = (int)((size.cx * cTwipsPerInch)/PixelsPerInch);
  1194. }
  1195. // chop of 3 more characters for good measure
  1196. nLen-=3;
  1197. nLen = TruncatePos(szBuf, nLen);
  1198. szBuf[nLen]='\0';
  1199. nLen = lstrlen(szBuf);
  1200. GetTextExtentPoint32(hdc, szBuf, nLen, &size);
  1201. sizeCxTwips = (int)((size.cx * cTwipsPerInch)/PixelsPerInch);
  1202. }
  1203. while ((sizeCxTwips < MaxWidth) && (nLen < ARRAYSIZE(szBuf)-1))
  1204. {
  1205. StrCatBuff(szBuf, TEXT("."), ARRAYSIZE(szBuf));
  1206. nLen = lstrlen(szBuf);
  1207. GetTextExtentPoint32(hdc, szBuf, nLen, &size);
  1208. sizeCxTwips = (int)((size.cx * cTwipsPerInch)/PixelsPerInch);
  1209. }
  1210. StrCatBuff(szBuf, lpszTab, ARRAYSIZE(szBuf));
  1211. AppendText(hWndRE, szBuf);
  1212. // Now we are ready to tag on the phone numbers
  1213. {
  1214. int nPhoneCount = 0; //counts how many phones there are
  1215. int nPhoneLabelSpaceTwips = GetNumberFromStringResource(idsPhoneTextSpaceTwips); //1150
  1216. for(j=memoBusinessPhone;j<=memoHomeCellular;j++)
  1217. {
  1218. if(MI.lpsz[j] && lstrlen(MI.lpsz[j]))
  1219. {
  1220. if(nPhoneCount != 0)
  1221. {
  1222. int k;
  1223. AppendText(hWndRE, szCRLF);
  1224. // Bug 73266
  1225. if(s_bUse20)
  1226. ReduceFontCmd(hWndRE, TRUE, nReduceFontBy, TRUE);
  1227. StrCpyN(szBuf, szEmpty, ARRAYSIZE(szBuf));
  1228. nLen = lstrlen(szBuf);
  1229. GetTextExtentPoint32(hdc, szBuf, nLen, &size);
  1230. sizeCxTwips = (int)((size.cx * cTwipsPerInch)/PixelsPerInch);
  1231. while ((sizeCxTwips < MaxWidth) && (nLen < ARRAYSIZE(szBuf)-1))
  1232. {
  1233. StrCatBuff(szBuf, lpszSpace, ARRAYSIZE(szBuf));
  1234. nLen = lstrlen(szBuf);
  1235. GetTextExtentPoint32(hdc, szBuf, nLen, &size);
  1236. sizeCxTwips = (int)((size.cx * cTwipsPerInch)/PixelsPerInch);
  1237. }
  1238. StrCatBuff(szBuf, lpszTab, ARRAYSIZE(szBuf));
  1239. AppendText(hWndRE, szBuf);
  1240. }
  1241. TrimSpaces(MI.lpszLabel[j]);
  1242. StrCpyN(szBuf, MI.lpszLabel[j], ARRAYSIZE(szBuf));
  1243. nLen = lstrlen(szBuf);
  1244. GetTextExtentPoint32(hdc, szBuf, nLen, &size);
  1245. sizeCxTwips = (int)((size.cx * cTwipsPerInch)/PixelsPerInch);
  1246. if(sizeCxTwips < nPhoneLabelSpaceTwips)
  1247. {
  1248. while ((sizeCxTwips < nPhoneLabelSpaceTwips) && (nLen < ARRAYSIZE(szBuf)-1))
  1249. {
  1250. StrCatBuff(szBuf, lpszSpace, ARRAYSIZE(szBuf));
  1251. nLen = lstrlen(szBuf);
  1252. GetTextExtentPoint32(hdc, szBuf, nLen, &size);
  1253. sizeCxTwips = (int)((size.cx * cTwipsPerInch)/PixelsPerInch);
  1254. }
  1255. StrCatBuff(szBuf, lpszTab, ARRAYSIZE(szBuf));
  1256. }
  1257. StrCatBuff(szBuf, MI.lpsz[j], ARRAYSIZE(szBuf));
  1258. AppendText(hWndRE, szBuf);
  1259. nPhoneCount++;
  1260. }
  1261. }
  1262. if(nPhoneCount == 0)
  1263. {
  1264. LoadString(hinstMapiX, idsPrintNoPhone, szBuf, ARRAYSIZE(szBuf));
  1265. AppendText(hWndRE, szBuf);
  1266. }
  1267. }
  1268. AppendText(hWndRE, szCRLF);
  1269. ReleaseDC(hWndRE, hdc);
  1270. }
  1271. SetTabsCmd(hWndRE, FALSE);
  1272. ReduceFontCmd(hWndRE, FALSE, nReduceFontBy, TRUE);
  1273. return;
  1274. }
  1275. //$$////////////////////////////////////////////////////////////////////////////////////////////
  1276. //
  1277. // WABStyleBusinessCard - Fills the Rich edit control with info from MI as per the
  1278. // business card style
  1279. //
  1280. // hWndRE - handle to Print Formating Rich Edit Control
  1281. // MI - MEMOINFO strcuture containing the info to print
  1282. //
  1283. ////////////////////////////////////////////////////////////////////////////////////////////////
  1284. void WABStyleBusinessCard(HWND hWndRE, MEMOINFO MI)
  1285. {
  1286. // We want an extra gap between certain groups of information
  1287. // we'll track these groups using these BOOLs
  1288. ULONG i,j,k;
  1289. int nReduceBy = GetNumberFromStringResource(idsBusCardFontReduceBy);
  1290. // Add the contact name as a heading
  1291. //TitleCmd(hWndRE, TRUE);
  1292. BoldCmd(hWndRE, TRUE);
  1293. //AppendText(hWndRE, lpszSpace);
  1294. AppendText(hWndRE, MI.lpsz[memoTitleName]);
  1295. AppendText(hWndRE, szCRLF);
  1296. //TitleCmd(hWndRE, FALSE);
  1297. BoldCmd(hWndRE, FALSE);
  1298. ParaCmd(hWndRE, TRUE);
  1299. AppendText(hWndRE, lpszFlatLine);
  1300. AppendText(hWndRE, szCRLF);
  1301. AppendText(hWndRE, szCRLF);
  1302. ParaCmd(hWndRE, FALSE);
  1303. ReduceFontCmd(hWndRE, TRUE, nReduceBy, TRUE);
  1304. for(j=memoName;j<memoMAX;j++)
  1305. {
  1306. if(MI.lpsz[j] && lstrlen(MI.lpsz[j]))
  1307. {
  1308. switch(j)
  1309. {
  1310. case memoJobTitle:
  1311. //case memoDepartment:
  1312. //case memoOffice:
  1313. case memoCompany:
  1314. case memoBusinessAddress:
  1315. break;
  1316. case memoEmail:
  1317. // Add the label
  1318. AppendText(hWndRE, MI.lpszLabel[j]);
  1319. AppendText(hWndRE, lpszTab);
  1320. break;
  1321. case memoBusinessWebPage:
  1322. case memoBusinessPhone:
  1323. case memoBusinessFax:
  1324. case memoBusinessPager:
  1325. case memoHomePhone:
  1326. case memoHomeFax:
  1327. case memoHomeCellular:
  1328. // Add the label
  1329. AppendText(hWndRE, MI.lpszLabel[j]);
  1330. AppendText(hWndRE, lpszSpace);
  1331. break;
  1332. default:
  1333. continue;
  1334. }
  1335. // Add the value
  1336. AppendText(hWndRE, MI.lpsz[j]);
  1337. // line break
  1338. AppendText(hWndRE, szCRLF);
  1339. }
  1340. } //for j...
  1341. ReduceFontCmd(hWndRE, FALSE, nReduceBy, TRUE);
  1342. // Closing line
  1343. ParaCmd(hWndRE, TRUE);
  1344. AppendText(hWndRE, lpszFlatLine);
  1345. ParaCmd(hWndRE, FALSE);
  1346. return;
  1347. }
  1348. //$$////////////////////////////////////////////////////////////////////////////////////////////
  1349. //
  1350. // WABStyleMemo - Fills the Rich edit control with info from MI as per the memo style
  1351. //
  1352. // hWndRE - handle to Print Formating Rich Edit Control
  1353. // MI - MEMOINFO strcuture containing the info to print
  1354. //
  1355. //
  1356. // The memo style consists of a dump of all the WAB Contacts properties one by one with
  1357. // labels. Some properties are grouped togethor (eg all the phone properties)
  1358. //
  1359. ////////////////////////////////////////////////////////////////////////////////////////////////
  1360. void WABStyleMemo(HWND hWndRE, MEMOINFO MI)
  1361. {
  1362. BOOL bGapAddress = FALSE; // a gap before the address fields
  1363. BOOL bGapPhone = FALSE; // a gap before the phone fields
  1364. BOOL bGapEmail = FALSE;
  1365. BOOL bGapNotes = FALSE;
  1366. BOOL bGapWeb = FALSE;
  1367. ULONG i,j,k;
  1368. // Add the heading
  1369. TitleCmd(hWndRE, TRUE);
  1370. AppendText(hWndRE, lpszSpace);
  1371. AppendText(hWndRE, MI.lpsz[memoTitleName]);
  1372. AppendText(hWndRE, szCRLF);
  1373. TitleCmd(hWndRE, FALSE);
  1374. ParaCmd(hWndRE, TRUE);
  1375. AppendText(hWndRE, lpszFlatLine);
  1376. AppendText(hWndRE, szCRLF);
  1377. AppendText(hWndRE, szCRLF);
  1378. ParaCmd(hWndRE, FALSE);
  1379. for(j=memoName;j<memoMAX;j++)
  1380. {
  1381. int nLastChar;
  1382. LPTSTR lpSpace = NULL;
  1383. ULONG nLen = 0;
  1384. if(MI.lpsz[j] && lstrlen(MI.lpsz[j]))
  1385. {
  1386. // Append an additional space if necessary ..
  1387. switch(j)
  1388. {
  1389. case memoBusinessAddress:
  1390. case memoHomeAddress:
  1391. if(!bGapAddress)
  1392. {
  1393. AppendText(hWndRE, szCRLF);
  1394. bGapAddress = TRUE;
  1395. }
  1396. break;
  1397. case memoBusinessPhone:
  1398. case memoBusinessFax:
  1399. case memoBusinessPager:
  1400. case memoHomePhone:
  1401. case memoHomeFax:
  1402. case memoHomeCellular:
  1403. if(!bGapPhone)
  1404. {
  1405. AppendText(hWndRE, szCRLF);
  1406. bGapPhone = TRUE;
  1407. }
  1408. break;
  1409. case memoEmail:
  1410. if(!bGapEmail)
  1411. {
  1412. AppendText(hWndRE, szCRLF);
  1413. bGapEmail = TRUE;
  1414. }
  1415. break;
  1416. case memoBusinessWebPage:
  1417. case memoHomeWebPage:
  1418. case memoGroupMembers: // stick in group members here to save an extra variable
  1419. if(!bGapWeb)
  1420. {
  1421. AppendText(hWndRE, szCRLF);
  1422. bGapWeb = TRUE;
  1423. }
  1424. break;
  1425. case memoNotes:
  1426. if(!bGapNotes)
  1427. {
  1428. AppendText(hWndRE, szCRLF);
  1429. bGapNotes = TRUE;
  1430. }
  1431. break;
  1432. } // switch
  1433. // Set the paragraph formating
  1434. ParaCmd(hWndRE, TRUE);
  1435. // Set the current insertion font to bold
  1436. BoldCmd(hWndRE, TRUE);
  1437. // Add the label
  1438. AppendText(hWndRE, MI.lpszLabel[j]);
  1439. BoldCmd(hWndRE, FALSE);
  1440. // Tab
  1441. AppendText(hWndRE, lpszTab);
  1442. // Add the value
  1443. AppendText(hWndRE, MI.lpsz[j]);
  1444. // line break
  1445. AppendText(hWndRE, szCRLF);
  1446. ParaCmd(hWndRE, FALSE);
  1447. }
  1448. } //for j...
  1449. // Closing line
  1450. ParaCmd(hWndRE, TRUE);
  1451. AppendText(hWndRE, lpszFlatLine);
  1452. ParaCmd(hWndRE, FALSE);
  1453. return;
  1454. }
  1455. //$$////////////////////////////////////////////////////////////////////////////////
  1456. //
  1457. // WABFormatData - takes the given information and formats it into the
  1458. // RichEdit Control for subsequent printing ..
  1459. //
  1460. // lpIAB - LPADRBOOK pointer
  1461. // hWndParent - HWND of Parent
  1462. // hWndRE - HWDN of rich edit control used for formatting
  1463. // hWndLV - List View containing the items which need to be printed
  1464. // dwRange - Range to print (ALL or SELECTION)
  1465. // dwStyle - Style to print (Phone List, Memo, Business Card)
  1466. // ppi - PRINT INFO struct
  1467. // bCurrentSortIsByLastName - Used to determine whether the names are printed
  1468. // by first name or by last name. Current sort option in the list view decides
  1469. //
  1470. ////////////////////////////////////////////////////////////////////////////////////
  1471. BOOL WABFormatData( LPADRBOOK lpIAB,
  1472. HWND hWndParent,
  1473. HWND hWndRE,
  1474. HWND hWndLV,
  1475. DWORD dwRange,
  1476. DWORD dwStyle,
  1477. PRINTINFO * ppi,
  1478. BOOL bCurrentSortIsByLastName)
  1479. {
  1480. BOOL bRet = FALSE;
  1481. ULONG ulcPropCount = 0;
  1482. LPSPropValue lpPropArray = NULL;
  1483. //LPTSTR lpszPrevEntry = NULL;
  1484. TCHAR szPrevEntry[MAX_DISPLAY_NAME_LENGTH]; //32 chars
  1485. if (!hWndRE || !hWndLV)
  1486. goto out;
  1487. if(ListView_GetItemCount(hWndLV) <= 0)
  1488. goto out;
  1489. if(dwStyle == stylePhoneList)
  1490. {
  1491. LoadString(hinstMapiX, idsDontDisplayInitials, szDontDisplayInitials, CharSizeOf(szDontDisplayInitials));
  1492. }
  1493. if((dwRange == rangeSelected) && (ListView_GetSelectedCount(hWndLV)<=0))
  1494. {
  1495. ShowMessageBox(hWndParent, IDS_ADDRBK_MESSAGE_NO_ITEM, MB_OK | MB_ICONEXCLAMATION);
  1496. goto out;
  1497. }
  1498. StrCpyN(szPrevEntry, szEmpty, ARRAYSIZE(szPrevEntry));
  1499. {
  1500. int iItemIndex = 0, i = 0;
  1501. int iLastItemIndex = -1;
  1502. int nItemCount;
  1503. if(dwRange == rangeSelected)
  1504. nItemCount = ListView_GetSelectedCount(hWndLV);
  1505. else if(dwRange == rangeAll)
  1506. nItemCount = ListView_GetItemCount(hWndLV);
  1507. for(i=0;i<nItemCount;i++)
  1508. {
  1509. int j;
  1510. LPTSTR lpszData = NULL;
  1511. ULONG ulMemSize = 0;
  1512. HRESULT hr;
  1513. MEMOINFO MI = {0};
  1514. LPRECIPIENT_INFO lpItem = NULL;
  1515. if(dwRange == rangeSelected)
  1516. iItemIndex = ListView_GetNextItem(hWndLV, iLastItemIndex, LVNI_SELECTED);
  1517. else if(dwRange == rangeAll)
  1518. iItemIndex = i;
  1519. lpItem = GetItemFromLV(hWndLV, iItemIndex);
  1520. if(lpItem)
  1521. {
  1522. if (HR_FAILED( HrGetPropArray( lpIAB,
  1523. NULL,
  1524. lpItem->cbEntryID,
  1525. lpItem->lpEntryID,
  1526. MAPI_UNICODE,
  1527. &ulcPropCount,
  1528. &lpPropArray) ) )
  1529. {
  1530. DebugPrintError(( TEXT("HrGetPropArray failed\n")));
  1531. goto out;
  1532. }
  1533. GetMemoInfoStruct(lpIAB, ulcPropCount, lpPropArray, dwStyle, &MI, bCurrentSortIsByLastName);
  1534. SetPrintDialogMsg(0, idsPrintFormattingName, MI.lpsz[memoTitleName]);
  1535. // Poll the cancel dialog to see if the user wants to cancel
  1536. if (!ppi->pfnAbortProc(ppi->hdcPrn, 0))
  1537. {
  1538. FreeMemoInfoStruct(&MI);
  1539. DebugPrintError(( TEXT("User canceled printing ...\n")));
  1540. goto out;
  1541. }
  1542. switch(dwStyle)
  1543. {
  1544. case styleMemo:
  1545. WABStyleMemo(hWndRE, MI);
  1546. break;
  1547. case styleBusinessCard:
  1548. WABStyleBusinessCard(hWndRE, MI);
  1549. break;
  1550. case stylePhoneList:
  1551. WABStylePhoneList(hWndRE, MI, szPrevEntry, ARRAYSIZE(szPrevEntry));
  1552. //if(lpszPrevEntry)
  1553. // LocalFreeAndNull(&lpszPrevEntry);
  1554. //lpszPrevEntry = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*(lstrlen(MI.lpsz[memoTitleName])+1));
  1555. //if(!lpszPrevEntry)
  1556. //goto out;
  1557. //lstrcpy(lpszPrevEntry, MI.lpsz[memoTitleName]);
  1558. break;
  1559. }
  1560. FreeMemoInfoStruct(&MI);
  1561. }
  1562. if(lpPropArray)
  1563. MAPIFreeBuffer(lpPropArray);
  1564. lpPropArray = NULL;
  1565. // fill in some space between multiple contacts
  1566. {
  1567. int numBreaks = (dwStyle == stylePhoneList) ? 1 : 4;
  1568. for(j=0;j<numBreaks;j++)
  1569. AppendText(hWndRE, szCRLF);
  1570. }
  1571. if(dwRange == rangeSelected)
  1572. iLastItemIndex = iItemIndex;
  1573. } // for i ...
  1574. }
  1575. bRet = TRUE;
  1576. out:
  1577. //if(lpszPrevEntry)
  1578. // LocalFreeAndNull(&lpszPrevEntry);
  1579. if(lpPropArray)
  1580. MAPIFreeBuffer(lpPropArray);
  1581. return bRet;
  1582. }
  1583. /*
  1584. * ScPrintBody
  1585. *
  1586. * Purpose:
  1587. * To print the body of each message
  1588. *
  1589. * Arguments:
  1590. * ppi Pointer to the PRINTINFO structure
  1591. * cyGap Gap above message text
  1592. //* pmsg Pointer to message whose body is to be printed
  1593. * hwndRE Pre-rendered body
  1594. * lpszTxt Txt to print
  1595. *
  1596. * Returns:
  1597. * SCODE indicating success or failure
  1598. *
  1599. */
  1600. SCODE ScPrintBody(PRINTINFO * ppi, int cyGap)
  1601. {
  1602. SCODE sc=S_OK;
  1603. RECT rcSep;
  1604. FORMATRANGE fr;
  1605. HWND hwndRE = ppi->hwndRE;
  1606. int ifrm;
  1607. LONG lTextLength = 0;
  1608. LONG lTextPrinted = 0;
  1609. DebugPrintTrace(( TEXT("ScPrintBody\n")));
  1610. // Put a gap between the fields the message text
  1611. rcSep = ppi->rcBand;
  1612. if (rcSep.top + cyGap > ppi->yFooter)
  1613. {
  1614. // Adding the gap will go past the page. Just go to the next page
  1615. sc = ScGetNextBand(ppi, TRUE);
  1616. }
  1617. else
  1618. {
  1619. // Keep on getting a band till the bottom of the band passes the gap
  1620. while (rcSep.top + cyGap > ppi->rcBand.bottom)
  1621. if ((sc = ScGetNextBand(ppi, TRUE)) != S_OK)
  1622. goto CleanUp;
  1623. // Adjust the band so that we don't damage the gap
  1624. ppi->rcBand.top += cyGap + 1;
  1625. }
  1626. #ifdef DEBUG_PRINTMSGS
  1627. InvalidateRect(ppi->hwndRE, NULL, TRUE);
  1628. UpdateWindow(ppi->hwndRE);
  1629. #endif
  1630. // Format the text for printing
  1631. fr.hdc = ppi->hdcPrn;
  1632. fr.hdcTarget = 0;
  1633. fr.rcPage.left = fr.rcPage.top = 0;
  1634. fr.rcPage.right = (int)LPixelsToTwips(ppi->sizePage.cx, ppi->sizeInch.cx);
  1635. fr.rcPage.bottom = (int)LPixelsToTwips(ppi->sizePage.cy, ppi->sizeInch.cy);
  1636. fr.chrg.cpMin = 0;
  1637. fr.chrg.cpMax = -1;
  1638. lTextLength = (LONG) SendMessage(hwndRE, WM_GETTEXTLENGTH, 0, 0);
  1639. lTextPrinted = 0;
  1640. // Handle no body case
  1641. if (lTextLength <= 0)
  1642. goto CleanUp;
  1643. // tell RichEdit not to erase the background before rendering text
  1644. SetBkMode(fr.hdc, TRANSPARENT);
  1645. do
  1646. {
  1647. fr.chrg.cpMin = lTextPrinted;
  1648. // Tell format range where to render to
  1649. fr.rc.top = (int) LPixelsToTwips(ppi->rcBand.top, ppi->sizeInch.cy);
  1650. fr.rc.left = (int) LPixelsToTwips(ppi->rcBand.left, ppi->sizeInch.cx);
  1651. fr.rc.right = (int) LPixelsToTwips(ppi->rcBand.right, ppi->sizeInch.cx);
  1652. fr.rc.bottom = (int) LPixelsToTwips(min(ppi->rcBand.bottom, ppi->yFooter), ppi->sizeInch.cy);
  1653. // Go draw it
  1654. DebugPrintTrace(( TEXT("Rendering\r\n")));
  1655. lTextPrinted = (LONG) SendMessage(hwndRE, EM_FORMATRANGE, TRUE,(LPARAM) &fr);
  1656. //TextOut(ppi->hdcPrn, fr.rc.left, fr.rc.top, lpszTxt, lstrlen(lpszTxt));
  1657. // weird bug with RichEdit20 .. lTextPrinted is actually reduces in size
  1658. // Another weird bug ... lTextPrinted is never incremented. [PaulHi]
  1659. if(lTextPrinted <= fr.chrg.cpMin)
  1660. break;
  1661. } while (lTextPrinted > 0 &&
  1662. lTextPrinted < lTextLength &&
  1663. (sc = ScGetNextBand(ppi, TRUE)) == S_OK);
  1664. //$ Raid 1137: Need to clear out the cached font characteristics
  1665. fr.chrg.cpMin = fr.chrg.cpMax + 1;
  1666. //SendMessage(hwndRE, EM_FORMATRANGE, 0, 0);
  1667. // Don't damage what we have just printed
  1668. ppi->rcBand.top = NTwipsToPixels(fr.rc.bottom, ppi->sizeInch.cy);
  1669. CleanUp:
  1670. DebugPrintTrace(( TEXT("ScPrintBody:%d\n"), sc));
  1671. return sc;
  1672. }
  1673. /*
  1674. * ScPrintMessage
  1675. *
  1676. * Purpose:
  1677. * To print the header and body of a message
  1678. *
  1679. * Arguments:
  1680. * ppi Pointer to the PRINTINFO structure
  1681. * pmsg Pointer to the message which needs its header
  1682. * to be printed.
  1683. * hwndRE Pre-rendered body
  1684. * phi Message header info
  1685. *
  1686. * Returns:
  1687. * SCODE indicating success or failure
  1688. *
  1689. */
  1690. SCODE ScPrintMessage(PRINTINFO * ppi, HWND hWndRE)
  1691. {
  1692. RECT rcExt;
  1693. RECT rcSep;
  1694. HFONT hfontOld = NULL;
  1695. HBRUSH hbrushOld = NULL;
  1696. HPEN hpenOld = NULL;
  1697. SIZE sizeExt;
  1698. int cyHeader;
  1699. SCODE sc = S_OK;
  1700. PARAFORMAT pf = { 0 };
  1701. pf.cbSize = sizeof(PARAFORMAT);
  1702. // If we currently have no band, get the next band
  1703. if (IsRectEmpty(&ppi->rcBand) &&
  1704. (sc = ScGetNextBand(ppi, TRUE)) != S_OK)
  1705. goto CleanUp;
  1706. // Determine how much room we need for the header string and separator
  1707. hfontOld = (HFONT)SelectObject(ppi->hdcPrn, ppi->hfontSep);
  1708. hbrushOld = (HBRUSH)SelectObject(ppi->hdcPrn, GetStockObject(BLACK_BRUSH));
  1709. hpenOld = (HPEN)SelectObject(ppi->hdcPrn, GetStockObject(BLACK_PEN));
  1710. // Find out how much space our text take will take
  1711. GetTextExtentPoint(ppi->hdcPrn, ppi->szHeader, lstrlen(ppi->szHeader),
  1712. &sizeExt);
  1713. cyHeader = 2 * sizeExt.cy + 1 + (cySepFontSize(ppi) / 4);
  1714. // Check if enough room on page. Move to the next page as needed
  1715. if (ppi->rcBand.top + cyHeader > ppi->yFooter)
  1716. {
  1717. // No more room on this page, see if it'll fit on the next page
  1718. if (ppi->rcMargin.top + cyHeader > ppi->yFooter)
  1719. {
  1720. DebugPrintTrace(( TEXT("Header too big for any page.\n")));
  1721. goto CleanUp;
  1722. }
  1723. // Go on to the next page
  1724. if ((sc = ScPrintRestOfPage(ppi, TRUE)) != S_OK)
  1725. goto CleanUp;
  1726. }
  1727. // Calculate the rectangle that our header will take up
  1728. rcExt = ppi->rcBand;
  1729. rcExt.bottom = rcExt.top + cyHeader;
  1730. rcSep = rcExt;
  1731. rcSep.top += sizeExt.cy;
  1732. rcSep.bottom = rcSep.top + (cySepFontSize(ppi) / 4);
  1733. rcSep.right = rcSep.left + sizeExt.cx;
  1734. // Draw the text and separator
  1735. TextOut(ppi->hdcPrn, rcExt.left, rcExt.top, ppi->szHeader,
  1736. lstrlen(ppi->szHeader));
  1737. Rectangle(ppi->hdcPrn, rcSep.left, rcSep.top, rcSep.right, rcSep.bottom);
  1738. MoveToEx(ppi->hdcPrn, rcSep.right, rcSep.top, NULL);
  1739. LineTo(ppi->hdcPrn, rcExt.right, rcSep.top);
  1740. rcExt.top = rcExt.bottom + 5;
  1741. /***/
  1742. // Adjust the band so that we don't damage the header
  1743. ppi->rcBand.top = rcExt.bottom + 1;
  1744. // Create a header in a richedit control
  1745. pf.dwMask = PFM_STARTINDENT | PFM_RIGHTINDENT | PFM_ALIGNMENT |
  1746. PFM_OFFSET | PFM_TABSTOPS;
  1747. pf.dxOffset = LGetHeaderIndent();
  1748. pf.cTabCount = 1;
  1749. pf.rgxTabs[0] = pf.dxOffset;
  1750. pf.wAlignment = PFA_LEFT;
  1751. sc = ScPrintBody(ppi, sizeExt.cy);
  1752. /***/
  1753. CleanUp:
  1754. if (hfontOld != NULL)
  1755. SelectObject(ppi->hdcPrn, hfontOld);
  1756. if (hbrushOld != NULL)
  1757. SelectObject(ppi->hdcPrn, hbrushOld);
  1758. if (hpenOld != NULL)
  1759. SelectObject(ppi->hdcPrn, hpenOld);
  1760. return sc;
  1761. }
  1762. #ifdef WIN16
  1763. typedef UINT (CALLBACK *LPPRINTHOOKPROC) (HWND, UINT, WPARAM, LPARAM);
  1764. typedef UINT (CALLBACK *LPSETUPHOOKPROC) (HWND, UINT, WPARAM, LPARAM);
  1765. #endif
  1766. #ifdef WIN16
  1767. typedef UINT (CALLBACK *LPPRINTHOOKPROC) (HWND, UINT, WPARAM, LPARAM);
  1768. typedef UINT (CALLBACK *LPSETUPHOOKPROC) (HWND, UINT, WPARAM, LPARAM);
  1769. #endif
  1770. //$$////////////////////////////////////////////////////////////////////////////////////////////
  1771. //
  1772. //
  1773. // SetPrintDlgExStruct - Fills in the default PDEX values
  1774. //
  1775. // hWnd - HWND of parent dialog
  1776. // PD - PrintDLG struct
  1777. // hWndLV - HWND of listView to print from - if there are no selections in the list view,
  1778. // the selections option is turned off in the print dialog
  1779. //
  1780. ////////////////////////////////////////////////////////////////////////////////////////////////
  1781. void SetPrintDlgExStruct(HWND hWnd, PRINTDLGEX * lpPD, HWND hWndLV, LPWABPRINTDIALOGCALLBACK lpWABPCO)
  1782. {
  1783. // set up the print dialog stuff
  1784. // Call the common print dialog to get the default
  1785. PRINTDLGEX pd={0};
  1786. pd.lStructSize = sizeof(PRINTDLGEX);
  1787. pd.hwndOwner = hWnd;
  1788. pd.hDevMode = (HANDLE) NULL;
  1789. pd.hDevNames = (HANDLE) NULL;
  1790. pd.hDC = (HDC) NULL;
  1791. pd.Flags = PD_RETURNDC | // return PrintDC
  1792. PD_DISABLEPRINTTOFILE |
  1793. PD_ENABLEPRINTTEMPLATE |
  1794. PD_HIDEPRINTTOFILE |
  1795. PD_NOPAGENUMS;
  1796. pd.Flags2 = 0;
  1797. if(ListView_GetSelectedCount(hWndLV) > 0)
  1798. pd.Flags |= PD_SELECTION;
  1799. else
  1800. pd.Flags |= PD_NOSELECTION;
  1801. pd.nCopies = 1;
  1802. pd.hInstance = hinstMapiX;
  1803. pd.lpPrintTemplateName = MAKEINTRESOURCE(IDD_DIALOG_PRINTDLGEX); //(LPSTR) NULL;
  1804. pd.lpCallback = (LPUNKNOWN)lpWABPCO; // app callback interface
  1805. pd.nPropertyPages = 0;
  1806. pd.lphPropertyPages = NULL;
  1807. pd.nStartPage = START_PAGE_GENERAL;
  1808. *lpPD = pd;
  1809. return;
  1810. }
  1811. //$$////////////////////////////////////////////////////////////////////////////////////////////
  1812. //
  1813. //
  1814. // SetPrintDlgStruct - Fills in the default PD values
  1815. //
  1816. // hWnd - HWND of parent dialog
  1817. // PD - PrintDLG struct
  1818. // hWndLV - HWND of listView to print from - if there are no selections in the list view,
  1819. // the selections option is turned off in the print dialog
  1820. //
  1821. ////////////////////////////////////////////////////////////////////////////////////////////////
  1822. void SetPrintDlgStruct(HWND hWnd, PRINTDLG * lpPD, HWND hWndLV, LPARAM lCustData)
  1823. {
  1824. // set up the print dialog stuff
  1825. // Call the common print dialog to get the default
  1826. PRINTDLG pd={0};
  1827. pd.lStructSize = sizeof(PRINTDLG);
  1828. pd.hDevMode = (HANDLE) NULL;
  1829. pd.hDevNames = (HANDLE) NULL;
  1830. pd.Flags = PD_RETURNDC | // return PrintDC
  1831. PD_NOPAGENUMS | // Disable Page number option
  1832. PD_DISABLEPRINTTOFILE |
  1833. PD_HIDEPRINTTOFILE |
  1834. PD_ENABLEPRINTHOOK |
  1835. PD_ENABLEPRINTTEMPLATE;
  1836. if(ListView_GetSelectedCount(hWndLV) > 0)
  1837. pd.Flags |= PD_SELECTION;
  1838. else
  1839. pd.Flags |= PD_NOSELECTION;
  1840. pd.hwndOwner = hWnd;
  1841. pd.hDC = (HDC) NULL;
  1842. pd.nFromPage = 1;
  1843. pd.nToPage = 1;
  1844. pd.nMinPage = 0;
  1845. pd.nMaxPage = 0;
  1846. pd.nCopies = 1;
  1847. pd.hInstance = hinstMapiX;
  1848. pd.lCustData = lCustData;
  1849. pd.lpfnPrintHook = (LPPRINTHOOKPROC) &fnPrintDialogProc; //NULL;
  1850. pd.lpfnSetupHook = (LPSETUPHOOKPROC) NULL;
  1851. pd.lpPrintTemplateName = MAKEINTRESOURCE(IDD_DIALOG_PRINTDLGORD); //(LPSTR) NULL;
  1852. pd.lpSetupTemplateName = (LPTSTR) NULL;
  1853. pd.hPrintTemplate = (HANDLE) NULL;
  1854. pd.hSetupTemplate = (HANDLE) NULL;
  1855. *lpPD = pd;
  1856. return;
  1857. }
  1858. /*
  1859. -
  1860. - HrGetPrintData
  1861. -
  1862. Determines whether to show the new print dialog or the old print dialog
  1863. Fills in all the structures appropriately and returns the values we
  1864. care about such as nCopies, Print style, etc
  1865. *
  1866. *
  1867. */
  1868. HRESULT HrGetPrintData(LPADRBOOK lpAdrBook, HWND hWndParent, HWND hWndLV,
  1869. HDC * lphdcPrint, int * lpnCopies,
  1870. DWORD * lpdwStyle, DWORD * lpdwRange)
  1871. {
  1872. DWORD dwSelectedStyle = styleMemo;
  1873. HRESULT hr = S_OK;
  1874. LPWABPRINTDIALOGCALLBACK lpWABPCO = NULL;
  1875. PRINTDLG pd = {0};
  1876. PRINTDLGEX pdEx = {0};
  1877. // Test for presence of NT5 PrintDlgEx
  1878. if(!HR_FAILED(hr = PrintDlgEx(NULL)))
  1879. {
  1880. if(HR_FAILED(hr = HrCreatePrintCallbackObject((LPIAB)lpAdrBook,&lpWABPCO,dwSelectedStyle)))
  1881. goto out;
  1882. if(!lpWABPCO)
  1883. {
  1884. hr = E_FAIL;
  1885. goto out;
  1886. }
  1887. SetPrintDlgExStruct(hWndParent, &pdEx, hWndLV, lpWABPCO);
  1888. if(HR_FAILED(hr = PrintDlgEx(&pdEx)))
  1889. {
  1890. DebugTrace( TEXT("PrintDlgEx returns 0x%.8x\n"),hr);
  1891. // #98841 Millenium returns fail in this case, but for PrintDlgEx(NULL) it returns S_OK (YST)
  1892. goto doOldPrint;
  1893. }
  1894. *lphdcPrint = pdEx.hDC;
  1895. *lpnCopies = pdEx.nCopies;
  1896. *lpdwStyle = lpWABPCO->dwSelectedStyle;
  1897. if (pdEx.Flags & PD_SELECTION)
  1898. *lpdwRange = rangeSelected;
  1899. else
  1900. *lpdwRange = rangeAll;
  1901. }
  1902. else
  1903. {
  1904. doOldPrint:
  1905. SetPrintDlgStruct(hWndParent, &pd, hWndLV, (LPARAM) &dwSelectedStyle);
  1906. // Show the print dialog
  1907. if(!PrintDlg(&pd))
  1908. goto out;
  1909. *lphdcPrint = pd.hDC;
  1910. *lpnCopies = pd.nCopies;
  1911. *lpdwStyle = dwSelectedStyle;
  1912. if (pd.Flags & PD_SELECTION)
  1913. *lpdwRange = rangeSelected;
  1914. else
  1915. *lpdwRange = rangeAll;
  1916. hr = S_OK;
  1917. }
  1918. out:
  1919. if(lpWABPCO)
  1920. lpWABPCO->lpVtbl->Release(lpWABPCO);
  1921. return hr;
  1922. }
  1923. //$$////////////////////////////////////////////////////////////////////////////////
  1924. //
  1925. // HrPrintItems - Prints selected contacts
  1926. // Prints the contents of the address book
  1927. // Pops up a dialog that lets user select what he wants to print
  1928. // Options are (or will be)
  1929. // All or selected
  1930. // Style - memo, business, or phone book
  1931. //
  1932. // Items are printed using the current sort style in the list view
  1933. //
  1934. //////////////////////////////////////////////////////////////////////////////////////
  1935. HRESULT HrPrintItems( HWND hWnd,
  1936. LPADRBOOK lpAdrBook,
  1937. HWND hWndLV,
  1938. BOOL bCurrentSortisByLastName)
  1939. {
  1940. HRESULT hr = E_FAIL;
  1941. HWND hWndRE = NULL; // we'll do our formating in a riceh edit control and use that for printing
  1942. PRINTINFO *ppi=0;
  1943. BOOL fStartedDoc = FALSE;
  1944. BOOL fStartedPage= FALSE;
  1945. DOCINFO docinfo={0};
  1946. HCURSOR hOldCur = NULL;
  1947. int i,nCode;
  1948. HINSTANCE hRELib = NULL;
  1949. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  1950. LPIAB lpIAB = (LPIAB)lpAdrBook;
  1951. HDC hdcPrint = NULL;
  1952. int nCopies = 0;
  1953. DWORD dwStyle;
  1954. DWORD dwRange;
  1955. // Double check if there are any print extensions that we need to accomodate
  1956. //
  1957. if(bCheckForPrintExtensions(NULL, 0))
  1958. {
  1959. // Found a print extension
  1960. hr = HrUseWABPrintExtension(hWnd, lpAdrBook, hWndLV);
  1961. goto out;
  1962. }
  1963. if(!(ppi = LocalAlloc(LMEM_ZEROINIT, sizeof(PRINTINFO))))
  1964. goto out;
  1965. ppi->hwndDlg = hWnd;
  1966. if(HR_FAILED(HrGetPrintData(lpAdrBook, hWnd, hWndLV, &hdcPrint, &nCopies, &dwStyle, &dwRange)))
  1967. goto out;
  1968. if(!hdcPrint)
  1969. goto out;
  1970. // Take care of zilch copies
  1971. //
  1972. // Actually it seems that this number is meaningless if the printer can handle multiple
  1973. // copies. If the printer can't handle multiple copies, we will get info in this number.
  1974. //
  1975. if(!nCopies)
  1976. nCopies = 1;
  1977. ppi->hdcPrn = hdcPrint;
  1978. // Create a RichEdit control in which we will do our formatting
  1979. hRELib = LoadLibrary( TEXT("riched20.dll"));
  1980. if(!hRELib)
  1981. {
  1982. hRELib = LoadLibrary( TEXT("riched32.dll"));
  1983. s_bUse20 = FALSE;
  1984. }
  1985. //IF_WIN16(hRELib = LoadLibrary( TEXT("riched.dll"));)
  1986. if(!hRELib)
  1987. goto out;
  1988. hWndRE = CreateWindowEx(0,
  1989. (s_bUse20 ? RICHEDIT_CLASS : TEXT("RichEdit")),
  1990. TEXT(""),WS_CHILD | ES_MULTILINE,
  1991. CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
  1992. hWnd,(HMENU) NULL,hinstMapiX,NULL);
  1993. if (!hWndRE)
  1994. goto out;
  1995. //////////////////////////
  1996. {
  1997. CHARFORMAT cf = {0};
  1998. TCHAR rgch[CCHMAX_STRINGRES];
  1999. DWORD dwCodepage ;
  2000. CHARSETINFO rCharsetInfo;
  2001. LOGFONT lfSystem;
  2002. BOOL bNeedLargeFont = FALSE;
  2003. cf.cbSize = sizeof(cf);
  2004. cf.dwMask = CFM_FACE;
  2005. SendMessage(hWndRE, EM_GETCHARFORMAT, (WPARAM) TRUE, (LPARAM) &cf);
  2006. if(LoadString(hinstMapiX, idsDefaultFontFace, rgch, ARRAYSIZE(rgch)))
  2007. StrCpyN(cf.szFaceName, rgch, ARRAYSIZE(cf.szFaceName));
  2008. else
  2009. StrCpyN(cf.szFaceName, szDefFont, ARRAYSIZE(cf.szFaceName));
  2010. // [a-msadek] bug#56478
  2011. // Arail does not support Thai so as all other base fonts
  2012. // The best way to determine the OS language is from system font charset
  2013. if(GetObject(GetStockObject(SYSTEM_FONT), sizeof(lfSystem), (LPVOID)&lfSystem))
  2014. {
  2015. if (lfSystem.lfCharSet == THAI_CHARSET)
  2016. {
  2017. StrCpyN(cf.szFaceName, szThaiDefFont, ARRAYSIZE(cf.szFaceName));
  2018. // Thai Font sizes are always smaller than English as the vowl and tone
  2019. // markes consumes some of the font height
  2020. bNeedLargeFont = TRUE;
  2021. }
  2022. }
  2023. // bug #53058 - set correct CharSet info for Eastern European
  2024. dwCodepage = GetACP();
  2025. // Get GDI charset info
  2026. if ( dwCodepage != 1252 && TranslateCharsetInfo((LPDWORD) IntToPtr(dwCodepage) , &rCharsetInfo, TCI_SRCCODEPAGE))
  2027. cf.bCharSet = (BYTE) rCharsetInfo.ciCharset;
  2028. SendMessage(hWndRE, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM) &cf);
  2029. if(bNeedLargeFont)
  2030. {
  2031. ReduceFontCmd(hWndRE, FALSE, 80, TRUE);
  2032. }
  2033. }
  2034. //////////////////////////
  2035. // At the top of the print job, print the header with the users name or with
  2036. // the default TEXT("Windows Address Book") title
  2037. {
  2038. TCHAR szHead[MAX_PATH];
  2039. DWORD dwLen = ARRAYSIZE(szHead);
  2040. SCODE sc;
  2041. *szHead = '\0';
  2042. if(bIsThereACurrentUser(lpIAB) && lstrlen(lpIAB->szProfileName))
  2043. StrCpyN(szHead, lpIAB->szProfileName, ARRAYSIZE(szHead));
  2044. else
  2045. GetUserName(szHead, &dwLen);
  2046. if(!lstrlen(szHead))
  2047. LoadString(hinstMapiX, IDS_ADDRBK_CAPTION, szHead, ARRAYSIZE(szHead));
  2048. if (( sc = ScInitPrintInfo( ppi, hWnd, szHead, &g_rcBorder, hWndRE)) != S_OK)
  2049. goto out;
  2050. }
  2051. // While the printing is in progress, we dont want the user to mess with the
  2052. // listview selection otherwise the print job will print the wrong entries
  2053. // Hence we disable this window (since the print cancel dialog is really a modeless dialog)
  2054. EnableWindow(hWnd, FALSE);
  2055. CreateShowAbortDialog(hWnd, 0, 0, ListView_GetSelectedCount(hWndLV), 0);
  2056. // Format the prop data into the Rich Edit Control
  2057. if(!WABFormatData(lpAdrBook, hWnd, hWndRE, hWndLV, dwRange, dwStyle, ppi, bCurrentSortisByLastName))
  2058. goto out;
  2059. if(bTimeToAbort())
  2060. goto out;
  2061. for(i=0;i<nCopies;i++)
  2062. {
  2063. TCHAR szBuf[MAX_PATH];
  2064. LoadString(hinstMapiX, idsPrintDocTitle, szBuf, ARRAYSIZE(szBuf));
  2065. docinfo.cbSize = sizeof(docinfo);
  2066. docinfo.lpszDocName = szBuf;
  2067. docinfo.lpszOutput = NULL;
  2068. SetMapMode(hdcPrint, MM_TEXT);
  2069. // Set the abort procedure
  2070. if ((nCode=SetAbortProc(ppi->hdcPrn, ppi->pfnAbortProc)) <= 0)
  2071. {
  2072. hr = E_FAIL;
  2073. break;
  2074. }
  2075. if(bTimeToAbort())
  2076. goto out;
  2077. // Start a print job
  2078. if (StartDoc(ppi->hdcPrn, &docinfo) <= 0)
  2079. {
  2080. DebugPrintError(( TEXT("StartDoc failed: %d\n"), GetLastError()));
  2081. goto out;
  2082. }
  2083. fStartedDoc = TRUE;
  2084. //StartPage(pd.hDC);
  2085. if(bTimeToAbort())
  2086. goto out;
  2087. // Go on and print the message!
  2088. if (ScPrintMessage(ppi, hWndRE) != S_OK)
  2089. goto out;
  2090. if(bTimeToAbort())
  2091. goto out;
  2092. // End the page
  2093. if(ScGetNextBand( ppi, FALSE) != S_OK)
  2094. goto out;
  2095. if(bTimeToAbort())
  2096. goto out;
  2097. // Finish up the print job if it had been started
  2098. if (fStartedDoc)
  2099. {
  2100. EndDoc(ppi->hdcPrn);
  2101. fStartedDoc = FALSE;
  2102. }
  2103. }
  2104. hr = hrSuccess;
  2105. out:
  2106. if(hWndRE)
  2107. {
  2108. SendMessage(hWndRE, WM_SETTEXT, 0, (LPARAM)szEmpty);
  2109. SendMessage(hWndRE, WM_CLEAR, 0, 0);
  2110. }
  2111. if(bTimeToAbort())
  2112. {
  2113. hr = MAPI_E_USER_CANCEL;
  2114. pt_bPrintUserAbort = FALSE;
  2115. }
  2116. // Re-enable the window and ensure it stays put
  2117. EnableWindow(hWnd, TRUE);
  2118. //SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOOWNERZORDER);
  2119. CloseAbortDlg();
  2120. // Finish up the print job if it had been started
  2121. if (fStartedDoc)
  2122. EndDoc(ppi->hdcPrn);
  2123. // Get rid of our Rich Edit control
  2124. if (hWndRE)
  2125. DestroyWindow(hWndRE);
  2126. if(hOldCur)
  2127. SetCursor(hOldCur);
  2128. if(ppi)
  2129. {
  2130. if(ppi->hfontPlain)
  2131. DeleteObject(ppi->hfontPlain);
  2132. if(ppi->hfontBold)
  2133. DeleteObject(ppi->hfontBold);
  2134. if(ppi->hfontSep)
  2135. DeleteObject(ppi->hfontSep);
  2136. LocalFreeAndNull(&ppi);
  2137. }
  2138. if(hRELib)
  2139. FreeLibrary((HMODULE) hRELib);
  2140. return hr;
  2141. }
  2142. /*
  2143. * Handles the WM_INITDIALOG for both PrintDlg and PrintDlgEx
  2144. */
  2145. BOOL bHandleWMInitDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, LPDWORD lpdwStyle)
  2146. {
  2147. DWORD dwStyle = lpdwStyle ? *lpdwStyle : styleMemo;
  2148. int nID;
  2149. switch (dwStyle)
  2150. {
  2151. case styleBusinessCard:
  2152. nID = IDC_PRINT_RADIO_CARD;
  2153. break;
  2154. case stylePhoneList:
  2155. nID = IDC_PRINT_RADIO_PHONELIST;
  2156. break;
  2157. default:
  2158. case styleMemo:
  2159. nID = IDC_PRINT_RADIO_MEMO; //default
  2160. break;
  2161. }
  2162. CheckRadioButton( hDlg, IDC_PRINT_RADIO_MEMO, IDC_PRINT_RADIO_PHONELIST, nID);
  2163. SetFocus(hDlg);
  2164. return 0;
  2165. }
  2166. /*
  2167. * Handles the WM_COMMAND for both PrintDlg and PrintDlgEx
  2168. */
  2169. BOOL bHandleWMCommand(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, LPDWORD lpdwStyle )
  2170. {
  2171. switch (GET_WM_COMMAND_ID(wParam,lParam))
  2172. {
  2173. case IDC_PRINT_RADIO_MEMO:
  2174. //lpPD->lCustData = (DWORD) styleMemo;
  2175. *lpdwStyle = (DWORD) styleMemo;
  2176. break;
  2177. case IDC_PRINT_RADIO_CARD:
  2178. //lpPD->lCustData = (DWORD) styleBusinessCard;
  2179. *lpdwStyle = (DWORD) styleBusinessCard;
  2180. break;
  2181. case IDC_PRINT_RADIO_PHONELIST:
  2182. //lpPD->lCustData = (DWORD) stylePhoneList;
  2183. *lpdwStyle = (DWORD) stylePhoneList;
  2184. break;
  2185. }
  2186. return 0;
  2187. }
  2188. /*
  2189. * Handles the WM_HELP for both PrintDlg and PrintDlgEx
  2190. */
  2191. BOOL bHandleWMHelp(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, LPDWORD lpdwStyle )
  2192. {
  2193. int id = ((LPHELPINFO)lParam)->iCtrlId;
  2194. if( id == IDC_PRINT_FRAME_STYLE ||
  2195. id == IDC_PRINT_RADIO_MEMO ||
  2196. id == IDC_PRINT_RADIO_CARD ||
  2197. id == IDC_PRINT_RADIO_PHONELIST)
  2198. {
  2199. WABWinHelp(((LPHELPINFO)lParam)->hItemHandle,
  2200. g_szWABHelpFileName,
  2201. HELP_WM_HELP,
  2202. (DWORD_PTR)(LPSTR) rgPrintHelpIDs );
  2203. }
  2204. return FALSE;
  2205. }
  2206. /*
  2207. * Handles the WM_CONTEXTMENU for both PrintDlg and PrintDlgEx
  2208. */
  2209. BOOL bHandleWMContextMenu(HWND hDlg, UINT message, WPARAM wParam,LPARAM lParam,LPDWORD lpdwStyle )
  2210. {
  2211. HWND hwnd = (HWND) wParam;
  2212. if( hwnd == GetDlgItem(hDlg, IDC_PRINT_FRAME_STYLE) ||
  2213. hwnd == GetDlgItem(hDlg, IDC_PRINT_RADIO_MEMO) ||
  2214. hwnd == GetDlgItem(hDlg, IDC_PRINT_RADIO_CARD) ||
  2215. hwnd == GetDlgItem(hDlg, IDC_PRINT_RADIO_PHONELIST) )
  2216. {
  2217. WABWinHelp((HWND) wParam,
  2218. g_szWABHelpFileName,
  2219. HELP_CONTEXTMENU,
  2220. (DWORD_PTR)(LPVOID) rgPrintHelpIDs );
  2221. }
  2222. return FALSE;
  2223. }
  2224. //$$*****************************************************************
  2225. //
  2226. // FUNCTION: fnPrintDialogProc
  2227. //
  2228. // PURPOSE: Printer dialog hook procedure
  2229. //
  2230. // We have modified the CommDlg print template with the
  2231. // WAB print styles.
  2232. // This is a hook procedure that takes care of our
  2233. // newly added controls
  2234. //
  2235. // When WM_INITDIALOG is called, the lParam contains a pointer to the
  2236. // PRINTDLG structure controling the print setup dialog
  2237. //
  2238. //*******************************************************************
  2239. INT_PTR CALLBACK fnPrintDialogProc( HWND hDlg,
  2240. UINT message,
  2241. WPARAM wParam,
  2242. LPARAM lParam)
  2243. {
  2244. LPDWORD lpdwStyle = (LPDWORD) GetWindowLongPtr(hDlg, DWLP_USER);
  2245. switch(message)
  2246. {
  2247. case WM_INITDIALOG:
  2248. {
  2249. LPPRINTDLG lpPD = (LPPRINTDLG) lParam;
  2250. #ifdef WIN16
  2251. // Strange situation here. If I don't create edt1 and edt2 which are used for page range, entire print dialog work incorrectly.
  2252. // So I just add two controls(edt1 and edt2) and hide those here.
  2253. ShowWindow(GetDlgItem(hDlg, edt1), SW_HIDE);
  2254. ShowWindow(GetDlgItem(hDlg, edt2), SW_HIDE);
  2255. #endif
  2256. if(lpPD)
  2257. {
  2258. lpdwStyle = (LPDWORD) lpPD->lCustData;
  2259. SetWindowLongPtr(hDlg, DWLP_USER, (LPARAM)lpdwStyle); //Save this for future reference
  2260. return bHandleWMInitDialog(hDlg,message,wParam,lParam,lpdwStyle);
  2261. }
  2262. }
  2263. SetFocus(hDlg);
  2264. return 0;
  2265. break;
  2266. case WM_COMMAND:
  2267. if(lpdwStyle)
  2268. return bHandleWMCommand(hDlg,message,wParam,lParam,lpdwStyle);
  2269. break;
  2270. case WM_HELP:
  2271. return bHandleWMHelp(hDlg,message,wParam,lParam,lpdwStyle);
  2272. break;
  2273. #ifndef WIN16
  2274. case WM_CONTEXTMENU:
  2275. return bHandleWMContextMenu(hDlg,message,wParam,lParam,lpdwStyle);
  2276. break;
  2277. #endif // !WIN16
  2278. default:
  2279. return FALSE;
  2280. break;
  2281. }
  2282. return FALSE;
  2283. }
  2284. /**************************************************************************************************
  2285. * ScInitPrintInfo
  2286. *
  2287. * Purpose:
  2288. * Initialize the fields of a print info structure relevant for
  2289. * the actual printing.
  2290. *
  2291. * Arguments:
  2292. * ppi Pointer to the PRINTINFO structure
  2293. * hwnd The owner of the print dialog box
  2294. * szHeader The string to be printed at the top of each
  2295. * message
  2296. * prcBorder Pointer to a rect whose fields contain the
  2297. * number of twips to use as a margin around the
  2298. * printed text.
  2299. * hWndRE rich edit control in which we will do our formatting
  2300. *
  2301. * Returns:
  2302. * SCODE indicating success or failure
  2303. *
  2304. ***************************************************************************************************/
  2305. SCODE ScInitPrintInfo( PRINTINFO * ppi,
  2306. HWND hwnd,
  2307. LPTSTR szHeader,
  2308. RECT * prcBorder,
  2309. HWND hWndRE)
  2310. {
  2311. SIZE sizeExt;
  2312. LOGFONT logfont = {0};
  2313. HFONT hfontOld;
  2314. TCHAR szT[20];
  2315. SCODE sc = S_OK;
  2316. TCHAR rgch[CCHMAX_STRINGRES];
  2317. // Save handle to our parent window
  2318. ppi->hwnd = hwnd;
  2319. // Save a pointer to our header string
  2320. ppi->szHeader = szHeader;
  2321. // Set up pointer to our abort procedure
  2322. ppi->pfnAbortProc = FAbortProc;
  2323. ppi->hwndRE = hWndRE;
  2324. // Determine the page size in pixels
  2325. ppi->sizePage.cx = GetDeviceCaps(ppi->hdcPrn, HORZRES);
  2326. ppi->sizePage.cy = GetDeviceCaps(ppi->hdcPrn, VERTRES);
  2327. // Exchange 13497: If we have nothing to render to abort now.
  2328. if (!ppi->sizePage.cx || !ppi->sizePage.cy)
  2329. {
  2330. sc = E_FAIL;
  2331. goto CleanUp;
  2332. }
  2333. ///MoveWindow(hWndRE, 0, 0, ppi->sizepage.cx, ppi->sizepage.cy, FALSE);
  2334. // Determine the number of pixels in a logical inch
  2335. ppi->sizeInch.cx = GetDeviceCaps(ppi->hdcPrn, LOGPIXELSX);
  2336. ppi->sizeInch.cy = GetDeviceCaps(ppi->hdcPrn, LOGPIXELSY);
  2337. // Exchange 13497: If we failed to get some info make some assumptions.
  2338. // At worst assume 300 dpi.
  2339. if (!ppi->sizeInch.cx)
  2340. ppi->sizeInch.cx = ppi->sizeInch.cy ? ppi->sizeInch.cy : 300;
  2341. if (!ppi->sizeInch.cy)
  2342. ppi->sizeInch.cy = 300;
  2343. //$ Raid 2667: Determine if we still fit within the page in twips
  2344. if (LPixelsToTwips(ppi->sizePage.cx, ppi->sizeInch.cx) > INT_MAX ||
  2345. LPixelsToTwips(ppi->sizePage.cy, ppi->sizeInch.cy) > INT_MAX)
  2346. {
  2347. sc = E_FAIL;
  2348. goto CleanUp;
  2349. }
  2350. // Set up the margin settings
  2351. ppi->rcMargin.top = NTwipsToPixels(prcBorder->top, ppi->sizeInch.cy);
  2352. ppi->rcMargin.bottom = ppi->sizePage.cy
  2353. - NTwipsToPixels(prcBorder->bottom, ppi->sizeInch.cy);
  2354. if (ppi->rcMargin.bottom < ppi->rcMargin.top)
  2355. {
  2356. // Bottom is above top. Top/Bottom margins ignored
  2357. ppi->rcMargin.top = 0;
  2358. ppi->rcMargin.bottom = ppi->sizePage.cy;
  2359. }
  2360. ppi->rcMargin.left = NTwipsToPixels(prcBorder->left, ppi->sizeInch.cx);
  2361. ppi->rcMargin.right = ppi->sizePage.cx
  2362. - NTwipsToPixels(prcBorder->right, ppi->sizeInch.cx);
  2363. if (ppi->rcMargin.right < ppi->rcMargin.left)
  2364. {
  2365. // Right is left of left. Left/Right margins ignored
  2366. ppi->rcMargin.left = 0;
  2367. ppi->rcMargin.right = ppi->sizePage.cx;
  2368. }
  2369. // Set up the separator font
  2370. //$ Raid 2773: Let user customize separator font
  2371. logfont.lfHeight = - cySepFontSize(ppi);
  2372. logfont.lfWeight = FW_BOLD;
  2373. logfont.lfCharSet = DEFAULT_CHARSET;
  2374. if (LoadString(hinstMapiX, idsDefaultFontFace, rgch, ARRAYSIZE(rgch)))
  2375. StrCpyN(logfont.lfFaceName, rgch, ARRAYSIZE(logfont.lfFaceName));
  2376. else
  2377. StrCpyN(logfont.lfFaceName, szDefFont, ARRAYSIZE(logfont.lfFaceName));
  2378. ppi->hfontSep = CreateFontIndirect(&logfont);
  2379. // Set up common font
  2380. ZeroMemory(&logfont, sizeof(LOGFONT));
  2381. logfont.lfHeight = - 10 * ppi->sizeInch.cy / cPtsPerInch;
  2382. logfont.lfWeight = FW_NORMAL;
  2383. logfont.lfCharSet = DEFAULT_CHARSET;
  2384. if(LoadString(hinstMapiX, idsDefaultFontFace, rgch, ARRAYSIZE(rgch)))
  2385. StrCpyN(logfont.lfFaceName, rgch, ARRAYSIZE(logfont.lfFaceName));
  2386. else
  2387. StrCpyN(logfont.lfFaceName, szDefFont, ARRAYSIZE(logfont.lfFaceName));
  2388. ppi->hfontPlain = CreateFontIndirect(&logfont);
  2389. logfont.lfWeight = FW_BOLD;
  2390. ppi->hfontBold = CreateFontIndirect(&logfont);
  2391. // Calculate where to put the footer
  2392. // Load up the formatting string to use for page numbers
  2393. //LoadString(hinstMapiX, idsFmtPageNumber, ppi->szPageNumber, ARRAYSIZE(ppi->szPageNumber));
  2394. StrCpyN(ppi->szPageNumber, TEXT("%d"), ARRAYSIZE(ppi->szPageNumber));
  2395. wnsprintf(szT, ARRAYSIZE(szT), ppi->szPageNumber, ppi->lPageNumber);
  2396. // Sample the height
  2397. hfontOld = (HFONT)SelectObject(ppi->hdcPrn, ppi->hfontPlain);
  2398. GetTextExtentPoint(ppi->hdcPrn, szT, lstrlen(szT), &sizeExt);
  2399. ppi->yFooter = ppi->rcMargin.bottom - sizeExt.cy;
  2400. SelectObject(ppi->hdcPrn, hfontOld);
  2401. // Make sure our footer doesn't go above the top of the page
  2402. if (ppi->yFooter < ppi->rcMargin.top)
  2403. sc = E_FAIL;
  2404. CleanUp:
  2405. return sc;
  2406. }
  2407. //$$////////////////////////////////////////
  2408. //
  2409. // GetNumberFromStringResource
  2410. //
  2411. ////////////////////////////////////////////
  2412. int GetNumberFromStringResource(int idNumString)
  2413. {
  2414. TCHAR szBuf[MAX_PATH];
  2415. if (LoadString(hinstMapiX, idNumString, szBuf, ARRAYSIZE(szBuf)))
  2416. return my_atoi(szBuf);
  2417. else
  2418. return 0;
  2419. }
  2420. /*--------------------------------------------------------------------------------------------------*/
  2421. /*--IPrintDialogCallback stuff----------------------------------------------------------------------*/
  2422. /*--Special stuff for the new NT5 Print Dialog------------------------------------------------------*/
  2423. /*--------------------------------------------------------------------------------------------------*/
  2424. WAB_PRINTDIALOGCALLBACK_Vtbl vtblWABPRINTDIALOGCALLBACK = {
  2425. VTABLE_FILL
  2426. WAB_PRINTDIALOGCALLBACK_QueryInterface,
  2427. WAB_PRINTDIALOGCALLBACK_AddRef,
  2428. WAB_PRINTDIALOGCALLBACK_Release,
  2429. WAB_PRINTDIALOGCALLBACK_InitDone,
  2430. WAB_PRINTDIALOGCALLBACK_SelectionChange,
  2431. WAB_PRINTDIALOGCALLBACK_HandleMessage
  2432. };
  2433. /*
  2434. - HrCreatePrintCallbackObject
  2435. -
  2436. *
  2437. * This callback object is needed so the new NT5 print dialog can provide send messages back to
  2438. * us for the customization we do for the print dialog ..
  2439. *
  2440. */
  2441. HRESULT HrCreatePrintCallbackObject(LPIAB lpIAB, LPWABPRINTDIALOGCALLBACK * lppWABPCO, DWORD dwSelectedStyle)
  2442. {
  2443. LPWABPRINTDIALOGCALLBACK lpWABPCO = NULL;
  2444. SCODE sc;
  2445. HRESULT hr = hrSuccess;
  2446. //
  2447. // Allocate space for the IAB structure
  2448. //
  2449. if (FAILED(sc = MAPIAllocateBuffer(sizeof(WABPRINTDIALOGCALLBACK), (LPVOID *) &lpWABPCO)))
  2450. {
  2451. hr = ResultFromScode(sc);
  2452. goto err;
  2453. }
  2454. MAPISetBufferName(lpWABPCO, TEXT("WAB Print Dialog Callback Object"));
  2455. ZeroMemory(lpWABPCO, sizeof(WABPRINTDIALOGCALLBACK));
  2456. lpWABPCO->lpVtbl = &vtblWABPRINTDIALOGCALLBACK;
  2457. lpWABPCO->lpIAB = lpIAB;
  2458. lpWABPCO->dwSelectedStyle = dwSelectedStyle;
  2459. lpWABPCO->lpVtbl->AddRef(lpWABPCO);
  2460. *lppWABPCO = lpWABPCO;
  2461. return(hrSuccess);
  2462. err:
  2463. FreeBufferAndNull(&lpWABPCO);
  2464. return(hr);
  2465. }
  2466. void ReleaseWABPrintCallbackObject(LPWABPRINTDIALOGCALLBACK lpWABPCO)
  2467. {
  2468. MAPIFreeBuffer(lpWABPCO);
  2469. }
  2470. STDMETHODIMP_(ULONG)
  2471. WAB_PRINTDIALOGCALLBACK_AddRef(LPWABPRINTDIALOGCALLBACK lpWABPCO)
  2472. {
  2473. return(++(lpWABPCO->lcInit));
  2474. }
  2475. STDMETHODIMP_(ULONG)
  2476. WAB_PRINTDIALOGCALLBACK_Release(LPWABPRINTDIALOGCALLBACK lpWABPCO)
  2477. {
  2478. ULONG ulc = (--(lpWABPCO->lcInit));
  2479. if(ulc==0)
  2480. ReleaseWABPrintCallbackObject(lpWABPCO);
  2481. return(ulc);
  2482. }
  2483. STDMETHODIMP
  2484. WAB_PRINTDIALOGCALLBACK_QueryInterface(LPWABPRINTDIALOGCALLBACK lpWABPCO,
  2485. REFIID lpiid,
  2486. LPVOID * lppNewObj)
  2487. {
  2488. LPVOID lp = NULL;
  2489. if(!lppNewObj)
  2490. return MAPI_E_INVALID_PARAMETER;
  2491. *lppNewObj = NULL;
  2492. if(IsEqualIID(lpiid, &IID_IUnknown))
  2493. lp = (LPVOID) lpWABPCO;
  2494. if(IsEqualIID(lpiid, &IID_IPrintDialogCallback))
  2495. lp = (LPVOID) lpWABPCO;
  2496. if(!lp)
  2497. return E_NOINTERFACE;
  2498. ((LPWABPRINTDIALOGCALLBACK) lp)->lpVtbl->AddRef((LPWABPRINTDIALOGCALLBACK) lp);
  2499. *lppNewObj = lp;
  2500. return S_OK;
  2501. }
  2502. STDMETHODIMP
  2503. WAB_PRINTDIALOGCALLBACK_InitDone(LPWABPRINTDIALOGCALLBACK lpWABPCO)
  2504. {
  2505. HRESULT hr = S_FALSE;
  2506. DebugTrace( TEXT("WAB_PRINTDIALOGCALLBACK_InitDone\n"));
  2507. return hr;
  2508. }
  2509. STDMETHODIMP
  2510. WAB_PRINTDIALOGCALLBACK_SelectionChange(LPWABPRINTDIALOGCALLBACK lpWABPCO)
  2511. {
  2512. HRESULT hr = S_FALSE;
  2513. DebugTrace( TEXT("WAB_PRINTDIALOGCALLBACK_SelectionChange\n"));
  2514. return hr;
  2515. }
  2516. STDMETHODIMP
  2517. WAB_PRINTDIALOGCALLBACK_HandleMessage(LPWABPRINTDIALOGCALLBACK lpWABPCO,
  2518. HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, LRESULT *pResult)
  2519. {
  2520. BOOL bRet = FALSE;
  2521. LPDWORD lpdwStyle = &lpWABPCO->dwSelectedStyle;
  2522. DebugTrace( TEXT("WAB_PRINTDIALOGCALLBACK_HandleMessage: 0x%.8x\n"), message);
  2523. switch(message)
  2524. {
  2525. case WM_INITDIALOG:
  2526. bRet = bHandleWMInitDialog(hDlg,message,wParam,lParam,lpdwStyle);
  2527. break;
  2528. case WM_COMMAND:
  2529. bRet = bHandleWMCommand(hDlg,message,wParam,lParam,lpdwStyle);
  2530. break;
  2531. case WM_HELP:
  2532. bRet = bHandleWMHelp(hDlg,message,wParam,lParam,lpdwStyle);
  2533. break;
  2534. case WM_CONTEXTMENU:
  2535. bRet = bHandleWMContextMenu(hDlg,message,wParam,lParam,lpdwStyle);
  2536. break;
  2537. default:
  2538. bRet = FALSE;
  2539. break;
  2540. }
  2541. return (bRet ? S_OK : S_FALSE);
  2542. }
  2543. /******************************************************************************************/
  2544. /*
  2545. - bCheckForPrintExtensions
  2546. -
  2547. * In case any app has implemented a Print Extension to the WAB, we should hook into
  2548. * that print extension
  2549. *
  2550. * lpDLLPath can be NULL or should point to a buffer big enough to receive the module Path
  2551. *
  2552. */
  2553. static const LPTSTR szExtDisplayMailUser = TEXT("Software\\Microsoft\\WAB\\WAB4\\ExtPrint");
  2554. extern HrGetActionAdrList(LPADRBOOK lpAdrBook,HWND hWndLV,LPADRLIST * lppAdrList,LPTSTR * lppURL, BOOL * lpbIsNTDSEntry);
  2555. BOOL bCheckForPrintExtensions(LPTSTR lpDLLPath, DWORD cchSize)
  2556. {
  2557. BOOL bRet = FALSE;
  2558. HKEY hKey = NULL;
  2559. if(ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE,szExtDisplayMailUser,0, KEY_READ,&hKey))
  2560. {
  2561. goto out;
  2562. }
  2563. {
  2564. TCHAR szExt[MAX_PATH];
  2565. DWORD dwIndex = 0, dwSize = ARRAYSIZE(szExt), dwType = 0;
  2566. *szExt = '\0';
  2567. while(ERROR_SUCCESS == RegEnumValue(hKey, dwIndex, szExt, &dwSize,
  2568. 0, &dwType, NULL, NULL))
  2569. {
  2570. // we found some entry in here .. the value name will be the full path
  2571. // to the module containing the print function
  2572. // Double-check that this module actually exists
  2573. if (szExt && lstrlen(szExt) && (GetFileAttributes(szExt) != 0xFFFFFFFF))
  2574. {
  2575. if(lpDLLPath)
  2576. StrCpyN(lpDLLPath, szExt, cchSize);
  2577. bRet = TRUE;
  2578. goto out;
  2579. }
  2580. }
  2581. }
  2582. out:
  2583. if(hKey)
  2584. RegCloseKey(hKey);
  2585. return bRet;
  2586. }
  2587. /*
  2588. -
  2589. - HrUseWABPrintExtension()
  2590. -
  2591. * Loads the WAB Print Extension from the extension DLL
  2592. * and calls into it
  2593. *
  2594. * hWnd - Handle of WAB parent
  2595. * lpAdrBook - lpAdrBook pointer
  2596. * hWndLV - listview from which a user may have chosen selections
  2597. *
  2598. */
  2599. HRESULT HrUseWABPrintExtension(HWND hWnd, LPADRBOOK lpAdrBook, HWND hWndLV)
  2600. {
  2601. TCHAR szExt[MAX_PATH];
  2602. HRESULT hr = E_FAIL;
  2603. HINSTANCE hInstPrint = NULL;
  2604. LPWABPRINTEXT lpfnWABPrintExt = NULL;
  2605. LPADRLIST lpAdrList = NULL;
  2606. LPWABOBJECT lpWABObject = (LPWABOBJECT)((LPIAB)lpAdrBook)->lpWABObject;
  2607. *szExt = '\0';
  2608. if(!bCheckForPrintExtensions(szExt, ARRAYSIZE(szExt)) || !lstrlen(szExt))
  2609. goto out;
  2610. if(!(hInstPrint = LoadLibrary(szExt)))
  2611. goto out;
  2612. lpfnWABPrintExt = (LPWABPRINTEXT) GetProcAddress(hInstPrint, "WABPrintExt");
  2613. if(!lpfnWABPrintExt)
  2614. goto out;
  2615. // Get the currently selected data from the list view
  2616. if(HR_FAILED(hr = HrGetActionAdrList(lpAdrBook,hWndLV,&lpAdrList,NULL,NULL)))
  2617. goto out;
  2618. hr = lpfnWABPrintExt(lpAdrBook, lpWABObject, hWnd, lpAdrList);
  2619. out:
  2620. if(lpAdrList)
  2621. FreePadrlist(lpAdrList);
  2622. if(hInstPrint)
  2623. FreeLibrary(hInstPrint);
  2624. return hr;
  2625. }