/*********************************************************************** * * ABCONT.C * * Microsoft At Work Fax AB directory container object * * This file contains the code for implementing the Microsoft At Work Fax AB * directory container object. * * This directory container was retrieved by OpenEntry on the entryid * retrieved from the single row of the hierarchy table (IVTROOT in root.c). * * Many things are not yet implemented in this object. For example, no * advanced search dialog, or details dialog are available. Also the * ICON to PR_DISPLAY_TYPE table isn't available. * * * The following routines are implemented in this file: * * HrNewFaxDirectory * ABC_Release * ABC_SaveChanges * ABC_OpenProperty * ABC_GetContentsTable * ABC_GetHierarchyTable * * HrGetDetailsDialog * * HrNewABCButton * ABCBUTT_QueryInterface * ABCBUTT_Release * ABCBUTT_Activate * ABCBUTT_GetState * * Copyright 1992, 1993 Microsoft Corporation. All Rights Reserved. * * Revision History: * * When Who What * -------- ------------------ --------------------------------------- * 1.1.94 MAPI Original source from MAPI sample AB Provider * 1.27.94 Yoram Yaacovi Modifications to make it an At Work Fax ABP * 3.6.94 Yoram Yaacovi Update to MAPI build 154 * 4.1.94 Yoram Yaacovi Update to MAPI and Sample AB build 157 * 8.1.94 Yoram Yaacovi Update to MAPI and Sample AB build 304 * 10.6.94 Yoram Yaacovi Update to MAPI and Sample AB build 313 * Mainly adding a ResolveName method to ABContainer * 11.3.94 Yoram Yaacovi Update to MAPI 318. * ***********************************************************************/ #include "faxab.h" #define PR_BUTTON_PRESS PROP_TAG(PT_OBJECT, 0x6603) #define PR_FAB_FILE_TEMP_A PROP_TAG(PT_STRING8,0x6605) #define PR_IMPORT_FROM_FILE_A PROP_TAG(PT_STRING8,0x6606) #define PR_IMPORT_TO_FILE_A PROP_TAG(PT_STRING8,0x6607) #define PR_BUTTON_IMPORT_A PROP_TAG(PT_STRING8,0x6608) #define PR_IMPORT_FORMAT_A PROP_TAG(PT_STRING8,0x6609) #define PR_DDLBX_IMPORT_FORMATS_A PROP_TAG(PT_STRING8,0x660a) #define FAB_FILE_NAME_NOTIF_ID 99L /***************************** **** Notification ********** *****************************/ typedef struct { MAPIUID muid; ULONG ulIdc; } NOTIFDATA; NOTIFDATA notifdata = { MUIDABMAWF, IDC_DIR_FAB_FILE_NAME }; /***************************** ** Display Table structures * *****************************/ DTBLEDIT editDirFileName = { SIZEOF(DTBLEDIT), 0, MAX_PATH, PR_FAB_FILE_TEMP_A }; DTBLEDIT editImportFromFile = { SIZEOF(DTBLEDIT), 0, MAX_PATH, PR_IMPORT_FROM_FILE_A }; DTBLEDIT editImportToFile = { SIZEOF(DTBLEDIT), 0, MAX_PATH, PR_IMPORT_TO_FILE_A }; DTBLBUTTON buttonImport = { SIZEOF(DTBLBUTTON), 0, PR_BUTTON_IMPORT_A }; DTBLBUTTON buttonDirChange = { SIZEOF(DTBLBUTTON), 0, PR_BUTTON_PRESS }; DTBLDDLBX ddlbxImportFormats = { SIZEOF(DTBLDDLBX), PR_DISPLAY_NAME_A, PR_IMPORT_FORMAT_A, PR_DDLBX_IMPORT_FORMATS_A }; /* General page layout */ DTCTL rgdtctlDirGeneral[] = { /* directory general propery page */ { DTCT_PAGE, 0, NULL, 0, NULL, 0, &dtblpage }, /* static controls and edit control containing fab file name */ { DTCT_LABEL, 0, NULL, 0, NULL, IDC_STATIC_CONTROL, &dtbllabel }, { DTCT_LABEL, 0, NULL, 0, NULL, IDC_STATIC_CONTROL, &dtbllabel }, { DTCT_EDIT, 0, (LPBYTE)¬ifdata, SIZEOF(NOTIFDATA), (LPTSTR)szFileNameFilter, IDC_DIR_FAB_FILE_NAME, &editDirFileName }, /* push button for changing fab file */ { DTCT_BUTTON, 0, NULL, 0, NULL, IDC_DIR_CHANGE, &buttonDirChange }, /* Import GroupBox */ { DTCT_GROUPBOX, 0, NULL, 0, NULL, IDC_STATIC_CONTROL, &dtblgroupbox }, // Import from file { DTCT_LABEL, 0, NULL, 0, NULL, IDC_STATIC_CONTROL, &dtbllabel }, { DTCT_EDIT, 0, NULL, 0, (LPTSTR)szFileNameFilter, IDC_IMPORT_FROM_FILE, &editImportFromFile }, // Import format { DTCT_LABEL, 0, NULL, 0, NULL, IDC_STATIC_CONTROL, &dtbllabel }, { DTCT_DDLBX, 0, NULL, 0, NULL, IDC_IMPORT_FORMAT, &ddlbxImportFormats }, // Import into file { DTCT_LABEL, 0, NULL, 0, NULL, IDC_STATIC_CONTROL, &dtbllabel }, { DTCT_EDIT, 0, NULL, 0, (LPTSTR)szFileNameFilter, IDC_IMPORT_TO_FILE, &editImportToFile }, // Import Button { DTCT_BUTTON, 0, NULL, 0, NULL, IDC_IMPORT, &buttonImport }, }; /* Display table pages for Directory */ DTPAGE rgdtpageDir[] = { { SIZEOF(rgdtctlDirGeneral) / SIZEOF(DTCTL), (LPTSTR)MAKEINTRESOURCE(DirGeneralPage), TEXT(""), rgdtctlDirGeneral } }; /* * ABCont jump table is defined here... */ ABC_Vtbl vtblABC = { (ABC_QueryInterface_METHOD *) ROOT_QueryInterface, (ABC_AddRef_METHOD *) ROOT_AddRef, (ABC_AddRef_METHOD *) ABC_Release, (ABC_GetLastError_METHOD *) ROOT_GetLastError, ABC_SaveChanges, (ABC_GetProps_METHOD *) WRAP_GetProps, (ABC_GetPropList_METHOD *) WRAP_GetPropList, ABC_OpenProperty, (ABC_SetProps_METHOD *) WRAP_SetProps, (ABC_DeleteProps_METHOD *) WRAP_DeleteProps, (ABC_CopyTo_METHOD *) WRAP_CopyTo, (ABC_CopyProps_METHOD *) WRAP_CopyProps, (ABC_GetNamesFromIDs_METHOD *) WRAP_GetNamesFromIDs, (ABC_GetIDsFromNames_METHOD *) WRAP_GetIDsFromNames, ABC_GetContentsTable, ABC_GetHierarchyTable, (ABC_OpenEntry_METHOD *) ROOT_OpenEntry, (ABC_SetSearchCriteria_METHOD *) ROOT_SetSearchCriteria, (ABC_GetSearchCriteria_METHOD *) ROOT_GetSearchCriteria, (ABC_CreateEntry_METHOD *) ROOT_CreateEntry, (ABC_CopyEntries_METHOD *) ROOT_CopyEntries, (ABC_DeleteEntries_METHOD *) ROOT_DeleteEntries, (ABC_ResolveNames_METHOD *) ROOT_ResolveNames }; static const SizedSPropTagArray(1, ABC_SPT_TMP_FAB) = {1, {PR_FAB_FILE_TEMP_A}}; /* * Private functions */ HRESULT HrNewABCButton( LPABCNT lpABC, ULONG ulInterfaceOptions, ULONG ulFlags, LPMAPICONTROL FAR * lppMAPICont); HRESULT HrGetSearchDialog(LPABCNT lpABC, LPMAPITABLE * lppSearchTable); HRESULT HrGetDetailsDialog(LPABCNT lpABC, LPMAPITABLE * lppDetailsTable); /************************************************************************* * - HrNewFaxDirectory - * Creates a Directory container object. * * */ /* * Properties that are initially set on this object */ enum { ivalabcPR_DISPLAY_TYPE = 0, ivalabcPR_OBJECT_TYPE, ivalabcPR_ENTRYID, ivalabcPR_RECORD_KEY, ivalabcPR_SEARCH_KEY, ivalabcPR_DISPLAY_NAME, ivalabcPR_CONTAINER_FLAGS, ivalabcPR_FAB_FILE, ivalabcPR_FAB_FILE_TEMP, ivalabcPR_IMPORT_FROM_FILE, ivalabcPR_IMPORT_TO_FILE, ivalabcPR_IMPORT_FORMAT, cvalabcMax }; HRESULT HrNewFaxDirectory( LPABCONT * lppABC, ULONG * lpulObjType, LPABLOGON lpABLogon, LPCIID lpInterface, HINSTANCE hLibrary, LPALLOCATEBUFFER lpAllocBuff, LPALLOCATEMORE lpAllocMore, LPFREEBUFFER lpFreeBuff, LPMALLOC lpMalloc ) { HINSTANCE hInst; HRESULT hResult = hrSuccess; LPABCNT lpABC = NULL; SCODE sc; LPPROPDATA lpPropData = NULL; SPropValue spv[cvalabcMax]; MAPIUID * lpMuidLogon; LPTSTR lpszFileName; #ifdef UNICODE CHAR szAnsiFileName[ MAX_PATH ]; #endif ULONG ulPropAccess = IPROP_CLEAN|IPROP_READWRITE; /* READWRITE is redundant */ DIR_ENTRYID eidRoot = { {0, 0, 0, 0}, MUIDABMAWF, MAWF_VERSION, MAWF_DIRECTORY }; /* Do I support this interface?? */ if (lpInterface) { if (memcmp(lpInterface, &IID_IABContainer, SIZEOF(IID)) && memcmp(lpInterface, &IID_IMAPIContainer, SIZEOF(IID)) && memcmp(lpInterface, &IID_IMAPIProp, SIZEOF(IID)) && memcmp(lpInterface, &IID_IUnknown, SIZEOF(IID))) { DebugTraceSc(HrNewSampDirectory, MAPI_E_INTERFACE_NOT_SUPPORTED); return ResultFromScode(MAPI_E_INTERFACE_NOT_SUPPORTED); } } /* * Allocate space for the directory container structure */ sc = lpAllocBuff( SIZEOF(ABCNT), (LPVOID *) & lpABC); if (sc != SUCCESS_SUCCESS) { DebugTraceSc( HrNewFaxDirectory, sc ); hResult = ResultFromScode( sc ); goto err; } lpABC->lpVtbl = &vtblABC; lpABC->lcInit = 1; lpABC->hResult = hrSuccess; lpABC->idsLastError = 0; lpABC->hLibrary = hLibrary; lpABC->lpAllocBuff = lpAllocBuff; lpABC->lpAllocMore = lpAllocMore; lpABC->lpFreeBuff = lpFreeBuff; lpABC->lpMalloc = lpMalloc; lpABC->lpABLogon = lpABLogon; lpABC->lpTDatDetails = NULL; // Get the instance handle, so that I can get the display strings off the resource file hInst = lpABC->hLibrary; /* * Create lpPropData */ sc = CreateIProp( (LPIID) &IID_IMAPIPropData, lpAllocBuff, lpAllocMore, lpFreeBuff, lpMalloc, &lpPropData ); if (FAILED(sc)) { DebugTraceSc(HrNewFaxDirectory, sc); hResult=ResultFromScode (sc); goto err; } /* * initialize the muid in the entry id */ lpMuidLogon = LpMuidFromLogon(lpABLogon); eidRoot.muidID = *lpMuidLogon; /* * Set up initial set of properties associated with this * container. */ spv[ivalabcPR_DISPLAY_TYPE].ulPropTag = PR_DISPLAY_TYPE; spv[ivalabcPR_DISPLAY_TYPE].Value.l = DT_NOT_SPECIFIC; spv[ivalabcPR_OBJECT_TYPE].ulPropTag = PR_OBJECT_TYPE; spv[ivalabcPR_OBJECT_TYPE].Value.l = MAPI_ABCONT; spv[ivalabcPR_ENTRYID].ulPropTag = PR_ENTRYID; spv[ivalabcPR_ENTRYID].Value.bin.cb = SIZEOF(DIR_ENTRYID); spv[ivalabcPR_ENTRYID].Value.bin.lpb = (LPBYTE) &eidRoot; spv[ivalabcPR_RECORD_KEY].ulPropTag = PR_RECORD_KEY; spv[ivalabcPR_RECORD_KEY].Value.bin.cb = SIZEOF(DIR_ENTRYID); spv[ivalabcPR_RECORD_KEY].Value.bin.lpb = (LPBYTE) &eidRoot; spv[ivalabcPR_SEARCH_KEY].ulPropTag = PR_SEARCH_KEY; spv[ivalabcPR_SEARCH_KEY].Value.bin.cb = SIZEOF(DIR_ENTRYID); spv[ivalabcPR_SEARCH_KEY].Value.bin.lpb = (LPBYTE) &eidRoot; // MAPI is not UNICODE for this one... spv[ivalabcPR_DISPLAY_NAME].ulPropTag = PR_DISPLAY_NAME_A; // MAPI 304 sample AB // GenerateContainerDN(lpABLogon, szBuf); // spv[ivalabcPR_DISPLAY_NAME].Value.LPSZ = szBuf; if ( (sc = lpAllocMore( MAX_DISPLAY_NAME, (LPVOID) lpABC, (LPVOID *) & spv[ivalabcPR_DISPLAY_NAME].Value.lpszA)) != SUCCESS_SUCCESS) { hResult = ResultFromScode( sc ); goto err; } else { // Load the strings // A display name longer than MAX_DISPLAY_NAME will be truncated // MAPI is not UNICODE for this attribute LoadStringA( hInst, IDS_APP_NAME, spv[ivalabcPR_DISPLAY_NAME].Value.lpszA, MAX_DISPLAY_NAME ); } spv[ivalabcPR_CONTAINER_FLAGS].ulPropTag = PR_CONTAINER_FLAGS; spv[ivalabcPR_CONTAINER_FLAGS].Value.l = AB_RECIPIENTS; /* * Get the current .FAB file name from our logon object */ hResult = HrLpszGetCurrentFileName(lpABLogon, &lpszFileName); if (HR_FAILED(hResult)) { goto err; } // MAPI ==> NO UNICODE FOR YOU! #ifdef UNICODE spv[ivalabcPR_FAB_FILE].ulPropTag = PR_FAB_FILE_A; szAnsiFileName[0] = 0; WideCharToMultiByte( CP_ACP, 0, lpszFileName, -1, szAnsiFileName, ARRAYSIZE(szAnsiFileName), NULL, NULL ); spv[ivalabcPR_FAB_FILE].Value.lpszA = szAnsiFileName; spv[ivalabcPR_FAB_FILE_TEMP].ulPropTag = PR_FAB_FILE_TEMP_A; spv[ivalabcPR_FAB_FILE_TEMP].Value.lpszA = szAnsiFileName; spv[ivalabcPR_IMPORT_FROM_FILE].ulPropTag = PR_IMPORT_FROM_FILE_A; spv[ivalabcPR_IMPORT_FROM_FILE].Value.lpszA = ""; spv[ivalabcPR_IMPORT_TO_FILE].ulPropTag = PR_IMPORT_TO_FILE_A; spv[ivalabcPR_IMPORT_TO_FILE].Value.lpszA = szAnsiFileName; #else spv[ivalabcPR_FAB_FILE].ulPropTag = PR_FAB_FILE_A; spv[ivalabcPR_FAB_FILE].Value.lpszA = (LPSTR)lpszFileName; spv[ivalabcPR_FAB_FILE_TEMP].ulPropTag = PR_FAB_FILE_TEMP_A; spv[ivalabcPR_FAB_FILE_TEMP].Value.lpszA = (LPSTR)lpszFileName; spv[ivalabcPR_IMPORT_FROM_FILE].ulPropTag = PR_IMPORT_FROM_FILE_A; spv[ivalabcPR_IMPORT_FROM_FILE].Value.lpszA = ""; spv[ivalabcPR_IMPORT_TO_FILE].ulPropTag = PR_IMPORT_TO_FILE_A; spv[ivalabcPR_IMPORT_TO_FILE].Value.lpszA = (LPSTR)lpszFileName; #endif spv[ivalabcPR_IMPORT_FORMAT].ulPropTag = PR_IMPORT_FORMAT_A; spv[ivalabcPR_IMPORT_FORMAT].Value.lpszA = "Your Favorite PIM"; /* * Set the default properties */ hResult = lpPropData->lpVtbl->SetProps( lpPropData, cvalabcMax, spv, NULL ); /* * No longer need this buffer */ lpFreeBuff(lpszFileName); if (HR_FAILED(hResult)) { DebugTraceSc( HrNewFaxDirectory, sc ); goto err; } lpPropData->lpVtbl->HrSetPropAccess( lpPropData, (LPSPropTagArray) &ABC_SPT_TMP_FAB, &ulPropAccess ); InitializeCriticalSection( &lpABC->cs ); lpABC->lpPropData = (LPMAPIPROP)lpPropData; *lppABC = (LPABCONT)lpABC; *lpulObjType = MAPI_ABCONT; out: DebugTraceResult(HrNewFaxDirectory, hResult); return hResult; err: /* * free the ABContainer object */ lpFreeBuff( lpABC ); /* * free the property storage object */ if (lpPropData) lpPropData->lpVtbl->Release(lpPropData); goto out; } /*************************************************** * * The actual ABContainer methods */ /* -------- * IUnknown */ /************************************************************************* * * - ABC_QueryInterface - * * Uses the ROOT method * */ /************************************************************************* * - ABC_AddRef - * * Uses the ROOT method * */ /************************************************** * - ABC_Release - * Decrement lpInit. * When lcInit == 0, free up the lpABC structure * */ STDMETHODIMP_(ULONG) ABC_Release(LPABCNT lpABC) { long lcInit; /* * Check to see if it has a jump table */ if (IsBadReadPtr(lpABC, SIZEOF(ABCNT))) { /* * No jump table found */ return 1; } /* * Check to see that it's the correct jump table */ if (lpABC->lpVtbl != &vtblABC) { /* * Not my jump table */ return 1; } EnterCriticalSection(&lpABC->cs); lcInit = --lpABC->lcInit; LeaveCriticalSection(&lpABC->cs); if (lcInit == 0) { /* * Get rid of the lpPropData */ if (lpABC->lpPropData) lpABC->lpPropData->lpVtbl->Release(lpABC->lpPropData); /* * Get rid of the details table */ if (lpABC->lpTDatDetails) lpABC->lpTDatDetails->lpVtbl->Release(lpABC->lpTDatDetails); /* * Destroy the critical section for this object */ DeleteCriticalSection(&lpABC->cs); /* * Set the Jump table to NULL. This way the client will find out * real fast if it's calling a method on a released object. That is, * the client will crash. Hopefully, this will happen during the * development stage of the client. */ lpABC->lpVtbl = NULL; /* * Need to free the object */ lpABC->lpFreeBuff(lpABC); return 0; } return lpABC->lcInit; } /* --------- * IMAPIProp */ /* * GetLastError - use ROOT's * * */ /************************************************************************* * - ABC_SaveChanges - * This is used to save changes associated with the search dialog * in order to get the advanced search restriction and to save changes * associated with the container details dialog. * */ SPropTagArray SPT_FAB_FILE = { 1, { PR_FAB_FILE_TEMP_A } }; STDMETHODIMP ABC_SaveChanges (LPABCNT lpABC, ULONG ulFlags) { HRESULT hResult = hrSuccess; ULONG ulCount; LPSPropValue lpspv = NULL; ULONG FAR * rgulAccess = NULL; ULONG ulAccess = IPROP_CLEAN|IPROP_READWRITE; /* READWRITE is redundant */ LPSPropTagArray lpspt = (LPSPropTagArray) &ABC_SPT_TMP_FAB; LPPROPDATA lpPropData = (LPPROPDATA) lpABC->lpPropData; #ifdef UNICODE WCHAR szFileName[ MAX_PATH ]; #endif /* * Check to see if it has a jump table */ if (IsBadReadPtr(lpABC, sizeof(ABCNT))) { /* * No jump table found */ hResult = ResultFromScode(E_INVALIDARG); return hResult; } /* * Check to see that it's the correct jump table */ if (lpABC->lpVtbl != &vtblABC) { /* * Not my jump table */ hResult = ResultFromScode(E_INVALIDARG); return hResult; } EnterCriticalSection(&lpABC->cs); /* * Check to see if anyone has dirtied the PR_FAB_FILE_TEMP */ lpPropData->lpVtbl->HrGetPropAccess( lpPropData, (LPSPropTagArray *) &lpspt, &rgulAccess); if (!rgulAccess || !((*rgulAccess) & IPROP_DIRTY)) { /* * No, nothing to update then head on out */ goto ret; } /* * Go ahead and set back to being clean */ (void )lpPropData->lpVtbl->HrSetPropAccess( lpPropData, (LPSPropTagArray) lpspt, &ulAccess); /* * Get the temporary fab file name */ hResult = lpPropData->lpVtbl->GetProps( lpPropData, &SPT_FAB_FILE, 0, // ansi &ulCount, &lpspv); if (HR_FAILED(hResult)) { goto ret; } if (lpspv->ulPropTag != PR_FAB_FILE_TEMP_A) { /* * There's no reason this property shouldn't be there. */ hResult = ResultFromScode(MAPI_E_CORRUPT_DATA); goto ret; } /* * Save the new name back into the object as PR_FAB_FILE */ lpspv->ulPropTag = PR_FAB_FILE_A; hResult = lpPropData->lpVtbl->SetProps( lpPropData, 1, // ANSI lpspv, NULL); if (HR_FAILED(hResult)) { /* * Do nothing... So I couldn't save it away this time... */ hResult = hrSuccess; goto ret; } /* * Update every other object that needs this new information */ #ifdef UNICODE szFileName[0] = 0; MultiByteToWideChar( CP_ACP, 0, lpspv->Value.lpszA, -1, szFileName, ARRAYSIZE(szFileName) ); hResult = HrReplaceCurrentFileName(lpABC->lpABLogon, szFileName); #else hResult = HrReplaceCurrentFileName(lpABC->lpABLogon, lpspv->Value.LPSZ); #endif ret: LeaveCriticalSection(&lpABC->cs); lpABC->lpFreeBuff(lpspv); lpABC->lpFreeBuff(rgulAccess); DebugTraceResult(ABC_SaveChanges, hResult); return hResult; } /************************************************************************* * - ABC_OpenProperty - * This method allows the opening of the following object: * * PR_BUTTON_PRESS :- Gets the MAPIControl object associated * with the button on this container's details. * PR_DETAILS_TABLE :- Gets the display table associated with * the details for this container. * PR_SEARCH :- Gets the advanced search object associated with * this container. * PR_CONTAINER_CONTENTS :- Same as GetContentsTable() * PR_CONTAINER_HIERARCHY :- Same as GetHierarchyTable() * */ STDMETHODIMP ABC_OpenProperty( LPABCNT lpABC, ULONG ulPropTag, LPCIID lpiid, ULONG ulInterfaceOptions, ULONG ulFlags, LPUNKNOWN * lppUnk ) { HRESULT hResult; /* * Check to see if it has a jump table */ if (IsBadReadPtr(lpABC, SIZEOF(ABCNT))) { /* * No jump table found */ hResult = ResultFromScode( E_INVALIDARG ); DebugTraceResult( ABC_OpenProperty, hResult ); goto out; } /* * Check to see that it's the correct jump table */ if (lpABC->lpVtbl != &vtblABC) { /* * Not my jump table */ hResult = ResultFromScode( E_INVALIDARG ); DebugTraceResult(ABC_OpenProperty, hResult); goto out; } if (IsBadWritePtr(lppUnk, sizeof(LPUNKNOWN))) { /* * Got to be able to return an object */ hResult = ResultFromScode(E_INVALIDARG); goto out; } if (IsBadReadPtr(lpiid, (UINT) SIZEOF(IID))) { /* * An interface ID is required for this call. */ hResult = ResultFromScode(E_INVALIDARG); goto out; } /* * check for unknown flags */ if (ulFlags & ~(MAPI_DEFERRED_ERRORS | MAPI_CREATE | MAPI_MODIFY)) { hResult = ResultFromScode (MAPI_E_UNKNOWN_FLAGS); DebugTraceResult(ABC_OpenProperty, hResult); goto out; } /* * Check for flags we can't support */ if (ulFlags & (MAPI_CREATE|MAPI_MODIFY)) { hResult = ResultFromScode (E_ACCESSDENIED); DebugTraceResult(ABC_OpenProperty, hResult); goto out; } if (ulInterfaceOptions & ~MAPI_UNICODE) { /* * Only UNICODE flag should be set for any of the objects that might * be returned from this object. */ hResult = ResultFromScode(MAPI_E_UNKNOWN_FLAGS); goto out; } if ( ulInterfaceOptions & MAPI_UNICODE ) { hResult = ResultFromScode(MAPI_E_BAD_CHARWIDTH); DebugTraceArg( ABC_OpenProperty, "bad character width" ); goto out; } /* * Details for this directory entry */ if ( (ulPropTag == PR_DETAILS_TABLE) || (ulPropTag == PR_BUTTON_PRESS) || (ulPropTag == PR_CONTAINER_CONTENTS) || (ulPropTag == PR_CONTAINER_HIERARCHY)|| (ulPropTag == PR_SEARCH) ) { /* * Check to see if they're expecting a table interface */ if ( (ulPropTag != PR_BUTTON_PRESS) && (ulPropTag != PR_SEARCH) && memcmp(lpiid, &IID_IMAPITable, sizeof(IID)) ) { hResult = ResultFromScode(MAPI_E_INTERFACE_NOT_SUPPORTED); goto out; } switch (ulPropTag) { case PR_BUTTON_PRESS: { /* * Check to see if they're expecting a generic control interface */ if (memcmp( lpiid, &IID_IMAPIControl, SIZEOF(IID) )) { hResult = ResultFromScode(MAPI_E_INTERFACE_NOT_SUPPORTED); goto out; } hResult = HrNewABCButton( lpABC, ulInterfaceOptions, ulFlags, (LPMAPICONTROL FAR *) lppUnk ); break; } case PR_DETAILS_TABLE: { hResult = HrGetDetailsDialog(lpABC, (LPMAPITABLE *) lppUnk); break; } case PR_SEARCH: { /* * Check to see if they're expecting a generic control interface */ if (memcmp(lpiid, &IID_IMAPIContainer, SIZEOF(IID))) { hResult = ResultFromScode(MAPI_E_INTERFACE_NOT_SUPPORTED); goto out; } hResult = HrNewSearch( (LPMAPICONTAINER *) lppUnk, lpABC->lpABLogon, lpiid, lpABC->hLibrary, lpABC->lpAllocBuff, lpABC->lpAllocMore, lpABC->lpFreeBuff, lpABC->lpMalloc ); break; } case PR_CONTAINER_CONTENTS: { hResult = ABC_GetContentsTable( lpABC, 0, (LPMAPITABLE *) lppUnk); break; } case PR_CONTAINER_HIERARCHY: { hResult = ABC_GetHierarchyTable( lpABC, 0, (LPMAPITABLE *) lppUnk); break; } default: break; } } else { hResult = ResultFromScode (MAPI_E_NO_SUPPORT); } out: DebugTraceResult(ABC_OpenProperty, hResult); return hResult; } /************************************************************************* * - ABC_GetContentsTable - * * Retrieves the IMAPITable that has the contents of this container. * The big one! */ STDMETHODIMP ABC_GetContentsTable( LPABCNT lpABC, ULONG ulFlags, LPMAPITABLE * lppTable ) { HRESULT hResult; /* * Validate parameters */ /* * Check to see if it's large enough to be this object */ if (IsBadReadPtr(lpABC, SIZEOF(ABCNT))) { /* * Not large enough to be this object */ hResult = ResultFromScode(E_INVALIDARG); goto out; } /* * Check to see that it's the correct jump table */ if (lpABC->lpVtbl != &vtblABC) { /* * Not my jump table */ hResult = ResultFromScode (E_INVALIDARG); goto out; } /* * Check lppTable to validate its writability */ if (IsBadWritePtr (lppTable, SIZEOF(LPMAPITABLE))) { hResult = ResultFromScode (E_INVALIDARG); goto out; } /* * Check flags */ if (ulFlags & ~(MAPI_UNICODE|MAPI_DEFERRED_ERRORS|MAPI_ASSOCIATED)) { hResult = ResultFromScode(MAPI_E_UNKNOWN_FLAGS); goto out; } /* * Certain flags are not supported */ if (ulFlags & (MAPI_ASSOCIATED)) { hResult = ResultFromScode(MAPI_E_NO_SUPPORT); goto out; } if ( ulFlags & MAPI_UNICODE ) { DebugTraceArg( ABC_GetContentsTable, "Bad character width" ); hResult = ResultFromScode( MAPI_E_BAD_CHARWIDTH ); goto out; } /* * Create the new Contents table */ hResult = HrNewIVTAbc( lppTable, lpABC->lpABLogon, (LPABCONT) lpABC, lpABC->hLibrary, lpABC->lpAllocBuff, lpABC->lpAllocMore, lpABC->lpFreeBuff, lpABC->lpMalloc ); out: DebugTraceResult(ABC_GetContentsTable, hResult); return hResult; } /************************************************************************* * - ABC_GetHierarchyTable - * * There is no hierarchy table associated with this object. * */ STDMETHODIMP ABC_GetHierarchyTable( LPABCNT lpABC, ULONG ulFlags, LPMAPITABLE * lppTable ) { HRESULT hResult; /* * Check to see if it has a lpVtbl object member */ if (IsBadReadPtr(lpABC, offsetof(ABCNT, lpVtbl)+SIZEOF(ABC_Vtbl *))) { /* * Not large enough */ hResult = MakeResult(E_INVALIDARG); DebugTraceResult(ABC_HierarchyTable, hResult); return hResult; } /* * Check to see that the Vtbl is large enough to include this method */ if (IsBadReadPtr(lpABC->lpVtbl, offsetof(ABC_Vtbl, GetHierarchyTable)+SIZEOF(ABC_GetHierarchyTable_METHOD *))) { /* * Jump table not derived from IUnknown */ hResult = MakeResult(E_INVALIDARG); DebugTraceResult(ABC_HierarchyTable, hResult); return hResult; } /* * Check to see if the method is the same */ if (ABC_GetHierarchyTable != lpABC->lpVtbl->GetHierarchyTable) { /* * Wrong object - the object passed doesn't have this * method. */ hResult = ResultFromScode(E_INVALIDARG); DebugTraceResult(ABC_HierarchyTable, hResult); return hResult; } /* * See if I can set the return variable */ if (IsBadWritePtr(lppTable, SIZEOF(LPMAPITABLE))) { hResult = ResultFromScode(E_INVALIDARG); goto out; } /* * Check flags: * The only valid flags are CONVENIENT_DEPTH and MAPI_DEFERRED_ERRORS */ if (ulFlags & ~(CONVENIENT_DEPTH | MAPI_DEFERRED_ERRORS)) { hResult = ResultFromScode(MAPI_E_UNKNOWN_FLAGS); goto out; } /* * We don't support this method on this object */ hResult = ResultFromScode(MAPI_E_NO_SUPPORT); out: DebugTraceResult(ABC_GetHierarchyTable, hResult); return hResult; } /* * OpenEntry() <- uses ROOT's */ /* * SetSearchCriteria() <- uses ROOT's */ /* * GetSearchCriteria() <- uses ROOT's */ /* * ABC_CreateEntry() <- uses ROOT's */ /* * ABC_CopyEntries() <- uses ROOT's */ /* * ABC_DeleteEntries() <- uses ROOT's */ /********************************************************************** * * Private functions */ /* - HrGetDetailsDialog - * Builds a display table for this directory. */ HRESULT HrGetDetailsDialog(LPABCNT lpABC, LPMAPITABLE * lppDetailsTable) { HRESULT hResult; /* Create a display table */ if (!lpABC->lpTDatDetails) { /* Create a display table */ hResult = BuildDisplayTable( lpABC->lpAllocBuff, lpABC->lpAllocMore, lpABC->lpFreeBuff, lpABC->lpMalloc, lpABC->hLibrary, SIZEOF(rgdtpageDir) / SIZEOF(DTPAGE), rgdtpageDir, 0, lppDetailsTable, &lpABC->lpTDatDetails); } else { hResult = lpABC->lpTDatDetails->lpVtbl->HrGetView( lpABC->lpTDatDetails, NULL, NULL, 0, lppDetailsTable); } DebugTraceResult(HrGetDetailsDialog, hResult); return hResult; } /* * Button object for this directory's details dialog */ ABCBUTT_Vtbl vtblABCBUTT = { ABCBUTT_QueryInterface, (ABCBUTT_AddRef_METHOD *) ROOT_AddRef, ABCBUTT_Release, (ABCBUTT_GetLastError_METHOD *) ROOT_GetLastError, ABCBUTT_Activate, ABCBUTT_GetState }; HRESULT HrNewABCButton( LPABCNT lpABC, ULONG ulInterfaceOptions, ULONG ulFlags, LPMAPICONTROL FAR * lppMAPICont ) { LPABCBUTT lpABCButt = NULL; SCODE scode; /* * Creates a the object behind the button control in the directory * details dialog... */ scode = lpABC->lpAllocBuff(SIZEOF(ABCBUTT),(LPVOID *) &lpABCButt); if (FAILED(scode)) { DebugTraceSc(HrNewABCButton, scode); return ResultFromScode(scode); } lpABCButt->lpVtbl = &vtblABCBUTT; lpABCButt->lcInit = 1; lpABCButt->hResult = hrSuccess; lpABCButt->idsLastError = 0; lpABCButt->hLibrary = lpABC->hLibrary; lpABCButt->lpAllocBuff = lpABC->lpAllocBuff; lpABCButt->lpAllocMore = lpABC->lpAllocMore; lpABCButt->lpFreeBuff = lpABC->lpFreeBuff; lpABCButt->lpMalloc = lpABC->lpMalloc; lpABCButt->lpABC = lpABC; lpABC->lpVtbl->AddRef(lpABC); InitializeCriticalSection(&lpABCButt->cs); *lppMAPICont = (LPMAPICONTROL) lpABCButt; return hrSuccess; } /************************************************************************* * * - ABCBUTT_QueryInterface - * * Allows QI'ing to IUnknown and IMAPIControl. * * */ STDMETHODIMP ABCBUTT_QueryInterface( LPABCBUTT lpABCButt, REFIID lpiid, LPVOID FAR * lppNewObj ) { HRESULT hResult = hrSuccess; /* Minimally validate the lpABCButt parameter */ if (IsBadReadPtr(lpABCButt, SIZEOF(ABCBUTT))) { hResult = ResultFromScode(E_INVALIDARG); goto out; } if (lpABCButt->lpVtbl != &vtblABCBUTT) { hResult = ResultFromScode(E_INVALIDARG); goto out; } /* Check the other parameters */ if (!lpiid || IsBadReadPtr(lpiid, (UINT) SIZEOF(IID))) { hResult = ResultFromScode(E_INVALIDARG); goto out; } if (IsBadWritePtr(lppNewObj, (UINT) SIZEOF(LPVOID))) { hResult = ResultFromScode(E_INVALIDARG); goto out; } /* See if the requested interface is one of ours */ if ( memcmp (lpiid, &IID_IUnknown, SIZEOF(IID)) && memcmp (lpiid, &IID_IMAPIControl, SIZEOF(IID)) ) { *lppNewObj = NULL; /* OLE requires zeroing [out] parameter */ hResult = ResultFromScode(E_NOINTERFACE); goto out; } /* We'll do this one. Bump the usage count and return a new pointer. */ EnterCriticalSection(&lpABCButt->cs); ++lpABCButt->lcInit; LeaveCriticalSection(&lpABCButt->cs); *lppNewObj = lpABCButt; out: DebugTraceResult(ABCBUTT_QueryInterface, hResult); return hResult; } /* - ABCBUTT_Release - * Releases and cleans up this object */ STDMETHODIMP_(ULONG) ABCBUTT_Release(LPABCBUTT lpABCButt) { long lcInit; /* Minimally validate the lpABCButt parameter */ if (IsBadReadPtr(lpABCButt, SIZEOF(ABCBUTT))) { return 1; } if (lpABCButt->lpVtbl != &vtblABCBUTT) { return 1; } EnterCriticalSection(&lpABCButt->cs); lcInit = --lpABCButt->lcInit; LeaveCriticalSection(&lpABCButt->cs); if (lcInit == 0) { /* * Release my parent */ lpABCButt->lpABC->lpVtbl->Release(lpABCButt->lpABC); /* * Destroy the critical section for this object */ DeleteCriticalSection(&lpABCButt->cs); /* * Set the Jump table to NULL. This way the client will find out * real fast if it's calling a method on a released object. That is, * the client will crash. Hopefully, this will happen during the * development stage of the client. */ lpABCButt->lpVtbl = NULL; /* * Free the object */ lpABCButt->lpFreeBuff(lpABCButt); return 0; } return lcInit; } /* - ABCBUTT_Activate - * * Activates this control. In this case, it brings up the common file browsing * dialog and allows the user to pick a different .SAB file. * * Note that if all is successful it sends a display table notification. The UI * will respond to this by updating the particular control that was said to have * changed in the notification. */ STDMETHODIMP ABCBUTT_Activate( LPABCBUTT lpABCButt, ULONG ulFlags, ULONG ulUIParam ) { HRESULT hResult = hrSuccess; OPENFILENAME openfilename; TCHAR szFileName[MAX_PATH]; TCHAR szDirName[MAX_PATH]; SPropValue sProp; LPSPropValue lpspv = NULL; ULONG ulCount,ich; #ifdef UNICODE CHAR szAnsiFileName[ MAX_PATH ]; #endif /* Minimally validate the lpABCButt parameter */ if (IsBadReadPtr(lpABCButt, SIZEOF(ABCBUTT))) { hResult = ResultFromScode(E_INVALIDARG); goto out; } if (lpABCButt->lpVtbl != &vtblABCBUTT) { hResult = ResultFromScode(E_INVALIDARG); goto out; } if (ulFlags) { /* * No flags defined for this method */ hResult = ResultFromScode(MAPI_E_UNKNOWN_FLAGS); goto out; } /* * First, get the old FAB file name so that it shows up in the * choose file dialog */ hResult = lpABCButt->lpABC->lpPropData->lpVtbl->GetProps( lpABCButt->lpABC->lpPropData, &SPT_FAB_FILE, 0, /* ansi */ &ulCount, &lpspv); if (HR_FAILED(hResult)) { goto out; } if (lpspv->ulPropTag != PR_FAB_FILE_TEMP_A) { /* * Property wasn't there... */ hResult = ResultFromScode(MAPI_E_CORRUPT_DATA); goto out; } #ifdef UNICODE szFileName[0] = 0; MultiByteToWideChar( CP_ACP, 0, lpspv->Value.lpszA, -1, szFileName, ARRAYSIZE(szFileName) ); #else lstrcpy(szFileName, lpspv->Value.lpszA); #endif szDirName[0] = TEXT('\0'); /* get the path name */ // MAPI --> NO UNICODE FOR YOU! (These must be ANSI) for (ich = lstrlenA(lpspv->Value.lpszA) - 1; ich >= 0; ich--) { if (lpspv->Value.lpszA[ich] == '\\') { lpspv->Value.lpszA[ich] = '\0'; break; } else if (lpspv->Value.lpszA[ich] == ':') { lpspv->Value.lpszA[ich + 1] = '\0'; break; } } #ifdef UNICODE szDirName[0] = 0; MultiByteToWideChar( CP_ACP, 0, lpspv->Value.lpszA, -1, szDirName, ARRAYSIZE(szDirName) ); #else lstrcpy(szDirName, lpspv->Value.lpszA); #endif /* * Get the user to select one */ openfilename.lStructSize = SIZEOF(OPENFILENAME); openfilename.hwndOwner = (HWND) ulUIParam; openfilename.hInstance = 0; /* Ignored */ openfilename.lpstrFilter = TEXT("Microsoft Fax Address Book files\0*.fab\0\0"); openfilename.lpstrCustomFilter = NULL; openfilename.nMaxCustFilter = 0; openfilename.nFilterIndex = 0; openfilename.lpstrFile = szFileName; openfilename.nMaxFile = MAX_PATH; openfilename.lpstrFileTitle = NULL; openfilename.nMaxFileTitle = 0; openfilename.lpstrInitialDir = szDirName; openfilename.lpstrTitle = TEXT("Microsoft Fax Address Book"); openfilename.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_NOCHANGEDIR; openfilename.nFileOffset = 0; openfilename.nFileExtension = 0; openfilename.lpstrDefExt = TEXT("fab"); openfilename.lCustData = 0; openfilename.lpfnHook = NULL; openfilename.lpTemplateName = NULL; /* * Call up the common dialog */ if (!GetOpenFileName( &openfilename )) { hResult = hrSuccess; goto out; } /* * Save FAB FileName into the container object */ sProp.ulPropTag = PR_FAB_FILE_TEMP_A; #ifdef UNICODE szAnsiFileName[0] = 0; WideCharToMultiByte( CP_ACP, 0, szFileName, -1, szAnsiFileName, ARRAYSIZE(szAnsiFileName), NULL, NULL ); sProp.Value.lpszA = szAnsiFileName; #else sProp.Value.lpszA = szFileName; #endif hResult = lpABCButt->lpABC->lpPropData->lpVtbl->SetProps( lpABCButt->lpABC->lpPropData, 1, // ansi &sProp, NULL); if (HR_FAILED(hResult)) { goto out; } /* * Notify the details table so that everyone with a view open * will get notified */ if (lpABCButt->lpABC->lpTDatDetails) { sProp.ulPropTag = PR_CONTROL_ID; sProp.Value.bin.lpb = (LPBYTE)¬ifdata; sProp.Value.bin.cb = SIZEOF(NOTIFDATA); hResult = lpABCButt->lpABC->lpTDatDetails->lpVtbl->HrNotify( lpABCButt->lpABC->lpTDatDetails, 0, 1, &sProp); } out: lpABCButt->lpFreeBuff(lpspv); DebugTraceResult(ABCBUTT_Activate, hResult); return hResult; } /* - ABCBUTT_GetState - * Says whether this control should appear enabled or not at this time. * */ STDMETHODIMP ABCBUTT_GetState( LPABCBUTT lpABCButt, ULONG ulFlags, ULONG * lpulState ) { HRESULT hResult = hrSuccess; /* Minimally validate the lpABCButt parameter */ if (IsBadReadPtr(lpABCButt, SIZEOF(ABCBUTT))) { hResult = ResultFromScode(E_INVALIDARG); goto out; } if (lpABCButt->lpVtbl != &vtblABCBUTT) { hResult = ResultFromScode(E_INVALIDARG); goto out; } if (IsBadWritePtr(lpulState, SIZEOF(ULONG))) { hResult = ResultFromScode(E_INVALIDARG); goto out; } if (ulFlags) { /* * No flags defined for this method */ hResult = ResultFromScode(MAPI_E_UNKNOWN_FLAGS); goto out; } /* * Means that at this time this button should appear enabled. */ *lpulState = MAPI_ENABLED; out: DebugTraceResult(ABCBUTT_GetState, hResult); return hResult; } #undef _FAXAB_ABCONT