#include #include "demand.h" #include #define FBadCh(c) ((c) - ' ' > 64) #define DEC(c) ((BYTE) (((c) - ' ') & 0x3f)) /* uuencode/decode a binary string */ #define ENC(c) ((BYTE) ((c) ? ((c) & 0x3f) + ' ': '`')) int rgLeft[3] = { 0, 2, 3 }; typedef USHORT CCH; STDAPI_(BOOL) FDecodeID(LPTSTR sz, LPBYTE pb, ULONG *pcb); STDAPI_(int) CchEncodedLine(int cb); STDAPI_(ULONG) CbOfEncoded(LPTSTR sz); ERR ErrSzToBinaryEID( LPSTR lpstrEID, ULONG * lpcbEID, LPVOID * lppvEID ); LPSTR FAR PASCAL LpstrFromBstrA( BSTR bstrSrc, LPSTR lpstrDest ); LPSTR FAR PASCAL LpstrFromBstr( BSTR bstrSrc, LPSTR lpstrDest ); int FAR PASCAL FBMAPIFreeStruct (LPVOID lpMapiIn, ULONG uCount, USHORT usFlag); ULONG PASCAL VB2Mapi( LPVOID lpVBIn, LPVOID lpMapiIn, ULONG uCount, USHORT usFlag ); LPMAPI_MESSAGE FAR PASCAL vbmsg2mapimsg( LPVB_MESSAGE lpVBMessage, LPSAFEARRAY lpsaVBRecips, LPSAFEARRAY lpsaVBFiles, ULONG * pulErr ); ERR FAR PASCAL ErrLpstrToBstrA( LPSTR cstr, BSTR * lpBstr ); ERR FAR PASCAL ErrLpstrToBstr( LPSTR cstr, BSTR * lpBstr ); STDAPI_(void) EncodeID(LPBYTE pb, ULONG cb, LPTSTR sz); STDAPI_(ULONG) CchOfEncoding(ULONG cbBinary); ERR ErrBinaryToSzEID( LPVOID lpvEID, ULONG cbEID, LPSTR * lppstrEID ); ULONG PASCAL Mapi2VB (LPVOID lpMapiIn, LPVOID lpVBIn, ULONG uCount, USHORT usFlag); /*--------------------------------------------------------------------- * * Copyright Microsoft Corporation, 1992 * _______________________________________________________________ * * PROGRAM: BMAPI.CPP * * PURPOSE: Contains library routines VB MAPI wrappers * * FUNCTIONS: * BMAPISendMail * BMAPIFindNext * BMAPIReadMail * BMAPIGetReadMail * BMAPISaveMail * BMAPIAddress * BMAPIGetAddress * BMAPIResolveName * BMAPIDetails * * MISCELLANEOUS: * * - All BMAPI procedures basically follow the same structure as * follows; * * BMAPI_ENTRY BMAPIRoutine (...) * { * Allocate C Structures * Translate VB structures to C structures * Call MAPI Procedure * Translate C structures to VB Structures * DeAllocate C Structures * Return * } * * * REVISION HISTORY: * * - Last modified by v-snatar * * * _____________________________________________________________ * * Copyright Microsoft Corporation, 1992-1997 * *----------------------------------------------------------------------*/ //--------------------------------------------------------------------------- // Name: BMAPISendMail() // // Description: // 32 bit support for VB MAPISendMail(). // // Parameters: // Returns: // Effects: // Notes: // Revision: //--------------------------------------------------------------------------- BMAPI_ENTRY BMAPISendMail (LHANDLE hSession, ULONG_PTR ulUIParam, LPVB_MESSAGE lpM, LPSAFEARRAY * lppsaRecips, LPSAFEARRAY * lppsaFiles, ULONG flFlags, ULONG ulReserved) { ULONG ulRet = SUCCESS_SUCCESS; LPMAPI_MESSAGE lpMail = NULL; // Translate VB data into C data. if ((lpMail = vbmsg2mapimsg( lpM, *lppsaRecips, *lppsaFiles, &ulRet )) == NULL) return ulRet; // Call MAPI Procedure ulRet = MAPISendMail( hSession, // session ulUIParam, // UIParam lpMail, // Mail flFlags, // Flags ulReserved ); // Reserved // Free up data allocated by call to vbmsg2mapimsg FBMAPIFreeStruct(lpMail, 1, MESSAGE); return ulRet; } //--------------------------------------------------------------------------- // Name: BMAPIFindNext() // // Description: // Implements FindNext MAPI API. // // Parameters: // Returns: // Effects: // Notes: // Revision: //--------------------------------------------------------------------------- BMAPI_ENTRY BMAPIFindNext( LHANDLE hSession, // Session ULONG_PTR ulUIParam, // UIParam BSTR * lpbstrType, // MessageType BSTR * lpbstrSeed, // Seed message Id ULONG flFlags, // Flags ULONG ulReserved, // Reserved BSTR * lpbstrId) // Message Id (in/out) { ULONG ulRet; LPSTR lpID = NULL; LPSTR lpSeed; LPSTR lpTypeArg; // Translate VB strings into C strings. We'll deallocate // the strings before we return. // Always allocate the MessageID string. This way we can redimension // it to fit the returned size. We'll never use the caller's buffer. // It turns out the VBSetHlstr call (from ErrLpstrToHlstr) will reassign // the string for us. if (!MemAlloc((LPVOID*)&lpID, 513)) return MAPI_E_INSUFFICIENT_MEMORY; lpSeed = LpstrFromBstrA( *lpbstrSeed, NULL); lpTypeArg = LpstrFromBstrA( *lpbstrType, NULL); // Call MAPI Procedure ulRet = MAPIFindNext( hSession, // Session ulUIParam, // UIParam lpTypeArg, // Message Type lpSeed, // Seed Message Id flFlags, // Flags, ulReserved, // Reserved lpID ); // Message ID // Translate Message ID into VB string if ( ulRet == SUCCESS_SUCCESS ) ErrLpstrToBstrA( lpID, lpbstrId); // Free up C strings allocated by call to LpstrFromHlstr SafeMemFree( lpID ); SafeMemFree( lpSeed ); SafeMemFree( lpTypeArg ); return ulRet; } //--------------------------------------------------------------------------- // Name: BMAPIReadMail() // // Description: // // Implements MAPIReadMail VB API. The memory allocated by // MAPIReadMail is NOT deallocated (with MAPIFreeBuffer) until // the caller calls BMAPIGetReadMail. The recipient and file // count is returned so that the caller can Re-dimension buffers // before calling BMAPI GetReadMail. A long pointer to the // ReadMail data is also returned since it is required in the // BAMPIGetReadMail call. // Parameters: // Returns: // Effects: // Notes: // Revision: //--------------------------------------------------------------------------- BMAPI_ENTRY BMAPIReadMail( PULONG_PTR lpulMessage, // pointer to output data (out) LPULONG nRecips, // number of recipients (out) LPULONG nFiles, // number of file attachments (out) LHANDLE hSession, // Session ULONG_PTR ulUIParam, // UIParam BSTR * lpbstrID, // Message Id ULONG flFlags, // Flags ULONG ulReserved ) // Reserved { LPSTR lpID; ULONG ulRet; LPMAPI_MESSAGE lpMail = NULL; // Translate VB String to C String lpID = LpstrFromBstrA( *lpbstrID, NULL ); // Read the message, lpMail is set by MAPI to point // to the memory allocated by MAPI. ulRet = MAPIReadMail( hSession, // Session ulUIParam, // UIParam lpID, // Message Id flFlags, // Flags ulReserved, // Reserved &lpMail ); // Pointer to MAPI Data (returned) // Check for read error return code if ( ulRet != SUCCESS_SUCCESS ) { // Clean up. Set return message to zero *lpulMessage = 0L; SafeMemFree( lpID ); return ulRet; } // Pull out the recipient and file array re-dim info *nFiles = lpMail->nFileCount; *nRecips = lpMail->nRecipCount; *lpulMessage = (ULONG_PTR) (LPVOID) lpMail; SafeMemFree( lpID ); return ulRet; } //--------------------------------------------------------------------------- // Name: BMAPIGetReadMail() // // Description: // // Copies data stored by MAPI ReadMail (see BMAPIReadMail) // into a VB Buffer passed by the caller. It is up to the // caller to make sure the buffer passed is large enough to // accomodate the data. // // Parameters: // Returns: // Effects: // Notes: // Revision: //--------------------------------------------------------------------------- BMAPI_ENTRY BMAPIGetReadMail( ULONG lpMessage, // Pointer to MAPI Mail LPVB_MESSAGE lpvbMessage, // Pointer to VB Message Buffer (out) LPSAFEARRAY * lppsaRecips, // Pointer to VB Recipient Buffer (out) LPSAFEARRAY * lppsaFiles, // Pointer to VB File attachment Buffer (out) LPVB_RECIPIENT lpvbOrig) // Pointer to VB Originator Buffer (out) { ULONG ulRet = SUCCESS_SUCCESS; ERR errVBrc; LPMAPI_MESSAGE lpMail; lpMail = (LPMAPI_MESSAGE)((ULONG_PTR)lpMessage); if ( !lpMail ) return MAPI_E_INSUFFICIENT_MEMORY; // copy Attachment info to callers VB Buffer if (ulRet = Mapi2VB( lpMail->lpFiles, *lppsaFiles, lpMail->nFileCount, FILE )) { MAPIFreeBuffer(lpMail); return ulRet; } // copy Recipient info to callers VB Buffer if ( ulRet = Mapi2VB( lpMail->lpRecips, *lppsaRecips, lpMail->nRecipCount, RECIPIENT | USESAFEARRAY ) ) { MAPIFreeBuffer( lpMail ); return ulRet; } // Copy MAPI Message to callers VB Buffer errVBrc = 0; if ( lpMail->lpOriginator ) { lpvbOrig->ulReserved = lpMail->lpOriginator->ulReserved; lpvbOrig->ulRecipClass = MAPI_ORIG; if ( lpMail->lpOriginator->lpszName ) errVBrc = (ERR)(errVBrc + ErrLpstrToBstrA( lpMail->lpOriginator->lpszName, &lpvbOrig->bstrName )); if ( lpMail->lpOriginator->lpszAddress ) errVBrc = (ERR)(errVBrc + ErrLpstrToBstrA( lpMail->lpOriginator->lpszAddress, &lpvbOrig->bstrAddress )); if (lpMail->lpOriginator->ulEIDSize) { LPSTR lpStrEID; // Hexize recipient EID and convert to OLE BSTR if ( ErrBinaryToSzEID( lpMail->lpOriginator->lpEntryID, lpMail->lpOriginator->ulEIDSize, &lpStrEID ) ) { errVBrc = TRUE; goto exit; } // To figure out size first convert to UNICODE errVBrc = ErrLpstrToBstr( lpStrEID, &lpvbOrig->bstrEID ); if ( errVBrc ) { goto exit_orig; } lpvbOrig->ulEIDSize = SysStringByteLen( lpvbOrig->bstrEID ) + sizeof(OLECHAR); SysFreeString( lpvbOrig->bstrEID ); errVBrc = (ERR)(errVBrc + ErrLpstrToBstrA( lpStrEID, &lpvbOrig->bstrEID )); exit_orig: SafeMemFree( lpStrEID ); } } lpvbMessage->flFlags = lpMail->flFlags; lpvbMessage->ulReserved = lpMail->ulReserved; lpvbMessage->nRecipCount = lpMail->nRecipCount; lpvbMessage->nFileCount = lpMail->nFileCount; if (lpMail->lpszSubject) errVBrc = (ERR)(errVBrc + ErrLpstrToBstrA( lpMail->lpszSubject, &lpvbMessage->bstrSubject)); if (lpMail->lpszNoteText) errVBrc = (ERR)(errVBrc + ErrLpstrToBstrA( lpMail->lpszNoteText, &lpvbMessage->bstrNoteText)); if (lpMail->lpszMessageType) errVBrc = (ERR)(errVBrc + ErrLpstrToBstrA( lpMail->lpszMessageType, &lpvbMessage->bstrMessageType)); if (lpMail->lpszDateReceived) errVBrc = (ERR)(errVBrc + ErrLpstrToBstrA( lpMail->lpszDateReceived, &lpvbMessage->bstrDate)); exit: MAPIFreeBuffer( lpMail ); if ( errVBrc ) ulRet = MAPI_E_FAILURE; return ulRet; } //--------------------------------------------------------------------------- // Name: BMAPISaveMail() // // Description: // Implements MAPISaveMail API. // // Parameters: // Returns: // Effects: // Notes: // Revision: //--------------------------------------------------------------------------- BMAPI_ENTRY BMAPISaveMail( LHANDLE hSession, // Session ULONG_PTR ulUIParam, // UIParam LPVB_MESSAGE lpM, // Pointer to VB Message Buffer LPSAFEARRAY * lppsaRecips, // Pointer to VB Recipient Buffer LPSAFEARRAY * lppsaFiles, // Pointer to VB File Attacment Buffer ULONG flFlags, // Flags ULONG ulReserved, // Reserved BSTR * lpbstrID) // Message ID { LPSTR lpID; ULONG ulRet= SUCCESS_SUCCESS; LPMAPI_MESSAGE lpMail; // Translate VB data to MAPI data lpID = LpstrFromBstrA( *lpbstrID, NULL ); // If we allocate Message ID then we can set the flag. // otherwise for backward compatability assume the callers buffer size. if ( lpID == NULL ) { if (!MemAlloc((LPVOID*)&lpID, 513)) return MAPI_E_INSUFFICIENT_MEMORY; } if ( (lpMail = vbmsg2mapimsg( lpM, *lppsaRecips, *lppsaFiles, &ulRet )) == NULL ) { SafeMemFree( lpID ); return ulRet; } ulRet = MAPISaveMail( hSession, ulUIParam, lpMail, flFlags, ulReserved, lpID ); if ( ulRet ) goto exit; if ( ErrLpstrToBstrA( lpID, lpbstrID ) ) ulRet = MAPI_E_INSUFFICIENT_MEMORY; exit: SafeMemFree( lpID ); FBMAPIFreeStruct( lpMail, 1, MESSAGE ); return ulRet; } //--------------------------------------------------------------------------- // Name: BMAPIAddress() // // Description: // // Purpose: Allows Visual Basic to call MAPIAddress. The // Recipient data is stored in a global memory block. To // retrieve the data the caller must call BMAPIGetAddress. // // Parameters: // Returns: // Effects: // Notes: // Revision: //--------------------------------------------------------------------------- BMAPI_ENTRY BMAPIAddress( PULONG_PTR lpulRecip, // Pointer to New Recipient Buffer (out) LHANDLE hSession, // Session ULONG_PTR ulUIParam, // UIParam BSTR * lpbstrCaption, // Caption string ULONG ulEditFields, // Number of Edit Controls BSTR * lpbstrLabel, // Label string LPULONG lpulRecipients, // Pointer to number of Recipients (in/out) LPSAFEARRAY * lppsaRecip, // Pointer to Initial Recipients VB_RECIPIENT ULONG ulFlags, // Flags ULONG ulReserved ) // Reserve { LPSTR lpLabel = NULL; LPSTR lpCaption = NULL; ULONG ulRet; ULONG nRecipients = 0; LPMAPI_RECIPIENT lpMapi = NULL; LPMAPI_RECIPIENT lpNewRecipients = NULL; // Convert VB Strings to C strings lpLabel = LpstrFromBstrA( *lpbstrLabel, NULL ); lpCaption = LpstrFromBstrA( *lpbstrCaption, NULL ); // Allocate memory and translate VB_RECIPIENTS to MAPI_RECIPIENTS. if ( *lpulRecipients ) { if (!MemAlloc((LPVOID*)&lpMapi, (*lpulRecipients * sizeof (MAPI_RECIPIENT)))) return MAPI_E_INSUFFICIENT_MEMORY; } if ( ulRet = VB2Mapi( (LPVOID)*lppsaRecip, (LPVOID)lpMapi, *lpulRecipients, RECIPIENT | USESAFEARRAY ) ) { SafeMemFree( lpLabel ); SafeMemFree( lpCaption ); FBMAPIFreeStruct( lpMapi, *lpulRecipients, RECIPIENT ); return ulRet; } // Call the MAPIAddress function ulRet = MAPIAddress( hSession, // Session ulUIParam, // UIParam lpCaption, // Caption ulEditFields, // Number of edit fields lpLabel, // Label *lpulRecipients, // Number of Recipients lpMapi, // Pointer to recipients ulFlags, // Flags ulReserved, // Reserved (LPULONG) &nRecipients, // Address for new recipient count (lpMapiRecipDesc far *)&lpNewRecipients); // Address of new recipient data // Free up MAPI structures created in this procedure SafeMemFree( lpLabel ); SafeMemFree( lpCaption ); FBMAPIFreeStruct( lpMapi, *lpulRecipients, RECIPIENT ); // Set the returned parameters and return if ( ulRet == SUCCESS_SUCCESS ) { *lpulRecipients = nRecipients; *lpulRecip = (ULONG_PTR) (LPVOID) lpNewRecipients; } return ulRet; } //--------------------------------------------------------------------------- // Name: BMAPIGetAddress() // // Description: // Converts a MapiRecipDesc array into an OLE 2.0 SAFEARRAY. // // Parameters: // Returns: // Effects: // Notes: // Revision: //--------------------------------------------------------------------------- BMAPI_ENTRY BMAPIGetAddress (ULONG ulRecipientData, // Pointer to recipient data ULONG cRecipients, // Number of recipients LPSAFEARRAY * lppsaRecips ) // VB recipient array { ULONG ulRet = SUCCESS_SUCCESS; LPMAPI_RECIPIENT lpData = NULL; if (cRecipients == 0) { MAPIFreeBuffer( (LPVOID)((ULONG_PTR)ulRecipientData) ); return SUCCESS_SUCCESS; } lpData = (LPMAPI_RECIPIENT)((ULONG_PTR)ulRecipientData); // Translate MAPI Address data to VB buffer ulRet = Mapi2VB( lpData, *lppsaRecips, cRecipients, RECIPIENT | USESAFEARRAY ); // Free up MAPI recipient data since it got copied over. MAPIFreeBuffer( lpData ); return ulRet; } //--------------------------------------------------------------------------- // Name: BMAPIDetails() // // Description: // Allows VB to call MAPIDetails procedure. // // Parameters: // Returns: // Effects: // Notes: // Revision: //--------------------------------------------------------------------------- BMAPI_ENTRY BMAPIDetails (LHANDLE hSession, // Session ULONG_PTR ulUIParam, // UIParam LPVB_RECIPIENT lpVB, // Pointer to VB recipient stucture ULONG ulFlags, // Flags ULONG ulReserved) // Reserved { ULONG ulRet; LPMAPI_RECIPIENT lpMapi = NULL; // Translate VB_RECIPIENTS to MAPI_RECIPIENTS. if (!MemAlloc((LPVOID*)&lpMapi,sizeof (MAPI_RECIPIENT))) return MAPI_E_INSUFFICIENT_MEMORY; if ( ulRet = VB2Mapi( lpVB, lpMapi, 1, RECIPIENT ) ) { FBMAPIFreeStruct( lpMapi, 1, RECIPIENT ); return ulRet; } // Call the Simple MAPI function ulRet = MAPIDetails( hSession, // Session ulUIParam, // UIParam lpMapi, // Pointer to MAPI Recipient structure ulFlags, // Flags ulReserved ); // Reserved FBMAPIFreeStruct( lpMapi, 1L, RECIPIENT ); return ulRet; } //--------------------------------------------------------------------------- // Name: BMAPIResolveName // // Description: // Implements VB MAPIResolveName // // Parameters: // Returns: // Effects: // Notes: // Revision: //--------------------------------------------------------------------------- BMAPI_ENTRY BMAPIResolveName (LHANDLE hSession, // Session ULONG_PTR ulUIParam, // UIParam BSTR bstrMapiName, // Name to be resolved ULONG ulFlags, // Flags ULONG ulReserved, // Reserved LPVB_RECIPIENT lpVB) // Pointer to VB recipient structure (out) { LPMAPI_RECIPIENT lpMapi = NULL; ULONG ulRet; LPSTR lpszMapiName; lpszMapiName = LpstrFromBstrA( bstrMapiName, NULL ); // Call the MAPIResolveName function ulRet = MAPIResolveName( hSession, // Session ulUIParam, // UIParam lpszMapiName, // Pointer to resolve name ulFlags, // Flags ulReserved, // Reserved (LPPMAPI_RECIPIENT) &lpMapi ); // Pointer to Recipient (returned) if (ulRet != SUCCESS_SUCCESS) return ulRet; // Translate MAPI data to VB data ulRet = Mapi2VB( lpMapi, lpVB, 1, RECIPIENT ); MAPIFreeBuffer( lpMapi ); return ulRet; } // Helper Functions //--------------------------------------------------------------------------- // Name: vbmsg2mapimsg() // // Description: // Translates VB Message structure to MAPI Message structure // // Parameters: // Returns: // Effects: // Notes: // Revision: //--------------------------------------------------------------------------- LPMAPI_MESSAGE FAR PASCAL vbmsg2mapimsg( LPVB_MESSAGE lpVBMessage, LPSAFEARRAY lpsaVBRecips, LPSAFEARRAY lpsaVBFiles, ULONG * pulErr ) { LPMAPI_FILE lpMapiFile=NULL; LPMAPI_MESSAGE lpMapiMessage=NULL; LPMAPI_RECIPIENT lpMapiRecipient=NULL; if (lpVBMessage == (LPVB_MESSAGE) NULL) { *pulErr = MAPI_E_FAILURE; return NULL; } // Allocate MAPI Message, Recipient and File structures // NOTE: Don't move the following lines of code without // making sure you de-allocate memory properly if the // calls fail. if (!MemAlloc((LPVOID*)&lpMapiMessage,sizeof(MapiMessage))) { *pulErr = MAPI_E_INSUFFICIENT_MEMORY; return NULL; } if (lpVBMessage->nFileCount > 0) { if (!MemAlloc((LPVOID*)&lpMapiFile, sizeof(MAPI_FILE)*lpVBMessage->nFileCount)) { FBMAPIFreeStruct( (LPVOID*)&lpMapiMessage, 1, MESSAGE ); *pulErr = MAPI_E_INSUFFICIENT_MEMORY; return NULL; } } if (lpVBMessage->nRecipCount > 0) { if (!MemAlloc((LPVOID*)&lpMapiRecipient, sizeof(MAPI_RECIPIENT)*lpVBMessage->nRecipCount)) { FBMAPIFreeStruct( lpMapiFile, lpVBMessage->nFileCount, FILE ); FBMAPIFreeStruct( lpMapiMessage, 1, MESSAGE ); *pulErr = MAPI_E_INSUFFICIENT_MEMORY; return NULL; } } // Translate structures from VB to MAPI if ( *pulErr = VB2Mapi( lpsaVBFiles, lpMapiFile, lpVBMessage->nFileCount, FILE | USESAFEARRAY ) ) { FBMAPIFreeStruct( lpMapiFile, lpVBMessage->nFileCount, FILE ); FBMAPIFreeStruct( lpMapiRecipient, lpVBMessage->nRecipCount, RECIPIENT ); FBMAPIFreeStruct( lpMapiMessage, 1, MESSAGE ); return NULL; } if ( *pulErr = VB2Mapi( lpsaVBRecips, lpMapiRecipient, lpVBMessage->nRecipCount, RECIPIENT | USESAFEARRAY ) ) { FBMAPIFreeStruct( lpMapiFile, lpVBMessage->nFileCount, FILE ); FBMAPIFreeStruct( lpMapiRecipient, lpVBMessage->nRecipCount, RECIPIENT ); FBMAPIFreeStruct( lpMapiMessage, 1, MESSAGE ); return NULL; } if ( *pulErr = VB2Mapi( lpVBMessage, lpMapiMessage, 1, MESSAGE ) ) { FBMAPIFreeStruct( lpMapiFile, lpVBMessage->nFileCount, FILE ); FBMAPIFreeStruct( lpMapiRecipient, lpVBMessage->nRecipCount, RECIPIENT ); FBMAPIFreeStruct( lpMapiMessage, 1, MESSAGE ); return NULL; } // Chain File and Recipient structures to Message structure lpMapiMessage->lpFiles = lpMapiFile; lpMapiMessage->lpRecips = lpMapiRecipient; return lpMapiMessage; } //--------------------------------------------------------------------------- // Name: VB2Mapi() // // Description: // Converts VB structures to MAPI structures. Arrays from // VB 4.0 arrive as OLE SAFEARRAYs. // // Parameters: // Returns: // Simple MAPI error code // // Effects: // Notes: // originally FALSE for failure, TRUE for success. // Revision: //--------------------------------------------------------------------------- ULONG PASCAL VB2Mapi( LPVOID lpVBIn, LPVOID lpMapiIn, ULONG uCount, USHORT usFlag ) { ULONG u; HRESULT hr = 0; ULONG ulErr = SUCCESS_SUCCESS; ERR Err = FALSE; LPVB_RECIPIENT lpVBR; LPMAPI_RECIPIENT lpMapiR; LPVB_MESSAGE lpVBM; LPMAPI_MESSAGE lpMapiM; LPVB_FILE lpVBF; LPMAPI_FILE lpMapiF; LPSAFEARRAY lpsa = NULL; if (lpVBIn == (LPVOID)NULL) { lpMapiIn = NULL; return SUCCESS_SUCCESS; } if (uCount <= 0) { lpMapiIn = NULL; return SUCCESS_SUCCESS; } if ( lpMapiIn == (LPVOID)NULL ) return MAPI_E_FAILURE; switch ( usFlag & ~(USESAFEARRAY) ) { case RECIPIENT: if ( usFlag & USESAFEARRAY ) { lpsa = (LPSAFEARRAY)lpVBIn; hr = SafeArrayAccessData( lpsa, (LPVOID*)&lpVBR ); if (hr) { ulErr = MAPI_E_FAILURE; goto exit; } if (!lpVBR || lpsa->rgsabound[0].cElements < uCount) { (void)SafeArrayUnaccessData( lpsa ); ulErr = MAPI_E_INVALID_RECIPS; goto exit; } } else { lpVBR = (LPVB_RECIPIENT)lpVBIn; } lpMapiR = (LPMAPI_RECIPIENT)lpMapiIn; for ( u = 0L; u < uCount; u++, lpMapiR++, lpVBR++ ) { lpMapiR->ulReserved = lpVBR->ulReserved; lpMapiR->ulRecipClass = lpVBR->ulRecipClass; if ( usFlag & USESAFEARRAY ) { lpMapiR->lpszName = LpstrFromBstr( lpVBR->bstrName, NULL ); lpMapiR->lpszAddress = LpstrFromBstr( lpVBR->bstrAddress, NULL ); } else { lpMapiR->lpszName = LpstrFromBstrA( lpVBR->bstrName, NULL ); lpMapiR->lpszAddress = LpstrFromBstrA( lpVBR->bstrAddress, NULL ); } if (lpVBR->ulEIDSize > 0L) { LPSTR lpStrT; // Convert EID string from OLE Bstr... if ( usFlag & USESAFEARRAY ) { if ( IsBadReadPtr( lpVBR->bstrEID, lpVBR->ulEIDSize ) ) { ulErr = MAPI_E_INVALID_RECIPS; goto exit; } lpStrT = LpstrFromBstr( lpVBR->bstrEID, NULL ); } else { // VB 4.0 took care of translating Wide Char to Multibyte. // ulEIDSize is still based on UNICODE byte size. Take // smallest approximation. if ( IsBadReadPtr( lpVBR->bstrEID, lpVBR->ulEIDSize / 2 ) ) { ulErr = MAPI_E_INVALID_RECIPS; goto exit; } lpStrT = LpstrFromBstrA( lpVBR->bstrEID, NULL ); } // and UnHexize. if ( lpStrT ) { Err = ErrSzToBinaryEID( lpStrT, &lpMapiR->ulEIDSize, &lpMapiR->lpEntryID ); SafeMemFree(lpStrT ); if ( Err ) { ulErr = MAPI_E_INVALID_RECIPS; goto exit; } } } else lpMapiR->lpEntryID = (LPVOID) NULL; } if ( usFlag & USESAFEARRAY ) (void)SafeArrayUnaccessData( lpsa ); break; case FILE: lpsa = (LPSAFEARRAY)lpVBIn; hr = SafeArrayAccessData( lpsa, (LPVOID*)&lpVBF ); if ( hr ) { ulErr = MAPI_E_FAILURE; goto exit; } if ( !lpVBF || lpsa->rgsabound[0].cElements < uCount ) { (void)SafeArrayUnaccessData( lpsa ); ulErr = MAPI_E_ATTACHMENT_NOT_FOUND; goto exit; } lpMapiF = (LPMAPI_FILE)lpMapiIn; for (u = 0L; u < uCount; u++, lpMapiF++, lpVBF++) { lpMapiF->ulReserved = lpVBF->ulReserved; lpMapiF->flFlags = lpVBF->flFlags; lpMapiF->nPosition = lpVBF->nPosition; lpMapiF->lpszPathName = LpstrFromBstr( lpVBF->bstrPathName, NULL ); lpMapiF->lpszFileName = LpstrFromBstr( lpVBF->bstrFileName, NULL ); lpMapiF->lpFileType = LpstrFromBstr( lpVBF->bstrFileType, NULL); } (void)SafeArrayUnaccessData( lpsa ); break; case MESSAGE: lpVBM = (LPVB_MESSAGE) lpVBIn; lpMapiM = (LPMAPI_MESSAGE) lpMapiIn; lpMapiM->ulReserved = lpVBM->ulReserved; lpMapiM->flFlags = lpVBM->flFlags; lpMapiM->nRecipCount = lpVBM->nRecipCount; lpMapiM->lpOriginator = NULL; lpMapiM->nFileCount = lpVBM->nFileCount; lpMapiM->lpRecips = NULL; lpMapiM->lpFiles = NULL; // errors are ignored lpMapiM->lpszSubject = LpstrFromBstrA( lpVBM->bstrSubject, NULL ); lpMapiM->lpszNoteText = LpstrFromBstrA( lpVBM->bstrNoteText, NULL ); lpMapiM->lpszConversationID = LpstrFromBstrA( lpVBM->bstrConversationID, NULL ); lpMapiM->lpszDateReceived = LpstrFromBstrA( lpVBM->bstrDate, NULL ); lpMapiM->lpszMessageType = LpstrFromBstrA( lpVBM->bstrMessageType, NULL ); break; default: ulErr = MAPI_E_FAILURE; goto exit; } exit: return ulErr; } //--------------------------------------------------------------------------- // Name: Mapi2VB // // Description: // Converts MAPI RECIPIENT, FILE, or MESSAGE structures to VB // Recipients and Files are handled as OLE SAFEARRAYs. // // Parameters: // Returns: // Simple Mapi error code // // Effects: // Notes: // originally FALSE for failure, TRUE for success. // Revision: //--------------------------------------------------------------------------- ULONG PASCAL Mapi2VB (LPVOID lpMapiIn, LPVOID lpVBIn, ULONG uCount, USHORT usFlag) { HRESULT hr = 0; ERR Err = FALSE; ULONG ulErr = SUCCESS_SUCCESS; ULONG u; LPVB_MESSAGE lpVBM; LPMAPI_MESSAGE lpMapiM; LPVB_RECIPIENT lpVBR; LPMAPI_RECIPIENT lpMapiR; LPVB_FILE lpVBF; LPMAPI_FILE lpMapiF; LPSAFEARRAY lpsa = NULL; // If lpVBIn is NULL, this is a bad thing if (lpVBIn == (LPVOID) NULL) return MAPI_E_FAILURE; // if lpMapiIn is NULL then set // lpVBIn to NULL and return success if (lpMapiIn == NULL) { lpVBIn = NULL; return SUCCESS_SUCCESS; } switch ( usFlag & ~(USESAFEARRAY) ) { case RECIPIENT: if ( usFlag & USESAFEARRAY ) { lpsa = (LPSAFEARRAY)lpVBIn; hr = SafeArrayAccessData( lpsa, (LPVOID*)&lpVBR ); if (hr) { ulErr = MAPI_E_FAILURE; goto exit; } if ( !lpVBR || lpsa->rgsabound[0].cElements < uCount ) { (void)SafeArrayUnaccessData(lpsa); ulErr = MAPI_E_INVALID_RECIPS; goto exit; } } else { lpVBR = (LPVB_RECIPIENT)lpVBIn; } lpMapiR = (LPMAPI_RECIPIENT)lpMapiIn; for (u = 0L; u < uCount; u++, lpMapiR++, lpVBR++) { lpVBR->ulReserved = lpMapiR->ulReserved; lpVBR->ulRecipClass = lpMapiR->ulRecipClass; if (usFlag & USESAFEARRAY) { if ( ErrLpstrToBstr( lpMapiR->lpszName, &lpVBR->bstrName ) ) { ulErr = MAPI_E_INVALID_RECIPS; goto exit; } if (Err = ErrLpstrToBstr( lpMapiR->lpszAddress, &lpVBR->bstrAddress ) ) { ulErr = MAPI_E_INVALID_RECIPS; goto exit; } } else { if ( ErrLpstrToBstrA( lpMapiR->lpszName, &lpVBR->bstrName ) ) { ulErr = MAPI_E_INVALID_RECIPS; goto exit; } if ( ErrLpstrToBstrA( lpMapiR->lpszAddress, &lpVBR->bstrAddress ) ) { ulErr = MAPI_E_INVALID_RECIPS; goto exit; } } if ( lpMapiR->ulEIDSize > 0L) { LPSTR lpStrEID; // Convert Recip EID to a hexized string if ( ErrBinaryToSzEID( lpMapiR->lpEntryID, lpMapiR->ulEIDSize, &lpStrEID ) ) { ulErr = MAPI_E_INVALID_RECIPS; goto exit; } // Convert to a BSTR // and figure out the size if ( usFlag & USESAFEARRAY ) { Err = ErrLpstrToBstr( lpStrEID, &lpVBR->bstrEID ); SafeMemFree( lpStrEID ); if (Err) { ulErr = MAPI_E_INVALID_RECIPS; goto exit; } lpVBR->ulEIDSize = SysStringByteLen( lpVBR->bstrEID ) + sizeof(OLECHAR); } else { // To figure out size first convert to UNICODE if ( ErrLpstrToBstr( lpStrEID, &lpVBR->bstrEID ) ) { SafeMemFree( lpStrEID ); ulErr = MAPI_E_INVALID_RECIPS; goto exit; } lpVBR->ulEIDSize = SysStringByteLen( lpVBR->bstrEID ) + sizeof(OLECHAR); SysFreeString( lpVBR->bstrEID ); Err = ErrLpstrToBstrA( lpStrEID, &lpVBR->bstrEID ); SafeMemFree( lpStrEID ); if ( Err ) { ulErr = MAPI_E_INVALID_RECIPS; goto exit; } } } } if ( usFlag & USESAFEARRAY ) (void)SafeArrayUnaccessData( lpsa ); break; case FILE: lpsa = (LPSAFEARRAY)lpVBIn; hr = SafeArrayAccessData( lpsa, (LPVOID*)&lpVBF ); if ( hr ) { ulErr = MAPI_E_FAILURE; goto exit; } if ( !lpVBF || lpsa->rgsabound[0].cElements < uCount ) { (void)SafeArrayUnaccessData( lpsa ); ulErr = MAPI_E_FAILURE; goto exit; } lpMapiF = (LPMAPI_FILE) lpMapiIn; for (u = 0L; u < uCount; u++, lpMapiF++, lpVBF++) { lpVBF->ulReserved = lpMapiF->ulReserved; lpVBF->flFlags = lpMapiF->flFlags; lpVBF->nPosition = lpMapiF->nPosition; if ( ErrLpstrToBstr( lpMapiF->lpszPathName, &lpVBF->bstrPathName ) ) { ulErr = MAPI_E_ATTACHMENT_NOT_FOUND; goto exit; } if ( ErrLpstrToBstr( lpMapiF->lpszFileName, &lpVBF->bstrFileName ) ) { ulErr = MAPI_E_ATTACHMENT_NOT_FOUND; goto exit; } // this is something to keep VBAPI from faulting if ( ErrLpstrToBstr( (LPSTR) "", &lpVBF->bstrFileType ) ) { ulErr = MAPI_E_ATTACHMENT_NOT_FOUND; goto exit; } } (void)SafeArrayUnaccessData( lpsa ); break; case MESSAGE: lpVBM = (LPVB_MESSAGE)lpVBIn; lpMapiM = (LPMAPI_MESSAGE)lpMapiIn; lpVBM->ulReserved = lpMapiM->ulReserved; lpVBM->flFlags = lpMapiM->flFlags; lpVBM->nRecipCount = lpMapiM->nRecipCount; lpVBM->nFileCount = lpMapiM->nFileCount; if ( ErrLpstrToBstr( lpMapiM->lpszSubject, &lpVBM->bstrSubject ) ) { ulErr = MAPI_E_INVALID_MESSAGE; goto exit; } if ( ErrLpstrToBstr( lpMapiM->lpszNoteText, &lpVBM->bstrNoteText ) ) { ulErr = MAPI_E_INVALID_MESSAGE; goto exit; } if ( ErrLpstrToBstr( lpMapiM->lpszConversationID, &lpVBM->bstrConversationID ) ) { ulErr = MAPI_E_INVALID_MESSAGE; goto exit; } if ( ErrLpstrToBstr( lpMapiM->lpszDateReceived, &lpVBM->bstrDate ) ) { ulErr = MAPI_E_INVALID_MESSAGE; goto exit; } if ( ErrLpstrToBstr( lpMapiM->lpszMessageType, &lpVBM->bstrMessageType ) ) { ulErr = MAPI_E_INVALID_MESSAGE; goto exit; } break; default: ulErr = MAPI_E_FAILURE; goto exit; } exit: return ulErr; } //--------------------------------------------------------------------------- // Name: FBMAPIFreeStruct() // // Description: // DeAllocates MAPI structure created in VB2MAPI // // Parameters: // Returns: // Effects: // Notes: // Revision: //--------------------------------------------------------------------------- int FAR PASCAL FBMAPIFreeStruct (LPVOID lpMapiIn, ULONG uCount, USHORT usFlag) { ULONG u; LPMAPI_RECIPIENT lpMapiR; LPMAPI_FILE lpMapiF; LPMAPI_MESSAGE lpMapiM; if (lpMapiIn == (LPVOID) NULL) return TRUE; switch ( usFlag ) { case RECIPIENT: lpMapiR = (LPMAPI_RECIPIENT)lpMapiIn; for ( u = 0L; u < uCount; u++, lpMapiR++ ) { SafeMemFree(lpMapiR->lpszName); SafeMemFree(lpMapiR->lpszAddress); SafeMemFree(lpMapiR->lpEntryID); } SafeMemFree(lpMapiIn); break; case FILE: lpMapiF = (LPMAPI_FILE) lpMapiIn; for ( u = 0L; u < uCount; u++, lpMapiF++ ) { SafeMemFree(lpMapiF->lpszPathName); SafeMemFree(lpMapiF->lpszFileName); SafeMemFree(lpMapiF->lpFileType); } SafeMemFree(lpMapiIn); break; case MESSAGE: lpMapiM = ( LPMAPI_MESSAGE ) lpMapiIn; if (lpMapiM->lpRecips) FBMAPIFreeStruct((LPVOID)lpMapiM->lpRecips, lpMapiM->nRecipCount, RECIPIENT); if (lpMapiM->lpFiles) FBMAPIFreeStruct((LPVOID) lpMapiM->lpFiles, lpMapiM->nFileCount, FILE); SafeMemFree( lpMapiM->lpszSubject ); SafeMemFree( lpMapiM->lpszNoteText ); SafeMemFree( lpMapiM->lpszMessageType ); SafeMemFree( lpMapiM->lpszDateReceived ); SafeMemFree( lpMapiM->lpszConversationID ); SafeMemFree( lpMapiM ); break; default: return FALSE; } return TRUE; } //--------------------------------------------------------------------------- // Name: LpstrFromBstr() // // Description: // Copies and converts OLE Bstr from UNICODE to an ANSI // C string. // // Parameters: // Returns: // String if successful // NULL if failure // Effects: // Notes: // Note that this function returns NULL for failure as well as // a NULL bstr. This was how the original VB 3.0 implementation // worked. // // Revision: //--------------------------------------------------------------------------- LPSTR FAR PASCAL LpstrFromBstr( BSTR bstrSrc, LPSTR lpstrDest ) { USHORT cbSrc; if ( !bstrSrc ) return NULL; // Copy over the bstr string to a 'C' string cbSrc = (USHORT)SysStringLen((OLECHAR *)bstrSrc); if (cbSrc == 0) return NULL; // make sure we handle truly multi byte character sets when // we convert from UNICODE to MultiByte. cbSrc = (USHORT)((cbSrc + 1) * sizeof(OLECHAR)); // If Destination is NULL then we'll allocate // memory to hold the string. The caller must // deallocate this at some time. if ( lpstrDest == NULL ) { if(!MemAlloc((LPVOID*)&lpstrDest, cbSrc)) return NULL; } if (!WideCharToMultiByte(CP_ACP, 0, bstrSrc, -1, lpstrDest, cbSrc, NULL, NULL)) { SafeMemFree(lpstrDest); lpstrDest = NULL; } return lpstrDest; } //--------------------------------------------------------------------------- // Name: LpstrFromBstrA // // Description: // Copies OLE Bstre ANSI string to C string. Allocates string space // from the global heap and returns a long // pointer to memory. The memory must be freed by the caller // with a call to BMAPIFree. // // Parameters: // Returns: // String if successful // NULL if failure // // Effects: // Notes: // Revision: //--------------------------------------------------------------------------- LPSTR FAR PASCAL LpstrFromBstrA( BSTR bstrSrc, LPSTR lpstrDest ) { USHORT cbSrc; // If Destination is NULL then we'll allocate memory to hold the // string. The caller must deallocate this at some time. cbSrc = (USHORT)SysStringByteLen((OLECHAR *)bstrSrc); // Copy over the hlstr string to a 'C' string if ( cbSrc == 0 ) return NULL; if ( lpstrDest == NULL ) { if (!MemAlloc((LPVOID*)&lpstrDest, cbSrc + 1)) return NULL; } memcpy( lpstrDest, bstrSrc, cbSrc ); lpstrDest[cbSrc] = '\0'; return lpstrDest; } //--------------------------------------------------------------------------- // Name: ErrSzToBinaryEID() // // Description: // Converts a hexized binary string to binary returning // the binary data and the size of the data. // // Parameters: // Returns: // FALSE if success. // TRUE if failure. // Effects: // Notes: // Revision: //--------------------------------------------------------------------------- ERR ErrSzToBinaryEID( LPSTR lpstrEID, ULONG * lpcbEID, LPVOID * lppvEID ) { ERR Err = FALSE; ULONG cbEID; cbEID = CbOfEncoded( lpstrEID ); if (!MemAlloc(lppvEID, cbEID)) { Err = TRUE; goto exit; } if (!FDecodeID( lpstrEID, (LPBYTE)*lppvEID, lpcbEID ) ) { Err = TRUE; SafeMemFree( *lppvEID ); *lppvEID = NULL; goto exit; } exit: return Err; } /* * Given an string that encodes some binary data, returns the * maximal size of the binary data. */ STDAPI_(ULONG) CbOfEncoded(LPTSTR sz) { return (lstrlen(sz) / 4 + 1) * 3; // slightly fat } /* * Given a byte count, returns the number of characters necessary * to encode that many bytes. */ STDAPI_(int) CchEncodedLine(int cb) { Assert(cb <= 45); return (cb / 3) * 4 + rgLeft[cb % 3]; } /* - FDecodeID - * Purpose: * Turns a character string produced by EncodeID back to a * byte string. Some validation of the input string is done. * * Arguments: * sz in The input character string. * pb out The decoded byte string. The output * string is not length-checked. * pcb out The size of the byte string * * Returns: * FALSE => the encoded string was garbled in some way * TRUE => all OK */ STDAPI_(BOOL) FDecodeID(LPTSTR sz, LPBYTE pb, ULONG *pcb) { int cchLine; int ich; CCH cch = (CCH)lstrlen(sz); LPTSTR szT = sz; AssertSz(!IsBadStringPtr(sz, INFINITE), "FDecodeID: sz fails address check"); AssertSz(!IsBadWritePtr(pb, 1), "FDecodeID: pb fails address check"); AssertSz(!IsBadWritePtr(pcb, sizeof(ULONG)), "FDecodeID: pcb fails address check"); *pcb = 0; while (*szT) { // Process line header if (FBadCh(*szT)) return FALSE; ich = DEC(*szT); // Byte count for "line" *pcb += ich; // running total of decoded info cchLine = CchEncodedLine(ich); // Length-check this "line" if (szT + cchLine + 1 > sz + cch) return FALSE; ++szT; // Process line contents for (ich = 0; ich < cchLine; ++ich) { if (FBadCh(*szT)) return FALSE; switch (ich % 4) { case 0: *pb = (BYTE) (DEC(*szT) << 2); break; case 1: *pb |= (DEC(*szT) >> 4) & 0x03; ++pb; *pb = (BYTE) (DEC(*szT) << 4); break; case 2: *pb |= (DEC(*szT) >> 2) & 0x0f; ++pb; *pb = (BYTE) (DEC(*szT) << 6); break; case 3: *pb |= DEC(*szT); ++pb; break; } ++szT; } } return TRUE; } //--------------------------------------------------------------------------- // Name: ErrLpstrToBstrA() // // Description: // Copies C string to OLE BSTR. Note that the bstr // contains an ANSI string. VB 4.0 will automatically // convert this ANSI string to unicode when the string if // this string is a member of a UDT and declared as a UDT. // Arrays of UDTs are handled as SAFEARRAYS. // // // Parameters: // Returns: // FALSE if successful // TRUE if failure // Effects: // Notes: // Revision: //--------------------------------------------------------------------------- ERR FAR PASCAL ErrLpstrToBstrA( LPSTR cstr, BSTR * lpBstr ) { UINT uiLen; if ( *lpBstr ) SysFreeString( *lpBstr ); uiLen = lstrlen( cstr ); *lpBstr = SysAllocStringByteLen( cstr, (uiLen) ? uiLen : 0 ); return (ERR)((*lpBstr) ? FALSE : TRUE); } //--------------------------------------------------------------------------- // Name: ErrBinaryToSzEID() // // Description: // Converts binary data to a hexized string. // // Parameters: // Returns: // FALSE if success. // TRUE if failure. // // Effects: // Notes: // Revision: //--------------------------------------------------------------------------- ERR ErrBinaryToSzEID( LPVOID lpvEID, ULONG cbEID, LPSTR * lppstrEID ) { ERR Err = FALSE; ULONG cbStr; cbStr = CchOfEncoding( cbEID ); if (!MemAlloc((LPVOID*)lppstrEID, cbStr)) { Err = TRUE; goto exit; } EncodeID( (LPBYTE)lpvEID, cbEID, *lppstrEID ); exit: return Err; } /* * Given the size of a binary string, returns the size of its * ASCII encoding. */ STDAPI_(ULONG) CchOfEncoding(ULONG cbBinary) { return (cbBinary / 3) * 4 // 3 bytes -> 4 characters + rgLeft[cbBinary % 3] // Leftover bytes -> N characters + ((cbBinary / 45) + 1) // overhead: 1 byte per line + 1; // null } /* - EncodeID - * Purpose: * Turns a byte string into a character string, using the * uuencode algorithm. * * Three bytes are mapped into 6 bits each of 4 characters, in * the range 0x21 - 0x60. The encoding is broken up into lines * of 60 characters or less. Each line begins with a count * byte (which specifies the number of bytes encoded, not * characters) and ends with a CRLF pair. * * Note that this encoding is sub-optimal for UNICODE: the * characters used still fall into the 7-bit ASCII range. * * Arguments: * pb in the byte string to encode * cb in length of the input string * sz out the encoded character string. No * length checking is performed on the * output. * */ STDAPI_(void) EncodeID(LPBYTE pb, ULONG cb, LPTSTR sz) { int cbLine; int ib; BYTE b; #ifdef DEBUG LPTSTR szBase = sz; ULONG cchTot = CchOfEncoding(cb); #endif AssertSz(!IsBadReadPtr(pb, (UINT) cb), "EncodeID: pb fails address check"); AssertSz(!IsBadWritePtr(sz, (UINT) cchTot), "EncodeID: sz fails address check"); while (cb) { cbLine = min(45, (int)cb); Assert(sz < szBase + cchTot); *sz++ = ENC(cbLine); for (ib = 0; ib < cbLine; ++ib) { Assert(sz < szBase + cchTot); b = 0; switch (ib % 3) { case 0: *sz++ = ENC(*pb >> 2); if (ib+1 < cbLine) b = (BYTE) ((pb[1] >> 4) & 0x0f); *sz++ = ENC((*pb << 4) & 0x30 | b); break; case 1: if (ib+1 < cbLine) b = (BYTE) ((pb[1] >> 6) & 0x03); *sz++ = ENC((*pb << 2) & 0x3c | b); break; case 2: *sz++ = ENC(*pb & 0x3f); break; } pb++; } cb -= cbLine; Assert(cb == 0 || sz + 1 < szBase + cchTot); } Assert(sz + 1 == szBase + cchTot); *sz = 0; } //--------------------------------------------------------------------------- // Name: ErrLpstrToBstr() // // Description: // Copies and converts a C string to an OLE BSTR. This // routine will convert MultiByte to WideChar. // Parameters: // Returns: // FALSE if successful // TRUE if failure // // Effects: // Notes: // SysReallocString returns FALSE if memory failure. // Revision: //--------------------------------------------------------------------------- ERR FAR PASCAL ErrLpstrToBstr( LPSTR cstr, BSTR * lpBstr ) { OLECHAR * lpszWC = NULL; INT cch = 0; ERR Err = FALSE; if ( !cstr ) { *lpBstr = NULL; return FALSE; } cch = lstrlen( cstr ); if (!MemAlloc((LPVOID*)&lpszWC, (cch + 1) * sizeof(OLECHAR))) return TRUE ; // convert ANSI to WideChar if ( !MultiByteToWideChar( GetACP(), 0, cstr, -1, lpszWC, cch + 1 ) ) { Err = TRUE; goto exit; } if ( *lpBstr ) { Err = (ERR)!SysReAllocString( lpBstr, lpszWC ); if ( Err ) goto exit; } else { *lpBstr = SysAllocString( lpszWC ); if ( !*lpBstr ) { Err = TRUE; goto exit; } } exit: SafeMemFree(lpszWC); return Err; }