windows-nt/Source/XPSP1/NT/printscan/fax/print/faxprint/faxui/cwabobj.cpp
2020-09-26 16:20:57 +08:00

1178 lines
24 KiB
C++

/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
cwabobj.cpp
Abstract:
Interface to the windows address book.
Environment:
Fax send wizard
Revision History:
10/23/97 -GeorgeJe-
Created it.
mm/dd/yy -author-
description
--*/
#include <windows.h>
#include <prsht.h>
#include <tchar.h>
#include <wab.h>
#include "faxui.h"
#include "cwabobj.h"
static
LPWSTR
DupUnicodeString(
LPWSTR pStr
);
static
LPWSTR
DupStringAnsiToUnicode(
LPSTR pAnsiStr
);
static
LPSPropValue
FindProp(
LPSPropValue rgprop,
ULONG cprop,
ULONG ulPropTag
);
static
AddRecipient(
PRECIPIENT *ppNewRecip,
LPWSTR DisplayName,
LPWSTR FaxNumber
);
static SizedSPropTagArray(5, sPropTags) =
{
5,
{
PR_DISPLAY_NAME_A,
PR_PRIMARY_FAX_NUMBER_A,
PR_HOME_FAX_NUMBER_A,
PR_BUSINESS_FAX_NUMBER_A,
PR_OBJECT_TYPE
}
};
CWabObj::CWabObj(
HINSTANCE hInstance
)
/*++
Routine Description:
Constructor for CWabObj class
Arguments:
hInstance - Instance handle
Return Value:
NONE
--*/
{
m_Initialized = FALSE;
m_lpAdrList = NULL;
m_hInstance = hInstance;
}
BOOL
CWabObj::Initialize(
VOID
)
/*++
Routine Description:
intialization function for CWabObj class
Arguments:
NONE
Return Value:
TRUE if the object is initialized successfully, else FALSE
--*/
{
TCHAR szDllPath[MAX_PATH];
HKEY hKey = NULL;
LONG rVal;
DWORD dwType;
DWORD cbData = MAX_PATH * sizeof(TCHAR);
HRESULT hr;
PCTSTR szDefaultPath = TEXT("%CommonProgramFiles%\\System\\wab32.dll");
m_Initialized = TRUE;
//
// get the path to wab32.dll
//
rVal = RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
REGVAL_WABPATH,
0,
KEY_READ,
&hKey
);
if (rVal == ERROR_SUCCESS) {
rVal = RegQueryValueEx(
hKey,
TEXT(""),
NULL,
&dwType,
(LPBYTE) szDllPath,
&cbData
);
RegCloseKey( hKey );
}
if (rVal != ERROR_SUCCESS) {
ExpandEnvironmentStrings(szDefaultPath,szDllPath,sizeof(szDllPath)/sizeof(TCHAR));
}
m_hWab = LoadLibrary( szDllPath );
if (m_hWab != NULL) {
m_lpWabOpen = (LPWABOPEN) GetProcAddress( m_hWab , "WABOpen" );
} else {
m_lpWabOpen = (LPWABOPEN) NULL;
}
if (m_lpWabOpen == NULL) {
hr = E_FAIL;
goto exit;
}
//
// open the wab
//
hr = m_lpWabOpen( &m_lpAdrBook, &m_lpWABObject, 0, 0 );
exit:
if (HR_FAILED(hr)) {
m_lpAdrBook = NULL;
m_lpWABObject = NULL;
m_Initialized = FALSE;
if (m_hWab != NULL) {
FreeLibrary( m_hWab );
}
m_hWab = NULL;
}
return(m_Initialized);
}
CWabObj::~CWabObj()
/*++
Routine Description:
Destructor for CWabObj class
Arguments:
NONE
Return Value:
NONE
--*/
{
if (m_lpAdrBook) {
m_lpAdrBook->Release();
}
if (m_lpWABObject) {
m_lpWABObject->Release();
}
if ( m_hWab ) {
FreeLibrary( m_hWab );
}
}
BOOL
CWabObj::Address(
HWND hWnd,
PRECIPIENT pRecipients,
PRECIPIENT * ppNewRecip
)
/*++
Routine Description:
Bring up the address book UI. Prepopulate the to box with the entries in
pRecipient. Return the modified entries in ppNewRecip.
Arguments:
hWnd - window handle to parent window
pRecipients - list of recipients to look up
ppNewRecipients - list of new/modified recipients
Return Value:
TRUE if all recipients had a fax number.
FALSE if one or more of them didn't.
--*/
{
ADRPARM AdrParms = { 0 };
LPADRLIST tmp;
HRESULT hr;
DWORD i;
DWORD nRecips;
PRECIPIENT tmpRecipient;
ULONG DestComps[3] = { MAPI_TO, MAPI_CC, MAPI_BCC };
DWORD cDropped;
nRecips = 0;
tmpRecipient = pRecipients;
m_hWnd = hWnd;
m_PickNumber = 0;
//
// count recipients and set up initial address list
//
while (tmpRecipient) {
nRecips++;
tmpRecipient = (PRECIPIENT) tmpRecipient->pNext;
}
if (nRecips > 0) {
hr = m_lpWABObject->AllocateBuffer( CbNewADRLIST( nRecips ), (LPVOID *) &m_lpAdrList );
m_lpAdrList->cEntries = nRecips;
} else {
m_lpAdrList = NULL;
}
for (i = 0, tmpRecipient = pRecipients; i < nRecips; i++, tmpRecipient = (PRECIPIENT) tmpRecipient->pNext) {
LPADRENTRY lpAdrEntry = &m_lpAdrList->aEntries[i];
lpAdrEntry->cValues = 3;
hr = m_lpWABObject->AllocateBuffer( sizeof( SPropValue ) * 3, (LPVOID *) &lpAdrEntry->rgPropVals );
ZeroMemory( lpAdrEntry->rgPropVals, sizeof( SPropValue ) * 3 );
lpAdrEntry->rgPropVals[0].ulPropTag = PR_DISPLAY_NAME_A;
lpAdrEntry->rgPropVals[0].Value.lpszA = DupStringUnicodeToAnsi( lpAdrEntry->rgPropVals, tmpRecipient->pName );
lpAdrEntry->rgPropVals[1].ulPropTag = PR_RECIPIENT_TYPE;
lpAdrEntry->rgPropVals[1].Value.l = MAPI_TO;
lpAdrEntry->rgPropVals[2].ulPropTag = PR_PRIMARY_FAX_NUMBER_A;
lpAdrEntry->rgPropVals[2].Value.lpszA = DupStringUnicodeToAnsi( lpAdrEntry->rgPropVals, tmpRecipient->pAddress );
}
tmp = m_lpAdrList;
AdrParms.cDestFields = 1;
AdrParms.ulFlags = DIALOG_MODAL;
AdrParms.nDestFieldFocus = 0;
AdrParms.lpulDestComps = DestComps;
AdrParms.lpszCaption = TEXT( "" );
//
// Bring up the address book UI
//
hr = m_lpAdrBook->Address(
(ULONG *) &hWnd,
&AdrParms,
&m_lpAdrList
);
if (FAILED (hr) || !m_lpAdrList || m_lpAdrList->cEntries == 0) {
//
// in this case the user pressed cancel, so we skip resolving any of our addresses that aren't listed in the
// WAB
//
cDropped = 0;
goto skipresolve;
}
//
// Resolve names
//
hr = m_lpAdrBook->ResolveName ((ULONG_PTR)hWnd, 0, NULL, m_lpAdrList);
skipresolve:
tmp = m_lpAdrList;
if (m_lpAdrList) {
for (i = cDropped = 0; i < m_lpAdrList->cEntries; i++) {
LPADRENTRY lpAdrEntry = &m_lpAdrList->aEntries[i];
if (!InterpretAddress( lpAdrEntry->rgPropVals, lpAdrEntry->cValues, ppNewRecip )){
cDropped++;
}
}
//
// Clean up
//
for (ULONG iEntry = 0; iEntry < m_lpAdrList->cEntries; ++iEntry)
{
if(m_lpAdrList->aEntries[iEntry].rgPropVals)
m_lpWABObject->FreeBuffer(m_lpAdrList->aEntries[iEntry].rgPropVals);
}
m_lpWABObject->FreeBuffer(m_lpAdrList);
m_lpAdrList = NULL;
}
m_hWnd = NULL;
return cDropped == 0;
}
BOOL
CWabObj::InterpretAddress(
LPSPropValue SPropVal,
ULONG cValues,
PRECIPIENT *ppNewRecip
)
/*++
Routine Description:
Interpret the address book entry represented by SPropVal.
Arguments:
SPropVal - Property values for address book entry.
cValues - number of property values
ppNewRecip - new recipient list
Return Value:
TRUE if all of the entries have a fax number.
FALSE otherwise.
--*/
{
LPSPropValue lpSPropVal;
LPWSTR FaxNumber, DisplayName;
BOOL rVal = FALSE;
//
// get the object type
//
lpSPropVal = FindProp( SPropVal, cValues, PR_OBJECT_TYPE );
if (lpSPropVal) {
//
// If the object is a mail user, get the fax numbers and add the recipient
// to the list. If the object is a distribtion list, process it.
//
switch (lpSPropVal->Value.l) {
case MAPI_MAILUSER:
if(GetRecipientInfo( SPropVal, cValues, &FaxNumber, &DisplayName )) {
AddRecipient( ppNewRecip, DisplayName, FaxNumber );
rVal = TRUE;
}
break;
case MAPI_DISTLIST:
rVal = InterpretDistList( SPropVal, cValues, ppNewRecip );
}
return rVal;
} else {
//
// If there is no object type then this is valid entry that we queried on that went unresolved.
// We know that there is a fax number so add it.
//
if(GetRecipientInfo( SPropVal, cValues, &FaxNumber, &DisplayName )) {
AddRecipient( ppNewRecip, DisplayName, FaxNumber );
rVal = TRUE;
}
}
return rVal;
}
BOOL
CWabObj::InterpretDistList(
LPSPropValue SPropVal,
ULONG cValues,
PRECIPIENT * ppNewRecip
)
/*++
Routine Description:
Process a distribution list.
Arguments:
SPropVal - Property values for distribution list.
cValues - Number of properties.
ppNewRecip - New recipient list.
Return Value:
TRUE if all of the entries have a fax number.
FALSE otherwise.
--*/
#define EXIT_IF_FAILED(hr) { if (FAILED(hr)) goto ExitDistList; }
{
LPSPropValue lpPropVals;
LPSRowSet pRows = NULL;
LPDISTLIST lpMailDistList = NULL;
LPMAPITABLE pMapiTable = NULL;
ULONG ulObjType, cRows;
HRESULT hr;
BOOL rVal = FALSE;
lpPropVals = FindProp( SPropVal, cValues, PR_ENTRYID );
if (lpPropVals) {
LPENTRYID lpEntryId = (LPENTRYID) lpPropVals->Value.bin.lpb;
DWORD cbEntryId = lpPropVals->Value.bin.cb;
//
// Open the recipient entry
//
hr = m_lpAdrBook->OpenEntry(
cbEntryId,
lpEntryId,
(LPCIID) NULL,
0,
&ulObjType,
(LPUNKNOWN *) &lpMailDistList
);
EXIT_IF_FAILED( hr );
//
// Get the contents table of the address entry
//
hr = lpMailDistList->GetContentsTable(
MAPI_DEFERRED_ERRORS,
&pMapiTable
);
EXIT_IF_FAILED(hr);
//
// Limit the query to only the properties we're interested in
//
hr = pMapiTable->SetColumns((LPSPropTagArray) &sPropTags, 0);
EXIT_IF_FAILED(hr);
//
// Get the total number of rows
//
hr = pMapiTable->GetRowCount(0, &cRows);
EXIT_IF_FAILED(hr);
//
// Get the individual entries of the distribution list
//
hr = pMapiTable->SeekRow(BOOKMARK_BEGINNING, 0, NULL);
EXIT_IF_FAILED(hr);
hr = pMapiTable->QueryRows(cRows, 0, &pRows);
EXIT_IF_FAILED(hr);
hr = S_OK;
if (pRows && pRows->cRows) {
//
// Handle each entry of the distribution list in turn:
// for simple entries, call InterpretAddress
// for embedded distribution list, call this function recursively
//
for (cRows = 0; cRows < pRows->cRows; cRows++) {
LPSPropValue lpProps = pRows->aRow[cRows].lpProps;
ULONG cRowValues = pRows->aRow[cRows].cValues;
lpPropVals = FindProp( lpProps, cRowValues, PR_OBJECT_TYPE );
if (lpPropVals) {
switch (lpPropVals->Value.l) {
case MAPI_MAILUSER:
rVal = InterpretAddress( lpProps, cRowValues, ppNewRecip );
break;
case MAPI_DISTLIST:
rVal = InterpretDistList( lpProps, cRowValues, ppNewRecip );
}
}
}
}
}
ExitDistList:
//
// Perform necessary clean up before returning to caller
//
if (pRows) {
for (cRows = 0; cRows < pRows->cRows; cRows++) {
m_lpWABObject->FreeBuffer(pRows->aRow[cRows].lpProps);
}
m_lpWABObject->FreeBuffer(pRows);
}
if (pMapiTable)
pMapiTable->Release();
if (lpMailDistList)
lpMailDistList->Release();
return rVal;
}
INT_PTR
CALLBACK
ChooseFaxNumberDlgProc(
HWND hDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
/*++
Routine Description:
Dialog proc for choose fax number dialog.
Arguments:
lParam - pointer to PickFax structure.
Return Value:
Control id of selection.
--*/
{
PPICKFAX pPickFax = (PPICKFAX) lParam;
TCHAR buffer[MAX_TITLE_LEN];
switch (uMsg) {
case WM_INITDIALOG:
SetDlgItemText(hDlg, IDC_DISPLAY_NAME, pPickFax->DisplayName);
buffer[0] = 0;
GetDlgItemText(hDlg, IDC_BUSINESS_FAX, buffer, MAX_TITLE_LEN);
_tcscat(buffer, pPickFax->BusinessFax);
SetDlgItemText(hDlg, IDC_BUSINESS_FAX, buffer);
buffer[0] = 0;
GetDlgItemText(hDlg, IDC_HOME_FAX, buffer, MAX_TITLE_LEN);
_tcscat(buffer, pPickFax->HomeFax);
SetDlgItemText(hDlg, IDC_HOME_FAX, buffer);
CheckDlgButton(hDlg, IDC_BUSINESS_FAX, BST_CHECKED);
return TRUE;
case WM_COMMAND:
switch(LOWORD( wParam )){
case IDOK:
if (IsDlgButtonChecked(hDlg, IDC_BUSINESS_FAX) == BST_CHECKED) {
if (IsDlgButtonChecked(hDlg, IDC_ALWAYS_OPTION) == BST_CHECKED) {
EndDialog(hDlg, IDC_ALLBUS);
}
else {
EndDialog(hDlg, IDC_BUSINESS_FAX);
}
}
else if (IsDlgButtonChecked(hDlg, IDC_HOME_FAX) == BST_CHECKED) {
if (IsDlgButtonChecked(hDlg, IDC_ALWAYS_OPTION) == BST_CHECKED) {
EndDialog(hDlg, IDC_ALLHOME);
}
else {
EndDialog(hDlg, IDC_HOME_FAX);
}
}
break;;
}
break;
default:
return FALSE;
}
return FALSE;
}
#define StrPropOk( strprop ) ((strprop) && (strprop)->Value.lpszA && *(strprop)->Value.lpszA)
BOOL
CWabObj::GetRecipientInfo(
LPSPropValue SPropVals,
ULONG cValues,
LPWSTR * FaxNumber,
LPWSTR * DisplayName
)
/*++
Routine Description:
Get the fax number and display name properties.
Arguments:
SPropVal - Property values for distribution list.
cValues - Number of properties.
FaxNumber - pointer to pointer to string to hold the fax number.
DisplayName - pointer to pointer to string to hold the display name.
Return Value:
TRUE if there is a fax number and display name.
FALSE otherwise.
--*/
{
LPSPropValue lpPropVals;
LPSPropValue lpPropArray;
BOOL Result = FALSE;
PICKFAX PickFax = { 0 };
*FaxNumber = *DisplayName = NULL;
//
// Get the entryid and open the entry.
//
lpPropVals = FindProp( SPropVals, cValues, PR_ENTRYID );
if (lpPropVals) {
ULONG lpulObjType;
LPMAILUSER lpMailUser = NULL;
LPENTRYID lpEntryId = (LPENTRYID) lpPropVals->Value.bin.lpb;
DWORD cbEntryId = lpPropVals->Value.bin.cb;
HRESULT hr;
ULONG countValues;
hr = m_lpAdrBook->OpenEntry(
cbEntryId,
lpEntryId,
(LPCIID) NULL,
0,
&lpulObjType,
(LPUNKNOWN *) &lpMailUser
);
if (HR_SUCCEEDED(hr)) {
//
// Get the properties.
//
hr = ((IMailUser *) lpMailUser)->GetProps( (LPSPropTagArray) &sPropTags, 0, &countValues, &lpPropArray );
if (HR_SUCCEEDED(hr)) {
lpPropVals = FindProp( lpPropArray, countValues, PR_BUSINESS_FAX_NUMBER_A );
if (StrPropOk( lpPropVals )) {
PickFax.BusinessFax = DupStringAnsiToUnicode( lpPropVals->Value.lpszA );
}
lpPropVals = FindProp( lpPropArray, countValues, PR_HOME_FAX_NUMBER_A );
if (StrPropOk( lpPropVals )) {
PickFax.HomeFax = DupStringAnsiToUnicode( lpPropVals->Value.lpszA );
}
lpPropVals = FindProp( lpPropArray, countValues, PR_DISPLAY_NAME_A );
if (StrPropOk( lpPropVals )) {
*DisplayName = PickFax.DisplayName = DupStringAnsiToUnicode( lpPropVals->Value.lpszA );
}
//
// If there are two fax numbers, ask the user to pick one.
//
if (PickFax.BusinessFax && PickFax.HomeFax) {
int dlgResult;
if (m_PickNumber != 0) {
dlgResult = m_PickNumber;
} else {
dlgResult = (int)DialogBoxParam(
(HINSTANCE) m_hInstance,
MAKEINTRESOURCE( IDD_CHOOSE_FAXNUMBER ),
m_hWnd,
ChooseFaxNumberDlgProc,
(LPARAM) &PickFax
);
}
switch( dlgResult ) {
case IDC_ALLBUS:
m_PickNumber = IDC_BUSINESS_FAX;
// fall through
case IDC_BUSINESS_FAX:
MemFree( PickFax.HomeFax );
*FaxNumber = PickFax.BusinessFax;
break;
case IDC_ALLHOME:
m_PickNumber = IDC_HOME_FAX;
// fall through
case IDC_HOME_FAX:
MemFree( PickFax.BusinessFax );
*FaxNumber = PickFax.HomeFax;
break;
}
} else if (PickFax.BusinessFax) {
*FaxNumber = PickFax.BusinessFax;
} else if (PickFax.HomeFax) {
*FaxNumber = PickFax.HomeFax;
}
}
m_lpWABObject->FreeBuffer( lpPropArray );
}
if (lpMailUser) {
lpMailUser->Release();
}
} else {
// If there is no entryid, then this is a valid entry that we queried on that went unresolved
// add if anyway. In this case we know that PR_PRIMARY_FAX_NUMBER_A and PR_DISPLAY_NAME_A will be
// present.
lpPropVals = FindProp( SPropVals, cValues, PR_PRIMARY_FAX_NUMBER_A );
if (lpPropVals) {
*FaxNumber = DupStringAnsiToUnicode( lpPropVals->Value.lpszA );
}
lpPropVals = FindProp( SPropVals, cValues, PR_DISPLAY_NAME_A );
if (lpPropVals) {
*DisplayName = DupStringAnsiToUnicode( lpPropVals->Value.lpszA );
}
}
if (FaxNumber && DisplayName) {
return (*FaxNumber != 0 && *DisplayName != 0);
} else {
return FALSE;
}
}
LPSPropValue
FindProp(
LPSPropValue rgprop,
ULONG cprop,
ULONG ulPropTag
)
/*++
Routine Description:
Searches for a given property tag in a propset. If the given
property tag has type PT_UNSPECIFIED, matches only on the
property ID; otherwise, matches on the entire tag.
Arguments:
rgprop - Property values.
cprop - Number of properties.
ulPropTag - Property to search for.
Return Value:
Pointer to property desired property value or NULL.
--*/
{
BOOL f = PROP_TYPE(ulPropTag) == PT_UNSPECIFIED;
LPSPropValue pprop = rgprop;
if (!cprop || !rgprop)
return NULL;
while (cprop--)
{
if (pprop->ulPropTag == ulPropTag ||
(f && PROP_ID(pprop->ulPropTag) == PROP_ID(ulPropTag)))
return pprop;
++pprop;
}
return NULL;
}
LPSTR
CWabObj::DupStringUnicodeToAnsi(
LPVOID lpObject,
LPWSTR pUnicodeStr
)
/*++
Routine Description:
Convert a Unicode string to a multi-byte string
Arguments:
pUnicodeStr - Pointer to the Unicode string to be duplicated
Return Value:
Pointer to the duplicated multi-byte string
NOTE:
This is only need because the WAB is not Unicode enabled on NT.
This uses the WAB memory allocator so it must be freed with FreeBuffer.
--*/
{
INT nChar;
LPSTR pAnsiStr;
//
// Figure out how much memory to allocate for the multi-byte string
//
if (! (nChar = WideCharToMultiByte(CP_ACP, 0, pUnicodeStr, -1, NULL, 0, NULL, NULL)) ||
! HR_SUCCEEDED( m_lpWABObject->AllocateMore( nChar, lpObject, (LPVOID *) &pAnsiStr )))
{
return NULL;
}
//
// Convert Unicode string to multi-byte string
//
WideCharToMultiByte(CP_ACP, 0, pUnicodeStr, -1, pAnsiStr, nChar, NULL, NULL);
return pAnsiStr;
}
LPWSTR
DupStringAnsiToUnicode(
LPSTR pAnsiStr
)
/*++
Routine Description:
Convert a multi-byte string to a Unicode string
Arguments:
pAnsiStr - Pointer to the Ansi string to be duplicated
Return Value:
Pointer to the duplicated Unicode string
NOTE:
This is only need because MAPI is not Unicode enabled on NT.
This routine uses MemAlloc to allocate memory so the caller needs
to use MemFree.
--*/
{
INT nChar;
LPWSTR pUnicodeStr;
//
// Figure out how much memory to allocate for the Unicode string
//
if (! (nChar = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pAnsiStr, -1, NULL, 0)) ||
! ( pUnicodeStr = (LPWSTR) MemAlloc( nChar * sizeof(WCHAR) ) ))
{
return NULL;
}
//
// Convert Unicode string to multi-byte string
//
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pAnsiStr, -1, pUnicodeStr, nChar);
return pUnicodeStr;
}
LPWSTR
DupUnicodeString(
LPWSTR pStr
)
/*++
Routine Description:
Duplicate a Unicode string.
Arguments:
pStr - pointer to string to duplicate.
Return Value:
pointer to duplicated string.
--*/
{
LPWSTR NewStr;
NewStr = (LPWSTR) MemAlloc( (wcslen( pStr ) + 1) * sizeof (WCHAR));
wcscpy( NewStr, pStr );
return NewStr;
}
AddRecipient(
PRECIPIENT *ppNewRecip,
LPWSTR DisplayName,
LPWSTR FaxNumber
)
/*++
Routine Description:
Add a recipient to the recipient list.
Arguments:
ppNewRecip - pointer to pointer to list to add item to.
DisplayName - recipient name.
FaxNumber - recipient fax number.
Return Value:
NA
--*/
{
PRECIPIENT NewRecip;
NewRecip = (PRECIPIENT) MemAllocZ( sizeof( RECIPIENT ) );
if (NewRecip) {
NewRecip->pName = DisplayName;
NewRecip->pAddress = FaxNumber;
NewRecip->pNext = (LPVOID) *ppNewRecip;
*ppNewRecip = NewRecip;
}
return 0;
}
extern "C"
BOOL
CallWabAddress(
HWND hDlg,
PUSERMEM pUserMem,
PRECIPIENT * ppNewRecipient
)
/*++
Routine Description:
C wrapper for CWabObj->Address
Arguments:
hDlg - parent window handle.
pUserMem - pointer to USERMEM structure
ppNewRecipient - list to add new recipients to.
Return Value:
TRUE if all of the entries have a fax number.
FALSE otherwise.
--*/
{
LPWABOBJ lpCWabObj = (LPWABOBJ) pUserMem->lpWabInit;
return lpCWabObj->Address(
hDlg,
pUserMem->pRecipients,
ppNewRecipient
);
}
extern "C"
LPVOID
InitializeWAB(
HINSTANCE hInstance
)
/*++
Routine Description:
Initialize the WAB.
Arguments:
hInstance - instance handle.
Return Value:
NONE
--*/
{
LPWABOBJ lpWabObj = new CWabObj( hInstance );
if (lpWabObj) {
if (!lpWabObj->Initialize()) {
delete (lpWabObj);
lpWabObj = NULL;
}
}
return (LPVOID) lpWabObj;
}
extern "C"
VOID
UnInitializeWAB(
LPVOID lpVoid
)
/*++
Routine Description:
UnInitialize the WAB.
Arguments:
NONE
Return Value:
NONE
--*/
{
LPWABOBJ lpWabObj = (LPWABOBJ) lpVoid;
delete lpWabObj;
}