/* * WABAPI.C - Main entry to WAB API * */ #include <_apipch.h> const LPTSTR lpszOldKeyName = TEXT("Software\\Microsoft\\WAB\\Wab File Name"); const LPTSTR lpszKeyName = TEXT("Software\\Microsoft\\WAB\\WAB4\\Wab File Name"); #if 0 CRITICAL_SECTION csOMIUnload; // @todo [PaulHi] DLL Leak. Remove this or implement static s_bIsReallyOnlyWABOpenExSession = FALSE; // [PaulHi] TRUE if any thread in process creates a // WAB object through the WABOpenEx() function #endif // // IWABObject jump table is defined here... // IWOINT_Vtbl vtblIWOINT = { VTABLE_FILL (IWOINT_QueryInterface_METHOD FAR *) UNKOBJ_QueryInterface, (IWOINT_AddRef_METHOD FAR *) UNKOBJ_AddRef, IWOINT_Release, (IWOINT_GetLastError_METHOD FAR *) UNKOBJ_GetLastError, IWOINT_AllocateBuffer, IWOINT_AllocateMore, IWOINT_FreeBuffer, IWOINT_Backup, IWOINT_Import, IWOINT_Find, IWOINT_VCardDisplay, IWOINT_LDAPUrl, IWOINT_VCardCreate, IWOINT_VCardRetrieve, IWOINT_GetMe, IWOINT_SetMe }; /* Interface which can be queried from lpWABOBJECT. * * It is important that the order of the interfaces supported be preserved * and that IID_IUnknown be the last in the list. */ IID const FAR * argpiidIWABOBJECT[] = { &IID_IUnknown }; #define WAB_USE_OUTLOOK_ALLOCATORS 0x20000000// Note: This internal flag needs to be // harmonious with external flags defined // in wabapi.h for WAB_PARAM structs /**************************************************************** * - CreateWABObject - * Purpose * Used for creating a WABObject interface in memory. * * Arguments * lppWABObject Pointer to memory location which will receive a * pointer to the new WABObject. * lpPropertyStore Property store structure * * Returns * SCODE * */ STDAPI_(SCODE) CreateWABObject(LPWAB_PARAM lpWP, LPPROPERTY_STORE lpPropertyStore, LPWABOBJECT FAR * lppWABObject) { SCODE sc; LPIWOINT lpIWOINT = NULL; // validate paremeters AssertSz(lppWABObject && !IsBadWritePtr(lppWABObject, sizeof(LPWABOBJECT)) && !IsBadWritePtr(lpPropertyStore, sizeof(LPPROPERTY_STORE)), TEXT("lppWABObject fails address check")); // // Create a IPDAT per object for lpMAPIPropInternal so that it gets // called first. if (FAILED(sc = MAPIAllocateBuffer(sizeof(*lpIWOINT), &lpIWOINT))) { goto error; } // Init the object to 0, NULL memset((BYTE *)lpIWOINT, 0, sizeof(*lpIWOINT)); MAPISetBufferName(lpIWOINT, TEXT("WABAPI: lpIWOINT in CreateWABObject")); // Tag each object that it is created using the OLK MAPI allocators. if ( lpWP && (lpWP->ulFlags & WAB_USE_OUTLOOK_ALLOCATORS) ) lpIWOINT->bSetOLKAllocators = TRUE; // Fill in the object specific instance data. lpIWOINT->inst.hinst = hinstMapiX;//HinstMapi(); #ifdef DEBUG if (lpIWOINT->inst.hinst == NULL) TraceSz1( TEXT("WABObject: GetModuleHandle failed with error %08lX"), GetLastError()); #endif /* DEBUG */ // // Open the property store // if (FAILED(sc = OpenAddRefPropertyStore(lpWP, lpPropertyStore))) { goto error; } lpIWOINT->lpPropertyStore = lpPropertyStore; // Initialize the TEXT("standard") object. This must be the last operation that can fail. // If not, explicitly call UNKOBJ_Deinit() for failures after a successful UNKOBJ_Init. if (FAILED(sc = UNKOBJ_Init((LPUNKOBJ)lpIWOINT, (UNKOBJ_Vtbl FAR *)&vtblIWOINT, sizeof(vtblIWOINT), (LPIID FAR *) argpiidIWABOBJECT, dimensionof(argpiidIWABOBJECT), &(lpIWOINT->inst)))) { DebugTrace( TEXT("CreateWABObject() - Error initializing IWOINT object (SCODE = 0x%08lX)\n"), sc); ReleasePropertyStore(lpPropertyStore); // undo the above operation goto error; } // Initialize the defaults in WABObject specific part of the object. lpIWOINT->ulObjAccess = IPROP_READWRITE; *lppWABObject = (LPWABOBJECT)lpIWOINT; return(S_OK); error: FreeBufferAndNull(&lpIWOINT); return(sc); } // -------- // IUnknown /* - IWOINT_Release - * Purpose: * Decrements reference count on the WABObject and * removes instance data if reference count becomes zero. * * Arguments: * lpWABObject The object to be released. * * Returns: * Decremented reference count * * Side effects: * * Errors: */ STDMETHODIMP_(ULONG) IWOINT_Release(LPIWOINT lpWABObject) { ULONG ulcRef; BOOL bSetOLKAllocators; #if !defined(NO_VALIDATION) // Make sure the object is valid. // if (BAD_STANDARD_OBJ(lpWABObject, IWOINT_, Release, lpVtbl)) { DebugTrace( TEXT("IWOINT::Release() - Bad object passed\n")); return(1); } #endif UNKOBJ_EnterCriticalSection((LPUNKOBJ)lpWABObject); ulcRef = --lpWABObject->ulcRef; UNKOBJ_LeaveCriticalSection((LPUNKOBJ)lpWABObject); // Free the object. // // No critical section lock is required since we are guaranteed to be // the only thread accessing the object (ie ulcRef == 0). // if (!ulcRef) { // Free the object. // UNKOBJ_Deinit((LPUNKOBJ)lpWABObject); lpWABObject->lpVtbl = NULL; ReleaseOutlookStore(lpWABObject->lpPropertyStore->hPropertyStore, lpWABObject->lpOutlookStore); ReleasePropertyStore(lpWABObject->lpPropertyStore); bSetOLKAllocators = lpWABObject->bSetOLKAllocators; FreeBufferAndNull(&lpWABObject); // [PaulHi] 5/5/99 Raid 77138 Null out Outlook allocator function // pointers if our global count goes to zero. if (bSetOLKAllocators) { Assert(g_nExtMemAllocCount > 0); InterlockedDecrement((LPLONG)&g_nExtMemAllocCount); if (g_nExtMemAllocCount == 0) { lpfnAllocateBufferExternal = NULL; lpfnAllocateMoreExternal = NULL; lpfnFreeBufferExternal = NULL; } } } return(ulcRef); } /* - IWOINT_AllocateBuffer - * Purpose: * Allocation routine * * Arguments: * lpWABOBJECT this = the open wab object * cbSize number of bytes to allocate * lppBuffer -> Returned buffer * * Returns: * SCODE * */ STDMETHODIMP_(SCODE) IWOINT_AllocateBuffer(LPIWOINT lpWABObject, ULONG cbSize, LPVOID FAR * lppBuffer) { SCODE sc = S_OK; #if !defined(NO_VALIDATION) // Make sure the object is valid. if (BAD_STANDARD_OBJ(lpWABObject, IWOINT_, AllocateBuffer, lpVtbl)) { DebugTrace( TEXT("IWABOBJECT::AllocateBuffer() - Bad object passed\n")); return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); } Validate_IWABObject_AllocateBuffer( lpWABObject, cbSize, lppBuffer); #endif // not NO_VALIDATION if(!lpWABObject || !lppBuffer) return MAPI_E_INVALID_PARAMETER; sc = MAPIAllocateBuffer(cbSize, lppBuffer); // error: UNKOBJ_SetLastError((LPUNKOBJ)lpWABObject, sc, 0); return(sc); } /* - IWOINT_AllocateMore - * Purpose: * Allocation routine * * Arguments: * lpWABOBJECT this = the open wab object * cbSize number of bytes to allocate * lpObject original allocation * lppBuffer -> Returned buffer * * Returns: * SCODE * */ STDMETHODIMP_(SCODE) IWOINT_AllocateMore(LPIWOINT lpWABObject, ULONG cbSize, LPVOID lpObject, LPVOID FAR * lppBuffer) { SCODE sc = S_OK; #if !defined(NO_VALIDATION) // Make sure the object is valid. if (BAD_STANDARD_OBJ(lpWABObject, IWOINT_, AllocateMore, lpVtbl)) { DebugTrace( TEXT("IWABOBJECT::AllocateMore() - Bad object passed\n")); return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); } Validate_IWABObject_AllocateMore( lpWABObject, cbSize, lpObject, lppBuffer); #endif // not NO_VALIDATION if(!lpWABObject || !lppBuffer || !lpObject) return MAPI_E_INVALID_PARAMETER; sc = MAPIAllocateMore(cbSize, lpObject, lppBuffer); // error: UNKOBJ_SetLastError((LPUNKOBJ)lpWABObject, sc, 0); return(sc); } /* - IWOINT_FreeBuffer - * Purpose: * Allocation routine * * Arguments: * lpWABOBJECT this = the open wab object * lpBuffer Buffer to free * * Returns: * SCODE * */ STDMETHODIMP_(SCODE) IWOINT_FreeBuffer(LPIWOINT lpWABObject, LPVOID lpBuffer) { SCODE sc = S_OK; #if !defined(NO_VALIDATION) // Make sure the object is valid. if (BAD_STANDARD_OBJ(lpWABObject, IWOINT_, FreeBuffer, lpVtbl)) { DebugTrace( TEXT("IWABOBJECT::FreeBuffer() - Bad object passed\n")); return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); } Validate_IWABObject_FreeBuffer( lpWABObject, lpBuffer); #endif // not NO_VALIDATION if(!lpWABObject || !lpBuffer) return MAPI_E_INVALID_PARAMETER; sc = MAPIFreeBuffer(lpBuffer); // error: UNKOBJ_SetLastError((LPUNKOBJ)lpWABObject, sc, 0); return(sc); } /* - IWOINT_Backup - * Purpose: * Backup the current database to a file. * * Arguments: * lpWABOBJECT this = the open wab object * lpFileName Filename to backup to * * Returns: * HRESULT * */ STDMETHODIMP IWOINT_Backup(LPIWOINT lpWABObject, LPSTR lpFileName) { SCODE sc = S_OK; #if !defined(NO_VALIDATION) // Make sure the object is valid. if (BAD_STANDARD_OBJ(lpWABObject, IWOINT_, Backup, lpVtbl)) { DebugTrace( TEXT("IWABOBJECT::Backup() - Bad object passed\n")); return ResultFromScode(MAPI_E_INVALID_PARAMETER); } Validate_IWABObject_Backup( lpWABObject, lpFileName); #endif // not NO_VALIDATION // Not yet implemented. DebugTrace( TEXT("IWABOBJECT::Backup() - Not yet implemented!\n")); sc = MAPI_E_NO_SUPPORT; // error: UNKOBJ_SetLastError((LPUNKOBJ)lpWABObject, sc, 0); return(MakeResult(sc)); } /* - IWOINT_Import - * Purpose: * Imports an address book into the current WAB database. * * Arguments: * lpWABOBJECT this = the open wab object * lpwip - WABIMPORTPARAM struct * * Returns: * HRESULT - MAPI_W_ERRORS_RETURNED if some errors occured during import * Failure code if something really failed, S_OK otherwise .. * */ STDMETHODIMP IWOINT_Import(LPIWOINT lpWABObject, LPSTR lpWIP) { LPWABIMPORTPARAM lpwip = (LPWABIMPORTPARAM) lpWIP; LPTSTR lpFile = NULL; HRESULT hr = S_OK; #if !defined(NO_VALIDATION) // Make sure the object is valid. if (BAD_STANDARD_OBJ(lpWABObject, IWOINT_, Import, lpVtbl)) { DebugTrace( TEXT("IWABOBJECT::Import() - Bad object passed\n")); return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); } Validate_IWABObject_Import( lpWABObject, lpWIP); #endif // not NO_VALIDATION if(!lpwip || !lpwip->lpAdrBook || !lpWABObject) return MAPI_E_INVALID_PARAMETER; lpFile = ConvertAtoW(lpwip->lpszFileName); hr = HrImportWABFile(lpwip->hWnd, lpwip->lpAdrBook, lpwip->ulFlags, lpFile); LocalFreeAndNull(&lpFile); return hr; } /* - IWOINT_Find - * Purpose: * Displays the Find dialog so we can do Start | Find | People * * Arguments: * lpWABOBJECT this = the open wab object * hWnd hWnd of parent for the find dialog * * Returns: * HRESULT * */ STDMETHODIMP IWOINT_Find(LPIWOINT lpWABObject, LPADRBOOK lpAdrBook, HWND hWnd) { HRESULT hr = S_OK; LPPTGDATA lpPTGData=GetThreadStoragePointer(); #if !defined(NO_VALIDATION) // Make sure the object is valid. if (BAD_STANDARD_OBJ(lpWABObject, IWOINT_, Find, lpVtbl)) { DebugTrace( TEXT("IWABOBJECT::Find() - Bad object passed\n")); return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); } #endif // not NO_VALIDATION if(!lpWABObject || !lpAdrBook) return MAPI_E_INVALID_PARAMETER; hr = HrShowSearchDialog(lpAdrBook, hWnd, (LPADRPARM_FINDINFO) NULL, (LPLDAPURL) NULL, NULL); return(hr); } /* - IWOINT_VCardDisplay - * Purpose: * Displays One off props on a vCard File * * Arguments: * lpWABOBJECT this = the open wab object * lpAdrBook lpAdrBook object * hWnd hWnd of parent for the find dialog * lpszFileName Null terminated file name to display * * Returns: * HRESULT * */ STDMETHODIMP IWOINT_VCardDisplay(LPIWOINT lpWABObject, LPADRBOOK lpAdrBook, HWND hWnd, LPSTR szvCardFile) { HRESULT hr = S_OK; LPTSTR lpVCard = NULL; #if !defined(NO_VALIDATION) // Make sure the object is valid. if (BAD_STANDARD_OBJ(lpWABObject, IWOINT_, VCardDisplay, lpVtbl)) { DebugTrace( TEXT("IWABOBJECT::VCardDisplay() - Bad object passed\n")); return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); } #endif // not NO_VALIDATION if(!lpWABObject || !lpAdrBook) return MAPI_E_INVALID_PARAMETER; lpVCard = ConvertAtoW(szvCardFile); hr = HrShowOneOffDetailsOnVCard( lpAdrBook, hWnd, lpVCard); LocalFreeAndNull(&lpVCard); return(hr); } /* - IWOINT_VCardCreate - * Purpose: * Takes input mailuser object, and converts its properties * into a vCard file * * Arguments: * lpWABOBJECT this = the open wab object * lpAdrBook lpAdrBook object * hWnd hWnd of parent for the find dialog * lpszFileName Null terminated file name to create * lpMailUser MailUser object to convert to vCard * * Returns: * HRESULT * */ STDMETHODIMP IWOINT_VCardCreate(LPIWOINT lpWABObject, LPADRBOOK lpAdrBook, ULONG ulFlags, LPSTR szvCardFile, LPMAILUSER lpMailUser) { HRESULT hr = S_OK; LPTSTR lpVCardFile = NULL; #if !defined(NO_VALIDATION) // Make sure the object is valid. if (BAD_STANDARD_OBJ(lpWABObject, IWOINT_, VCardDisplay, lpVtbl)) { DebugTrace( TEXT("IWABOBJECT::VCardDisplay() - Bad object passed\n")); return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); } #endif // not NO_VALIDATION if(!lpWABObject || !lpAdrBook || !lpMailUser) return MAPI_E_INVALID_PARAMETER; lpVCardFile = ConvertAtoW(szvCardFile); hr = VCardCreate(lpAdrBook, NULL, 0, lpVCardFile, lpMailUser); LocalFreeAndNull(&lpVCardFile); return(hr); } /* - IWOINT_VCardRetrieve - * Purpose: * Opens a vCard file and creates a corresponding MailUser out of it * * Arguments: * lpWABOBJECT this = the open wab object * lpAdrBook lpAdrBook object * ulFlags STREAM or FILE * lpszFileName Null terminated file name to display * lppMailUser returned MailUser object * * Returns: * HRESULT * */ STDMETHODIMP IWOINT_VCardRetrieve(LPIWOINT lpWABObject, LPADRBOOK lpAdrBook, ULONG ulFlags, LPSTR szvCard, LPMAILUSER * lppMailUser) { HRESULT hr = S_OK; LPSTR lpStream = NULL; LPTSTR lpFileName = NULL; #if !defined(NO_VALIDATION) // Make sure the object is valid. if (BAD_STANDARD_OBJ(lpWABObject, IWOINT_, VCardDisplay, lpVtbl)) { DebugTrace( TEXT("IWABOBJECT::VCardDisplay() - Bad object passed\n")); return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); } #endif // not NO_VALIDATION if( !lpWABObject || !lpAdrBook || !lppMailUser || !szvCard || (!(ulFlags&WAB_VCARD_STREAM) && !lstrlenA(szvCard)) ) return MAPI_E_INVALID_PARAMETER; if(ulFlags & WAB_VCARD_STREAM) { DWORD cchSizeStream = (lstrlenA(szvCard)+1); if (!(lpStream = LocalAlloc(LMEM_ZEROINIT, (sizeof(lpStream[0]) * cchSizeStream)))) return MAPI_E_NOT_ENOUGH_MEMORY; StrCpyNA(lpStream, szvCard, cchSizeStream); } else { lpFileName = ConvertAtoW(szvCard); } hr = VCardRetrieve(lpAdrBook, NULL, 0, lpFileName, lpStream, lppMailUser); LocalFreeAndNull(&lpFileName); LocalFreeAndNull(&lpStream); return(hr); } /* - IWOINT_LDAPUrl - * Purpose: * Handles an LDAP URL * * Arguments: * lpWABOBJECT this = the open wab object * lpAdrBook lpAdrBook object * hWnd hWnd of parent for the find dialog * ulFlags flags saying how we want the results returned * lpszUrl Null terminated file name to display * lppMailUser Possible Mailuser to return based on flag * * With this API, users can pass in a Wide string URL by casting it to a * LPSTR and setting ulFlags to MAPI_UNICODE .. if we detect MAPI_UNICODE, * we cast the string back to a WideChar * Returns: * HRESULT * */ STDMETHODIMP IWOINT_LDAPUrl( LPIWOINT lpWABObject, LPADRBOOK lpAdrBook, HWND hWnd, ULONG ulFlags, LPSTR szLDAPUrl, LPMAILUSER * lppMailUser) { HRESULT hr = S_OK; LPTSTR lpUrl = NULL; #if !defined(NO_VALIDATION) // Make sure the object is valid. if (BAD_STANDARD_OBJ(lpWABObject, IWOINT_, LDAPUrl, lpVtbl)) { DebugTrace( TEXT("IWABOBJECT::LDAPUrl() - Bad object passed\n")); return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); } #endif // not NO_VALIDATION if(!lpWABObject || !lpAdrBook || !szLDAPUrl)// || !lstrlen(szLDAPUrl)) return MAPI_E_INVALID_PARAMETER; if(ulFlags & MAPI_UNICODE) { lpUrl = (LPWSTR)szLDAPUrl; } else { lpUrl = ConvertAtoW(szLDAPUrl); } if(!lstrlen(lpUrl)) { hr = MAPI_E_INVALID_PARAMETER; goto out; } hr = HrProcessLDAPUrl( lpAdrBook, hWnd, ulFlags | ((!ulFlags && hWnd) ? MAPI_DIALOG : 0), lpUrl, lppMailUser); out: if(lpUrl && lpUrl != (LPTSTR)szLDAPUrl) LocalFreeAndNull(&lpUrl); return hr; } /* - IWOINT_GetMe - * Purpose: * Retrieves the 'Me' entry from the WAB .. if the entry doesnt exist, * prompts the user to create one or select someone from his address book. * Unless the caller surpresses the dialog by passing in AB_NO_DIALOG, in * which case, the entry is created behind-the-scenes. Caller can also * call this function to check existence of a ME entry without causing a new * one created as a side effect - to do that they specify the WABOBJECT_ME_NOCREATE flag * which causes failure with MAPI_E_NOT_FOUND if nothing found * * Arguments: * lpWABOBJECT this = the open wab object * lpAdrBook lpAdrBook object * ulFlags 0 or AB_NO_DIALOG * or WABOBJECT_ME_NOCREATE * lpdwAction if supplied, returns WABOBJECT_ME_NEW if a new ME was created * SBinary * returns the entry id of the ME, * ulParam HWND of parent cast as a (ULONG) * * Returns: * HRESULT * */ STDMETHODIMP IWOINT_GetMe( LPIWOINT lpWABObject, LPADRBOOK lpAdrBook, ULONG ulFlags, DWORD * lpdwAction, SBinary * lpsbEID, ULONG ulParam) { HRESULT hr = S_OK; #if !defined(NO_VALIDATION) // Make sure the object is valid. if (BAD_STANDARD_OBJ(lpWABObject, IWOINT_, GetMe, lpVtbl)) { DebugTrace( TEXT("IWABOBJECT::GetMe() - Bad object passed\n")); return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); } #endif // not NO_VALIDATION if(!lpWABObject || !lpAdrBook) return MAPI_E_INVALID_PARAMETER; hr = HrGetMeObject(lpAdrBook, ulFlags, lpdwAction, lpsbEID, ulParam); return hr; } /* - IWOINT_SetMe - * Purpose: * Sets the specified object as the Me object .. only 1 Me object will exist in a WAB * Hence it strips the previous Me object, if different, of its Me status. * If no entryid is passed in, and MAPI_DIALOG is specified, a dialog pops up * asking the user to create a ME or to select a ME object .. the selection in the SetMe * dialog is set to the current ME object, if any * If no entryid is passed in, and MAPI_DIALOG is not specified, the function fails * If an entryid is passed in, and MAPI_DIALOG is specified, the SetME dialog is displayed * with the corresponding entryid-object selected in it * If an entryid is passed in, and MAPI_DIALOG is not specified, the entryid, if exists, is * set as the ME object and the old ME object stripped * * Arguments: * lpWABOBJECT this = the open wab object * lpAdrBook lpAdrBook object * ulFlags 0 or MAPI_DIALOG * sbEID entry id of the object to set as ME, * ulParam HWND of parent for DIalogs cast as a ULONG * * Returns: * HRESULT * */ STDMETHODIMP IWOINT_SetMe( LPIWOINT lpWABObject, LPADRBOOK lpAdrBook, ULONG ulFlags, SBinary sbEID, ULONG ulParam) { HRESULT hr = S_OK; #if !defined(NO_VALIDATION) // Make sure the object is valid. if (BAD_STANDARD_OBJ(lpWABObject, IWOINT_, SetMe, lpVtbl)) { DebugTrace( TEXT("IWABOBJECT::GetMe() - Bad object passed\n")); return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); } #endif // not NO_VALIDATION if( !lpAdrBook || ((!sbEID.cb||!sbEID.lpb) && !ulFlags) ) { hr = MAPI_E_INVALID_PARAMETER; goto exit; } hr = HrSetMeObject(lpAdrBook, ulFlags, sbEID, ulParam); exit: return hr; } /* - ReleasePropertyStore - * Purpose: * Keep track of property store refcount * * Arguments: * lpPropertyStore PROPERTY_STORE structure * * Returns: * Current reference count. When 0, property store is * no longer open. * */ ULONG ReleasePropertyStore(LPPROPERTY_STORE lpPropertyStore) { if (lpPropertyStore->ulRefCount) { IF_WIN32(Assert(lpPropertyStore->hPropertyStore);) if (0 == (--(lpPropertyStore->ulRefCount))) { // Reference goes to zero, release the property store ClosePropertyStore(lpPropertyStore->hPropertyStore,0); lpPropertyStore->hPropertyStore = NULL; // Free the container list FreeBufferAndNull(&(lpPropertyStore->rgolkci)); lpPropertyStore->colkci = 0; // [PaulHi] Raid #61556 // Must reset this global variable or OUT32WAB.DLL will crash // the next time it is loaded and the store opened. pmsessOutlookWabSPI = NULL; } } return(lpPropertyStore->ulRefCount); } #ifdef WIN16 BOOL WINAPI WABInitThread() { // allocate a TLS index if ((dwTlsIndex = TlsAlloc()) == 0xfffffff) return FALSE; return TRUE; } #endif #define WAB_USE_OUTLOOK_CONTACT_STORE 0x10000000// Note: This internal flag needs to be // harmonious with external flags defined // in wabapi.h for WAB_PARAM structs // // Input information to pass to WABOpen from IE4 WAB // typedef struct _tagWAB_PARAM_V4 { ULONG cbSize; // sizeof(WAB_PARAM). HWND hwnd; // hWnd of calling client Application. Can be NULL LPTSTR szFileName; // WAB File name to open. if NULL, opens default. ULONG ulFlags; // Currently no flags. } WAB_PARAM_V4, * LPWAB_PARAM_V4; /* - WABOpen - * Purpose: * Entry point into the WAB API * * Arguments: * lppAdrBook Returned IAdrBook object * lppWABOBJECT Returned WABObject * Reserved1 Reserved for future filename? * Reserved2 Reserved for future flags * * Returns: * HRESULT * S_OK * E_FAIL // some generic error * MAPI_E_NOT_ENOUGH_MEMORY: // ran out of memory * MAPI_E_NO_ACCESS: // file is locked by someone * MAPI_E_CORRUPT_DATA: // file corrupt * MAPI_E_DISK_ERROR: // some disk related error opening file * MAPI_E_INVALID_OBJECT: // secified file exists but its GUID doesnt match * */ STDMETHODIMP WABOpen(LPADRBOOK FAR * lppAdrBook, LPWABOBJECT FAR * lppWABObject, LPWAB_PARAM lpWP, DWORD Reserved2) { SCODE sc = SUCCESS_SUCCESS; HRESULT hResult = hrSuccess; static PROPERTY_STORE PropertyStore = {NULL, 0, 0, 0, NULL, 0}; static OUTLOOK_STORE OutlookStore = {NULL, 0}; BOOL bUseOutlook = FALSE; LPPTGDATA lpPTGData=GetThreadStoragePointer(); LPTSTR lpFile = NULL; AssertSz(lppAdrBook && !IsBadWritePtr(lppAdrBook, sizeof(LPADRBOOK)), TEXT("lppAdrBook fails address check")); AssertSz(lppWABObject && !IsBadWritePtr(lppWABObject, sizeof(LPWABOBJECT)), TEXT("lppWABObject fails address check")); if(!lppAdrBook || !lppWABObject) return MAPI_E_INVALID_PARAMETER; IF_WIN16(ScInitMapiUtil(0);) // First check if this is supposed to be an Outlook session // If we are explicitly told to use the contact store ... if((lpWP && (lpWP->ulFlags & WAB_USE_OUTLOOK_CONTACT_STORE)) && PropertyStore.ulRefCount == 0) // Bad bug where wabopen process calls outlook which // calls wabopenex and we flunk everywhere since this PropertyStore // information is a static in the original process.. // force the wabopenex to be a wabopen if this rare case happens bUseOutlook = TRUE; else { // if a file name is specified and this is not wabopenex, then override any // outlook use .. this way we can explicitly call the wab to open a .wab file // from anywhere if(lpWP && lpWP->szFileName && lstrlenA(lpWP->szFileName)) bUseOutlook = FALSE; else bUseOutlook = bUseOutlookStore(); } #if 0 // @todo [PaulHi] DLL Leak. Remove this or implement // [PaulHi] Set this process global boolean ONLY if the WAB is opened through the WABOpenEx() // function ,i.e., by the Outlook process if (lpWP && (lpWP->ulFlags & WAB_USE_OUTLOOK_CONTACT_STORE)) { EnterCriticalSection(&csOMIUnload); s_bIsReallyOnlyWABOpenExSession = TRUE; LeaveCriticalSection(&csOMIUnload); } #endif // // if a .wab file is already initialized in this process space, just inherit that file // [PaulHi] 12/5/98 Raid #56437 // We still need to allow the Outlook refcount to increment if this store has been created. // So we need to check both the WAB PropertyStore and OutlookStore ref counts to determine // if we should prevent the Outlook store from being opened. // Note that these two lines fixes the following problem: // 1) User opens OE5 (which opens WAB in non-outlook store mode) // 2) User has the Outlook set as their default mail client. // 3) User uses the WAB to initiate a send email. // 4) Since Outlook is the default client it is launched, and in turn opens WAB // in outlook store mode. At this point the WAB is already open in non-outlook store // mode so we want to prevent the Outlook store from being initialized. // if (PropertyStore.ulRefCount && !OutlookStore.ulRefCount) bUseOutlook = FALSE; if(bUseOutlook) { // If this call fails, we will just end up defaulting to the WAB store... // so we can ignore any errors here OpenAddRefOutlookStore(&OutlookStore); } // // Create the WAB Object // if (FAILED(sc = CreateWABObject(lpWP, &PropertyStore, lppWABObject))) { hResult = ResultFromScode(sc); if(bUseOutlook) // IE6 bug 15174 pt_bIsWABOpenExSession = FALSE; goto exit; } // // Create the IAdrBook Object // if (HR_FAILED(hResult = HrNewIAB(&PropertyStore, *lppWABObject, lppAdrBook))) { // IAdrBook creation failed, fail WABOpen and clean up. UlRelease(*lppWABObject); goto exit; } DebugTrace( TEXT("WABOpen succeeds\n")); if(bUseOutlook) { if( lppWABObject && *lppWABObject && OutlookStore.hOutlookStore) { ((LPIWOINT)(*lppWABObject))->lpOutlookStore = &OutlookStore; } // Bug - Outlook needs a way for its secondary threads to know this is a WABOpenEx session // without their calling WABOpenEx (They pass the iAdrBook pointer around it seems). Hence // tag this IADRbook pointer if(!HR_FAILED(hResult) && lppAdrBook && *lppAdrBook && pt_bIsWABOpenExSession) ((LPIAB)(*lppAdrBook))->lpPropertyStore->bIsWABOpenExSession = TRUE; } if(lppAdrBook && *lppAdrBook) { // Load the WABs private named properties HrLoadPrivateWABProps((LPIAB) *lppAdrBook); if(lpWP && (lpWP->cbSize > sizeof(WAB_PARAM_V4)) ) ((LPIAB)*lppAdrBook)->guidPSExt = lpWP->guidPSExt; // As long as this is not an Outlook session, profiles are always // enabled in the UI if( !pt_bIsWABOpenExSession && !((LPIAB)(*lppAdrBook))->lpPropertyStore->bIsWABOpenExSession ) { ((LPIAB)(*lppAdrBook))->bProfilesEnabled = TRUE; } if( ((LPIAB)(*lppAdrBook))->bProfilesEnabled ) { if(lpWP && (lpWP->ulFlags & WAB_ENABLE_PROFILES)) // only check for profiles the first time we enter for this process { if(PropertyStore.ulRefCount >= 2) { ((LPIAB)(*lppAdrBook))->bProfilesAPIEnabled = ((LPIAB)(*lppAdrBook))->bProfilesIdent = TRUE; } else { ((LPIAB)(*lppAdrBook))->bProfilesAPIEnabled = PropertyStore.bProfileAPIs; } if(((LPIAB)(*lppAdrBook))->bProfilesAPIEnabled ) hResult = HrLogonAndGetCurrentUserProfile(lpWP->hwnd, ((LPIAB)(*lppAdrBook)), FALSE, FALSE); // if there is some identity related error we should then revert to // non-identity mode if(HR_FAILED(hResult)) { PropertyStore.bProfileAPIs = ((LPIAB)(*lppAdrBook))->bProfilesAPIEnabled = FALSE; hResult = S_OK; } else PropertyStore.bProfileAPIs = ((LPIAB)(*lppAdrBook))->bProfilesAPIEnabled = TRUE; } } if( ((LPIAB)(*lppAdrBook))->bProfilesEnabled ) { if(HR_FAILED(hResult = HrGetWABProfiles((LPIAB) *lppAdrBook))) { // UGH! If this failed then we are quite in trouble and won't be able to support a profile-enabled // session without crashing badly .. hence above failure is critical enough to stop // loading the WAB (*lppAdrBook)->lpVtbl->Release(*lppAdrBook); (*lppWABObject)->lpVtbl->Release(*lppWABObject); } } ReadWABCustomColumnProps((LPIAB) *lppAdrBook); // need to be aware of Identity Notifications if this is a profile aware WAB independent // of whether the store is switched to using Outlook or not // // If the caller specifically asked for profiles // (then assume it is identity aware and register for Identity Notifications // because if the caller is using Identites, WAB launched as a child window // needs to be able to shut down when it gets a switch_identites message if( lpWP && (lpWP->ulFlags & WAB_ENABLE_PROFILES)) HrRegisterUnregisterForIDNotifications( (LPIAB) *lppAdrBook, TRUE); if( lpWP && (lpWP->ulFlags & WAB_USE_OE_SENDMAIL)) ((LPIAB) *lppAdrBook)->bUseOEForSendMail = TRUE; } exit: return(hResult); } /* - WABOpenEx - * Purpose: * Extended Entry point into the WAB API * * Arguments: * lppAdrBook Returned IAdrBook object * lppWABOBJECT Returned WABObject * lpMP WAB Parameter structure (NULL by default) * Reserved Optional IMAPISession parameter * fnAllocateBuffer AllocateBuffer function (may be NULL) * fnAllocateMore AllocateMore function (may be NULL) * fnFreeBuffer FreeBuffer function (may be NULL) * * Returns: * HRESULT * S_OK * E_FAIL // some generic error * MAPI_E_NOT_ENOUGH_MEMORY: // ran out of memory * MAPI_E_NO_ACCESS: // file is locked by someone * MAPI_E_CORRUPT_DATA: // file corrupt * MAPI_E_DISK_ERROR: // some disk related error opening file * MAPI_E_INVALID_OBJECT: // secified file exists but its GUID doesnt match * */ STDMETHODIMP WABOpenEx(LPADRBOOK FAR * lppAdrBook, LPWABOBJECT FAR * lppWABObject, LPWAB_PARAM lpWP, DWORD Reserved, ALLOCATEBUFFER * lpfnAllocateBuffer, ALLOCATEMORE * lpfnAllocateMore, FREEBUFFER * lpfnFreeBuffer) { HRESULT hResult = hrSuccess; SCODE sc = SUCCESS_SUCCESS; WAB_PARAM wp = {0}; if (Reserved) { // This is an IMAPISession that needs to be passed to the // Outlook storage provider interface .. pmsessOutlookWabSPI = (LPUNKNOWN)IntToPtr(Reserved); } if(!lppWABObject || !lppAdrBook) return MAPI_E_INVALID_PARAMETER; wp.cbSize = sizeof(WAB_PARAM); if(!lpWP) lpWP = ℘ lpWP->ulFlags |= WAB_USE_OUTLOOK_CONTACT_STORE; // Did we get allocators? Set up the globals if (lpfnAllocateBuffer || lpfnAllocateMore || lpfnFreeBuffer) { if (lpfnAllocateBuffer && lpfnAllocateMore && lpfnFreeBuffer) { DebugTrace( TEXT("WABOpenEx found external allocators\n")); lpfnAllocateBufferExternal = lpfnAllocateBuffer; lpfnAllocateMoreExternal = lpfnAllocateMore; lpfnFreeBufferExternal = lpfnFreeBuffer; lpWP->ulFlags |= WAB_USE_OUTLOOK_ALLOCATORS; InterlockedIncrement((LPLONG)&g_nExtMemAllocCount); // Incremented twice for each object created; IAB and IWO InterlockedIncrement((LPLONG)&g_nExtMemAllocCount); } else { DebugTrace( TEXT("WABOpenEx got one or two allocator functions, but not all three\n")); hResult = ResultFromScode(MAPI_E_INVALID_PARAMETER); goto exit; } } hResult = WABOpen( lppAdrBook, lppWABObject, lpWP, 0); if(lpWP == &wp) lpWP = NULL; if(HR_FAILED(hResult)) goto exit; exit: return(hResult); } /* - - GetNewDataDirName * * Purpose: * Gets the path of the new data directory in which the WAB file should be placed * * We look for: * Roaming User App Data Dir; else * Program Files\IE\OE\Current User\Address Book; else * Common Files\Microsoft Shared\Address Book; else * Create c:\Address book\ else * Create c:\wab\ * * Returns a valid, existing directory name terminated by a \ * */ HRESULT GetNewDataDirName(LPTSTR szDir, DWORD cchSizeDir) { HRESULT hr = E_FAIL; const LPTSTR lpszShellFolders = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"); const LPTSTR lpszAppData = TEXT("AppData"); const LPTSTR lpszCurrentVer = TEXT("Software\\Microsoft\\Windows\\CurrentVersion"); const LPTSTR lpszCommonFiles = TEXT("CommonFilesDir"); const LPTSTR lpszMicrosoftShared = TEXT("\\Microsoft Shared"); const LPTSTR lpszAddressBook = TEXT("\\Address Book"); const LPTSTR lpszOEKey = TEXT("Software\\Microsoft\\Outlook Express\\5.0"); const LPTSTR lpszOERoot = TEXT("Store Root"); const LPTSTR lpszMicrosoft = TEXT("\\Microsoft"); const LPTSTR lpszCAddressBook = TEXT("c:\\Address book"); const LPTSTR lpszCWAB = TEXT("c:\\WAB"); HKEY hKey = NULL; DWORD dwSize = 0; DWORD dwType = 0; TCHAR szPath[MAX_PATH]; TCHAR szUser[MAX_PATH]; *szPath='\0'; if(!szDir) goto out; if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER,lpszShellFolders,0,KEY_READ,&hKey)) { // Look for the App Data directory dwSize = ARRAYSIZE(szPath); if(ERROR_SUCCESS == RegQueryValueEx(hKey, lpszAppData, NULL, &dwType, (LPBYTE) szPath, &dwSize)) { if(lstrlen(szPath)) { StrCpyN(szDir, szPath, cchSizeDir); if(GetFileAttributes(szDir) != 0xFFFFFFFF) { StrCatBuff(szDir, lpszMicrosoft, cchSizeDir); if(GetFileAttributes(szDir) == 0xFFFFFFFF) CreateDirectory(szDir, NULL); StrCatBuff(szDir, lpszAddressBook, cchSizeDir); if(GetFileAttributes(szDir) == 0xFFFFFFFF) CreateDirectory(szDir, NULL); } hr = S_OK; goto out; } } } if(hKey) RegCloseKey(hKey); hKey = NULL; // Didnt find this directory // Look for MyDocuments folder - it will only be installed with Office so no gaurantee it will be found // - there doesnt seem to be a definite location for this except under // CurrentVersion\Explorer\Shell Folders\Personal // Didnt find a My Documents directory // See if OE is installed for the current user .. /** commented out until OE has stable dir structure if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, lpszOEKey, 0, KEY_READ, &hKey)) { dwSize = CharSizeOf(szPath); if(ERROR_SUCCESS == RegQueryValueEx(hKey, lpszOERoot, NULL, &dwType, (LPBYTE) szPath, &dwSize)) { if(lstrlen(szPath)) { StrCatBuff(szPath,lpszAddressBook, ARRAYSIZE(szPath)); //if directory doesnt exist, create it CreateDirectory(szPath, NULL); //ignore error if it already exists if(GetFileAttributes(szPath) != 0xFFFFFFFF) { StrCpyN(szDir, szPath, cchSizeDir); hr = S_OK; goto out; } } } } if(hKey) RegCloseKey(hKey); */ hKey = NULL; // No user name .. just get the common files directory and put TEXT("Microsoft Shared\Address Book") under it if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, lpszCurrentVer, 0, KEY_READ, &hKey)) { dwSize = ARRAYSIZE(szPath); if(ERROR_SUCCESS == RegQueryValueEx(hKey, lpszCommonFiles, NULL, &dwType, (LPBYTE) szPath, &dwSize)) { if(lstrlen(szPath)) { StrCatBuff(szPath, lpszMicrosoftShared, ARRAYSIZE(szPath)); CreateDirectory(szPath, NULL); if(GetFileAttributes(szPath) != 0xFFFFFFFF) { StrCatBuff(szPath, lpszAddressBook, ARRAYSIZE(szPath)); CreateDirectory(szPath, NULL); if(GetFileAttributes(szPath) != 0xFFFFFFFF) { StrCpyN(szDir, szPath, cchSizeDir); hr = S_OK; goto out; } } } } } // if all of the above failed then we'll have problems since this function must NEVER fail when // it is called, // Hence go ahead and try to create c:\address book (which might fail on an 8.3 machine) in which case // create c:\wab if(CreateDirectory(lpszCAddressBook, NULL)) { StrCpyN(szDir, lpszCAddressBook, cchSizeDir); StrCatBuff(szDir, TEXT("\\"), cchSizeDir); hr = S_OK; goto out; } // failed - try c:\wab if(CreateDirectory(lpszCWAB, NULL)) { StrCpyN(szDir, lpszCWAB, cchSizeDir); hr = S_OK; goto out; } // still failed !!!!!???!!? !@#!@#!!! // just return the windows directory if we can if (GetWindowsDirectory(szPath, ARRAYSIZE(szPath))) { StrCpyN(szDir, szPath, cchSizeDir); hr = S_OK; goto out; } // still failed !!!!!???!!? !@#!@#!!! // just return 'c:' StrCpyN(szDir, TEXT("c:\\"), cchSizeDir); hr = S_OK; out: if(hKey) RegCloseKey(hKey); if(szDir && lstrlen(szDir)) { // Add a terminating slash to the directory name if one doesnt exist if( *(szDir+lstrlen(szDir)-1) != '\\' ) StrCatBuff(szDir, szBackSlash, cchSizeDir); } return hr; } /* - - DoFirstRunMigrationAndProcessing * * Purpose: * If this is an IE4 or later first run, move the old WAB file from * windows to a new location and/or create a new WAB file so that the * old WAB file is not mucked around with * */ HRESULT DoFirstRunMigrationAndProcessing() { HRESULT hr = S_OK; const LPTSTR lpszFirstRunValue = TEXT("FirstRun"); const LPTSTR lpszIE3Ext = TEXT(".ie3"); DWORD dwType = 0; DWORD dwValue = 0; LPPTGDATA lpPTGData=GetThreadStoragePointer(); TCHAR szDir[MAX_PATH]; TCHAR szFileName[MAX_PATH]; HKEY hKey = NULL; DWORD dwSize = sizeof(DWORD); // First check if this is a first run - if its not a first run then we can just skip out if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, lpNewWABRegKey, 0, KEY_READ, &hKey)) { if(ERROR_SUCCESS == RegQueryValueEx( hKey, lpszFirstRunValue, NULL, &dwType, (LPBYTE) &dwValue, &dwSize)) { goto out; } } if(hKey) RegCloseKey(hKey); hKey = NULL; // So this is the first run .. // First thing to do is to Migrate the LDAP accounts in this session only ... // Set the first run flag pt_bFirstRun = TRUE; // Get the directory name of the new directory in which the WAB file will be created/copied *szDir = '\0'; if (hr = GetNewDataDirName(szDir, ARRAYSIZE(szDir))) goto out; *szFileName = '\0'; // Do we have a pre-existing wab data file ? Check by looking in the registry for the appropriate reg key if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, lpszOldKeyName, 0, KEY_ALL_ACCESS, &hKey)) { TCHAR szOldPath[MAX_PATH]; TCHAR szWinPath[MAX_PATH]; TCHAR szNewName[MAX_PATH]; // Get the file path .. dwSize = ARRAYSIZE(szOldPath); *szOldPath = '\0'; if(ERROR_SUCCESS == RegQueryValueEx(hKey, NULL, NULL, &dwType, (LPBYTE)szOldPath, &dwSize)) { if(lstrlen(szOldPath) && GetFileAttributes(szOldPath)!= 0xFFFFFFFF) { LPTSTR lp1= NULL, lp2 = NULL; // isolate the wab file name here lp1 = szOldPath; while(lp1 && *lp1) { if(*lp1 == '\\') lp2 = lp1; lp1 = CharNext(lp1); } if(!lp2) lp2 = szOldPath; else { lp1 = lp2; lp2 = CharNext(lp1); } StrCpyN(szFileName, lp2, ARRAYSIZE(szFileName)); // rename the old file as an ie3 file by appending .ie3 to the end of the file name StrCpyN(szNewName, szOldPath, ARRAYSIZE(szNewName)); StrCatBuff(szNewName, lpszIE3Ext, ARRAYSIZE(szNewName)); if(MoveFile(szOldPath, szNewName)) { // Update the new name and path in the old registry setting RegSetValueEx(hKey, NULL, 0, REG_SZ, (LPBYTE)szNewName, (lstrlen(szNewName)+1) * sizeof(TCHAR) ); } StrCpyN(szOldPath, szNewName, ARRAYSIZE(szOldPath)); *szNewName = '\0'; // Is this in the Windows Directory ?? *szWinPath = '\0'; GetWindowsDirectory(szWinPath, ARRAYSIZE(szWinPath)); if(lstrlen(szWinPath) && lstrlen(szWinPath) < lstrlen(szOldPath)) { // Terminate the old file path just before the filename // If the file is in the Windows directory, the remaining filename // will be the same as the windows path if(*lp1 == '\\') //lp1 was set above { // First check that the windows directory is not the root directory (e.g. C:\) if(lstrlen(szWinPath) == 3 && szWinPath[1]==':' && szWinPath[2]=='\\') lp1 = CharNext(lp1); // Move lp1 past the '\' *lp1 = '\0'; } if(!lstrcmpi(szOldPath, szWinPath)) { dwSize = ARRAYSIZE(szOldPath); RegQueryValueEx(hKey, NULL, 0, &dwType, (LPBYTE) szOldPath, &dwSize); StrCpyN(szNewName, szDir, ARRAYSIZE(szNewName)); StrCatBuff(szNewName, szFileName, ARRAYSIZE(szNewName)); StrCatBuff(szNewName, lpszIE3Ext, ARRAYSIZE(szNewName)); // move this file to the new directory if(MoveFile(szOldPath, szNewName)) { // Update the newname in the registry RegSetValueEx(hKey, NULL, 0, REG_SZ, (LPBYTE)szNewName, (lstrlen(szNewName)+1) * sizeof(TCHAR) ); } StrCpyN(szOldPath, szNewName, ARRAYSIZE(szOldPath)); } } // Since the old WAB file exists, we will make a copy and put it in the newdir StrCpyN(szNewName, szDir, ARRAYSIZE(szNewName)); StrCatBuff(szNewName, szFileName, ARRAYSIZE(szNewName)); CopyFile(szOldPath, szNewName, TRUE); { // if the CopyFile fails because something already exists in the new dir, still update // the path to the new dir (prevent using the old file no matter what) HKEY hKeyNew = NULL; DWORD dwDisposition = 0; if(ERROR_SUCCESS == RegCreateKeyEx(HKEY_CURRENT_USER, lpszKeyName, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hKeyNew, &dwDisposition)) { RegSetValueEx(hKeyNew, NULL, 0, REG_SZ, (LPBYTE)szNewName, (lstrlen(szNewName)+1) * sizeof(TCHAR) ); } if(hKeyNew) RegCloseKey(hKeyNew); } } } } // update the first run flag if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, lpNewWABRegKey, 0, KEY_ALL_ACCESS, &hKey)) { dwValue = 1; dwSize = sizeof(dwValue); if(ERROR_SUCCESS != RegSetValueEx( hKey, lpszFirstRunValue, 0, REG_DWORD, (LPBYTE) &dwValue, dwSize)) { goto out; } } if(hKey) RegCloseKey(hKey); hKey = NULL; hr = S_OK; out: if(hKey) RegCloseKey(hKey); return hr; } // Random test data .. ignore // static OlkContInfo rgOlk[2]; // LPTSTR lp1 = "Contact Folder 1"; // LPTSTR lp2 = "Second Contact Folder"; extern void ConvertOlkConttoWABCont( ULONG * lpcolk, OutlookContInfo ** lprgolk, ULONG * lpcolkci, OlkContInfo ** lprgolkci); /* - OpenAddRefPropertyStore - * Purpose: * Get the property store name from the registry and open it. * Addref it * * Arguments: * lpPropertyStore PROPERTY_STORE structure * * Returns: * SCODE * * Notes: * This routine is kind of a mess with all these gotos and special cases * for failed registry functions. I'm not sure why, but the registry * functions operate differently on NT and Win95, but in both cases, * they sometimes act as though the key already exists even when it doesn't. * */ SCODE OpenAddRefPropertyStore(LPWAB_PARAM lpWP, LPPROPERTY_STORE lpPropertyStore) { HRESULT hResult = hrSuccess; SCODE sc = SUCCESS_SUCCESS; TCHAR szFileName[MAX_PATH]; LPTSTR lpCurrent; HKEY hKey = NULL; DWORD cchLenName = ARRAYSIZE(szFileName); DWORD cchCurrent = 0; DWORD dwDisposition = 0; DWORD dwType = 0; HWND hWnd = NULL; ULONG ulFlags = AB_OPEN_ALWAYS; LPTSTR lpszWABExt = TEXT(".wab"); BOOL fNewKey = FALSE; LPPTGDATA lpPTGData=GetThreadStoragePointer(); szFileName[0]='\0'; if (lpWP) { // The cbSize parameter will, in the future, tell us what version // of the WAB_PARAM is being called so we can upgrade the WAB_PARAM // structure in future releases. For this version the cbSize // doesnt really matter. hWnd = lpWP->hwnd; if(!lpWP->ulFlags && lpWP->szFileName ) { LPWSTR lpW = ConvertAtoW(lpWP->szFileName); if (lpW != NULL) { lstrcpy(szFileName, lpW); LocalFreeAndNull(&lpW); } } } if (! lpPropertyStore->ulRefCount) { if (pt_bIsWABOpenExSession) { hResult = OpenPropertyStore(NULL, 0, hWnd, &(lpPropertyStore->hPropertyStore)); if (SUCCEEDED(hResult)) { LPWABSTORAGEPROVIDER lpWSP; ULONG colk = 0; OutlookContInfo * rgolk = NULL; Assert(lpPropertyStore->hPropertyStore); Assert(!lpPropertyStore->rgolkci); Assert(!lpPropertyStore->colkci); lpWSP = (LPWABSTORAGEPROVIDER)(lpPropertyStore->hPropertyStore); hResult = lpWSP->lpVtbl->GetContainerList(lpWSP, &colk, &rgolk); if(!HR_FAILED(hResult)) { DebugTrace(TEXT("WABStorageProvider::GetContainerList returns:%x\n"),hResult); ConvertOlkConttoWABCont(&colk, &rgolk, &lpPropertyStore->colkci, &lpPropertyStore->rgolkci); FreeBufferAndNull(&rgolk); } else { lpWSP->lpVtbl->Release(lpWSP); lpPropertyStore->hPropertyStore = NULL; } } if (FAILED(hResult)) { sc = ResultFromScode(hResult); goto error; } //lpPropertyStore->colkci = 2; //rgOlk[0].lpEntryID = rgOlk[1].lpEntryID = lpPropertyStore->rgolkci[0].lpEntryID; //rgOlk[0].lpszName = lp1; //rgOlk[1].lpszName = lp2; //lpPropertyStore->rgolkci = rgOlk; goto out; } // // Get the default WAB file name from the registry // if we don't have a name supplied in lpWP // try_again: if(!lstrlen(szFileName)) { DoFirstRunMigrationAndProcessing(); // First, try to open an existing key if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, lpszKeyName, 0, // options, MBZ KEY_ALL_ACCESS, &hKey)) { dwDisposition = REG_OPENED_EXISTING_KEY; } else { // Create the key if (ERROR_SUCCESS != RegCreateKeyEx(HKEY_CURRENT_USER, lpszKeyName, 0, //reserved NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dwDisposition)) { DebugTrace( TEXT("RegCreateKeyEx failed\n")); sc = MAPI_E_NOT_FOUND; // ?? goto error; } } if (dwDisposition == REG_CREATED_NEW_KEY) { new_key: // prevent more than one retry if (fNewKey) { hResult = ResultFromScode(MAPI_E_NOT_INITIALIZED); goto error; } fNewKey = TRUE; // // New key ... need to give it a value .. // // BUG - dont use windows directory for new wab files .. // use one of the application data directories ... if (GetNewDataDirName(szFileName, ARRAYSIZE(szFileName))) { DebugTrace( TEXT("GetNewDataDirName failed\n")); sc = MAPI_E_NOT_FOUND; // ?? goto error; } cchCurrent = lstrlen(szFileName); //Tag on a trailing slash if 1 doesnt exist .. if (szFileName[cchCurrent-1] != '\\') { StrCatBuff(szFileName, szBackSlash, ARRAYSIZE(szFileName)); } // Get a user name ... cchCurrent = lstrlen(szFileName); lpCurrent = szFileName + cchCurrent; cchLenName = (ARRAYSIZE(szFileName) - cchCurrent); if (!GetUserName(lpCurrent, &cchLenName)) { cchLenName = (ARRAYSIZE(szFileName) - cchCurrent); // On failure just create some dummy file name StrCpyN(lpCurrent, TEXT("AddrBook"), cchLenName); } // Fix any invalid characters in the filename while (*lpCurrent) { switch (*lpCurrent) { case '\\': case '/': case '<': case '>': case ':': case '"': case '|': case '?': case '*': case '.': *lpCurrent = '_'; // replace with underscore break; default: break; } lpCurrent++; } StrCatBuff(szFileName, lpszWABExt, ARRAYSIZE(szFileName)); cchLenName = sizeof(TCHAR)*lstrlen(szFileName); //save this as the value of the Wab file in the registry if (ERROR_SUCCESS != RegSetValueEx(hKey, NULL, 0, REG_SZ, (LPBYTE)szFileName, cchLenName)) { DebugTrace( TEXT("RegSetValue failed\n")); sc = MAPI_E_NOT_FOUND; // ?? goto error; } } else { // Didn't create a new key, so get the key value if (ERROR_SUCCESS != RegQueryValueEx(hKey, NULL, NULL, &dwType, //reserved (LPBYTE)szFileName, &cchLenName)) { DebugTrace( TEXT("RegSetValue failed\n")); goto new_key; } else if (! lstrlen(szFileName)) { DebugTrace( TEXT("Warning: Found empty name key!\n")); goto new_key; } //Check that the name in the existing key is a valid filename // If it is not a valid file name then we should remove it // from the registry and create a new default file name if(0xFFFFFFFF == GetFileAttributes(szFileName)) { // There is some problem with this file ... // Remove it from the registry and recreate a new file name // only if the path doesnt exist. Its possible that the file // doesnt exist, in which case we create a new file in open // property store DWORD dwErr = GetLastError(); //NT5 bug 180007 - upgrading from Win95 to WinNT 5, if the // old file name had quotes around it, CreateFile will fail and // so will GetFileAttributes. // Strip out the quotes and try again if( (dwErr == ERROR_PATH_NOT_FOUND || dwErr == ERROR_INVALID_NAME) && lstrlen(szFileName) && szFileName[0] == '"' && szFileName[lstrlen(szFileName)-1] == '"') { // remove the quotes szFileName[lstrlen(szFileName)-1] = '\0'; StrCpyN(szFileName, szFileName+1, ARRAYSIZE(szFileName)); if(0xFFFFFFFF != GetFileAttributes(szFileName)) goto open_file; } // otherwise some unknown error with the file name - just discard the // file name and try again RegCloseKey(hKey); RegDeleteKey(HKEY_CURRENT_USER, lpszKeyName); szFileName[0]='\0'; fNewKey = FALSE; goto try_again; } } } open_file: // // now we have the file name, open the property store // if (HR_FAILED(hResult = OpenPropertyStore(szFileName, AB_OPEN_ALWAYS, hWnd, // HWND for potential Message Boxes &(lpPropertyStore->hPropertyStore)))) { // The above call should always pass unless we ran out of disk space or // some such thing .. DebugTrace( TEXT("OpenPropertyStore failed\n")); if(hResult == MAPI_E_NO_ACCESS) { sc = GetScode(hResult); goto error; } // There is a chance that this may have failed due to a long file name // which the machine could not accept. if(lstrlen(szFileName) > 8 + 1 + lstrlen(lpszWABExt)) // 8+.+3 { LPTSTR lpLast = szFileName; LPTSTR lpTemp = szFileName; while(*lpTemp) { if((*lpTemp) == '\\') lpLast = lpTemp; lpTemp = CharNext(lpTemp); } // lpLast points to the last \ .. everything after this will be the file name if(lstrlen(lpLast+1) > 12) { // we need to truncate this name *(lpLast+8) = '\0'; StrCatBuff(szFileName, lpszWABExt, ARRAYSIZE(szFileName)); hResult = OpenPropertyStore(szFileName, AB_OPEN_ALWAYS, hWnd, // HWND for potential Message Boxes &(lpPropertyStore->hPropertyStore)); } } if(HR_FAILED(hResult)) { sc = GetScode(hResult); goto error; } } } out: lpPropertyStore->ulRefCount++; error: if (hKey) { RegCloseKey(hKey); } return(sc); } /* - ReleaseOutlookStore - * Purpose: * Keep track of outlook store dll refcount * * Arguments: * lpOutlookStore OUTLOOK_STORE structure * * Returns: * Current reference count. When 0, unload outlook-wab dll * no longer open. * */ ULONG ReleaseOutlookStore(HANDLE hPropertyStore, LPOUTLOOK_STORE lpOutlookStore) { if(lpOutlookStore) { lpOutlookStore->ulRefCount--; if(0==lpOutlookStore->ulRefCount) { LPPTGDATA lpPTGData=GetThreadStoragePointer(); if(pt_bIsWABOpenExSession && hPropertyStore) { // This is a WABOpenEx session using outlooks storage provider LPWABSTORAGEPROVIDER lpWSP = (LPWABSTORAGEPROVIDER) hPropertyStore; lpWSP->lpVtbl->Release(lpWSP); } if(lpOutlookStore->hOutlookStore) { FreeLibrary(lpOutlookStore->hOutlookStore); lpOutlookStore->hOutlookStore = NULL; #if 0 // @todo [PaulHi] DLL Leak. Remove this or implement // [PaulHi] 3/12/99 @hack Serious HACK warning // The Outlook outlwab.dll store module is not unloading some Outlook // dlls. This causes Outlook to get confused about who loaded these dlls // and whether Outlook or OE should service MAPI calls. // HACK Forcibly remove these dlls HACK // But only if the WAB WASN'T opened by OL process. EnterCriticalSection(&csOMIUnload); if (!s_bIsReallyOnlyWABOpenExSession) { LPCSTR c_lpszOMI9DLL = "omi9.dll"; LPCSTR c_lpszOMI9PSTDLL = "omipst9.dll"; LPCSTR c_lpszOMINTDLL = "omint.dll"; LPCSTR c_lpszOMINTPSTDLL = "omipstnt.dll"; HINSTANCE hinst; // It is essential to unload the omipst9.dll and omipstnt.dll // modules first because they load the omi9.dll and omint.dll // modules. The FreeLibary() on the omi9/omint modules should // not be necessary. if ( hinst = GetModuleHandleA(c_lpszOMI9PSTDLL) ) FreeLibrary(hinst); if ( hinst = GetModuleHandleA(c_lpszOMINTPSTDLL) ) FreeLibrary(hinst); if ( hinst = GetModuleHandleA(c_lpszOMI9DLL) ) FreeLibrary(hinst); if ( hinst = GetModuleHandleA(c_lpszOMINTDLL) ) FreeLibrary(hinst); } LeaveCriticalSection(&csOMIUnload); #endif } } return lpOutlookStore->ulRefCount; } return 0; } /* - OpenAddRefOutlookStore - * Purpose: * Open or ref count outlook-wab dll * * Arguments: * lpOutlookStore OUTLOOK_STORE structure * * Returns: * */ SCODE OpenAddRefOutlookStore(LPOUTLOOK_STORE lpOutlookStore) { LPPTGDATA lpPTGData=GetThreadStoragePointer(); if(!lpOutlookStore) return(MAPI_E_INVALID_PARAMETER); if(!lpOutlookStore->ulRefCount) { TCHAR szOutlWABPath[MAX_PATH]; *szOutlWABPath = '\0'; if (!bCheckForOutlookWABDll(szOutlWABPath, ARRAYSIZE(szOutlWABPath)) || !lstrlen(szOutlWABPath) || !(lpOutlookStore->hOutlookStore = LoadLibrary(szOutlWABPath)) ) return MAPI_E_NOT_INITIALIZED; // Load the Outlook WABStorageProvider Dll Entry Point here // First try to load the Unicode version (doesn't exist but we're thinking forward here) lpfnWABOpenStorageProvider = (LPWABOPENSTORAGEPROVIDER) GetProcAddress(lpOutlookStore->hOutlookStore, WAB_SPI_ENTRY_POINT_W); if(lpfnWABOpenStorageProvider) pt_bIsUnicodeOutlook = TRUE; else { pt_bIsUnicodeOutlook = FALSE; lpfnWABOpenStorageProvider = (LPWABOPENSTORAGEPROVIDER) GetProcAddress(lpOutlookStore->hOutlookStore, WAB_SPI_ENTRY_POINT); } } if(lpfnWABOpenStorageProvider && lpOutlookStore->hOutlookStore) { // Tag this thread as a valid Outlook store session // If this flag below is false, we willd default to // using the WAB store pt_bIsWABOpenExSession = TRUE; } lpOutlookStore->ulRefCount++; return S_OK; }