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

1446 lines
38 KiB

  1. /***********************************************************************
  2. *
  3. * ABUSER.C
  4. *
  5. * Microsoft At Work Fax AB Mail User object
  6. * This file contains the code for implementing the Microsoft At Work Fax AB
  7. * Mail user.
  8. *
  9. * The mail user has a read-only interface. Hence a few of the methods
  10. * will always return MAPI_E_NO_ACCESS. Certain aspects of this
  11. * implementation are not implemented, such as retrieving the display
  12. * table in order to build up a details screen in the UI. For the most
  13. * part, however, this interface has enough to retrieve enough properties
  14. * to actually send mail.
  15. *
  16. * An important thing that's not implemented in this version is the
  17. * verification of the entryid to see if it's still valid. In most
  18. * mail systems, you would want to check to see if a particular recipient
  19. * still exists before actually trying to send mail to that recipient.
  20. *
  21. * The following routines are implemented in this file:
  22. *
  23. *
  24. * HrHrNewFaxUser
  25. * ABU_QueryInterface
  26. * ABU_Release
  27. * ABU_OpenProperty
  28. * HrBuildListBoxTable
  29. * HrBuildDDListboxTable
  30. * HrBuildComboBoxTable
  31. *
  32. * Copyright 1992, 1993 Microsoft Corporation. All Rights Reserved.
  33. *
  34. * Revision History:
  35. *
  36. * When Who What
  37. * -------- ------------------ ---------------------------------------
  38. * 1.1.94 MAPI Original source from MAPI sample AB Provider
  39. * 1.27.94 Yoram Yaacovi Modifications to make it an At Work Fax ABP
  40. * 3.7.94 Yoram Yaacovi Update to MAPI build 154
  41. * 8.3.94 Yoram Yaacovi Update to MAPI build 304 and new Fax AB spec
  42. * 11.11.94 Yoram Yaacovi Update to MAPI 318
  43. *
  44. ***********************************************************************/
  45. #include "faxab.h"
  46. #ifdef UNICODE
  47. #include <wchar.h>
  48. #else
  49. #include <stdio.h>
  50. #endif
  51. #define _FAXAB_ABUSER
  52. /*
  53. * Private functions
  54. */
  55. /*****************************
  56. ** Display Table structures *
  57. *****************************/
  58. // Cover page name of the user
  59. DTBLEDIT
  60. editUserDisplayName =
  61. {
  62. SIZEOF(DTBLEDIT),
  63. 0,
  64. MAX_DISPLAY_NAME,
  65. PR_FAX_CP_NAME_A
  66. };
  67. // The area code component of the email address (fax number)
  68. DTBLEDIT
  69. editUserAreaCode =
  70. {
  71. SIZEOF(DTBLEDIT),
  72. 0,
  73. AREA_CODE_SIZE,
  74. PR_AREA_CODE_A
  75. };
  76. // The number component of the email address (fax number)
  77. DTBLEDIT
  78. editUserTelNumber =
  79. {
  80. SIZEOF(DTBLEDIT),
  81. 0,
  82. TELEPHONE_NUMBER_SIZE,
  83. PR_TEL_NUMBER_A
  84. };
  85. // The country codes list box
  86. DTBLDDLBX
  87. ddlbxCountryCodes =
  88. {
  89. SIZEOF(DTBLDDLBX),
  90. PR_DISPLAY_NAME_A,
  91. PR_COUNTRY_ID,
  92. PR_DDLBX_COUNTRIES_TABLE
  93. };
  94. // Description the the Fax AB pane in MAPI dialog description language
  95. static DTCTL rgdtctlUserGeneral[] =
  96. {
  97. /* general property page */
  98. { DTCT_PAGE, 0, NULL, 0, NULL, 0, &dtblpage },
  99. /* cover page name static control and edit control */
  100. { DTCT_LABEL, 0, NULL, 0, NULL, IDC_RECIP_DISPLAY_NAME_LABEL, &dtbllabel },
  101. { DTCT_EDIT, 0, NULL, 0, (LPTSTR)szNoFilter, IDC_RECIP_DISPLAY_NAME, &editUserDisplayName },
  102. /* Country codes label and drop down list box */
  103. { DTCT_LABEL, 0, NULL, 0, NULL, IDC_RECIP_COUNTRY_CODE_LABEL, &dtbllabel },
  104. { DTCT_DDLBX, 0, NULL, 0, NULL, IDC_RECIP_COUNTRY_CODE, &ddlbxCountryCodes },
  105. /* Area code and fax number label */
  106. { DTCT_LABEL, 0, NULL, 0, NULL, IDC_RECIP_FAX_NUMBER_LABEL, &dtbllabel },
  107. /* area code edit control */
  108. { DTCT_EDIT, 0, NULL, 0, (LPTSTR)szDigitsOnlyFilter, IDC_RECIP_FAX_NUMBER_AREA_CODE, &editUserAreaCode },
  109. /* Fax number static control and edit control */
  110. { DTCT_LABEL, 0, NULL, 0, NULL, IDC_RECIP_FAX_NUMBER_LABEL2, &dtbllabel },
  111. { DTCT_EDIT, 0, NULL, 0, (LPTSTR)szDigitsOnlyFilter, IDC_RECIP_FAX_NUMBER, &editUserTelNumber}
  112. };
  113. #if defined (RECIP_OPTIONS)
  114. // User options property page. currently not implemented
  115. DTCTL rgdtctlUserOptions[] =
  116. {
  117. /* options property page */
  118. { DTCT_PAGE, 0, NULL, 0, NULL, 0, &dtblpage },
  119. /* static control and listbox */
  120. { DTCT_LABEL, 0, NULL, 0, NULL, IDC_STATIC_CONTROL, &dtbllabel },
  121. };
  122. #endif
  123. /* Display table pages */
  124. /* shared with oouser.c */
  125. static DTPAGE rgdtpageUser[] =
  126. {
  127. {
  128. ARRAYSIZE(rgdtctlUserGeneral),
  129. (LPTSTR)MAKEINTRESOURCE(MAWFRecipient),
  130. TEXT(""),
  131. rgdtctlUserGeneral
  132. },
  133. #if defined (RECIP_OPTIONS)
  134. {
  135. ARRAYSIZE(rgdtctlUserOptions),
  136. (LPTSTR)MAKEINTRESOURCE(UserOptionsPage),
  137. TEXT(""),
  138. rgdtctlUserOptions
  139. }
  140. #endif
  141. };
  142. WORD sizeof_rgdtpageUser = SIZEOF(rgdtpageUser);
  143. /*
  144. * ABUser jump table is defined here...
  145. */
  146. ABU_Vtbl vtblABU =
  147. {
  148. ABU_QueryInterface,
  149. (ABU_AddRef_METHOD *) ROOT_AddRef,
  150. ABU_Release,
  151. (ABU_GetLastError_METHOD *) ROOT_GetLastError,
  152. (ABU_SaveChanges_METHOD *) WRAP_SaveChanges,
  153. (ABU_GetProps_METHOD *) WRAP_GetProps,
  154. (ABU_GetPropList_METHOD *) WRAP_GetPropList,
  155. ABU_OpenProperty,
  156. (ABU_SetProps_METHOD *) WRAP_SetProps,
  157. (ABU_DeleteProps_METHOD *) WRAP_DeleteProps,
  158. (ABU_CopyTo_METHOD *) WRAP_CopyTo,
  159. (ABU_CopyProps_METHOD *) WRAP_CopyProps,
  160. (ABU_GetNamesFromIDs_METHOD *) WRAP_GetNamesFromIDs,
  161. (ABU_GetIDsFromNames_METHOD *) WRAP_GetIDsFromNames,
  162. };
  163. enum { ivalusrPR_DISPLAY_TYPE = 0,
  164. ivalusrPR_OBJECT_TYPE,
  165. ivalusrPR_ENTRYID,
  166. ivalusrPR_RECORD_KEY,
  167. ivalusrPR_DISPLAY_NAME,
  168. ivalusrPR_TRANSMITABLE_DISPLAY_NAME,
  169. ivalusrPR_FAX_CP_NAME,
  170. ivalusrPR_EMAIL_ADDRESS,
  171. ivalusrPR_ADDRTYPE,
  172. ivalusrPR_SEARCH_KEY,
  173. ivalusrPR_AREA_CODE,
  174. ivalusrPR_TEL_NUMBER,
  175. ivalusrPR_COUNTRY_ID,
  176. ivalusrPR_TEMPLATEID,
  177. cvalusrMax };
  178. /*************************************************************************
  179. *
  180. - HrNewFaxUser
  181. -
  182. * Creates the IMAPIProp associated with a mail user.
  183. *
  184. *
  185. */
  186. HRESULT
  187. HrNewFaxUser( LPMAILUSER * lppMAPIPropEntry,
  188. ULONG * lpulObjType,
  189. ULONG cbEntryID,
  190. LPENTRYID lpEntryID,
  191. LPABLOGON lpABPLogon,
  192. LPCIID lpInterface,
  193. HINSTANCE hLibrary,
  194. LPALLOCATEBUFFER lpAllocBuff,
  195. LPALLOCATEMORE lpAllocMore,
  196. LPFREEBUFFER lpFreeBuff,
  197. LPMALLOC lpMalloc )
  198. {
  199. LPABUSER lpABUser = NULL;
  200. SCODE sc;
  201. HRESULT hr = hrSuccess;
  202. LPPROPDATA lpPropData = NULL;
  203. SPropValue spv[cvalusrMax];
  204. ULONG cbT = 0;
  205. LPBYTE lpbT = NULL;
  206. LPSTR lpszEMA = NULL;
  207. PARSEDTELNUMBER sParsedFaxAddr;
  208. DWORD dwCountryID;
  209. #ifdef UNICODE
  210. CHAR szAnsiDisplayName[ MAX_PATH ];
  211. CHAR szAnsiEmailAddress[ MAX_PATH ];
  212. CHAR szAnsiTelNumber[ 50 ];
  213. CHAR szAnsiAreaCode[ 5 ];
  214. CHAR szAnsiEMT[ 25 ];
  215. #endif
  216. /* Do I support this interface?? */
  217. if (lpInterface)
  218. {
  219. if ( memcmp(lpInterface, &IID_IMailUser, SIZEOF(IID)) &&
  220. memcmp(lpInterface, &IID_IMAPIProp, SIZEOF(IID)) &&
  221. memcmp(lpInterface, &IID_IUnknown, SIZEOF(IID))
  222. )
  223. {
  224. DebugTraceSc(HrNewSampUser, MAPI_E_INTERFACE_NOT_SUPPORTED);
  225. return ResultFromScode(MAPI_E_INTERFACE_NOT_SUPPORTED);
  226. }
  227. }
  228. /*
  229. * Allocate space for the ABUSER structure
  230. */
  231. sc = lpAllocBuff( SIZEOF(ABUSER), (LPVOID *) & lpABUser);
  232. if (FAILED(sc))
  233. {
  234. hr = ResultFromScode (sc);
  235. goto err;
  236. }
  237. lpABUser->lpVtbl = &vtblABU;
  238. lpABUser->lcInit = 1;
  239. lpABUser->hResult = hrSuccess;
  240. lpABUser->idsLastError = 0;
  241. lpABUser->hLibrary = hLibrary;
  242. lpABUser->lpAllocBuff = lpAllocBuff;
  243. lpABUser->lpAllocMore = lpAllocMore;
  244. lpABUser->lpFreeBuff = lpFreeBuff;
  245. lpABUser->lpMalloc = lpMalloc;
  246. lpABUser->lpABLogon = lpABPLogon;
  247. lpABUser->lpTDatDDListBox = NULL;
  248. /*
  249. * Create lpPropData
  250. */
  251. sc = CreateIProp( (LPIID) &IID_IMAPIPropData,
  252. lpAllocBuff,
  253. lpAllocMore,
  254. lpFreeBuff,
  255. lpMalloc,
  256. &lpPropData
  257. );
  258. if (FAILED(sc))
  259. {
  260. hr = ResultFromScode (sc);
  261. goto err;
  262. }
  263. /*
  264. * Set up initial set of properties associated with this
  265. * container.
  266. */
  267. /*
  268. * Easy ones first
  269. */
  270. spv[ivalusrPR_DISPLAY_TYPE].ulPropTag = PR_DISPLAY_TYPE;
  271. spv[ivalusrPR_DISPLAY_TYPE].Value.l = DT_MAILUSER;
  272. spv[ivalusrPR_OBJECT_TYPE].ulPropTag = PR_OBJECT_TYPE;
  273. spv[ivalusrPR_OBJECT_TYPE].Value.l = MAPI_MAILUSER;
  274. spv[ivalusrPR_ENTRYID].ulPropTag = PR_ENTRYID;
  275. spv[ivalusrPR_ENTRYID].Value.bin.cb = SIZEOF(USR_ENTRYID);
  276. spv[ivalusrPR_ENTRYID].Value.bin.lpb = (LPBYTE) lpEntryID;
  277. /*
  278. * Now the calculated props
  279. */
  280. spv[ivalusrPR_RECORD_KEY].ulPropTag = PR_RECORD_KEY;
  281. spv[ivalusrPR_RECORD_KEY].Value.bin.cb = SIZEOF(USR_ENTRYID);
  282. spv[ivalusrPR_RECORD_KEY].Value.bin.lpb = (LPBYTE) lpEntryID;
  283. spv[ivalusrPR_DISPLAY_NAME].ulPropTag = PR_DISPLAY_NAME_A;
  284. #ifdef UNICODE
  285. szAnsiDisplayName[0] = 0;
  286. WideCharToMultiByte( CP_ACP, 0,
  287. ((LPUSR_ENTRYID) lpEntryID)->abcrec.rgchDisplayName, -1,
  288. szAnsiDisplayName, ARRAYSIZE(szAnsiDisplayName),
  289. NULL, NULL
  290. );
  291. spv[ivalusrPR_DISPLAY_NAME].Value.lpszA = szAnsiDisplayName;
  292. #else
  293. spv[ivalusrPR_DISPLAY_NAME].Value.lpszA = ((LPUSR_ENTRYID) lpEntryID)->abcrec.rgchDisplayName;
  294. #endif
  295. /* Should always be the same as PR_DISPLAY_NAME */
  296. spv[ivalusrPR_TRANSMITABLE_DISPLAY_NAME].ulPropTag = PR_TRANSMITABLE_DISPLAY_NAME_A;
  297. #ifdef UNICODE
  298. spv[ivalusrPR_TRANSMITABLE_DISPLAY_NAME].Value.lpszA = szAnsiDisplayName;
  299. #else
  300. spv[ivalusrPR_TRANSMITABLE_DISPLAY_NAME].Value.LPSZ = ((LPUSR_ENTRYID) lpEntryID)->abcrec.rgchDisplayName;
  301. #endif
  302. // Make the cover page name identical to the display name
  303. spv[ivalusrPR_FAX_CP_NAME].ulPropTag = PR_FAX_CP_NAME_A;
  304. #ifdef UNICODE
  305. spv[ivalusrPR_FAX_CP_NAME].Value.lpszA = szAnsiDisplayName;
  306. #else
  307. spv[ivalusrPR_FAX_CP_NAME].Value.LPSZ = ((LPUSR_ENTRYID)lpEntryID)->abcrec.rgchDisplayName;
  308. #endif
  309. spv[ivalusrPR_EMAIL_ADDRESS].ulPropTag = PR_EMAIL_ADDRESS_A;
  310. #ifdef UNICODE
  311. szAnsiEmailAddress[0] = 0;
  312. WideCharToMultiByte( CP_ACP, 0,
  313. ((LPUSR_ENTRYID) lpEntryID)->abcrec.rgchEmailAddress, -1,
  314. szAnsiEmailAddress, ARRAYSIZE(szAnsiEmailAddress),
  315. NULL, NULL
  316. );
  317. spv[ivalusrPR_EMAIL_ADDRESS].Value.lpszA = szAnsiEmailAddress;
  318. lpszEMA = szAnsiEmailAddress;
  319. #else
  320. spv[ivalusrPR_EMAIL_ADDRESS].Value.LPSZ = ((LPUSR_ENTRYID) lpEntryID)->abcrec.rgchEmailAddress;
  321. lpszEMA = ((LPUSR_ENTRYID) lpEntryID)->abcrec.rgchEmailAddress;
  322. #endif
  323. spv[ivalusrPR_ADDRTYPE].ulPropTag = PR_ADDRTYPE_A;
  324. #ifdef UNICODE
  325. szAnsiEMT[0] = 0;
  326. WideCharToMultiByte( CP_ACP, 0, lpszEMT, -1, szAnsiEMT, ARRAYSIZE(szAnsiEMT), NULL, NULL );
  327. spv[ivalusrPR_ADDRTYPE].Value.lpszA = szAnsiEMT;
  328. #else
  329. spv[ivalusrPR_ADDRTYPE].Value.LPSZ = lpszEMT;
  330. #endif
  331. /*
  332. * Build the search key...
  333. */
  334. /* Search keys for mailable recipients that have email addresses are
  335. * defined as "EmailType':'EmailAddress\0". We do the +2 for the ':' and
  336. * '\0'.
  337. */
  338. #ifdef UNICODE
  339. cbT = lstrlenA(lpszEMA) + lstrlenA(szAnsiEMT) + 2;
  340. #else
  341. cbT = lstrlen(lpszEMA) + lstrlen(lpszEMT) + 2;
  342. #endif
  343. sc = lpAllocBuff( cbT, (LPVOID *) &lpbT );
  344. if (FAILED(sc))
  345. {
  346. hr = ResultFromScode(sc);
  347. goto err;
  348. }
  349. #ifdef UNICODE
  350. lstrcpyA((LPSTR) lpbT, szAnsiEMT);
  351. #else
  352. lstrcpyA((LPSTR) lpbT, lpszEMT);
  353. #endif
  354. lstrcatA((LPSTR) lpbT, ":");
  355. lstrcatA((LPSTR) lpbT, lpszEMA);
  356. CharUpperBuffA((LPSTR) lpbT, (UINT) cbT);
  357. spv[ivalusrPR_SEARCH_KEY].ulPropTag = PR_SEARCH_KEY;
  358. spv[ivalusrPR_SEARCH_KEY].Value.bin.cb = cbT;
  359. spv[ivalusrPR_SEARCH_KEY].Value.bin.lpb = lpbT;
  360. // Need to decode the email address into "displayable" components
  361. // and set them on the object so that MAPI can display
  362. // Country code is stored separately in the address book.
  363. DecodeFaxAddress((LPTSTR)((LPUSR_ENTRYID)lpEntryID)->abcrec.rgchEmailAddress, &sParsedFaxAddr);
  364. // EncodeFaxAddress(tempString, &sParsedFaxAddr);
  365. /*
  366. * Now set the "displayable" components on the user object
  367. */
  368. spv[ivalusrPR_TEL_NUMBER].ulPropTag = PR_TEL_NUMBER_A;
  369. #ifdef UNICODE
  370. szAnsiTelNumber[0] = 0;
  371. WideCharToMultiByte( CP_ACP, 0, sParsedFaxAddr.szTelNumber, -1, szAnsiTelNumber, ARRAYSIZE(szAnsiTelNumber), NULL, NULL );
  372. spv[ivalusrPR_TEL_NUMBER].Value.lpszA = szAnsiTelNumber;
  373. #else
  374. spv[ivalusrPR_TEL_NUMBER].Value.LPSZ = sParsedFaxAddr.szTelNumber;
  375. #endif
  376. // Country ID/code brings some trouble. I need the country ID, but it
  377. // might be that it is not in the FAB. If it's not, I need to try my
  378. // best on getting the country ID from the country code
  379. spv[ivalusrPR_COUNTRY_ID].ulPropTag = PR_COUNTRY_ID;
  380. #ifdef UNICODE
  381. dwCountryID = (DWORD) wcstol(((LPUSR_ENTRYID)lpEntryID)->abcrec.rgchCountryID,NULL,10);
  382. #else
  383. dwCountryID = (DWORD) atol(((LPUSR_ENTRYID)lpEntryID)->abcrec.rgchCountryID);
  384. #endif
  385. if (dwCountryID == 0)
  386. {
  387. // no country code in the FAB
  388. // GetCountryID will return 1 (U.S.) for country ID in case of error
  389. // GetCountryID((DWORD) atol(sParsedFaxAddr.szCountryCode), &dwCountryID);
  390. // This should work just the same since country code should map into a country
  391. // ID (actually into several. Best I can do is get the first country that
  392. // uses this country code. Could analyze area codes, ask the user, etc....
  393. #ifdef UNICODE
  394. dwCountryID = (DWORD) wcstol(sParsedFaxAddr.szCountryCode,NULL,10);
  395. #else
  396. dwCountryID = (DWORD) atol(sParsedFaxAddr.szCountryCode);
  397. #endif
  398. }
  399. spv[ivalusrPR_COUNTRY_ID].Value.ul = dwCountryID;
  400. // if no area code in the address, and it's not a 'no country' thing, get the
  401. // area code of the current location
  402. if ((!lstrcmp(sParsedFaxAddr.szAreaCode, TEXT(""))) && (dwCountryID != 0))
  403. {
  404. lstrcpy(sParsedFaxAddr.szAreaCode, (LPCTSTR) GetCurrentLocationAreaCode());
  405. }
  406. spv[ivalusrPR_AREA_CODE].ulPropTag = PR_AREA_CODE_A;
  407. #ifdef UNICODE
  408. szAnsiAreaCode[0] = 0;
  409. WideCharToMultiByte( CP_ACP, 0, sParsedFaxAddr.szAreaCode, -1, szAnsiAreaCode, ARRAYSIZE(szAnsiAreaCode), NULL, NULL );
  410. spv[ivalusrPR_AREA_CODE].Value.lpszA = szAnsiAreaCode;
  411. #else
  412. spv[ivalusrPR_AREA_CODE].Value.LPSZ = sParsedFaxAddr.szAreaCode;
  413. #endif
  414. /*
  415. * Note that we're using our entryID for our templateID.
  416. * This is a really simple way to implement templateIDs.
  417. * (See TID.C)
  418. */
  419. spv[ivalusrPR_TEMPLATEID].ulPropTag = PR_TEMPLATEID;
  420. spv[ivalusrPR_TEMPLATEID].Value.bin.cb = SIZEOF(USR_ENTRYID);
  421. spv[ivalusrPR_TEMPLATEID].Value.bin.lpb = (LPBYTE) lpEntryID;
  422. /*
  423. * Set the default properties
  424. */
  425. hr = lpPropData->lpVtbl->SetProps( lpPropData,
  426. cvalusrMax,
  427. spv,
  428. NULL
  429. );
  430. if (HR_FAILED(hr))
  431. {
  432. goto err;
  433. }
  434. /*
  435. * Although this object is basically read only, we wanted to show
  436. * an example of how the check-boxes and other controls on the
  437. * "Options" pane work. If we had set this objet to be read only,
  438. * the values behind those controls would have been static.
  439. */
  440. (void)lpPropData->lpVtbl->HrSetObjAccess(lpPropData, IPROP_READWRITE);
  441. lpABUser->lpPropData = (LPMAPIPROP) lpPropData;
  442. InitializeCriticalSection(&lpABUser->cs);
  443. *lppMAPIPropEntry = (LPVOID) lpABUser;
  444. *lpulObjType = MAPI_MAILUSER;
  445. out:
  446. lpFreeBuff(lpbT);
  447. DebugTraceResult(HrNewSampUser, hr);
  448. return hr;
  449. err:
  450. if (lpPropData)
  451. lpPropData->lpVtbl->Release(lpPropData);
  452. lpFreeBuff(lpABUser);
  453. goto out;
  454. }
  455. /***************************************************
  456. *
  457. * The actual ABContainer methods
  458. */
  459. /* --------
  460. * IUnknown
  461. */
  462. /*************************************************************************
  463. *
  464. *
  465. - ABU_QueryInterface
  466. -
  467. *
  468. * This method is reused in TID.C, OOTID.C, and ABOOSER.C. Hence the
  469. * difference in checking of the 'this' pointer from other methods within
  470. * this object.
  471. */
  472. STDMETHODIMP
  473. ABU_QueryInterface( LPABUSER lpABUser,
  474. REFIID lpiid,
  475. LPVOID FAR * lppNewObj
  476. )
  477. {
  478. HRESULT hr = hrSuccess;
  479. /* Minimally check the lpABUer interface
  480. * Can't do any more extensive checking that this because this method is reused
  481. * in OOUSER.C.
  482. */
  483. if (IsBadReadPtr(lpABUser, offsetof(ABUSER, lpVtbl)+SIZEOF(ABU_Vtbl *)))
  484. {
  485. hr = ResultFromScode(E_INVALIDARG);
  486. goto out;
  487. }
  488. if (IsBadReadPtr(lpABUser->lpVtbl,
  489. offsetof(ABU_Vtbl, QueryInterface)+SIZEOF(ABU_QueryInterface_METHOD *)))
  490. {
  491. hr = ResultFromScode(E_INVALIDARG);
  492. goto out;
  493. }
  494. if (ABU_QueryInterface != lpABUser->lpVtbl->QueryInterface)
  495. {
  496. hr = ResultFromScode(E_INVALIDARG);
  497. goto out;
  498. }
  499. /* Validate other parameters */
  500. if (IsBadReadPtr(lpiid, (UINT) SIZEOF(IID)))
  501. {
  502. hr = ResultFromScode(E_INVALIDARG);
  503. goto out;
  504. }
  505. if (IsBadWritePtr(lppNewObj, SIZEOF(LPVOID)))
  506. {
  507. hr = ResultFromScode(E_INVALIDARG);
  508. goto out;
  509. }
  510. /* See if the requested interface is one of ours */
  511. if ( memcmp(lpiid, &IID_IUnknown, SIZEOF(IID)) &&
  512. memcmp(lpiid, &IID_IMAPIProp, SIZEOF(IID)) &&
  513. memcmp(lpiid, &IID_IMailUser, SIZEOF(IID))
  514. )
  515. {
  516. *lppNewObj = NULL; /* OLE requires zeroing [out] parameter */
  517. hr = ResultFromScode(E_NOINTERFACE);
  518. goto out;
  519. }
  520. /* We'll do this one. Bump the usage count and return a new pointer. */
  521. EnterCriticalSection(&lpABUser->cs);
  522. ++lpABUser->lcInit;
  523. LeaveCriticalSection(&lpABUser->cs);
  524. *lppNewObj = lpABUser;
  525. out:
  526. DebugTraceResult(ABU_QueryInterface, hr);
  527. return hr;
  528. }
  529. /*
  530. * Use ROOTs - no need duplicating code
  531. *
  532. * ROOT_AddRef
  533. */
  534. /**************************************************
  535. *
  536. - ABU_Release
  537. -
  538. * Decrement lpInit.
  539. * When lcInit == 0, free up the lpABUser structure
  540. *
  541. */
  542. STDMETHODIMP_(ULONG)
  543. ABU_Release (LPABUSER lpABUser)
  544. {
  545. LONG lcInit;
  546. /*
  547. * Check to see if it's big enough to hold this object
  548. */
  549. if (IsBadReadPtr(lpABUser, SIZEOF(ABUSER)))
  550. {
  551. /*
  552. * Not large enough
  553. */
  554. return 1;
  555. }
  556. /*
  557. * Check to see that it's the correct vtbl
  558. */
  559. if (lpABUser->lpVtbl != &vtblABU)
  560. {
  561. /*
  562. * Not my vtbl
  563. */
  564. return 1;
  565. }
  566. EnterCriticalSection(&lpABUser->cs);
  567. lcInit = --lpABUser->lcInit;
  568. LeaveCriticalSection(&lpABUser->cs);
  569. if (lcInit == 0)
  570. {
  571. /*
  572. * Get rid of the lpPropData
  573. */
  574. lpABUser->lpPropData->lpVtbl->Release(lpABUser->lpPropData);
  575. /*
  576. * Get rid of the country codes table
  577. */
  578. if (lpABUser->lpTDatDDListBox)
  579. lpABUser->lpTDatDDListBox->lpVtbl->Release(lpABUser->lpTDatDDListBox);
  580. /*
  581. * Destroy the critical section for this object
  582. */
  583. DeleteCriticalSection(&lpABUser->cs);
  584. /*
  585. * Set the vtbl to NULL. This way the client will find out
  586. * real fast if it's calling a method on a released object. That is,
  587. * the client will crash. Hopefully, this will happen during the
  588. * development stage of the client.
  589. */
  590. lpABUser->lpVtbl = NULL;
  591. /*
  592. * Need to free the object
  593. */
  594. lpABUser->lpFreeBuff( lpABUser );
  595. return 0;
  596. }
  597. return lcInit;
  598. }
  599. /* ---------
  600. * IMAPIProp
  601. */
  602. /*
  603. * GetLastError - use ROOTs
  604. *
  605. *
  606. */
  607. /*************************************************************************
  608. *
  609. - ABU_OpenProperty
  610. -
  611. *
  612. * This is how we get the display table associated with this users
  613. * details screen.
  614. */
  615. STDMETHODIMP
  616. ABU_OpenProperty( LPABUSER lpABUser,
  617. ULONG ulPropTag,
  618. LPCIID lpiid,
  619. ULONG ulInterfaceOptions,
  620. ULONG ulFlags,
  621. LPUNKNOWN * lppUnk
  622. )
  623. {
  624. HRESULT hResult;
  625. /*
  626. * Check to see if it's big enough to hold this object
  627. */
  628. if (IsBadReadPtr(lpABUser, SIZEOF(ABUSER)))
  629. {
  630. /*
  631. * Not large enough
  632. */
  633. hResult = ResultFromScode(E_INVALIDARG);
  634. DebugTraceResult(ABU_OpenProperty, hResult);
  635. return hResult;
  636. }
  637. /*
  638. * Check to see that it's the correct vtbl
  639. */
  640. if (lpABUser->lpVtbl != &vtblABU)
  641. {
  642. /*
  643. * Not my vtbl
  644. */
  645. hResult = ResultFromScode(E_INVALIDARG);
  646. DebugTraceResult(ABU_OpenProperty, hResult);
  647. return hResult;
  648. }
  649. if (IsBadWritePtr(lppUnk, SIZEOF(LPUNKNOWN)))
  650. {
  651. /*
  652. * Got to be able to return an object
  653. */
  654. hResult = ResultFromScode(E_INVALIDARG);
  655. DebugTraceResult(ABU_OpenProperty, hResult);
  656. return hResult;
  657. }
  658. if (IsBadReadPtr(lpiid, (UINT) SIZEOF(IID)))
  659. {
  660. /*
  661. * An interface ID is required for this call.
  662. */
  663. hResult = ResultFromScode(E_INVALIDARG);
  664. DebugTraceResult(ABU_OpenProperty, hResult);
  665. return hResult;
  666. }
  667. if (ulFlags & ~(MAPI_CREATE|MAPI_MODIFY|MAPI_DEFERRED_ERRORS))
  668. {
  669. hResult = ResultFromScode(MAPI_E_UNKNOWN_FLAGS);
  670. DebugTraceResult(ABU_OpenProperty, hResult);
  671. return hResult;
  672. }
  673. if (ulInterfaceOptions & ~MAPI_UNICODE )
  674. {
  675. /*
  676. * Only the Unicode flag should be set for any of the objects that might
  677. * be returned from this object.
  678. */
  679. hResult = ResultFromScode(MAPI_E_UNKNOWN_FLAGS);
  680. DebugTraceResult(ABU_OpenProperty, hResult);
  681. return hResult;
  682. }
  683. if ( ulInterfaceOptions & MAPI_UNICODE )
  684. {
  685. hResult = ResultFromScode(MAPI_E_BAD_CHARWIDTH);
  686. DebugTraceResult(ABU_OpenProperty, hResult);
  687. return hResult;
  688. }
  689. if (ulFlags & MAPI_CREATE)
  690. {
  691. hResult = ResultFromScode(E_ACCESSDENIED);
  692. DebugTraceResult(ABU_OpenProperty, hResult);
  693. return hResult;
  694. }
  695. // If the caller is trying to open a table property and is not expecting a table interface..
  696. switch (ulPropTag)
  697. {
  698. case PR_DETAILS_TABLE:
  699. case PR_DDLBX_COUNTRIES_TABLE:
  700. if (memcmp( lpiid, &IID_IMAPITable, SIZEOF(IID) ))
  701. {
  702. // ... we will abort right here
  703. hResult = ResultFromScode(MAPI_E_INTERFACE_NOT_SUPPORTED);
  704. goto out;
  705. }
  706. break;
  707. default:
  708. break;
  709. }
  710. EnterCriticalSection(&lpABUser->cs);
  711. /* Now lets handle the requested property */
  712. switch (ulPropTag)
  713. {
  714. case PR_DETAILS_TABLE:
  715. /* Looking for the display table*/
  716. /* Create a display table */
  717. hResult = BuildDisplayTable( lpABUser->lpAllocBuff,
  718. lpABUser->lpAllocMore,
  719. lpABUser->lpFreeBuff,
  720. lpABUser->lpMalloc,
  721. lpABUser->hLibrary,
  722. ARRAYSIZE(rgdtpageUser),
  723. rgdtpageUser,
  724. 0,
  725. (LPMAPITABLE*)lppUnk,
  726. NULL
  727. );
  728. // if error, will just report the hResult to the caller
  729. break;
  730. case PR_DDLBX_COUNTRIES_TABLE:
  731. // This table is not changing dynamically. No need to rebuild if already built.
  732. if (!lpABUser->lpTDatDDListBox)
  733. {
  734. hResult = HrBuildDDLBXCountriesTable(lpABUser);
  735. if (HR_FAILED(hResult))
  736. goto out;
  737. }
  738. Assert(lpABUser->lpTDatDDListBox);
  739. /* Get a view from the TAD*/
  740. hResult = lpABUser->lpTDatDDListBox->lpVtbl->HrGetView(
  741. lpABUser->lpTDatDDListBox,
  742. NULL,
  743. NULL,
  744. 0,
  745. (LPMAPITABLE *) lppUnk);
  746. break;
  747. default:
  748. hResult = ResultFromScode(MAPI_E_NO_SUPPORT);
  749. break;
  750. }
  751. out:
  752. LeaveCriticalSection(&lpABUser->cs);
  753. DebugTraceResult(ABU_OpenProperty, hResult);
  754. return hResult;
  755. }
  756. /**********************************************************************
  757. *
  758. * Private functions
  759. */
  760. /****************************************************************************
  761. FUNCTION: SortCountriesList
  762. PURPOSE: prepares (for qsort) and sorts a countries list returned by TAPI,
  763. by country name (TAPI returns a list sorted by the country ID)
  764. PARAMETERS: [in] lpLineCountryList - the list of countries retuned by TAPI
  765. [out] lpCountriesList - a sorted list country names/IDs structures
  766. ****************************************************************************/
  767. void
  768. SortCountriesList(
  769. HINSTANCE hInst,
  770. LPLINECOUNTRYLIST lpLineCountryList,
  771. LPCOUNTRIESLIST lpCountriesList
  772. )
  773. {
  774. LPLINECOUNTRYENTRY lprgLineCountryEntry = NULL;
  775. ULONG country;
  776. //
  777. // Create a "no country" entry
  778. //
  779. LoadString( hInst, IDS_NONE, lpCountriesList[0].szDisplayName, MAX_DISPLAY_NAME);
  780. lpCountriesList[0].dwValue = 0;
  781. //
  782. // Point to the first country in the structure
  783. //
  784. lprgLineCountryEntry =
  785. (LPLINECOUNTRYENTRY)((LPBYTE)(lpLineCountryList)
  786. + lpLineCountryList->dwCountryListOffset);
  787. //
  788. // Loop through LINECOUNTRYENTRY structures and add to the array
  789. //
  790. for (country=0; country < lpLineCountryList->dwNumCountries; country++)
  791. {
  792. if ((lprgLineCountryEntry[country].dwCountryNameSize != 0) &&
  793. (lprgLineCountryEntry[country].dwCountryNameOffset != 0L))
  794. {
  795. LPTSTR szCountryName = (LPTSTR)((LPBYTE) lpLineCountryList + lprgLineCountryEntry[country].dwCountryNameOffset);
  796. DWORD dwCountryID = lprgLineCountryEntry[country].dwCountryID;
  797. DWORD dwCountryCode = lprgLineCountryEntry[country].dwCountryCode;
  798. //
  799. // Create a "country-name (area-code)" string
  800. //
  801. #ifdef UNICODE
  802. _snwprintf(
  803. #else
  804. _snprintf(
  805. #endif
  806. lpCountriesList[country+1].szDisplayName,
  807. COUNTRY_NAME_SIZE,
  808. TEXT("%s (%d)"),
  809. szCountryName,
  810. dwCountryCode
  811. );
  812. lpCountriesList[country+1].dwValue = dwCountryID;
  813. }
  814. }
  815. //
  816. // now sort the array by the country name
  817. //
  818. qsort(
  819. lpCountriesList,
  820. lpLineCountryList->dwNumCountries + 1,
  821. SIZEOF(COUNTRIESLIST),
  822. #ifdef UNICODE
  823. _wcsicmp
  824. #else
  825. _mbsicmp
  826. #endif
  827. );
  828. }
  829. /****************************************************************************
  830. FUNCTION: HrBuildDDLBXCountriesTable
  831. PURPOSE: builds a country codes table to use by MAPI to display the
  832. countries list box
  833. PARAMETERS: [in] lpABUser - the user object
  834. RETURNS: hResult
  835. ****************************************************************************/
  836. enum { ivallbxPR_DISPLAY_NAME = 0,
  837. ivallbxPR_ENTRYID,
  838. ivallbxPR_DISPLAY_TYPE,
  839. ivallbxPR_COUNTRY_ID,
  840. cvallbxMax };
  841. const SizedSPropTagArray(cvallbxMax, tagaColSetCountries) =
  842. {
  843. cvallbxMax,
  844. {
  845. PR_DISPLAY_NAME_A,
  846. PR_ENTRYID,
  847. PR_DISPLAY_TYPE,
  848. PR_COUNTRY_ID,
  849. }
  850. };
  851. OPTIONS_ENTRYID OptionsEntryID=
  852. {
  853. {0, 0, 0, 0},
  854. MUIDABMAWF,
  855. MAWF_VERSION,
  856. MAWF_UNKNOWN,
  857. 0
  858. };
  859. HRESULT
  860. HrBuildDDLBXCountriesTable(LPABUSER lpABUser)
  861. {
  862. SCODE sc;
  863. HRESULT hResult;
  864. SPropValue rgsPropValue[cvallbxMax];
  865. SRow sRow;
  866. TCHAR szDisplay[100];
  867. ULONG country;
  868. HINSTANCE hInst;
  869. LPLINECOUNTRYLIST lpLineCountryList = NULL; // TAPI
  870. LPLINECOUNTRYENTRY lprgLineCountryEntry = NULL; // TAPI
  871. LPCOUNTRIESLIST lpCountriesList = NULL; // Mine
  872. #ifdef UNICODE
  873. CHAR szAnsiDisplay[100];
  874. #endif
  875. // get the instance, so I can load strings from the resource file
  876. hInst = lpABUser->hLibrary;
  877. /* Create a TaD*/
  878. sc = CreateTable( (LPIID)&IID_IMAPITableData,
  879. lpABUser->lpAllocBuff,
  880. lpABUser->lpAllocMore,
  881. lpABUser->lpFreeBuff,
  882. lpABUser->lpMalloc,
  883. 0,
  884. PR_DISPLAY_NAME_A,
  885. (LPSPropTagArray)&tagaColSetCountries,
  886. &(lpABUser->lpTDatDDListBox)
  887. );
  888. if (FAILED(sc))
  889. {
  890. hResult = ResultFromScode(sc);
  891. goto out;
  892. }
  893. // constants
  894. sRow.cValues = cvallbxMax;
  895. sRow.lpProps = rgsPropValue;
  896. rgsPropValue[ivallbxPR_DISPLAY_NAME].ulPropTag = PR_DISPLAY_NAME_A;
  897. #ifdef UNICODE
  898. szAnsiDisplay[0] = 0;
  899. rgsPropValue[ivallbxPR_DISPLAY_NAME].Value.lpszA = szAnsiDisplay;
  900. #else
  901. szDisplay[0] = 0;
  902. rgsPropValue[ivallbxPR_DISPLAY_NAME].Value.lpszA = szDisplay;
  903. #endif
  904. /*
  905. * For this release of MAPI the following two properties are required
  906. * for all listboxes exposed in any details dialog. This requirement is
  907. * scheduled to be removed before ship
  908. */
  909. rgsPropValue[ivallbxPR_ENTRYID].ulPropTag = PR_ENTRYID;
  910. rgsPropValue[ivallbxPR_ENTRYID].Value.bin.lpb = (LPBYTE) &OptionsEntryID;
  911. rgsPropValue[ivallbxPR_ENTRYID].Value.bin.cb = CBOPTIONS_ENTRYID;
  912. rgsPropValue[ivallbxPR_DISPLAY_TYPE].ulPropTag = PR_DISPLAY_TYPE;
  913. rgsPropValue[ivallbxPR_DISPLAY_TYPE].Value.l = 0; /* There are no defines for this yet */
  914. rgsPropValue[ivallbxPR_COUNTRY_ID].ulPropTag = PR_COUNTRY_ID;
  915. /*
  916. * Create the country list
  917. */
  918. // get the country info structure from TAPI
  919. if (!GetCountry(0, &lpLineCountryList))
  920. goto out;
  921. //
  922. // allocate a buffer for the country names and IDs
  923. // the allocation here is a best guess and could be wrong
  924. //
  925. sc = lpABUser->lpAllocBuff(
  926. (lpLineCountryList->dwNumCountries+1) * sizeof(COUNTRIESLIST),
  927. (LPVOID *) & lpCountriesList);
  928. if (FAILED(sc))
  929. {
  930. hResult = ResultFromScode (sc);
  931. goto out;
  932. }
  933. SortCountriesList(hInst, lpLineCountryList, lpCountriesList);
  934. // lpCountriesList now points to the sorted list of countries
  935. for (country=0; country < (lpLineCountryList->dwNumCountries + 1); country++)
  936. {
  937. OptionsEntryID.ulRowNumber = country;
  938. szDisplay[0] = 0;
  939. lstrcpy(szDisplay, lpCountriesList[country].szDisplayName);
  940. #ifdef UNICODE
  941. szAnsiDisplay[0] = 0;
  942. WideCharToMultiByte( CP_ACP, 0, szDisplay, -1, szAnsiDisplay, ARRAYSIZE(szAnsiDisplay), NULL, NULL );
  943. #endif
  944. rgsPropValue[ivallbxPR_COUNTRY_ID].Value.ul = lpCountriesList[country].dwValue;
  945. hResult = lpABUser->lpTDatDDListBox->lpVtbl->HrModifyRow(
  946. lpABUser->lpTDatDDListBox,
  947. &sRow);
  948. if (HR_FAILED(hResult))
  949. {
  950. /*
  951. * Mask errors here...
  952. * We want to do this because it's probibly still a valid
  953. * table data object that I can get views from. Most likely
  954. * just some of the rows will be missing...
  955. */
  956. hResult = hrSuccess;
  957. break;
  958. }
  959. }
  960. /*
  961. * get rid of any warnings
  962. */
  963. hResult = hrSuccess;
  964. out:
  965. // Free the buffer
  966. // Buffer was allocated by GetCountry using my alllocation function
  967. if (lpLineCountryList)
  968. LocalFree( lpLineCountryList );
  969. lpABUser->lpFreeBuff(lpCountriesList);
  970. DebugTraceResult(HrBuildDDLBXCountriesTable, hResult);
  971. return hResult;
  972. }
  973. /*******************************************************
  974. *
  975. * The button Interface
  976. *
  977. *******************************************************/
  978. // The General button methods
  979. ABUBUTT_Vtbl vtblABUBUTT =
  980. {
  981. ABUBUTT_QueryInterface,
  982. (ABUBUTT_AddRef_METHOD *) ROOT_AddRef,
  983. ABUBUTT_Release,
  984. (ABUBUTT_GetLastError_METHOD *) ROOT_GetLastError,
  985. ABUBUTT_Activate,
  986. ABUBUTT_GetState
  987. };
  988. HRESULT
  989. HrNewABUserButton( LPMAPICONTROL * lppMAPICont,
  990. LPABLOGON lpABLogon,
  991. HINSTANCE hLibrary,
  992. LPALLOCATEBUFFER lpAllocBuff,
  993. LPALLOCATEMORE lpAllocMore,
  994. LPFREEBUFFER lpFreeBuff,
  995. LPMALLOC lpMalloc,
  996. ULONG ulPropTag
  997. )
  998. {
  999. LPABUBUTT lpABUButt = NULL;
  1000. SCODE scode;
  1001. /*
  1002. * Creates a the object behind the button
  1003. */
  1004. if ((scode = lpAllocBuff( SIZEOF (ABUBUTT),
  1005. (LPVOID *) & lpABUButt)) != SUCCESS_SUCCESS
  1006. )
  1007. {
  1008. DebugTraceSc(HrNewABUserButton, scode);
  1009. return ResultFromScode (scode);
  1010. }
  1011. lpABUButt->lpVtbl = &vtblABUBUTT;
  1012. lpABUButt->lcInit = 1;
  1013. lpABUButt->hResult = hrSuccess;
  1014. lpABUButt->idsLastError = 0;
  1015. lpABUButt->hLibrary = hLibrary;
  1016. lpABUButt->lpAllocBuff = lpAllocBuff;
  1017. lpABUButt->lpAllocMore = lpAllocMore;
  1018. lpABUButt->lpFreeBuff = lpFreeBuff;
  1019. lpABUButt->lpMalloc = lpMalloc;
  1020. lpABUButt->lpABLogon = lpABLogon;
  1021. // So that I'll know later which button this object refers to
  1022. // currently not used. Will use only if more than one button on the template
  1023. lpABUButt->ulPropTag = ulPropTag;
  1024. /*
  1025. * I need my parent object to stay around while this object
  1026. * does so that I can get to it in my Activate() method.
  1027. * To do this just AddRef() it.
  1028. */
  1029. // lpABC->lpVtbl->AddRef(lpABC);
  1030. InitializeCriticalSection(&lpABUButt->cs);
  1031. *lppMAPICont = (LPMAPICONTROL) lpABUButt;
  1032. return hrSuccess;
  1033. }
  1034. /*************************************************************************
  1035. *
  1036. *
  1037. - ABUBUTT_QueryInterface
  1038. -
  1039. *
  1040. * Allows QI'ing to IUnknown and IMAPIControl.
  1041. *
  1042. */
  1043. STDMETHODIMP
  1044. ABUBUTT_QueryInterface( LPABUBUTT lpABUButt,
  1045. REFIID lpiid,
  1046. LPVOID FAR * lppNewObj
  1047. )
  1048. {
  1049. HRESULT hResult = hrSuccess;
  1050. /* Minimally validate the lpABUButt parameter */
  1051. if (IsBadReadPtr(lpABUButt, SIZEOF(ABUBUTT)))
  1052. {
  1053. hResult = ResultFromScode(E_INVALIDARG);
  1054. goto out;
  1055. }
  1056. if (lpABUButt->lpVtbl != &vtblABUBUTT)
  1057. {
  1058. hResult = ResultFromScode(E_INVALIDARG);
  1059. goto out;
  1060. }
  1061. /* Check the other parameters */
  1062. if (!lpiid || IsBadReadPtr(lpiid, (UINT) SIZEOF(IID)))
  1063. {
  1064. hResult = ResultFromScode(E_INVALIDARG);
  1065. goto out;
  1066. }
  1067. if (IsBadWritePtr(lppNewObj, (UINT) SIZEOF(LPVOID)))
  1068. {
  1069. hResult = ResultFromScode(E_INVALIDARG);
  1070. goto out;
  1071. }
  1072. /* See if the requested interface is one of ours */
  1073. if ( memcmp(lpiid, &IID_IUnknown, SIZEOF(IID)) &&
  1074. memcmp(lpiid, &IID_IMAPIControl, SIZEOF(IID))
  1075. )
  1076. {
  1077. *lppNewObj = NULL; /* OLE requires zeroing [out] parameter */
  1078. hResult = ResultFromScode(E_NOINTERFACE);
  1079. goto out;
  1080. }
  1081. /* We'll do this one. Bump the usage count and return a new pointer. */
  1082. EnterCriticalSection(&lpABUButt->cs);
  1083. ++lpABUButt->lcInit;
  1084. LeaveCriticalSection(&lpABUButt->cs);
  1085. *lppNewObj = lpABUButt;
  1086. out:
  1087. DebugTraceResult(ABUBUTT_QueryInterface, hResult);
  1088. return hResult;
  1089. }
  1090. /*
  1091. - ABUBUTT_Release
  1092. -
  1093. * Releases and cleans up this object
  1094. */
  1095. STDMETHODIMP_(ULONG)
  1096. ABUBUTT_Release(LPABUBUTT lpABUButt)
  1097. {
  1098. long lcInit;
  1099. /* Minimally validate the lpABUButt parameter */
  1100. if (IsBadReadPtr(lpABUButt, SIZEOF(ABUBUTT)))
  1101. {
  1102. return 1;
  1103. }
  1104. if (lpABUButt->lpVtbl != &vtblABUBUTT)
  1105. {
  1106. return 1;
  1107. }
  1108. EnterCriticalSection(&lpABUButt->cs);
  1109. lcInit = --lpABUButt->lcInit;
  1110. LeaveCriticalSection(&lpABUButt->cs);
  1111. if (lcInit == 0)
  1112. {
  1113. /*
  1114. * Release my parent
  1115. */
  1116. // lpABUButt->lpABC->lpVtbl->Release(lpABUButt->lpABC);
  1117. /*
  1118. * Destroy the critical section for this object
  1119. */
  1120. DeleteCriticalSection(&lpABUButt->cs);
  1121. /*
  1122. * Set the Jump table to NULL. This way the client will find out
  1123. * real fast if it's calling a method on a released object. That is,
  1124. * the client will crash. Hopefully, this will happen during the
  1125. * development stage of the client.
  1126. */
  1127. lpABUButt->lpVtbl = NULL;
  1128. /*
  1129. * Free the object
  1130. */
  1131. lpABUButt->lpFreeBuff(lpABUButt);
  1132. return 0;
  1133. }
  1134. return lcInit;
  1135. }
  1136. /*************************************************************************
  1137. *
  1138. *
  1139. - ABUBUTT_Activate
  1140. -
  1141. * Called when the user presses the button
  1142. *
  1143. *
  1144. */
  1145. STDMETHODIMP
  1146. ABUBUTT_Activate( LPABUBUTT lpABUButt,
  1147. ULONG ulFlags,
  1148. ULONG ulUIParam
  1149. )
  1150. {
  1151. SCODE sc = SUCCESS_SUCCESS;
  1152. switch (lpABUButt->ulPropTag)
  1153. {
  1154. default:
  1155. DebugTraceSc(ABUBUTT_Activate, lpABUButt->ulPropTag);
  1156. return ResultFromScode (E_FAIL);
  1157. }
  1158. return hrSuccess;
  1159. }
  1160. /*************************************************************************
  1161. *
  1162. *
  1163. - ABUBUTT_GetState
  1164. -
  1165. * Called by the client to find out if the button is enabled or disabled.
  1166. *
  1167. *
  1168. */
  1169. STDMETHODIMP
  1170. ABUBUTT_GetState( LPABUBUTT lpABUButt,
  1171. ULONG ulFlags,
  1172. ULONG * lpulState )
  1173. {
  1174. switch (lpABUButt->ulPropTag)
  1175. {
  1176. default:
  1177. DebugTraceSc(ABUBUTT_GetState, lpABUButt->ulPropTag);
  1178. return ResultFromScode (E_FAIL);
  1179. }
  1180. return hrSuccess;
  1181. }
  1182. #undef _FAXAB_ABUSER