You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3145 lines
97 KiB
3145 lines
97 KiB
/*
|
|
* wabprint.c
|
|
*
|
|
* Purpose:
|
|
* Print Contacts
|
|
*
|
|
* Owner:
|
|
* vikramm.
|
|
*
|
|
* History:
|
|
*
|
|
* Ported from Athena mailnews\mail\msgprint.cpp 10/30/96
|
|
*
|
|
* Copyright (C) Microsoft Corp. 1993, 1994.
|
|
*/
|
|
|
|
|
|
#include <_apipch.h>
|
|
|
|
// Function prototypes
|
|
extern BOOL PrintDlg(LPPRINTDLG lppd);
|
|
extern HRESULT PrintDlgEx(LPPRINTDLGEX lppdex);
|
|
|
|
INT_PTR CALLBACK fnPrintDialogProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
|
|
HRESULT HrCreatePrintCallbackObject(LPIAB lpIAB, LPWABPRINTDIALOGCALLBACK * lppWABPCO, DWORD dwSelectedStyle);
|
|
void ReleaseWABPrintCallbackObject(LPWABPRINTDIALOGCALLBACK lpWABPCO);
|
|
SCODE ScInitPrintInfo( PRINTINFO * ppi, HWND hwnd, LPTSTR szHeader, RECT * prcBorder, HWND hWndRE);
|
|
int GetNumberFromStringResource(int idNumString);
|
|
BOOL bCheckForPrintExtensions(LPTSTR lpDLLPath, DWORD cchSize);
|
|
HRESULT HrUseWABPrintExtension(HWND hWnd, LPADRBOOK lpAdrBook, HWND hWndLV);
|
|
|
|
|
|
//
|
|
// Some string constants used in text formatting
|
|
//
|
|
const LPTSTR lpszTab = TEXT("\t");
|
|
const LPTSTR lpszFlatLine = TEXT("________________________________________________________________");
|
|
const LPTSTR lpszSpace = TEXT(" ");
|
|
|
|
|
|
//
|
|
// Print options ...
|
|
//
|
|
enum _PrintRange
|
|
{
|
|
rangeAll=0,
|
|
rangeSelected
|
|
};
|
|
|
|
enum _PrintStyles
|
|
{
|
|
styleMemo=0,
|
|
styleBusinessCard,
|
|
stylePhoneList
|
|
};
|
|
|
|
static DWORD rgPrintHelpIDs[] =
|
|
{
|
|
IDC_PRINT_FRAME_STYLE, IDH_WAB_COMM_GROUPBOX,
|
|
IDC_PRINT_RADIO_MEMO, IDH_WAB_PRINT_MEMO,
|
|
IDC_PRINT_RADIO_CARD, IDH_WAB_PRINT_BIZCARD,
|
|
IDC_PRINT_RADIO_PHONELIST, IDH_WAB_PRINT_PHONELIST,
|
|
0,0
|
|
};
|
|
|
|
|
|
//
|
|
// This structure contains information about a specific contact
|
|
//
|
|
enum _MemoStrings
|
|
{
|
|
memoTitleName=0, // the big name that will be displayed based on the current sort settings ..
|
|
memoName,
|
|
memoJobTitle,
|
|
memoDepartment,
|
|
memoOffice,
|
|
memoCompany,
|
|
memoBusinessAddress, // Don't mess with the order of home and business address tags
|
|
memoBusinessAddressStreet,
|
|
memoBusinessAddressCity,
|
|
memoBusinessAddressState,
|
|
memoBusinessAddressZip,
|
|
memoBusinessAddressCountry,
|
|
memoHomeAddress,
|
|
memoHomeAddressStreet,
|
|
memoHomeAddressCity,
|
|
memoHomeAddressState,
|
|
memoHomeAddressZip,
|
|
memoHomeAddressCountry,
|
|
memoBusinessPhone, // Dont mess with the phone numbers - they should all be together in this order
|
|
memoBusinessFax,
|
|
memoBusinessPager,
|
|
memoHomePhone,
|
|
memoHomeFax,
|
|
memoHomeCellular,
|
|
memoEmail,
|
|
memoBusinessWebPage,
|
|
memoHomeWebPage,
|
|
memoNotes,
|
|
memoGroupMembers,
|
|
memoMAX
|
|
};
|
|
|
|
typedef struct _MemoInfo
|
|
{
|
|
LPTSTR lpszLabel[memoMAX];
|
|
LPTSTR lpsz[memoMAX];
|
|
} MEMOINFO, * LPMEMOINFO;
|
|
|
|
|
|
TCHAR szDontDisplayInitials[16];
|
|
|
|
/*
|
|
* c o n s t a n t s
|
|
*/
|
|
#define cTwipsPerInch 1440
|
|
#define cPtsPerInch 72
|
|
#ifndef WIN16
|
|
#define INT_MAX 2147483647
|
|
#endif
|
|
#define cySepFontSize(_ppi) (12 * (_ppi)->sizeInch.cy / cPtsPerInch)
|
|
|
|
#define CCHMAX_STRINGRES MAX_UI_STR
|
|
|
|
|
|
/*
|
|
* m a c r o s
|
|
*/
|
|
#define ScPrintRestOfPage(_ppi,_fAdvance) ScGetNextBand( (_ppi), (_fAdvance))
|
|
|
|
|
|
/*
|
|
* g l o b a l s
|
|
*/
|
|
static TCHAR szDefFont[] = TEXT("Arial");
|
|
static TCHAR szThaiDefFont[] = TEXT("Cordia New");
|
|
static BOOL s_bUse20 = TRUE;
|
|
|
|
// Default margin settings
|
|
static RECT g_rcBorder =
|
|
{
|
|
cTwipsPerInch * 1 / 2, // distance from left
|
|
cTwipsPerInch * 3 / 4, // distance from top
|
|
cTwipsPerInch * 1 / 2, // distance from right
|
|
cTwipsPerInch * 1 / 2 // distance from bottom
|
|
};
|
|
|
|
|
|
/*
|
|
* p r o t o t y p e s
|
|
*/
|
|
SCODE ScGetNextBand( PRINTINFO * ppi, BOOL fAdvance );
|
|
LONG LGetHeaderIndent();
|
|
|
|
|
|
|
|
|
|
//$$/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CleanPrintAddressString
|
|
//
|
|
// The Home and Business addresses are FormatMessaged and may contain redundant
|
|
// spaces and line breaks if input data is incomplete
|
|
// We strip out those spaces etc
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
void CleanPrintAddressString(LPTSTR szAddress)
|
|
{
|
|
LPTSTR lpTemp = szAddress;
|
|
LPTSTR lpTemp2 = NULL;
|
|
|
|
// The original template for styleMemo is
|
|
// TEXT("%1\r\n\t%2 %3 %4\r\n\t%5")
|
|
//
|
|
// Worst case, we will get
|
|
// TEXT("\r\n\t \r\n\t")
|
|
//
|
|
// We want to reduce double spaces to single space
|
|
// We want to strip out empty line breaks
|
|
// We want to strip out redundant tabs
|
|
//
|
|
// For style styleBusinessCard, there are no tabs and we
|
|
// strip out redundancies accordingly
|
|
//
|
|
|
|
TrimSpaces(szAddress);
|
|
|
|
// Squish multiple space blocks to a single space
|
|
while (*lpTemp) {
|
|
if (IsSpace(lpTemp) && IsSpace(CharNext(lpTemp))) {
|
|
DWORD cchSize = lstrlen(lpTemp); // Boy I hate using this kind of logic, but it works here.
|
|
|
|
// There are >= 2 spaces starting at lpTemp
|
|
lpTemp2 = CharNext(lpTemp); // point to 2nd space
|
|
StrCpyN(lpTemp, lpTemp2, cchSize);
|
|
continue; // Cycle again with same lpTemp
|
|
}
|
|
lpTemp = CharNext(lpTemp);
|
|
}
|
|
|
|
TrimSpaces(szAddress);
|
|
|
|
lpTemp = szAddress;
|
|
|
|
// Dont let it start with a line break
|
|
while(*lpTemp == '\r' && *(lpTemp+1) == '\n')
|
|
{
|
|
DWORD cchSize = lstrlen(lpTemp); // Boy I hate using this kind of logic, but it works here.
|
|
|
|
lpTemp2 = lpTemp+2;
|
|
if(*lpTemp2 == '\t')
|
|
lpTemp2 = CharNext(lpTemp2);
|
|
StrCpyN(lpTemp, lpTemp2, cchSize);
|
|
TrimSpaces(lpTemp);
|
|
}
|
|
|
|
// Dont let it end with a line break
|
|
if(lstrlen(szAddress))
|
|
{
|
|
int nLen = lstrlen(szAddress);
|
|
lpTemp = szAddress;
|
|
while( (*(lpTemp + nLen - 3)=='\r' && *(lpTemp + nLen - 2)=='\n') ||
|
|
(*(lpTemp + nLen - 2)=='\r' && *(lpTemp + nLen - 1)=='\n') )
|
|
{
|
|
if(*(lpTemp + nLen -3) == '\r')
|
|
*(lpTemp + nLen - 3)='\0';
|
|
else
|
|
*(lpTemp + nLen - 2)='\0';
|
|
|
|
TrimSpaces(szAddress);
|
|
nLen = lstrlen(szAddress);
|
|
lpTemp = szAddress;
|
|
}
|
|
}
|
|
|
|
TrimSpaces(szAddress);
|
|
|
|
return;
|
|
}
|
|
|
|
//$$////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// AddTabsToLineBreaks - For the memo format, our paragraph format for the
|
|
// data on the right side gives each paragraph a default indentation
|
|
// of 1 tab space after the first line. However if the data contains
|
|
// line breaks, the paragraph format gets messed up. So we take
|
|
// a data string and insert a tab after each line break. There are
|
|
// only a few data values such as Address and Notes that need this
|
|
// multi-line treatment.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
void AddTabsToLineBreaks(LPTSTR * lppsz)
|
|
{
|
|
ULONG nBreaks = 0, nLen = 0;
|
|
LPTSTR lpTemp,lpStart;
|
|
LPTSTR lpsz;
|
|
DWORD cchSize;
|
|
|
|
if(!lppsz || !(*lppsz))
|
|
goto out;
|
|
|
|
lpTemp = *lppsz;
|
|
|
|
// count the number of breaks which are not followed by tabs
|
|
while(*lpTemp)
|
|
{
|
|
if(*lpTemp == '\n' && *(lpTemp+1) != '\t')
|
|
nBreaks++;
|
|
lpTemp = CharNext(lpTemp);
|
|
}
|
|
|
|
if(!nBreaks)
|
|
goto out;
|
|
|
|
// Allocate a new string
|
|
cchSize = (lstrlen(*lppsz)+1+nBreaks);
|
|
lpsz = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cchSize);
|
|
if(!lpsz)
|
|
goto out;
|
|
|
|
lpTemp = *lppsz;
|
|
lpStart = lpTemp;
|
|
|
|
StrCpyN(lpsz, szEmpty, cchSize);
|
|
|
|
// Copy over the old string into the new with appropriate breaks
|
|
while(*lpTemp)
|
|
{
|
|
if((*lpTemp == '\n') && (*(lpTemp+1)!='\t'))
|
|
{
|
|
*lpTemp = '\0';
|
|
StrCatBuff(lpsz, lpStart, cchSize);
|
|
StrCatBuff(lpsz, TEXT("\n"), cchSize);
|
|
StrCatBuff(lpsz, lpszTab, cchSize);
|
|
lpStart = lpTemp+1;
|
|
lpTemp = lpStart;
|
|
}
|
|
else
|
|
lpTemp = CharNext(lpTemp);
|
|
}
|
|
|
|
if(lstrlen(lpStart))
|
|
StrCatBuff(lpsz, lpStart, cchSize);
|
|
|
|
LocalFreeAndNull(lppsz);
|
|
*lppsz = lpsz;
|
|
|
|
out:
|
|
return;
|
|
}
|
|
|
|
//$$////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FreeMemoInfoStruct - Frees the MemoInfo struct allocated strings
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
void FreeMemoInfoStruct(LPMEMOINFO lpMI)
|
|
{
|
|
int i;
|
|
for(i=0;i<memoMAX;i++)
|
|
{
|
|
if(lpMI->lpsz[i] && (lpMI->lpsz[i] != szEmpty))
|
|
#ifdef WIN16
|
|
if(i == memoBusinessAddress || i == memoHomeAddress)
|
|
FormatMessageFreeMem(lpMI->lpsz[i]);
|
|
else
|
|
#endif
|
|
LocalFree(lpMI->lpsz[i]);
|
|
if(lpMI->lpszLabel[i] && (lpMI->lpszLabel[i] != szEmpty))
|
|
LocalFree(lpMI->lpszLabel[i]);
|
|
}
|
|
}
|
|
|
|
|
|
//$$////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// GetMemoInfoStruct - Parses the data in a PropArray and puts it into a Memo_Info struch along with
|
|
// the propert labels, bsaed on the given style
|
|
//
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void GetMemoInfoStruct(LPADRBOOK lpAdrBook,
|
|
ULONG ulcPropCount,
|
|
LPSPropValue lpPropArray,
|
|
DWORD dwStyle,
|
|
LPMEMOINFO lpMI,
|
|
BOOL bCurrentSortIsByLastName)
|
|
{
|
|
ULONG i,j;
|
|
TCHAR szBuf[MAX_UI_STR];
|
|
|
|
LPTSTR lpszFirst = NULL;
|
|
LPTSTR lpszMiddle = NULL;
|
|
LPTSTR lpszLast = NULL;
|
|
LPTSTR lpszDisplayName = NULL;
|
|
LPTSTR lpszCompany = NULL;
|
|
LPTSTR lpszNickName = NULL;
|
|
|
|
BOOL bIsGroup = FALSE;
|
|
int len = 0;
|
|
|
|
if(!lpPropArray || !ulcPropCount)
|
|
goto out;
|
|
|
|
// special case initialization
|
|
for(j=memoHomeAddressStreet;j<=memoHomeAddressCountry;j++)
|
|
{
|
|
lpMI->lpsz[j]=szEmpty;
|
|
}
|
|
|
|
for(j=memoBusinessAddressStreet;j<=memoBusinessAddressCountry;j++)
|
|
{
|
|
lpMI->lpsz[j]=szEmpty;
|
|
}
|
|
|
|
// Find out if this is a mailuser or a group
|
|
for(i=0;i<ulcPropCount;i++)
|
|
{
|
|
if(lpPropArray[i].ulPropTag == PR_OBJECT_TYPE)
|
|
{
|
|
bIsGroup = (lpPropArray[i].Value.l == MAPI_DISTLIST);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
for(i=0;i<ulcPropCount;i++)
|
|
{
|
|
LPTSTR lpszData = NULL;
|
|
int nIndex = -1;
|
|
int nStringID = 0;
|
|
|
|
switch(lpPropArray[i].ulPropTag)
|
|
{
|
|
case PR_DISPLAY_NAME:
|
|
nIndex = memoName;
|
|
if(bIsGroup)
|
|
nStringID = idsPrintGroupName;
|
|
else
|
|
nStringID = idsPrintDisplayName;
|
|
lpszDisplayName = lpPropArray[i].Value.LPSZ;
|
|
break;
|
|
case PR_NICKNAME:
|
|
lpszNickName = lpPropArray[i].Value.LPSZ;
|
|
break;
|
|
case PR_GIVEN_NAME:
|
|
lpszFirst = lpPropArray[i].Value.LPSZ;
|
|
break;
|
|
case PR_SURNAME:
|
|
lpszLast = lpPropArray[i].Value.LPSZ;
|
|
break;
|
|
case PR_MIDDLE_NAME:
|
|
lpszMiddle = lpPropArray[i].Value.LPSZ;
|
|
break;
|
|
case PR_TITLE:
|
|
nIndex = memoJobTitle;
|
|
nStringID = idsPrintTitle;
|
|
break;
|
|
case PR_DEPARTMENT_NAME:
|
|
nIndex = memoDepartment;
|
|
nStringID = idsPrintDepartment;
|
|
break;
|
|
case PR_OFFICE_LOCATION:
|
|
nIndex = memoOffice;
|
|
nStringID = idsPrintOffice;
|
|
break;
|
|
case PR_COMPANY_NAME:
|
|
lpszCompany = lpPropArray[i].Value.LPSZ;
|
|
nIndex = memoCompany;
|
|
nStringID = idsPrintCompany;
|
|
break;
|
|
|
|
case PR_BUSINESS_ADDRESS_STREET:
|
|
nIndex = memoBusinessAddressStreet;
|
|
break;
|
|
case PR_BUSINESS_ADDRESS_CITY:
|
|
nIndex = memoBusinessAddressCity;
|
|
break;
|
|
case PR_BUSINESS_ADDRESS_STATE_OR_PROVINCE:
|
|
nIndex = memoBusinessAddressState;
|
|
break;
|
|
case PR_BUSINESS_ADDRESS_POSTAL_CODE:
|
|
nIndex = memoBusinessAddressZip;
|
|
break;
|
|
case PR_BUSINESS_ADDRESS_COUNTRY:
|
|
nIndex = memoBusinessAddressCountry;
|
|
break;
|
|
|
|
case PR_HOME_ADDRESS_STREET:
|
|
nIndex = memoHomeAddressStreet;
|
|
break;
|
|
case PR_HOME_ADDRESS_CITY:
|
|
nIndex = memoHomeAddressCity;
|
|
break;
|
|
case PR_HOME_ADDRESS_STATE_OR_PROVINCE:
|
|
nIndex = memoHomeAddressState;
|
|
break;
|
|
case PR_HOME_ADDRESS_POSTAL_CODE:
|
|
nIndex = memoHomeAddressZip;
|
|
break;
|
|
case PR_HOME_ADDRESS_COUNTRY:
|
|
nIndex = memoHomeAddressCountry;
|
|
break;
|
|
|
|
case PR_BUSINESS_TELEPHONE_NUMBER:
|
|
nIndex = memoBusinessPhone;
|
|
nStringID = (dwStyle == styleMemo) ? idsPrintBusinessPhone : idsPrintBusCardBusinessPhone;
|
|
break;
|
|
case PR_BUSINESS_FAX_NUMBER:
|
|
nIndex = memoBusinessFax;
|
|
nStringID = (dwStyle == styleMemo) ? idsPrintBusinessFax : idsPrintBusCardBusinessFax;
|
|
break;
|
|
case PR_PAGER_TELEPHONE_NUMBER:
|
|
nIndex = memoBusinessPager;
|
|
nStringID = idsPrintBusinessPager;
|
|
break;
|
|
case PR_HOME_TELEPHONE_NUMBER:
|
|
nIndex = memoHomePhone;
|
|
nStringID = (dwStyle == styleMemo) ? idsPrintHomePhone : idsPrintBusCardHomePhone;
|
|
break;
|
|
case PR_HOME_FAX_NUMBER:
|
|
nIndex = memoHomeFax;
|
|
nStringID = idsPrintHomeFax;
|
|
break;
|
|
case PR_CELLULAR_TELEPHONE_NUMBER:
|
|
nIndex = memoHomeCellular;
|
|
nStringID = idsPrintHomeCellular;
|
|
break;
|
|
case PR_BUSINESS_HOME_PAGE:
|
|
nIndex = memoBusinessWebPage;
|
|
nStringID = idsPrintBusinessWebPage;
|
|
break;
|
|
case PR_PERSONAL_HOME_PAGE:
|
|
nIndex = memoHomeWebPage;
|
|
nStringID = idsPrintHomeWebPage;
|
|
break;
|
|
case PR_COMMENT:
|
|
nIndex = memoNotes;
|
|
nStringID = idsPrintNotes;
|
|
break;
|
|
default:
|
|
continue;
|
|
break;
|
|
}
|
|
|
|
if(nIndex != -1)
|
|
{
|
|
if(nStringID != 0)
|
|
{
|
|
LoadString(hinstMapiX, nStringID, szBuf, ARRAYSIZE(szBuf));
|
|
lpMI->lpszLabel[nIndex] = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*(lstrlen(szBuf)+1));
|
|
if(!lpMI->lpszLabel[nIndex])
|
|
goto out;
|
|
StrCpyN(lpMI->lpszLabel[nIndex], szBuf, lstrlen(szBuf)+1);
|
|
}
|
|
|
|
lpMI->lpsz[nIndex] = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*(lstrlen(lpPropArray[i].Value.LPSZ)+1));
|
|
if(!lpMI->lpsz[nIndex])
|
|
goto out;
|
|
StrCpyN(lpMI->lpsz[nIndex], lpPropArray[i].Value.LPSZ, lstrlen(lpPropArray[i].Value.LPSZ)+1);
|
|
}
|
|
}
|
|
|
|
// Email is a special case since a contact can hace PR_EMAIL_ADDRESS or
|
|
// PR_CONTACT_EMAIL_ADDRESSES or both or neither
|
|
// We first look for PR_CONTACT_EMAIL_ADDRESS .. if not found, then for
|
|
// PR_EMAIL_ADDRESS
|
|
{
|
|
BOOL bMVEmail = FALSE;
|
|
LPTSTR lpszEmails = NULL;
|
|
|
|
for(i=0;i<ulcPropCount;i++)
|
|
{
|
|
if(lpPropArray[i].ulPropTag == PR_CONTACT_EMAIL_ADDRESSES)
|
|
{
|
|
ULONG k,ulBufSize=0;
|
|
for (k=0;k<lpPropArray[i].Value.MVSZ.cValues;k++)
|
|
{
|
|
ulBufSize += sizeof(TCHAR)*(lstrlen(lpPropArray[i].Value.MVSZ.LPPSZ[k])+1);
|
|
ulBufSize += sizeof(TCHAR)*(lstrlen(szCRLF)+1);
|
|
ulBufSize += sizeof(TCHAR)*(lstrlen(lpszTab)+1);
|
|
}
|
|
ulBufSize -= sizeof(TCHAR)*(lstrlen(szCRLF)+1);
|
|
ulBufSize -= sizeof(TCHAR)*(lstrlen(lpszTab)+1);
|
|
|
|
lpszEmails = LocalAlloc(LMEM_ZEROINIT, ulBufSize);
|
|
if(!lpszEmails)
|
|
{
|
|
DebugPrintError(( TEXT("Local Alloc Failed\n")));
|
|
goto out;
|
|
}
|
|
StrCpyN(lpszEmails, szEmpty, ulBufSize/sizeof(TCHAR));
|
|
for (k=0;k<lpPropArray[i].Value.MVSZ.cValues;k++)
|
|
{
|
|
if(k>0)
|
|
{
|
|
StrCatBuff(lpszEmails, szCRLF,ulBufSize/sizeof(TCHAR) );
|
|
StrCatBuff(lpszEmails, lpszTab, ulBufSize/sizeof(TCHAR));
|
|
}
|
|
StrCatBuff(lpszEmails,lpPropArray[i].Value.MVSZ.LPPSZ[k], ulBufSize/sizeof(TCHAR));
|
|
}
|
|
|
|
bMVEmail = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(!bMVEmail)
|
|
{
|
|
// No CONTACT_EMAIL_ADDRESSES
|
|
// Should look for email address
|
|
for(i=0;i<ulcPropCount;i++)
|
|
{
|
|
if(lpPropArray[i].ulPropTag == PR_EMAIL_ADDRESS)
|
|
{
|
|
ULONG cchSize = lstrlen(lpPropArray[i].Value.LPSZ)+1;
|
|
lpszEmails = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cchSize);
|
|
if(!lpszEmails)
|
|
goto out;
|
|
StrCpyN(lpszEmails, lpPropArray[i].Value.LPSZ, cchSize);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(lpszEmails)
|
|
{
|
|
ULONG cchSize = lstrlen(szBuf)+1;
|
|
|
|
lpMI->lpsz[memoEmail] = lpszEmails;
|
|
|
|
LoadString(hinstMapiX, idsPrintEmail, szBuf, ARRAYSIZE(szBuf));
|
|
|
|
lpMI->lpszLabel[memoEmail] = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cchSize);
|
|
if(!lpMI->lpszLabel[memoEmail])
|
|
goto out;
|
|
StrCpyN(lpMI->lpszLabel[memoEmail], szBuf, cchSize);
|
|
}
|
|
}
|
|
|
|
//Now we have to format the Home and Business Addresses
|
|
//
|
|
|
|
{
|
|
LPTSTR lpszData[5];
|
|
|
|
for(i=memoHomeAddressStreet;i<=memoHomeAddressCountry;i++)
|
|
{
|
|
// Win9x bug FormatMessage cannot have more than 1023 chars
|
|
len += lstrlen(lpMI->lpsz[i]);
|
|
if(len < 1023)
|
|
lpszData[i-memoHomeAddressStreet] = lpMI->lpsz[i];
|
|
else
|
|
lpszData[i-memoHomeAddressStreet] = NULL;
|
|
}
|
|
for(i=memoHomeAddressStreet;i<=memoHomeAddressCountry;i++)
|
|
{
|
|
if(lpMI->lpsz[i] && lpMI->lpsz[i] != szEmpty)
|
|
{
|
|
LPTSTR lpszHomeAddress = NULL;
|
|
TCHAR szBuf[MAX_UI_STR];
|
|
|
|
int nStringID = (dwStyle == styleMemo) ? idsPrintAddressTemplate : idsPrintBusCardAddressTemplate ;
|
|
|
|
LoadString(hinstMapiX, nStringID, szBuf, CharSizeOf(szBuf));
|
|
|
|
if (FormatMessage(FORMAT_MESSAGE_FROM_STRING |
|
|
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
|
FORMAT_MESSAGE_ARGUMENT_ARRAY,
|
|
szBuf,
|
|
0, // stringid
|
|
0, // dwLanguageId
|
|
(LPTSTR)&lpszHomeAddress, // output buffer
|
|
0, //MAX_UI_STR
|
|
(va_list *)&lpszData[0]))
|
|
{
|
|
CleanPrintAddressString(lpszHomeAddress);
|
|
lpMI->lpsz[memoHomeAddress] = lpszHomeAddress;
|
|
szBuf[0]='\0';
|
|
LoadString(hinstMapiX, idsPrintHomeAddress, szBuf, CharSizeOf(szBuf));
|
|
lpMI->lpszLabel[memoHomeAddress] = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*(lstrlen(szBuf)+1));
|
|
if(!lpMI->lpszLabel[memoHomeAddress])
|
|
goto out;
|
|
StrCpyN(lpMI->lpszLabel[memoHomeAddress], szBuf, lstrlen(szBuf)+1 );
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
len = 0;
|
|
for(i=memoBusinessAddressStreet;i<=memoBusinessAddressCountry;i++)
|
|
{
|
|
// Win9x bug FormatMessage cannot have more than 1023 chars
|
|
len += lstrlen(lpMI->lpsz[i]);
|
|
if(len < 1023)
|
|
lpszData[i-memoBusinessAddressStreet] = lpMI->lpsz[i];
|
|
else
|
|
lpszData[i-memoBusinessAddressStreet] = NULL;
|
|
}
|
|
for(i=memoBusinessAddressStreet;i<=memoBusinessAddressCountry;i++)
|
|
{
|
|
if(lpMI->lpsz[i] && lpMI->lpsz[i] != szEmpty)
|
|
{
|
|
LPTSTR lpszBusinessAddress = NULL;
|
|
TCHAR szBuf[MAX_UI_STR];
|
|
int nStringID = (dwStyle == styleMemo) ? idsPrintAddressTemplate : idsPrintBusCardAddressTemplate ;
|
|
TCHAR szTmp[MAX_PATH], *lpszTmp;
|
|
|
|
LoadString(hinstMapiX, nStringID, szBuf, CharSizeOf(szBuf));
|
|
|
|
if (FormatMessage(FORMAT_MESSAGE_FROM_STRING |
|
|
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
|
FORMAT_MESSAGE_ARGUMENT_ARRAY,
|
|
szBuf,
|
|
0, // stringid
|
|
0, // dwLanguageId
|
|
(LPTSTR)&lpszBusinessAddress, // output buffer
|
|
0, //MAX_UI_STR
|
|
(va_list *)&lpszData[0]))
|
|
{
|
|
CleanPrintAddressString(lpszBusinessAddress);
|
|
lpMI->lpsz[memoBusinessAddress] = lpszBusinessAddress;
|
|
szBuf[0]='\0';
|
|
LoadString(hinstMapiX, idsPrintBusinessAddress, szBuf, CharSizeOf(szBuf));
|
|
lpMI->lpszLabel[memoBusinessAddress] = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*(lstrlen(szBuf)+1));
|
|
if(!lpMI->lpszLabel[memoBusinessAddress])
|
|
goto out;
|
|
StrCpyN(lpMI->lpszLabel[memoBusinessAddress], szBuf, lstrlen(szBuf)+1);
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
// Set the name that will be printed out for each entry
|
|
// This is dependent on the current view and on the local language setting
|
|
{
|
|
LPTSTR lpszTmp = NULL;
|
|
|
|
if( bCurrentSortIsByLastName != bDNisByLN)
|
|
{
|
|
// for auto add to WABs we dont have all this info .. so
|
|
// if we just have a displayname we use it as it is
|
|
if(lpszFirst || lpszMiddle || lpszLast || lpszNickName || (lpszCompany && !lpszDisplayName))
|
|
{
|
|
if(SetLocalizedDisplayName(lpszFirst,
|
|
lpszMiddle,
|
|
lpszLast,
|
|
lpszCompany,
|
|
lpszNickName,
|
|
NULL, //&szBuf,
|
|
0,
|
|
bCurrentSortIsByLastName,
|
|
NULL,
|
|
&lpszTmp))
|
|
{
|
|
lpMI->lpsz[memoTitleName]=lpszTmp;
|
|
}
|
|
}
|
|
}
|
|
if(!lpMI->lpsz[memoTitleName])
|
|
{
|
|
// use whatever DisplayName we have
|
|
lpMI->lpsz[memoTitleName] = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*(lstrlen(lpszDisplayName)+1));
|
|
if(!lpMI->lpsz[memoTitleName])
|
|
goto out;
|
|
StrCpyN(lpMI->lpsz[memoTitleName],lpszDisplayName, lstrlen(lpszDisplayName)+1);
|
|
}
|
|
}
|
|
|
|
if(bIsGroup)
|
|
{
|
|
LPTSTR lpszMembers = NULL;
|
|
ULONG nLen = 0;
|
|
|
|
// Get the group members
|
|
for(i=0;i<ulcPropCount;i++)
|
|
{
|
|
if(lpPropArray[i].ulPropTag == PR_WAB_DL_ENTRIES || lpPropArray[i].ulPropTag == PR_WAB_DL_ONEOFFS )
|
|
{
|
|
// Look at each entry in the PR_WAB_DL_ENTRIES.
|
|
for (j = 0; j < lpPropArray[i].Value.MVbin.cValues; j++)
|
|
{
|
|
ULONG cbEID = lpPropArray[i].Value.MVbin.lpbin[j].cb;
|
|
LPENTRYID lpEID = (LPENTRYID)lpPropArray[i].Value.MVbin.lpbin[j].lpb;
|
|
ULONG ulcProps=0;
|
|
LPSPropValue lpProps=NULL;
|
|
LPTSTR lpszName = NULL;
|
|
ULONG k;
|
|
|
|
if (HR_FAILED( HrGetPropArray( lpAdrBook,NULL,cbEID,lpEID,MAPI_UNICODE,&ulcProps,&lpProps)))
|
|
{
|
|
DebugPrintError(( TEXT("HrGetPropArray failed\n")));
|
|
continue;
|
|
}
|
|
|
|
for(k=0;k<ulcProps;k++)
|
|
{
|
|
if(lpProps[k].ulPropTag == PR_DISPLAY_NAME)
|
|
{
|
|
lpszName = lpProps[k].Value.LPSZ;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(lpszName)
|
|
{
|
|
LPTSTR lpsz;
|
|
if(!lpszMembers)
|
|
nLen = 0;
|
|
else
|
|
{
|
|
nLen = lstrlen(lpszMembers)+1;
|
|
nLen += lstrlen(lpszTab) + lstrlen(szCRLF) + 1;
|
|
}
|
|
|
|
nLen += lstrlen(lpszName)+1;
|
|
|
|
lpsz = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*nLen);
|
|
if(!lpsz)
|
|
{
|
|
if(lpProps)
|
|
MAPIFreeBuffer(lpProps);
|
|
goto out;
|
|
}
|
|
|
|
*lpsz='\0';
|
|
if(lpszMembers)
|
|
{
|
|
StrCpyN(lpsz,lpszMembers, nLen);
|
|
StrCatBuff(lpsz,szCRLF, nLen);
|
|
StrCatBuff(lpsz,lpszTab, nLen);
|
|
}
|
|
StrCatBuff(lpsz,lpszName, nLen);
|
|
LocalFreeAndNull(&lpszMembers);
|
|
lpszMembers = lpsz;
|
|
}
|
|
|
|
if(lpProps)
|
|
MAPIFreeBuffer(lpProps);
|
|
} // for(j...
|
|
}
|
|
} // for(i...
|
|
|
|
if(lpszMembers)
|
|
{
|
|
ULONG cchSize = lstrlen(szBuf)+1;
|
|
szBuf[0]='\0';
|
|
LoadString(hinstMapiX, idsPrintGroupMembers, szBuf, ARRAYSIZE(szBuf));
|
|
lpMI->lpszLabel[memoGroupMembers] = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cchSize);
|
|
if(!lpMI->lpszLabel[memoGroupMembers])
|
|
goto out;
|
|
StrCpyN(lpMI->lpszLabel[memoGroupMembers], szBuf, cchSize);
|
|
lpMI->lpsz[memoGroupMembers]=lpszMembers;
|
|
}
|
|
}
|
|
|
|
//Speacial case formatting of multiline data
|
|
if(dwStyle == styleMemo)
|
|
{
|
|
AddTabsToLineBreaks(&(lpMI->lpsz[memoNotes]));
|
|
AddTabsToLineBreaks(&(lpMI->lpsz[memoHomeAddress]));
|
|
AddTabsToLineBreaks(&(lpMI->lpsz[memoBusinessAddress]));
|
|
}
|
|
|
|
out:
|
|
// special case uninitialization
|
|
for(j=memoHomeAddressStreet;j<=memoHomeAddressCountry;j++)
|
|
{
|
|
if(lpMI->lpsz[j] && (lpMI->lpsz[j] != szEmpty))
|
|
LocalFreeAndNull(&(lpMI->lpsz[j]));
|
|
}
|
|
|
|
for(j=memoBusinessAddressStreet;j<=memoBusinessAddressCountry;j++)
|
|
{
|
|
if(lpMI->lpsz[j] && (lpMI->lpsz[j] != szEmpty))
|
|
LocalFreeAndNull(&(lpMI->lpsz[j]));
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* NTwipsToPixels
|
|
*
|
|
* Purpose:
|
|
* Converts a measurement in twips into pixels
|
|
*
|
|
* Arguments:
|
|
* nTwips the value to be converted
|
|
* cPixels number of pixels per inch
|
|
*
|
|
* Returns:
|
|
* Returns a int representing the number of pixels in nTwips
|
|
*/
|
|
int NTwipsToPixels(int nTwips, int cPixelsPerInch)
|
|
{
|
|
LONG lT = (LONG) nTwips * (LONG) cPixelsPerInch / (LONG) cTwipsPerInch;
|
|
|
|
return (int) lT;
|
|
}
|
|
|
|
/*
|
|
* LPixelsToTwips
|
|
*
|
|
* Purpose:
|
|
* Converts a measurement in pixles into twips
|
|
*
|
|
* Arguments:
|
|
* nPixels the value to be converted
|
|
* cPixels number of pixels per inch
|
|
*
|
|
* Returns:
|
|
* Returns a int representing the number of pixels in nTwips
|
|
*/
|
|
LONG LPixelsToTwips(int nPixels, int cPixelsPerInch)
|
|
{
|
|
|
|
LONG lT = (LONG) nPixels * (LONG) cTwipsPerInch / (LONG) cPixelsPerInch;
|
|
|
|
return lT;
|
|
}
|
|
|
|
|
|
/*
|
|
* PrintPageNumber
|
|
*
|
|
* Purpose:
|
|
* To print the page number for each page
|
|
*
|
|
* Arguments:
|
|
* ppi Pointer to the PRINTINFO structure
|
|
*
|
|
* Returns:
|
|
* SCODE indicating success or failure.
|
|
* Currently always return S_OK
|
|
*/
|
|
void PrintPageNumber(PRINTINFO * ppi)
|
|
{
|
|
RECT rcExt;
|
|
HFONT hfontOld;
|
|
TCHAR szT[20];
|
|
|
|
DebugPrintTrace(( TEXT("PrintPageNumber\n")));
|
|
|
|
// Find out how much space our text take will take
|
|
rcExt = ppi->rcBand;
|
|
rcExt.top = ppi->yFooter;
|
|
hfontOld = (HFONT)SelectObject(ppi->hdcPrn, ppi->hfontPlain);
|
|
DrawText(ppi->hdcPrn, szT, wnsprintf(szT, ARRAYSIZE(szT), ppi->szPageNumber,
|
|
ppi->lPageNumber), &rcExt, DT_CENTER);
|
|
SelectObject(ppi->hdcPrn, hfontOld);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* ScGetNextBand
|
|
*
|
|
* Purpose:
|
|
* Retrieves the next band to print on. Adjusts the band to conform
|
|
* to the margins established in the PRINTINFO structure. Bumps up
|
|
* the page number as appropriate.
|
|
*
|
|
* Arguments:
|
|
* ppi print information
|
|
* fAdvance flag whether to move to the next page
|
|
*
|
|
* Returns:
|
|
* SCODE indicating the success or failure
|
|
*/
|
|
SCODE ScGetNextBand(PRINTINFO * ppi, BOOL fAdvance)
|
|
{
|
|
SCODE sc = S_OK;
|
|
int nCode;
|
|
|
|
DebugPrintTrace(( TEXT("ScGetNextBand\n")));
|
|
|
|
// Call the abort proc to see if the user wishes to stop
|
|
|
|
if (!ppi->pfnAbortProc(ppi->hdcPrn, 0))
|
|
{
|
|
sc=E_FAIL;
|
|
nCode = AbortDoc(ppi->hdcPrn);
|
|
if(nCode < 0)
|
|
{
|
|
DebugPrintTrace(( TEXT("Abort Doc error: %d\n"),GetLastError()));
|
|
ShowMessageBox(ppi->hwndDlg, idsPrintJobCannotStop, MB_OK | MB_ICONEXCLAMATION);
|
|
}
|
|
goto CleanUp;
|
|
}
|
|
|
|
// brettm:
|
|
// USE_BANDING stuff removed, as we're always on Win32
|
|
|
|
// End the previous page
|
|
if (ppi->lPageNumber)
|
|
{
|
|
nCode = EndPage(ppi->hdcPrn);
|
|
DebugPrintTrace(( TEXT("+++++++++EndPage\n")));
|
|
if (nCode <= 0)
|
|
{
|
|
sc=E_FAIL;
|
|
goto CleanUp;
|
|
}
|
|
}
|
|
|
|
if (fAdvance)
|
|
{
|
|
nCode = StartPage(ppi->hdcPrn);
|
|
DebugPrintTrace(( TEXT("+++++++++StartPage\n")));
|
|
// Start a new page
|
|
if (nCode <= 0)
|
|
{
|
|
sc=E_FAIL;
|
|
goto CleanUp;
|
|
}
|
|
// Let the entire page be the band
|
|
ppi->rcBand = ppi->rcMargin;
|
|
ppi->fEndOfPage = TRUE; // end of page!
|
|
|
|
// Bump up the page number and print
|
|
ppi->lPrevPage = ppi->lPageNumber++;
|
|
PrintPageNumber(ppi);
|
|
{
|
|
TCHAR szBuf[MAX_UI_STR];
|
|
TCHAR szString[MAX_UI_STR];
|
|
LoadString(hinstMapiX, idsPrintingPageNumber, szString, ARRAYSIZE(szString));
|
|
wnsprintf(szBuf, ARRAYSIZE(szBuf), szString, ppi->lPageNumber);
|
|
SetPrintDialogMsg(0, 0, szBuf);
|
|
}
|
|
}
|
|
|
|
CleanUp:
|
|
return sc;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
* LGetHeaderIndent
|
|
*
|
|
* Purpose:
|
|
* Retrieves from the resource file the suggested indent overhang for
|
|
* headers.
|
|
*
|
|
* Arguments:
|
|
* none.
|
|
*
|
|
* Returns:
|
|
* LONG The suggested indent overhang in twips
|
|
*/
|
|
LONG LGetHeaderIndent()
|
|
{
|
|
LONG lOver = 1440; // default
|
|
//TCHAR szT[10];
|
|
|
|
//if (LoadString(hinstMapiX, idsHeaderIndent, szT, CharSizeOf(szT)))
|
|
// lOver = atoi(szT);
|
|
return lOver;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//$$////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// AppendText - Simple routine that appends a given string to the End of the text
|
|
// in the given richedit control
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
void AppendText(HWND hWndRE, LPTSTR lpsz)
|
|
{
|
|
// Set the insertion point to the end of the current text
|
|
int nLastChar = (int) SendMessage(hWndRE, WM_GETTEXTLENGTH, 0, 0);
|
|
CHARRANGE charRange = {0};
|
|
|
|
charRange.cpMin = charRange.cpMax = nLastChar + 1;
|
|
SendMessage(hWndRE, EM_EXSETSEL, 0, (LPARAM) &charRange);
|
|
|
|
// Insert the text
|
|
// [PaulHi] 7/7/99 Raid 82350 RichEdit 1.0 can't handle Unicode
|
|
// strings even though the window is created Unicode.
|
|
if (s_bUse20)
|
|
{
|
|
// RichEdit 2.0
|
|
SendMessage(hWndRE, EM_REPLACESEL, (WPARAM) FALSE, (LPARAM) lpsz);
|
|
}
|
|
else
|
|
{
|
|
// RichEdit 1.0
|
|
LPSTR lpszTemp = ConvertWtoA(lpsz);
|
|
|
|
Assert(lpszTemp);
|
|
if (lpszTemp)
|
|
SendMessageA(hWndRE, EM_REPLACESEL, (WPARAM) FALSE, (LPARAM) lpszTemp);
|
|
|
|
LocalFreeAndNull(&lpszTemp);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
//$$////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ParaCmd - Sets/Unsets paragraph formatting in the Rich Edit Control
|
|
//
|
|
// We want all the information on the right side to be indented
|
|
// so we will put an indent on that information and remove it when
|
|
// adding labels
|
|
////////////////////////////////////////////////////////////////////////////
|
|
void ParaCmd(HWND hWndRE, BOOL bIndent)
|
|
{
|
|
// We want no indentation on the first line and we want a
|
|
// 1 tab indentation on the second line onwards
|
|
|
|
PARAFORMAT pf ={0};
|
|
int nTabStop = (int) (1.5 * cTwipsPerInch);
|
|
|
|
pf.cbSize = sizeof(pf);
|
|
pf.dwMask = PFM_OFFSET |
|
|
PFM_TABSTOPS |
|
|
PFM_NUMBERING;
|
|
|
|
SendMessage(hWndRE, EM_GETPARAFORMAT, (WPARAM) TRUE, (LPARAM) &pf);
|
|
|
|
|
|
pf.wNumbering = 0;
|
|
|
|
|
|
if (bIndent)
|
|
{
|
|
//pf.dxStartIndent = nTabStop;
|
|
pf.dxOffset = nTabStop;
|
|
pf.cTabCount = 1;
|
|
pf.rgxTabs[0] = nTabStop;
|
|
}
|
|
else
|
|
{
|
|
//pf.dxStartIndent = 0;
|
|
pf.dxOffset = 0;
|
|
pf.cTabCount = 1;
|
|
pf.rgxTabs[0] = 720; //seems to be the default = 0.5 inches
|
|
}
|
|
|
|
SendMessage(hWndRE, EM_SETPARAFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &pf);
|
|
return;
|
|
}
|
|
|
|
//$$////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// BoldCmd - Sets/Unsets current font to bold in the Rich Edit Control
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
void BoldCmd(HWND hWndRE, BOOL bBold)
|
|
{
|
|
CHARFORMAT cf = {0};
|
|
|
|
cf.cbSize = sizeof(cf);
|
|
cf.dwMask = CFM_BOLD;
|
|
|
|
SendMessage(hWndRE, EM_GETCHARFORMAT, (WPARAM) TRUE, (LPARAM) &cf);
|
|
|
|
if (bBold)
|
|
cf.dwEffects = cf.dwEffects | CFE_BOLD;
|
|
else
|
|
cf.dwEffects = cf.dwEffects & ~CFE_BOLD;
|
|
|
|
SendMessage(hWndRE, EM_SETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf);
|
|
|
|
return;
|
|
}
|
|
|
|
//$$////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// TitleCmd - Sets/Unsets title text (BOLD, Bigger) in the Rich Edit Control
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
void TitleCmd(HWND hWndRE, BOOL bBold)
|
|
{
|
|
CHARFORMAT cf = {0};
|
|
PARAFORMAT pf = {0};
|
|
|
|
cf.cbSize = sizeof(cf);
|
|
cf.dwMask = CFM_BOLD /*| CFM_ITALIC*/ | CFM_SIZE;
|
|
|
|
pf.cbSize = sizeof(pf);
|
|
pf.dwMask = PFM_NUMBERING;
|
|
|
|
SendMessage(hWndRE, EM_GETPARAFORMAT, (WPARAM) TRUE, (LPARAM) &pf);
|
|
SendMessage(hWndRE, EM_GETCHARFORMAT, (WPARAM) TRUE, (LPARAM) &cf);
|
|
|
|
if (bBold)
|
|
{
|
|
cf.dwEffects = cf.dwEffects | CFE_BOLD; // | CFE_ITALIC;
|
|
cf.yHeight += 50;
|
|
pf.wNumbering = PFN_BULLET;
|
|
}
|
|
else
|
|
{
|
|
cf.dwEffects = cf.dwEffects & ~CFE_BOLD;
|
|
// cf.dwEffects = cf.dwEffects & ~CFE_ITALIC;
|
|
cf.yHeight -= 50;
|
|
pf.wNumbering = 0;
|
|
}
|
|
|
|
SendMessage(hWndRE, EM_SETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf);
|
|
SendMessage(hWndRE, EM_SETPARAFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &pf);
|
|
|
|
return;
|
|
}
|
|
|
|
//$$////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ReduceFontCmd - Reduces the displayed font in the Rich Edit Control
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
void ReduceFontCmd(HWND hWndRE, BOOL bReduce, int nReduceBy, BOOL bSelectionOnly)
|
|
{
|
|
CHARFORMAT cf = {0};
|
|
|
|
cf.cbSize = sizeof(cf);
|
|
cf.dwMask = CFM_SIZE;
|
|
|
|
SendMessage(hWndRE, EM_GETCHARFORMAT, (WPARAM) bSelectionOnly, (LPARAM) &cf);
|
|
|
|
if (bReduce)
|
|
cf.yHeight -= nReduceBy; //40;
|
|
else
|
|
cf.yHeight += nReduceBy; //40;
|
|
|
|
SendMessage(hWndRE, EM_SETCHARFORMAT, (WPARAM) bSelectionOnly ? SCF_SELECTION : SCF_DEFAULT, (LPARAM) &cf);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//$$////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// SetTabsCmd - Sets and Unsets the Tabs in the RichEdit Control
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
void SetTabsCmd(HWND hWndRE, BOOL bSet)
|
|
{
|
|
PARAFORMAT pf ={0};
|
|
int nTabStop = (int) (1.5 * cTwipsPerInch);
|
|
int j;
|
|
|
|
pf.cbSize = sizeof(pf);
|
|
pf.dwMask = PFM_TABSTOPS | PFM_NUMBERING;
|
|
|
|
SendMessage(hWndRE, EM_GETPARAFORMAT, (WPARAM) TRUE, (LPARAM) &pf);
|
|
|
|
pf.wNumbering = 0;
|
|
|
|
if (bSet)
|
|
{
|
|
for(j=0;j<5;j++)
|
|
pf.rgxTabs[j] = nTabStop;
|
|
}
|
|
else
|
|
{
|
|
for(j=0;j<5;j++)
|
|
pf.rgxTabs[j] = 720;
|
|
}
|
|
|
|
SendMessage(hWndRE, EM_SETPARAFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &pf);
|
|
|
|
return;
|
|
}
|
|
|
|
//$$////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// WABStylePhoneList - Fills the Rich edit control with info from MI as per the
|
|
// Phone List style
|
|
//
|
|
// hWndRE - handle to Print Formating Rich Edit Control
|
|
// MI - MEMOINFO strcuture containing the info to print
|
|
// lpszPrevEntry - the first TCHAR of the previous entry - this lets us break the list
|
|
// alphabetically - this points to a preallocated buffer
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void WABStylePhoneList(HWND hWndRE, MEMOINFO MI, LPTSTR lpszPrevEntry, DWORD cchSizePrevEntry)
|
|
{
|
|
// We want an extra gap between certain groups of information
|
|
// we'll track these groups using these BOOLs
|
|
ULONG i,j,k;
|
|
|
|
TCHAR szBufChar1[16];
|
|
TCHAR szBufChar2[16];
|
|
LPTSTR lpTemp = NULL;
|
|
int nReduceFontBy = GetNumberFromStringResource(idsPhoneFontReduceBy);
|
|
|
|
|
|
// First we compare the first character of the current string with the previous
|
|
// string - if it is the same, then we do nothing - if it different, we ouput
|
|
// the lower case TCHAR as a heading for the phone directory
|
|
//
|
|
// If the character is not alphanumeric, we ignore it as a heading (e.g. ' )
|
|
|
|
// Bug: 25710
|
|
// We ignore these initialls totally if localizers have set idsDontDisplayInitials
|
|
// these initials to anything other than 0 because in some FE languages
|
|
// names have double characters in them and they look strange with a single
|
|
// character up front
|
|
if(szDontDisplayInitials[0] == '0')
|
|
{
|
|
StrCpyN(szBufChar1, lpszPrevEntry, ARRAYSIZE(szBufChar1));
|
|
|
|
if(lstrlen(MI.lpsz[memoTitleName]) > 16)
|
|
{
|
|
ULONG iLen = TruncatePos(MI.lpsz[memoTitleName], 16-1);
|
|
CopyMemory(szBufChar2, MI.lpsz[memoTitleName], sizeof(TCHAR)*iLen);
|
|
szBufChar2[iLen]='\0';
|
|
}
|
|
else
|
|
StrCpyN(szBufChar2, MI.lpsz[memoTitleName], ARRAYSIZE(szBufChar2));
|
|
|
|
/***********
|
|
// Bug 14615 - this alphanumeric filtering doesnt work for DBCS and FE names
|
|
//
|
|
|
|
// Ignore all non-alpha numeric characters
|
|
lpTemp = szBufChar2;
|
|
{
|
|
//Temp Hack
|
|
TCHAR szTemp[16];
|
|
LPTSTR lpTemp2 = NULL;
|
|
StrCpyN(szTemp, lpTemp, ARRAYSIZE(szTemp));
|
|
lpTemp2 = CharNext(szTemp);
|
|
*lpTemp2 = '\0';
|
|
while(lpTemp && lstrlen(lpTemp))
|
|
{
|
|
if(IsCharAlphaNumeric(szTemp[0]))
|
|
break;
|
|
lpTemp = CharNext(lpTemp);
|
|
StrCpyN(szTemp, lpTemp, ARRAYSIZE(szTemp));
|
|
lpTemp2 = CharNext(szTemp);
|
|
*lpTemp2 = '\0';
|
|
}
|
|
}
|
|
if(lpTemp != szBufChar2)
|
|
StrCpyN(szBufChar2, lpTemp, ARRAYSIZE(szBufChar2));
|
|
***************/
|
|
|
|
|
|
// Isolate the first TCHAR of the above strings
|
|
lpTemp = CharNext(szBufChar1);
|
|
*lpTemp = '\0';
|
|
lpTemp = CharNext(szBufChar2);
|
|
*lpTemp = '\0';
|
|
|
|
// Compare these two characters
|
|
CharLower(szBufChar1);
|
|
CharLower(szBufChar2);
|
|
|
|
if(lstrcmp(szBufChar1, szBufChar2))
|
|
{
|
|
// They are different
|
|
|
|
// Add the TCHAR as a title string
|
|
AppendText(hWndRE, szCRLF);
|
|
TitleCmd(hWndRE, TRUE);
|
|
BoldCmd(hWndRE, TRUE);
|
|
AppendText(hWndRE, lpszSpace);
|
|
AppendText(hWndRE, szBufChar2);
|
|
AppendText(hWndRE, szCRLF);
|
|
TitleCmd(hWndRE, FALSE);
|
|
BoldCmd(hWndRE, FALSE);
|
|
ParaCmd(hWndRE, TRUE);
|
|
AppendText(hWndRE, lpszFlatLine);
|
|
AppendText(hWndRE, szCRLF);
|
|
AppendText(hWndRE, szCRLF);
|
|
ParaCmd(hWndRE, FALSE);
|
|
|
|
StrCpyN(lpszPrevEntry, szBufChar2, cchSizePrevEntry);
|
|
}
|
|
} //dontdisplayinitials
|
|
|
|
ReduceFontCmd(hWndRE, TRUE, nReduceFontBy, TRUE);
|
|
SetTabsCmd(hWndRE, TRUE);
|
|
|
|
|
|
// Figure out how much space the name will take up ...
|
|
{
|
|
TCHAR szBuf[MAX_PATH];
|
|
int nMaxTabs = 2;
|
|
int nTabStop = (int)(1.5 * cTwipsPerInch);
|
|
int MaxWidth = nMaxTabs * nTabStop;
|
|
int sizeCxTwips;
|
|
int PixelsPerInch;
|
|
|
|
int nLen = lstrlen(MI.lpsz[memoTitleName]);
|
|
SIZE size = {0};
|
|
HDC hdc = GetDC(hWndRE);
|
|
|
|
{
|
|
HDC hDC = GetDC(NULL);
|
|
PixelsPerInch = GetDeviceCaps(hDC, LOGPIXELSX);
|
|
ReleaseDC(NULL, hDC);
|
|
}
|
|
|
|
|
|
if (nLen >= MAX_PATH)
|
|
{
|
|
ULONG iLen = TruncatePos(MI.lpsz[memoTitleName], MAX_PATH-1);
|
|
CopyMemory(szBuf, MI.lpsz[memoTitleName], sizeof(TCHAR)*iLen);
|
|
szBuf[iLen]='\0';
|
|
}
|
|
else
|
|
StrCpyN(szBuf, MI.lpsz[memoTitleName], ARRAYSIZE(szBuf));
|
|
|
|
nLen = lstrlen(szBuf);
|
|
GetTextExtentPoint32(hdc, szBuf, nLen, &size);
|
|
|
|
sizeCxTwips = (int)((size.cx * cTwipsPerInch)/PixelsPerInch);
|
|
|
|
// We dont want our displayed name to be more than 2 tabstops
|
|
// so we decide where to truncate the name to fit it on screen
|
|
if(sizeCxTwips > MaxWidth)
|
|
{
|
|
while(sizeCxTwips > MaxWidth)
|
|
{
|
|
nLen--;
|
|
nLen = TruncatePos(szBuf, nLen);
|
|
szBuf[nLen]='\0';
|
|
nLen = lstrlen(szBuf);
|
|
GetTextExtentPoint32(hdc, szBuf, nLen, &size);
|
|
sizeCxTwips = (int)((size.cx * cTwipsPerInch)/PixelsPerInch);
|
|
}
|
|
// chop of 3 more characters for good measure
|
|
nLen-=3;
|
|
nLen = TruncatePos(szBuf, nLen);
|
|
szBuf[nLen]='\0';
|
|
nLen = lstrlen(szBuf);
|
|
GetTextExtentPoint32(hdc, szBuf, nLen, &size);
|
|
sizeCxTwips = (int)((size.cx * cTwipsPerInch)/PixelsPerInch);
|
|
}
|
|
|
|
|
|
while ((sizeCxTwips < MaxWidth) && (nLen < ARRAYSIZE(szBuf)-1))
|
|
{
|
|
StrCatBuff(szBuf, TEXT("."), ARRAYSIZE(szBuf));
|
|
nLen = lstrlen(szBuf);
|
|
GetTextExtentPoint32(hdc, szBuf, nLen, &size);
|
|
sizeCxTwips = (int)((size.cx * cTwipsPerInch)/PixelsPerInch);
|
|
}
|
|
|
|
StrCatBuff(szBuf, lpszTab, ARRAYSIZE(szBuf));
|
|
AppendText(hWndRE, szBuf);
|
|
|
|
// Now we are ready to tag on the phone numbers
|
|
{
|
|
int nPhoneCount = 0; //counts how many phones there are
|
|
int nPhoneLabelSpaceTwips = GetNumberFromStringResource(idsPhoneTextSpaceTwips); //1150
|
|
|
|
for(j=memoBusinessPhone;j<=memoHomeCellular;j++)
|
|
{
|
|
if(MI.lpsz[j] && lstrlen(MI.lpsz[j]))
|
|
{
|
|
if(nPhoneCount != 0)
|
|
{
|
|
int k;
|
|
AppendText(hWndRE, szCRLF);
|
|
|
|
// Bug 73266
|
|
if(s_bUse20)
|
|
ReduceFontCmd(hWndRE, TRUE, nReduceFontBy, TRUE);
|
|
|
|
StrCpyN(szBuf, szEmpty, ARRAYSIZE(szBuf));
|
|
nLen = lstrlen(szBuf);
|
|
GetTextExtentPoint32(hdc, szBuf, nLen, &size);
|
|
sizeCxTwips = (int)((size.cx * cTwipsPerInch)/PixelsPerInch);
|
|
while ((sizeCxTwips < MaxWidth) && (nLen < ARRAYSIZE(szBuf)-1))
|
|
{
|
|
StrCatBuff(szBuf, lpszSpace, ARRAYSIZE(szBuf));
|
|
nLen = lstrlen(szBuf);
|
|
GetTextExtentPoint32(hdc, szBuf, nLen, &size);
|
|
sizeCxTwips = (int)((size.cx * cTwipsPerInch)/PixelsPerInch);
|
|
}
|
|
StrCatBuff(szBuf, lpszTab, ARRAYSIZE(szBuf));
|
|
AppendText(hWndRE, szBuf);
|
|
}
|
|
|
|
TrimSpaces(MI.lpszLabel[j]);
|
|
StrCpyN(szBuf, MI.lpszLabel[j], ARRAYSIZE(szBuf));
|
|
|
|
nLen = lstrlen(szBuf);
|
|
GetTextExtentPoint32(hdc, szBuf, nLen, &size);
|
|
sizeCxTwips = (int)((size.cx * cTwipsPerInch)/PixelsPerInch);
|
|
|
|
if(sizeCxTwips < nPhoneLabelSpaceTwips)
|
|
{
|
|
while ((sizeCxTwips < nPhoneLabelSpaceTwips) && (nLen < ARRAYSIZE(szBuf)-1))
|
|
{
|
|
StrCatBuff(szBuf, lpszSpace, ARRAYSIZE(szBuf));
|
|
nLen = lstrlen(szBuf);
|
|
GetTextExtentPoint32(hdc, szBuf, nLen, &size);
|
|
sizeCxTwips = (int)((size.cx * cTwipsPerInch)/PixelsPerInch);
|
|
}
|
|
StrCatBuff(szBuf, lpszTab, ARRAYSIZE(szBuf));
|
|
}
|
|
StrCatBuff(szBuf, MI.lpsz[j], ARRAYSIZE(szBuf));
|
|
AppendText(hWndRE, szBuf);
|
|
nPhoneCount++;
|
|
}
|
|
}
|
|
if(nPhoneCount == 0)
|
|
{
|
|
LoadString(hinstMapiX, idsPrintNoPhone, szBuf, ARRAYSIZE(szBuf));
|
|
AppendText(hWndRE, szBuf);
|
|
}
|
|
}
|
|
|
|
AppendText(hWndRE, szCRLF);
|
|
|
|
ReleaseDC(hWndRE, hdc);
|
|
}
|
|
|
|
SetTabsCmd(hWndRE, FALSE);
|
|
ReduceFontCmd(hWndRE, FALSE, nReduceFontBy, TRUE);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//$$////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// WABStyleBusinessCard - Fills the Rich edit control with info from MI as per the
|
|
// business card style
|
|
//
|
|
// hWndRE - handle to Print Formating Rich Edit Control
|
|
// MI - MEMOINFO strcuture containing the info to print
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void WABStyleBusinessCard(HWND hWndRE, MEMOINFO MI)
|
|
{
|
|
// We want an extra gap between certain groups of information
|
|
// we'll track these groups using these BOOLs
|
|
ULONG i,j,k;
|
|
int nReduceBy = GetNumberFromStringResource(idsBusCardFontReduceBy);
|
|
|
|
// Add the contact name as a heading
|
|
//TitleCmd(hWndRE, TRUE);
|
|
BoldCmd(hWndRE, TRUE);
|
|
//AppendText(hWndRE, lpszSpace);
|
|
AppendText(hWndRE, MI.lpsz[memoTitleName]);
|
|
AppendText(hWndRE, szCRLF);
|
|
//TitleCmd(hWndRE, FALSE);
|
|
BoldCmd(hWndRE, FALSE);
|
|
|
|
ParaCmd(hWndRE, TRUE);
|
|
AppendText(hWndRE, lpszFlatLine);
|
|
AppendText(hWndRE, szCRLF);
|
|
AppendText(hWndRE, szCRLF);
|
|
ParaCmd(hWndRE, FALSE);
|
|
|
|
ReduceFontCmd(hWndRE, TRUE, nReduceBy, TRUE);
|
|
|
|
for(j=memoName;j<memoMAX;j++)
|
|
{
|
|
if(MI.lpsz[j] && lstrlen(MI.lpsz[j]))
|
|
{
|
|
switch(j)
|
|
{
|
|
case memoJobTitle:
|
|
//case memoDepartment:
|
|
//case memoOffice:
|
|
case memoCompany:
|
|
case memoBusinessAddress:
|
|
break;
|
|
case memoEmail:
|
|
// Add the label
|
|
AppendText(hWndRE, MI.lpszLabel[j]);
|
|
AppendText(hWndRE, lpszTab);
|
|
break;
|
|
case memoBusinessWebPage:
|
|
case memoBusinessPhone:
|
|
case memoBusinessFax:
|
|
case memoBusinessPager:
|
|
case memoHomePhone:
|
|
case memoHomeFax:
|
|
case memoHomeCellular:
|
|
// Add the label
|
|
AppendText(hWndRE, MI.lpszLabel[j]);
|
|
AppendText(hWndRE, lpszSpace);
|
|
break;
|
|
default:
|
|
continue;
|
|
}
|
|
|
|
// Add the value
|
|
AppendText(hWndRE, MI.lpsz[j]);
|
|
// line break
|
|
AppendText(hWndRE, szCRLF);
|
|
}
|
|
|
|
} //for j...
|
|
|
|
ReduceFontCmd(hWndRE, FALSE, nReduceBy, TRUE);
|
|
|
|
// Closing line
|
|
ParaCmd(hWndRE, TRUE);
|
|
AppendText(hWndRE, lpszFlatLine);
|
|
ParaCmd(hWndRE, FALSE);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//$$////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// WABStyleMemo - Fills the Rich edit control with info from MI as per the memo style
|
|
//
|
|
// hWndRE - handle to Print Formating Rich Edit Control
|
|
// MI - MEMOINFO strcuture containing the info to print
|
|
//
|
|
//
|
|
// The memo style consists of a dump of all the WAB Contacts properties one by one with
|
|
// labels. Some properties are grouped togethor (eg all the phone properties)
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void WABStyleMemo(HWND hWndRE, MEMOINFO MI)
|
|
{
|
|
BOOL bGapAddress = FALSE; // a gap before the address fields
|
|
BOOL bGapPhone = FALSE; // a gap before the phone fields
|
|
BOOL bGapEmail = FALSE;
|
|
BOOL bGapNotes = FALSE;
|
|
BOOL bGapWeb = FALSE;
|
|
ULONG i,j,k;
|
|
|
|
// Add the heading
|
|
TitleCmd(hWndRE, TRUE);
|
|
AppendText(hWndRE, lpszSpace);
|
|
AppendText(hWndRE, MI.lpsz[memoTitleName]);
|
|
AppendText(hWndRE, szCRLF);
|
|
TitleCmd(hWndRE, FALSE);
|
|
|
|
ParaCmd(hWndRE, TRUE);
|
|
AppendText(hWndRE, lpszFlatLine);
|
|
AppendText(hWndRE, szCRLF);
|
|
AppendText(hWndRE, szCRLF);
|
|
ParaCmd(hWndRE, FALSE);
|
|
|
|
|
|
for(j=memoName;j<memoMAX;j++)
|
|
{
|
|
int nLastChar;
|
|
LPTSTR lpSpace = NULL;
|
|
ULONG nLen = 0;
|
|
|
|
if(MI.lpsz[j] && lstrlen(MI.lpsz[j]))
|
|
{
|
|
// Append an additional space if necessary ..
|
|
switch(j)
|
|
{
|
|
case memoBusinessAddress:
|
|
case memoHomeAddress:
|
|
if(!bGapAddress)
|
|
{
|
|
AppendText(hWndRE, szCRLF);
|
|
bGapAddress = TRUE;
|
|
}
|
|
break;
|
|
case memoBusinessPhone:
|
|
case memoBusinessFax:
|
|
case memoBusinessPager:
|
|
case memoHomePhone:
|
|
case memoHomeFax:
|
|
case memoHomeCellular:
|
|
if(!bGapPhone)
|
|
{
|
|
AppendText(hWndRE, szCRLF);
|
|
bGapPhone = TRUE;
|
|
}
|
|
break;
|
|
case memoEmail:
|
|
if(!bGapEmail)
|
|
{
|
|
AppendText(hWndRE, szCRLF);
|
|
bGapEmail = TRUE;
|
|
}
|
|
break;
|
|
case memoBusinessWebPage:
|
|
case memoHomeWebPage:
|
|
case memoGroupMembers: // stick in group members here to save an extra variable
|
|
if(!bGapWeb)
|
|
{
|
|
AppendText(hWndRE, szCRLF);
|
|
bGapWeb = TRUE;
|
|
}
|
|
break;
|
|
case memoNotes:
|
|
if(!bGapNotes)
|
|
{
|
|
AppendText(hWndRE, szCRLF);
|
|
bGapNotes = TRUE;
|
|
}
|
|
break;
|
|
} // switch
|
|
|
|
// Set the paragraph formating
|
|
ParaCmd(hWndRE, TRUE);
|
|
// Set the current insertion font to bold
|
|
BoldCmd(hWndRE, TRUE);
|
|
// Add the label
|
|
AppendText(hWndRE, MI.lpszLabel[j]);
|
|
BoldCmd(hWndRE, FALSE);
|
|
// Tab
|
|
AppendText(hWndRE, lpszTab);
|
|
// Add the value
|
|
AppendText(hWndRE, MI.lpsz[j]);
|
|
// line break
|
|
AppendText(hWndRE, szCRLF);
|
|
ParaCmd(hWndRE, FALSE);
|
|
}
|
|
|
|
} //for j...
|
|
|
|
// Closing line
|
|
ParaCmd(hWndRE, TRUE);
|
|
AppendText(hWndRE, lpszFlatLine);
|
|
ParaCmd(hWndRE, FALSE);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//$$////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// WABFormatData - takes the given information and formats it into the
|
|
// RichEdit Control for subsequent printing ..
|
|
//
|
|
// lpIAB - LPADRBOOK pointer
|
|
// hWndParent - HWND of Parent
|
|
// hWndRE - HWDN of rich edit control used for formatting
|
|
// hWndLV - List View containing the items which need to be printed
|
|
// dwRange - Range to print (ALL or SELECTION)
|
|
// dwStyle - Style to print (Phone List, Memo, Business Card)
|
|
// ppi - PRINT INFO struct
|
|
// bCurrentSortIsByLastName - Used to determine whether the names are printed
|
|
// by first name or by last name. Current sort option in the list view decides
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
BOOL WABFormatData( LPADRBOOK lpIAB,
|
|
HWND hWndParent,
|
|
HWND hWndRE,
|
|
HWND hWndLV,
|
|
DWORD dwRange,
|
|
DWORD dwStyle,
|
|
PRINTINFO * ppi,
|
|
BOOL bCurrentSortIsByLastName)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
ULONG ulcPropCount = 0;
|
|
LPSPropValue lpPropArray = NULL;
|
|
//LPTSTR lpszPrevEntry = NULL;
|
|
TCHAR szPrevEntry[MAX_DISPLAY_NAME_LENGTH]; //32 chars
|
|
|
|
if (!hWndRE || !hWndLV)
|
|
goto out;
|
|
|
|
if(ListView_GetItemCount(hWndLV) <= 0)
|
|
goto out;
|
|
|
|
if(dwStyle == stylePhoneList)
|
|
{
|
|
LoadString(hinstMapiX, idsDontDisplayInitials, szDontDisplayInitials, CharSizeOf(szDontDisplayInitials));
|
|
}
|
|
|
|
if((dwRange == rangeSelected) && (ListView_GetSelectedCount(hWndLV)<=0))
|
|
{
|
|
ShowMessageBox(hWndParent, IDS_ADDRBK_MESSAGE_NO_ITEM, MB_OK | MB_ICONEXCLAMATION);
|
|
goto out;
|
|
}
|
|
|
|
StrCpyN(szPrevEntry, szEmpty, ARRAYSIZE(szPrevEntry));
|
|
|
|
{
|
|
int iItemIndex = 0, i = 0;
|
|
int iLastItemIndex = -1;
|
|
int nItemCount;
|
|
|
|
if(dwRange == rangeSelected)
|
|
nItemCount = ListView_GetSelectedCount(hWndLV);
|
|
else if(dwRange == rangeAll)
|
|
nItemCount = ListView_GetItemCount(hWndLV);
|
|
|
|
|
|
for(i=0;i<nItemCount;i++)
|
|
{
|
|
int j;
|
|
LPTSTR lpszData = NULL;
|
|
ULONG ulMemSize = 0;
|
|
HRESULT hr;
|
|
MEMOINFO MI = {0};
|
|
LPRECIPIENT_INFO lpItem = NULL;
|
|
|
|
if(dwRange == rangeSelected)
|
|
iItemIndex = ListView_GetNextItem(hWndLV, iLastItemIndex, LVNI_SELECTED);
|
|
else if(dwRange == rangeAll)
|
|
iItemIndex = i;
|
|
|
|
lpItem = GetItemFromLV(hWndLV, iItemIndex);
|
|
|
|
if(lpItem)
|
|
{
|
|
if (HR_FAILED( HrGetPropArray( lpIAB,
|
|
NULL,
|
|
lpItem->cbEntryID,
|
|
lpItem->lpEntryID,
|
|
MAPI_UNICODE,
|
|
&ulcPropCount,
|
|
&lpPropArray) ) )
|
|
{
|
|
DebugPrintError(( TEXT("HrGetPropArray failed\n")));
|
|
goto out;
|
|
}
|
|
|
|
GetMemoInfoStruct(lpIAB, ulcPropCount, lpPropArray, dwStyle, &MI, bCurrentSortIsByLastName);
|
|
|
|
SetPrintDialogMsg(0, idsPrintFormattingName, MI.lpsz[memoTitleName]);
|
|
|
|
// Poll the cancel dialog to see if the user wants to cancel
|
|
if (!ppi->pfnAbortProc(ppi->hdcPrn, 0))
|
|
{
|
|
FreeMemoInfoStruct(&MI);
|
|
DebugPrintError(( TEXT("User canceled printing ...\n")));
|
|
goto out;
|
|
}
|
|
|
|
switch(dwStyle)
|
|
{
|
|
case styleMemo:
|
|
WABStyleMemo(hWndRE, MI);
|
|
break;
|
|
case styleBusinessCard:
|
|
WABStyleBusinessCard(hWndRE, MI);
|
|
break;
|
|
case stylePhoneList:
|
|
WABStylePhoneList(hWndRE, MI, szPrevEntry, ARRAYSIZE(szPrevEntry));
|
|
//if(lpszPrevEntry)
|
|
// LocalFreeAndNull(&lpszPrevEntry);
|
|
//lpszPrevEntry = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*(lstrlen(MI.lpsz[memoTitleName])+1));
|
|
//if(!lpszPrevEntry)
|
|
//goto out;
|
|
//lstrcpy(lpszPrevEntry, MI.lpsz[memoTitleName]);
|
|
break;
|
|
}
|
|
|
|
FreeMemoInfoStruct(&MI);
|
|
}
|
|
|
|
if(lpPropArray)
|
|
MAPIFreeBuffer(lpPropArray);
|
|
|
|
lpPropArray = NULL;
|
|
|
|
// fill in some space between multiple contacts
|
|
{
|
|
int numBreaks = (dwStyle == stylePhoneList) ? 1 : 4;
|
|
for(j=0;j<numBreaks;j++)
|
|
AppendText(hWndRE, szCRLF);
|
|
}
|
|
|
|
if(dwRange == rangeSelected)
|
|
iLastItemIndex = iItemIndex;
|
|
|
|
} // for i ...
|
|
}
|
|
|
|
|
|
bRet = TRUE;
|
|
out:
|
|
|
|
//if(lpszPrevEntry)
|
|
// LocalFreeAndNull(&lpszPrevEntry);
|
|
|
|
if(lpPropArray)
|
|
MAPIFreeBuffer(lpPropArray);
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
* ScPrintBody
|
|
*
|
|
* Purpose:
|
|
* To print the body of each message
|
|
*
|
|
* Arguments:
|
|
* ppi Pointer to the PRINTINFO structure
|
|
* cyGap Gap above message text
|
|
//* pmsg Pointer to message whose body is to be printed
|
|
* hwndRE Pre-rendered body
|
|
* lpszTxt Txt to print
|
|
*
|
|
* Returns:
|
|
* SCODE indicating success or failure
|
|
*
|
|
*/
|
|
SCODE ScPrintBody(PRINTINFO * ppi, int cyGap)
|
|
{
|
|
SCODE sc=S_OK;
|
|
RECT rcSep;
|
|
FORMATRANGE fr;
|
|
HWND hwndRE = ppi->hwndRE;
|
|
|
|
int ifrm;
|
|
LONG lTextLength = 0;
|
|
LONG lTextPrinted = 0;
|
|
|
|
DebugPrintTrace(( TEXT("ScPrintBody\n")));
|
|
|
|
// Put a gap between the fields the message text
|
|
|
|
rcSep = ppi->rcBand;
|
|
if (rcSep.top + cyGap > ppi->yFooter)
|
|
{
|
|
// Adding the gap will go past the page. Just go to the next page
|
|
sc = ScGetNextBand(ppi, TRUE);
|
|
}
|
|
else
|
|
{
|
|
// Keep on getting a band till the bottom of the band passes the gap
|
|
while (rcSep.top + cyGap > ppi->rcBand.bottom)
|
|
if ((sc = ScGetNextBand(ppi, TRUE)) != S_OK)
|
|
goto CleanUp;
|
|
|
|
// Adjust the band so that we don't damage the gap
|
|
ppi->rcBand.top += cyGap + 1;
|
|
}
|
|
|
|
|
|
#ifdef DEBUG_PRINTMSGS
|
|
InvalidateRect(ppi->hwndRE, NULL, TRUE);
|
|
UpdateWindow(ppi->hwndRE);
|
|
#endif
|
|
|
|
// Format the text for printing
|
|
fr.hdc = ppi->hdcPrn;
|
|
fr.hdcTarget = 0;
|
|
fr.rcPage.left = fr.rcPage.top = 0;
|
|
fr.rcPage.right = (int)LPixelsToTwips(ppi->sizePage.cx, ppi->sizeInch.cx);
|
|
fr.rcPage.bottom = (int)LPixelsToTwips(ppi->sizePage.cy, ppi->sizeInch.cy);
|
|
fr.chrg.cpMin = 0;
|
|
fr.chrg.cpMax = -1;
|
|
|
|
lTextLength = (LONG) SendMessage(hwndRE, WM_GETTEXTLENGTH, 0, 0);
|
|
lTextPrinted = 0;
|
|
|
|
// Handle no body case
|
|
if (lTextLength <= 0)
|
|
goto CleanUp;
|
|
|
|
// tell RichEdit not to erase the background before rendering text
|
|
SetBkMode(fr.hdc, TRANSPARENT);
|
|
|
|
do
|
|
{
|
|
fr.chrg.cpMin = lTextPrinted;
|
|
|
|
// Tell format range where to render to
|
|
fr.rc.top = (int) LPixelsToTwips(ppi->rcBand.top, ppi->sizeInch.cy);
|
|
fr.rc.left = (int) LPixelsToTwips(ppi->rcBand.left, ppi->sizeInch.cx);
|
|
fr.rc.right = (int) LPixelsToTwips(ppi->rcBand.right, ppi->sizeInch.cx);
|
|
fr.rc.bottom = (int) LPixelsToTwips(min(ppi->rcBand.bottom, ppi->yFooter), ppi->sizeInch.cy);
|
|
|
|
// Go draw it
|
|
DebugPrintTrace(( TEXT("Rendering\r\n")));
|
|
lTextPrinted = (LONG) SendMessage(hwndRE, EM_FORMATRANGE, TRUE,(LPARAM) &fr);
|
|
//TextOut(ppi->hdcPrn, fr.rc.left, fr.rc.top, lpszTxt, lstrlen(lpszTxt));
|
|
|
|
// weird bug with RichEdit20 .. lTextPrinted is actually reduces in size
|
|
// Another weird bug ... lTextPrinted is never incremented. [PaulHi]
|
|
if(lTextPrinted <= fr.chrg.cpMin)
|
|
break;
|
|
|
|
} while (lTextPrinted > 0 &&
|
|
lTextPrinted < lTextLength &&
|
|
(sc = ScGetNextBand(ppi, TRUE)) == S_OK);
|
|
|
|
//$ Raid 1137: Need to clear out the cached font characteristics
|
|
fr.chrg.cpMin = fr.chrg.cpMax + 1;
|
|
//SendMessage(hwndRE, EM_FORMATRANGE, 0, 0);
|
|
|
|
// Don't damage what we have just printed
|
|
ppi->rcBand.top = NTwipsToPixels(fr.rc.bottom, ppi->sizeInch.cy);
|
|
|
|
CleanUp:
|
|
DebugPrintTrace(( TEXT("ScPrintBody:%d\n"), sc));
|
|
return sc;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
* ScPrintMessage
|
|
*
|
|
* Purpose:
|
|
* To print the header and body of a message
|
|
*
|
|
* Arguments:
|
|
* ppi Pointer to the PRINTINFO structure
|
|
* pmsg Pointer to the message which needs its header
|
|
* to be printed.
|
|
* hwndRE Pre-rendered body
|
|
* phi Message header info
|
|
*
|
|
* Returns:
|
|
* SCODE indicating success or failure
|
|
*
|
|
*/
|
|
SCODE ScPrintMessage(PRINTINFO * ppi, HWND hWndRE)
|
|
{
|
|
RECT rcExt;
|
|
RECT rcSep;
|
|
HFONT hfontOld = NULL;
|
|
HBRUSH hbrushOld = NULL;
|
|
HPEN hpenOld = NULL;
|
|
SIZE sizeExt;
|
|
int cyHeader;
|
|
SCODE sc = S_OK;
|
|
PARAFORMAT pf = { 0 };
|
|
|
|
pf.cbSize = sizeof(PARAFORMAT);
|
|
|
|
|
|
// If we currently have no band, get the next band
|
|
if (IsRectEmpty(&ppi->rcBand) &&
|
|
(sc = ScGetNextBand(ppi, TRUE)) != S_OK)
|
|
goto CleanUp;
|
|
|
|
// Determine how much room we need for the header string and separator
|
|
|
|
hfontOld = (HFONT)SelectObject(ppi->hdcPrn, ppi->hfontSep);
|
|
hbrushOld = (HBRUSH)SelectObject(ppi->hdcPrn, GetStockObject(BLACK_BRUSH));
|
|
hpenOld = (HPEN)SelectObject(ppi->hdcPrn, GetStockObject(BLACK_PEN));
|
|
|
|
// Find out how much space our text take will take
|
|
GetTextExtentPoint(ppi->hdcPrn, ppi->szHeader, lstrlen(ppi->szHeader),
|
|
&sizeExt);
|
|
cyHeader = 2 * sizeExt.cy + 1 + (cySepFontSize(ppi) / 4);
|
|
|
|
// Check if enough room on page. Move to the next page as needed
|
|
|
|
if (ppi->rcBand.top + cyHeader > ppi->yFooter)
|
|
{
|
|
// No more room on this page, see if it'll fit on the next page
|
|
if (ppi->rcMargin.top + cyHeader > ppi->yFooter)
|
|
{
|
|
DebugPrintTrace(( TEXT("Header too big for any page.\n")));
|
|
goto CleanUp;
|
|
}
|
|
|
|
// Go on to the next page
|
|
if ((sc = ScPrintRestOfPage(ppi, TRUE)) != S_OK)
|
|
goto CleanUp;
|
|
}
|
|
|
|
// Calculate the rectangle that our header will take up
|
|
rcExt = ppi->rcBand;
|
|
rcExt.bottom = rcExt.top + cyHeader;
|
|
rcSep = rcExt;
|
|
rcSep.top += sizeExt.cy;
|
|
rcSep.bottom = rcSep.top + (cySepFontSize(ppi) / 4);
|
|
rcSep.right = rcSep.left + sizeExt.cx;
|
|
|
|
// Draw the text and separator
|
|
TextOut(ppi->hdcPrn, rcExt.left, rcExt.top, ppi->szHeader,
|
|
lstrlen(ppi->szHeader));
|
|
|
|
Rectangle(ppi->hdcPrn, rcSep.left, rcSep.top, rcSep.right, rcSep.bottom);
|
|
MoveToEx(ppi->hdcPrn, rcSep.right, rcSep.top, NULL);
|
|
LineTo(ppi->hdcPrn, rcExt.right, rcSep.top);
|
|
|
|
rcExt.top = rcExt.bottom + 5;
|
|
|
|
|
|
/***/
|
|
// Adjust the band so that we don't damage the header
|
|
ppi->rcBand.top = rcExt.bottom + 1;
|
|
|
|
// Create a header in a richedit control
|
|
|
|
pf.dwMask = PFM_STARTINDENT | PFM_RIGHTINDENT | PFM_ALIGNMENT |
|
|
PFM_OFFSET | PFM_TABSTOPS;
|
|
pf.dxOffset = LGetHeaderIndent();
|
|
pf.cTabCount = 1;
|
|
pf.rgxTabs[0] = pf.dxOffset;
|
|
pf.wAlignment = PFA_LEFT;
|
|
|
|
sc = ScPrintBody(ppi, sizeExt.cy);
|
|
/***/
|
|
CleanUp:
|
|
if (hfontOld != NULL)
|
|
SelectObject(ppi->hdcPrn, hfontOld);
|
|
if (hbrushOld != NULL)
|
|
SelectObject(ppi->hdcPrn, hbrushOld);
|
|
if (hpenOld != NULL)
|
|
SelectObject(ppi->hdcPrn, hpenOld);
|
|
|
|
return sc;
|
|
}
|
|
|
|
|
|
#ifdef WIN16
|
|
typedef UINT (CALLBACK *LPPRINTHOOKPROC) (HWND, UINT, WPARAM, LPARAM);
|
|
typedef UINT (CALLBACK *LPSETUPHOOKPROC) (HWND, UINT, WPARAM, LPARAM);
|
|
#endif
|
|
|
|
|
|
#ifdef WIN16
|
|
typedef UINT (CALLBACK *LPPRINTHOOKPROC) (HWND, UINT, WPARAM, LPARAM);
|
|
typedef UINT (CALLBACK *LPSETUPHOOKPROC) (HWND, UINT, WPARAM, LPARAM);
|
|
#endif
|
|
|
|
//$$////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
// SetPrintDlgExStruct - Fills in the default PDEX values
|
|
//
|
|
// hWnd - HWND of parent dialog
|
|
// PD - PrintDLG struct
|
|
// hWndLV - HWND of listView to print from - if there are no selections in the list view,
|
|
// the selections option is turned off in the print dialog
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void SetPrintDlgExStruct(HWND hWnd, PRINTDLGEX * lpPD, HWND hWndLV, LPWABPRINTDIALOGCALLBACK lpWABPCO)
|
|
{
|
|
// set up the print dialog stuff
|
|
// Call the common print dialog to get the default
|
|
PRINTDLGEX pd={0};
|
|
|
|
pd.lStructSize = sizeof(PRINTDLGEX);
|
|
pd.hwndOwner = hWnd;
|
|
pd.hDevMode = (HANDLE) NULL;
|
|
pd.hDevNames = (HANDLE) NULL;
|
|
pd.hDC = (HDC) NULL;
|
|
pd.Flags = PD_RETURNDC | // return PrintDC
|
|
PD_DISABLEPRINTTOFILE |
|
|
PD_ENABLEPRINTTEMPLATE |
|
|
PD_HIDEPRINTTOFILE |
|
|
PD_NOPAGENUMS;
|
|
pd.Flags2 = 0;
|
|
if(ListView_GetSelectedCount(hWndLV) > 0)
|
|
pd.Flags |= PD_SELECTION;
|
|
else
|
|
pd.Flags |= PD_NOSELECTION;
|
|
|
|
pd.nCopies = 1;
|
|
|
|
pd.hInstance = hinstMapiX;
|
|
pd.lpPrintTemplateName = MAKEINTRESOURCE(IDD_DIALOG_PRINTDLGEX); //(LPSTR) NULL;
|
|
pd.lpCallback = (LPUNKNOWN)lpWABPCO; // app callback interface
|
|
|
|
pd.nPropertyPages = 0;
|
|
pd.lphPropertyPages = NULL;
|
|
|
|
pd.nStartPage = START_PAGE_GENERAL;
|
|
|
|
*lpPD = pd;
|
|
|
|
return;
|
|
}
|
|
|
|
//$$////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
// SetPrintDlgStruct - Fills in the default PD values
|
|
//
|
|
// hWnd - HWND of parent dialog
|
|
// PD - PrintDLG struct
|
|
// hWndLV - HWND of listView to print from - if there are no selections in the list view,
|
|
// the selections option is turned off in the print dialog
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void SetPrintDlgStruct(HWND hWnd, PRINTDLG * lpPD, HWND hWndLV, LPARAM lCustData)
|
|
{
|
|
// set up the print dialog stuff
|
|
// Call the common print dialog to get the default
|
|
PRINTDLG pd={0};
|
|
|
|
pd.lStructSize = sizeof(PRINTDLG);
|
|
pd.hDevMode = (HANDLE) NULL;
|
|
pd.hDevNames = (HANDLE) NULL;
|
|
|
|
pd.Flags = PD_RETURNDC | // return PrintDC
|
|
PD_NOPAGENUMS | // Disable Page number option
|
|
PD_DISABLEPRINTTOFILE |
|
|
PD_HIDEPRINTTOFILE |
|
|
PD_ENABLEPRINTHOOK |
|
|
PD_ENABLEPRINTTEMPLATE;
|
|
|
|
if(ListView_GetSelectedCount(hWndLV) > 0)
|
|
pd.Flags |= PD_SELECTION;
|
|
else
|
|
pd.Flags |= PD_NOSELECTION;
|
|
|
|
pd.hwndOwner = hWnd;
|
|
pd.hDC = (HDC) NULL;
|
|
pd.nFromPage = 1;
|
|
pd.nToPage = 1;
|
|
pd.nMinPage = 0;
|
|
pd.nMaxPage = 0;
|
|
pd.nCopies = 1;
|
|
pd.hInstance = hinstMapiX;
|
|
pd.lCustData = lCustData;
|
|
pd.lpfnPrintHook = (LPPRINTHOOKPROC) &fnPrintDialogProc; //NULL;
|
|
pd.lpfnSetupHook = (LPSETUPHOOKPROC) NULL;
|
|
pd.lpPrintTemplateName = MAKEINTRESOURCE(IDD_DIALOG_PRINTDLGORD); //(LPSTR) NULL;
|
|
pd.lpSetupTemplateName = (LPTSTR) NULL;
|
|
pd.hPrintTemplate = (HANDLE) NULL;
|
|
pd.hSetupTemplate = (HANDLE) NULL;
|
|
|
|
*lpPD = pd;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
-
|
|
- HrGetPrintData
|
|
-
|
|
Determines whether to show the new print dialog or the old print dialog
|
|
Fills in all the structures appropriately and returns the values we
|
|
care about such as nCopies, Print style, etc
|
|
*
|
|
*
|
|
*/
|
|
HRESULT HrGetPrintData(LPADRBOOK lpAdrBook, HWND hWndParent, HWND hWndLV,
|
|
HDC * lphdcPrint, int * lpnCopies,
|
|
DWORD * lpdwStyle, DWORD * lpdwRange)
|
|
{
|
|
DWORD dwSelectedStyle = styleMemo;
|
|
HRESULT hr = S_OK;
|
|
LPWABPRINTDIALOGCALLBACK lpWABPCO = NULL;
|
|
PRINTDLG pd = {0};
|
|
PRINTDLGEX pdEx = {0};
|
|
|
|
// Test for presence of NT5 PrintDlgEx
|
|
|
|
if(!HR_FAILED(hr = PrintDlgEx(NULL)))
|
|
{
|
|
if(HR_FAILED(hr = HrCreatePrintCallbackObject((LPIAB)lpAdrBook,&lpWABPCO,dwSelectedStyle)))
|
|
goto out;
|
|
if(!lpWABPCO)
|
|
{
|
|
hr = E_FAIL;
|
|
goto out;
|
|
}
|
|
SetPrintDlgExStruct(hWndParent, &pdEx, hWndLV, lpWABPCO);
|
|
if(HR_FAILED(hr = PrintDlgEx(&pdEx)))
|
|
{
|
|
DebugTrace( TEXT("PrintDlgEx returns 0x%.8x\n"),hr);
|
|
// #98841 Millenium returns fail in this case, but for PrintDlgEx(NULL) it returns S_OK (YST)
|
|
goto doOldPrint;
|
|
}
|
|
*lphdcPrint = pdEx.hDC;
|
|
*lpnCopies = pdEx.nCopies;
|
|
*lpdwStyle = lpWABPCO->dwSelectedStyle;
|
|
if (pdEx.Flags & PD_SELECTION)
|
|
*lpdwRange = rangeSelected;
|
|
else
|
|
*lpdwRange = rangeAll;
|
|
}
|
|
else
|
|
{
|
|
doOldPrint:
|
|
SetPrintDlgStruct(hWndParent, &pd, hWndLV, (LPARAM) &dwSelectedStyle);
|
|
// Show the print dialog
|
|
if(!PrintDlg(&pd))
|
|
goto out;
|
|
*lphdcPrint = pd.hDC;
|
|
*lpnCopies = pd.nCopies;
|
|
*lpdwStyle = dwSelectedStyle;
|
|
if (pd.Flags & PD_SELECTION)
|
|
*lpdwRange = rangeSelected;
|
|
else
|
|
*lpdwRange = rangeAll;
|
|
hr = S_OK;
|
|
}
|
|
out:
|
|
if(lpWABPCO)
|
|
lpWABPCO->lpVtbl->Release(lpWABPCO);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//$$////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// HrPrintItems - Prints selected contacts
|
|
// Prints the contents of the address book
|
|
// Pops up a dialog that lets user select what he wants to print
|
|
// Options are (or will be)
|
|
// All or selected
|
|
// Style - memo, business, or phone book
|
|
//
|
|
// Items are printed using the current sort style in the list view
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////////////
|
|
HRESULT HrPrintItems( HWND hWnd,
|
|
LPADRBOOK lpAdrBook,
|
|
HWND hWndLV,
|
|
BOOL bCurrentSortisByLastName)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
HWND hWndRE = NULL; // we'll do our formating in a riceh edit control and use that for printing
|
|
PRINTINFO *ppi=0;
|
|
BOOL fStartedDoc = FALSE;
|
|
BOOL fStartedPage= FALSE;
|
|
DOCINFO docinfo={0};
|
|
HCURSOR hOldCur = NULL;
|
|
int i,nCode;
|
|
HINSTANCE hRELib = NULL;
|
|
LPPTGDATA lpPTGData=GetThreadStoragePointer();
|
|
LPIAB lpIAB = (LPIAB)lpAdrBook;
|
|
|
|
HDC hdcPrint = NULL;
|
|
int nCopies = 0;
|
|
DWORD dwStyle;
|
|
DWORD dwRange;
|
|
|
|
// Double check if there are any print extensions that we need to accomodate
|
|
//
|
|
if(bCheckForPrintExtensions(NULL, 0))
|
|
{
|
|
// Found a print extension
|
|
hr = HrUseWABPrintExtension(hWnd, lpAdrBook, hWndLV);
|
|
goto out;
|
|
}
|
|
|
|
if(!(ppi = LocalAlloc(LMEM_ZEROINIT, sizeof(PRINTINFO))))
|
|
goto out;
|
|
ppi->hwndDlg = hWnd;
|
|
|
|
if(HR_FAILED(HrGetPrintData(lpAdrBook, hWnd, hWndLV, &hdcPrint, &nCopies, &dwStyle, &dwRange)))
|
|
goto out;
|
|
|
|
if(!hdcPrint)
|
|
goto out;
|
|
|
|
// Take care of zilch copies
|
|
//
|
|
// Actually it seems that this number is meaningless if the printer can handle multiple
|
|
// copies. If the printer can't handle multiple copies, we will get info in this number.
|
|
//
|
|
if(!nCopies)
|
|
nCopies = 1;
|
|
|
|
ppi->hdcPrn = hdcPrint;
|
|
|
|
// Create a RichEdit control in which we will do our formatting
|
|
hRELib = LoadLibrary( TEXT("riched20.dll"));
|
|
if(!hRELib)
|
|
{
|
|
hRELib = LoadLibrary( TEXT("riched32.dll"));
|
|
s_bUse20 = FALSE;
|
|
}
|
|
//IF_WIN16(hRELib = LoadLibrary( TEXT("riched.dll"));)
|
|
if(!hRELib)
|
|
goto out;
|
|
|
|
hWndRE = CreateWindowEx(0,
|
|
(s_bUse20 ? RICHEDIT_CLASS : TEXT("RichEdit")),
|
|
TEXT(""),WS_CHILD | ES_MULTILINE,
|
|
CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
|
|
hWnd,(HMENU) NULL,hinstMapiX,NULL);
|
|
|
|
if (!hWndRE)
|
|
goto out;
|
|
|
|
//////////////////////////
|
|
{
|
|
CHARFORMAT cf = {0};
|
|
TCHAR rgch[CCHMAX_STRINGRES];
|
|
DWORD dwCodepage ;
|
|
CHARSETINFO rCharsetInfo;
|
|
LOGFONT lfSystem;
|
|
BOOL bNeedLargeFont = FALSE;
|
|
|
|
cf.cbSize = sizeof(cf);
|
|
cf.dwMask = CFM_FACE;
|
|
|
|
SendMessage(hWndRE, EM_GETCHARFORMAT, (WPARAM) TRUE, (LPARAM) &cf);
|
|
|
|
if(LoadString(hinstMapiX, idsDefaultFontFace, rgch, ARRAYSIZE(rgch)))
|
|
StrCpyN(cf.szFaceName, rgch, ARRAYSIZE(cf.szFaceName));
|
|
else
|
|
StrCpyN(cf.szFaceName, szDefFont, ARRAYSIZE(cf.szFaceName));
|
|
|
|
// [a-msadek] bug#56478
|
|
// Arail does not support Thai so as all other base fonts
|
|
// The best way to determine the OS language is from system font charset
|
|
if(GetObject(GetStockObject(SYSTEM_FONT), sizeof(lfSystem), (LPVOID)&lfSystem))
|
|
{
|
|
if (lfSystem.lfCharSet == THAI_CHARSET)
|
|
{
|
|
StrCpyN(cf.szFaceName, szThaiDefFont, ARRAYSIZE(cf.szFaceName));
|
|
|
|
// Thai Font sizes are always smaller than English as the vowl and tone
|
|
// markes consumes some of the font height
|
|
bNeedLargeFont = TRUE;
|
|
}
|
|
}
|
|
|
|
// bug #53058 - set correct CharSet info for Eastern European
|
|
dwCodepage = GetACP();
|
|
// Get GDI charset info
|
|
if ( dwCodepage != 1252 && TranslateCharsetInfo((LPDWORD) IntToPtr(dwCodepage) , &rCharsetInfo, TCI_SRCCODEPAGE))
|
|
cf.bCharSet = (BYTE) rCharsetInfo.ciCharset;
|
|
|
|
SendMessage(hWndRE, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM) &cf);
|
|
if(bNeedLargeFont)
|
|
{
|
|
ReduceFontCmd(hWndRE, FALSE, 80, TRUE);
|
|
}
|
|
|
|
}
|
|
//////////////////////////
|
|
|
|
|
|
// At the top of the print job, print the header with the users name or with
|
|
// the default TEXT("Windows Address Book") title
|
|
{
|
|
TCHAR szHead[MAX_PATH];
|
|
DWORD dwLen = ARRAYSIZE(szHead);
|
|
SCODE sc;
|
|
*szHead = '\0';
|
|
if(bIsThereACurrentUser(lpIAB) && lstrlen(lpIAB->szProfileName))
|
|
StrCpyN(szHead, lpIAB->szProfileName, ARRAYSIZE(szHead));
|
|
else
|
|
GetUserName(szHead, &dwLen);
|
|
if(!lstrlen(szHead))
|
|
LoadString(hinstMapiX, IDS_ADDRBK_CAPTION, szHead, ARRAYSIZE(szHead));
|
|
|
|
if (( sc = ScInitPrintInfo( ppi, hWnd, szHead, &g_rcBorder, hWndRE)) != S_OK)
|
|
goto out;
|
|
}
|
|
|
|
// While the printing is in progress, we dont want the user to mess with the
|
|
// listview selection otherwise the print job will print the wrong entries
|
|
// Hence we disable this window (since the print cancel dialog is really a modeless dialog)
|
|
EnableWindow(hWnd, FALSE);
|
|
|
|
CreateShowAbortDialog(hWnd, 0, 0, ListView_GetSelectedCount(hWndLV), 0);
|
|
|
|
// Format the prop data into the Rich Edit Control
|
|
if(!WABFormatData(lpAdrBook, hWnd, hWndRE, hWndLV, dwRange, dwStyle, ppi, bCurrentSortisByLastName))
|
|
goto out;
|
|
|
|
if(bTimeToAbort())
|
|
goto out;
|
|
|
|
for(i=0;i<nCopies;i++)
|
|
{
|
|
TCHAR szBuf[MAX_PATH];
|
|
|
|
LoadString(hinstMapiX, idsPrintDocTitle, szBuf, ARRAYSIZE(szBuf));
|
|
|
|
docinfo.cbSize = sizeof(docinfo);
|
|
docinfo.lpszDocName = szBuf;
|
|
docinfo.lpszOutput = NULL;
|
|
|
|
SetMapMode(hdcPrint, MM_TEXT);
|
|
|
|
// Set the abort procedure
|
|
if ((nCode=SetAbortProc(ppi->hdcPrn, ppi->pfnAbortProc)) <= 0)
|
|
{
|
|
hr = E_FAIL;
|
|
break;
|
|
}
|
|
|
|
if(bTimeToAbort())
|
|
goto out;
|
|
|
|
// Start a print job
|
|
if (StartDoc(ppi->hdcPrn, &docinfo) <= 0)
|
|
{
|
|
DebugPrintError(( TEXT("StartDoc failed: %d\n"), GetLastError()));
|
|
goto out;
|
|
}
|
|
fStartedDoc = TRUE;
|
|
|
|
//StartPage(pd.hDC);
|
|
if(bTimeToAbort())
|
|
goto out;
|
|
|
|
|
|
// Go on and print the message!
|
|
if (ScPrintMessage(ppi, hWndRE) != S_OK)
|
|
goto out;
|
|
|
|
if(bTimeToAbort())
|
|
goto out;
|
|
|
|
// End the page
|
|
if(ScGetNextBand( ppi, FALSE) != S_OK)
|
|
goto out;
|
|
|
|
if(bTimeToAbort())
|
|
goto out;
|
|
|
|
// Finish up the print job if it had been started
|
|
if (fStartedDoc)
|
|
{
|
|
EndDoc(ppi->hdcPrn);
|
|
fStartedDoc = FALSE;
|
|
}
|
|
}
|
|
|
|
hr = hrSuccess;
|
|
|
|
out:
|
|
|
|
if(hWndRE)
|
|
{
|
|
SendMessage(hWndRE, WM_SETTEXT, 0, (LPARAM)szEmpty);
|
|
SendMessage(hWndRE, WM_CLEAR, 0, 0);
|
|
}
|
|
|
|
if(bTimeToAbort())
|
|
{
|
|
hr = MAPI_E_USER_CANCEL;
|
|
pt_bPrintUserAbort = FALSE;
|
|
}
|
|
|
|
// Re-enable the window and ensure it stays put
|
|
EnableWindow(hWnd, TRUE);
|
|
//SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOOWNERZORDER);
|
|
|
|
CloseAbortDlg();
|
|
|
|
// Finish up the print job if it had been started
|
|
if (fStartedDoc)
|
|
EndDoc(ppi->hdcPrn);
|
|
|
|
// Get rid of our Rich Edit control
|
|
if (hWndRE)
|
|
DestroyWindow(hWndRE);
|
|
|
|
if(hOldCur)
|
|
SetCursor(hOldCur);
|
|
|
|
if(ppi)
|
|
{
|
|
if(ppi->hfontPlain)
|
|
DeleteObject(ppi->hfontPlain);
|
|
if(ppi->hfontBold)
|
|
DeleteObject(ppi->hfontBold);
|
|
if(ppi->hfontSep)
|
|
DeleteObject(ppi->hfontSep);
|
|
LocalFreeAndNull(&ppi);
|
|
}
|
|
|
|
if(hRELib)
|
|
FreeLibrary((HMODULE) hRELib);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/*
|
|
* Handles the WM_INITDIALOG for both PrintDlg and PrintDlgEx
|
|
*/
|
|
BOOL bHandleWMInitDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, LPDWORD lpdwStyle)
|
|
{
|
|
DWORD dwStyle = lpdwStyle ? *lpdwStyle : styleMemo;
|
|
int nID;
|
|
|
|
switch (dwStyle)
|
|
{
|
|
case styleBusinessCard:
|
|
nID = IDC_PRINT_RADIO_CARD;
|
|
break;
|
|
case stylePhoneList:
|
|
nID = IDC_PRINT_RADIO_PHONELIST;
|
|
break;
|
|
default:
|
|
case styleMemo:
|
|
nID = IDC_PRINT_RADIO_MEMO; //default
|
|
break;
|
|
}
|
|
CheckRadioButton( hDlg, IDC_PRINT_RADIO_MEMO, IDC_PRINT_RADIO_PHONELIST, nID);
|
|
SetFocus(hDlg);
|
|
return 0;
|
|
}
|
|
/*
|
|
* Handles the WM_COMMAND for both PrintDlg and PrintDlgEx
|
|
*/
|
|
BOOL bHandleWMCommand(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, LPDWORD lpdwStyle )
|
|
{
|
|
switch (GET_WM_COMMAND_ID(wParam,lParam))
|
|
{
|
|
case IDC_PRINT_RADIO_MEMO:
|
|
//lpPD->lCustData = (DWORD) styleMemo;
|
|
*lpdwStyle = (DWORD) styleMemo;
|
|
break;
|
|
case IDC_PRINT_RADIO_CARD:
|
|
//lpPD->lCustData = (DWORD) styleBusinessCard;
|
|
*lpdwStyle = (DWORD) styleBusinessCard;
|
|
break;
|
|
case IDC_PRINT_RADIO_PHONELIST:
|
|
//lpPD->lCustData = (DWORD) stylePhoneList;
|
|
*lpdwStyle = (DWORD) stylePhoneList;
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
/*
|
|
* Handles the WM_HELP for both PrintDlg and PrintDlgEx
|
|
*/
|
|
BOOL bHandleWMHelp(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, LPDWORD lpdwStyle )
|
|
{
|
|
int id = ((LPHELPINFO)lParam)->iCtrlId;
|
|
if( id == IDC_PRINT_FRAME_STYLE ||
|
|
id == IDC_PRINT_RADIO_MEMO ||
|
|
id == IDC_PRINT_RADIO_CARD ||
|
|
id == IDC_PRINT_RADIO_PHONELIST)
|
|
{
|
|
WABWinHelp(((LPHELPINFO)lParam)->hItemHandle,
|
|
g_szWABHelpFileName,
|
|
HELP_WM_HELP,
|
|
(DWORD_PTR)(LPSTR) rgPrintHelpIDs );
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
/*
|
|
* Handles the WM_CONTEXTMENU for both PrintDlg and PrintDlgEx
|
|
*/
|
|
BOOL bHandleWMContextMenu(HWND hDlg, UINT message, WPARAM wParam,LPARAM lParam,LPDWORD lpdwStyle )
|
|
{
|
|
HWND hwnd = (HWND) wParam;
|
|
if( hwnd == GetDlgItem(hDlg, IDC_PRINT_FRAME_STYLE) ||
|
|
hwnd == GetDlgItem(hDlg, IDC_PRINT_RADIO_MEMO) ||
|
|
hwnd == GetDlgItem(hDlg, IDC_PRINT_RADIO_CARD) ||
|
|
hwnd == GetDlgItem(hDlg, IDC_PRINT_RADIO_PHONELIST) )
|
|
{
|
|
WABWinHelp((HWND) wParam,
|
|
g_szWABHelpFileName,
|
|
HELP_CONTEXTMENU,
|
|
(DWORD_PTR)(LPVOID) rgPrintHelpIDs );
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//$$*****************************************************************
|
|
//
|
|
// FUNCTION: fnPrintDialogProc
|
|
//
|
|
// PURPOSE: Printer dialog hook procedure
|
|
//
|
|
// We have modified the CommDlg print template with the
|
|
// WAB print styles.
|
|
// This is a hook procedure that takes care of our
|
|
// newly added controls
|
|
//
|
|
// When WM_INITDIALOG is called, the lParam contains a pointer to the
|
|
// PRINTDLG structure controling the print setup dialog
|
|
//
|
|
//*******************************************************************
|
|
INT_PTR CALLBACK fnPrintDialogProc( HWND hDlg,
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
|
|
LPDWORD lpdwStyle = (LPDWORD) GetWindowLongPtr(hDlg, DWLP_USER);
|
|
|
|
switch(message)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
LPPRINTDLG lpPD = (LPPRINTDLG) lParam;
|
|
#ifdef WIN16
|
|
// Strange situation here. If I don't create edt1 and edt2 which are used for page range, entire print dialog work incorrectly.
|
|
// So I just add two controls(edt1 and edt2) and hide those here.
|
|
ShowWindow(GetDlgItem(hDlg, edt1), SW_HIDE);
|
|
ShowWindow(GetDlgItem(hDlg, edt2), SW_HIDE);
|
|
#endif
|
|
if(lpPD)
|
|
{
|
|
lpdwStyle = (LPDWORD) lpPD->lCustData;
|
|
SetWindowLongPtr(hDlg, DWLP_USER, (LPARAM)lpdwStyle); //Save this for future reference
|
|
return bHandleWMInitDialog(hDlg,message,wParam,lParam,lpdwStyle);
|
|
}
|
|
}
|
|
SetFocus(hDlg);
|
|
return 0;
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
if(lpdwStyle)
|
|
return bHandleWMCommand(hDlg,message,wParam,lParam,lpdwStyle);
|
|
break;
|
|
|
|
case WM_HELP:
|
|
return bHandleWMHelp(hDlg,message,wParam,lParam,lpdwStyle);
|
|
break;
|
|
|
|
|
|
#ifndef WIN16
|
|
case WM_CONTEXTMENU:
|
|
return bHandleWMContextMenu(hDlg,message,wParam,lParam,lpdwStyle);
|
|
break;
|
|
#endif // !WIN16
|
|
|
|
|
|
|
|
default:
|
|
return FALSE;
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/**************************************************************************************************
|
|
* ScInitPrintInfo
|
|
*
|
|
* Purpose:
|
|
* Initialize the fields of a print info structure relevant for
|
|
* the actual printing.
|
|
*
|
|
* Arguments:
|
|
* ppi Pointer to the PRINTINFO structure
|
|
* hwnd The owner of the print dialog box
|
|
* szHeader The string to be printed at the top of each
|
|
* message
|
|
* prcBorder Pointer to a rect whose fields contain the
|
|
* number of twips to use as a margin around the
|
|
* printed text.
|
|
* hWndRE rich edit control in which we will do our formatting
|
|
*
|
|
* Returns:
|
|
* SCODE indicating success or failure
|
|
*
|
|
***************************************************************************************************/
|
|
SCODE ScInitPrintInfo( PRINTINFO * ppi,
|
|
HWND hwnd,
|
|
LPTSTR szHeader,
|
|
RECT * prcBorder,
|
|
HWND hWndRE)
|
|
{
|
|
SIZE sizeExt;
|
|
LOGFONT logfont = {0};
|
|
HFONT hfontOld;
|
|
TCHAR szT[20];
|
|
SCODE sc = S_OK;
|
|
TCHAR rgch[CCHMAX_STRINGRES];
|
|
|
|
// Save handle to our parent window
|
|
ppi->hwnd = hwnd;
|
|
|
|
// Save a pointer to our header string
|
|
ppi->szHeader = szHeader;
|
|
|
|
// Set up pointer to our abort procedure
|
|
ppi->pfnAbortProc = FAbortProc;
|
|
|
|
ppi->hwndRE = hWndRE;
|
|
|
|
// Determine the page size in pixels
|
|
ppi->sizePage.cx = GetDeviceCaps(ppi->hdcPrn, HORZRES);
|
|
ppi->sizePage.cy = GetDeviceCaps(ppi->hdcPrn, VERTRES);
|
|
|
|
// Exchange 13497: If we have nothing to render to abort now.
|
|
if (!ppi->sizePage.cx || !ppi->sizePage.cy)
|
|
{
|
|
sc = E_FAIL;
|
|
goto CleanUp;
|
|
}
|
|
|
|
///MoveWindow(hWndRE, 0, 0, ppi->sizepage.cx, ppi->sizepage.cy, FALSE);
|
|
|
|
// Determine the number of pixels in a logical inch
|
|
ppi->sizeInch.cx = GetDeviceCaps(ppi->hdcPrn, LOGPIXELSX);
|
|
ppi->sizeInch.cy = GetDeviceCaps(ppi->hdcPrn, LOGPIXELSY);
|
|
|
|
// Exchange 13497: If we failed to get some info make some assumptions.
|
|
// At worst assume 300 dpi.
|
|
if (!ppi->sizeInch.cx)
|
|
ppi->sizeInch.cx = ppi->sizeInch.cy ? ppi->sizeInch.cy : 300;
|
|
if (!ppi->sizeInch.cy)
|
|
ppi->sizeInch.cy = 300;
|
|
|
|
//$ Raid 2667: Determine if we still fit within the page in twips
|
|
if (LPixelsToTwips(ppi->sizePage.cx, ppi->sizeInch.cx) > INT_MAX ||
|
|
LPixelsToTwips(ppi->sizePage.cy, ppi->sizeInch.cy) > INT_MAX)
|
|
{
|
|
sc = E_FAIL;
|
|
goto CleanUp;
|
|
}
|
|
|
|
|
|
// Set up the margin settings
|
|
ppi->rcMargin.top = NTwipsToPixels(prcBorder->top, ppi->sizeInch.cy);
|
|
ppi->rcMargin.bottom = ppi->sizePage.cy
|
|
- NTwipsToPixels(prcBorder->bottom, ppi->sizeInch.cy);
|
|
if (ppi->rcMargin.bottom < ppi->rcMargin.top)
|
|
{
|
|
// Bottom is above top. Top/Bottom margins ignored
|
|
ppi->rcMargin.top = 0;
|
|
ppi->rcMargin.bottom = ppi->sizePage.cy;
|
|
}
|
|
|
|
ppi->rcMargin.left = NTwipsToPixels(prcBorder->left, ppi->sizeInch.cx);
|
|
ppi->rcMargin.right = ppi->sizePage.cx
|
|
- NTwipsToPixels(prcBorder->right, ppi->sizeInch.cx);
|
|
if (ppi->rcMargin.right < ppi->rcMargin.left)
|
|
{
|
|
// Right is left of left. Left/Right margins ignored
|
|
ppi->rcMargin.left = 0;
|
|
ppi->rcMargin.right = ppi->sizePage.cx;
|
|
}
|
|
|
|
|
|
// Set up the separator font
|
|
//$ Raid 2773: Let user customize separator font
|
|
logfont.lfHeight = - cySepFontSize(ppi);
|
|
logfont.lfWeight = FW_BOLD;
|
|
logfont.lfCharSet = DEFAULT_CHARSET;
|
|
if (LoadString(hinstMapiX, idsDefaultFontFace, rgch, ARRAYSIZE(rgch)))
|
|
StrCpyN(logfont.lfFaceName, rgch, ARRAYSIZE(logfont.lfFaceName));
|
|
else
|
|
StrCpyN(logfont.lfFaceName, szDefFont, ARRAYSIZE(logfont.lfFaceName));
|
|
|
|
ppi->hfontSep = CreateFontIndirect(&logfont);
|
|
|
|
// Set up common font
|
|
ZeroMemory(&logfont, sizeof(LOGFONT));
|
|
logfont.lfHeight = - 10 * ppi->sizeInch.cy / cPtsPerInch;
|
|
|
|
logfont.lfWeight = FW_NORMAL;
|
|
logfont.lfCharSet = DEFAULT_CHARSET;
|
|
if(LoadString(hinstMapiX, idsDefaultFontFace, rgch, ARRAYSIZE(rgch)))
|
|
StrCpyN(logfont.lfFaceName, rgch, ARRAYSIZE(logfont.lfFaceName));
|
|
else
|
|
StrCpyN(logfont.lfFaceName, szDefFont, ARRAYSIZE(logfont.lfFaceName));
|
|
ppi->hfontPlain = CreateFontIndirect(&logfont);
|
|
|
|
logfont.lfWeight = FW_BOLD;
|
|
ppi->hfontBold = CreateFontIndirect(&logfont);
|
|
|
|
// Calculate where to put the footer
|
|
|
|
// Load up the formatting string to use for page numbers
|
|
//LoadString(hinstMapiX, idsFmtPageNumber, ppi->szPageNumber, ARRAYSIZE(ppi->szPageNumber));
|
|
StrCpyN(ppi->szPageNumber, TEXT("%d"), ARRAYSIZE(ppi->szPageNumber));
|
|
wnsprintf(szT, ARRAYSIZE(szT), ppi->szPageNumber, ppi->lPageNumber);
|
|
|
|
// Sample the height
|
|
hfontOld = (HFONT)SelectObject(ppi->hdcPrn, ppi->hfontPlain);
|
|
GetTextExtentPoint(ppi->hdcPrn, szT, lstrlen(szT), &sizeExt);
|
|
ppi->yFooter = ppi->rcMargin.bottom - sizeExt.cy;
|
|
SelectObject(ppi->hdcPrn, hfontOld);
|
|
|
|
// Make sure our footer doesn't go above the top of the page
|
|
if (ppi->yFooter < ppi->rcMargin.top)
|
|
sc = E_FAIL;
|
|
|
|
CleanUp:
|
|
return sc;
|
|
}
|
|
|
|
|
|
|
|
//$$////////////////////////////////////////
|
|
//
|
|
// GetNumberFromStringResource
|
|
//
|
|
////////////////////////////////////////////
|
|
int GetNumberFromStringResource(int idNumString)
|
|
{
|
|
TCHAR szBuf[MAX_PATH];
|
|
|
|
if (LoadString(hinstMapiX, idNumString, szBuf, ARRAYSIZE(szBuf)))
|
|
return my_atoi(szBuf);
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/*--------------------------------------------------------------------------------------------------*/
|
|
/*--IPrintDialogCallback stuff----------------------------------------------------------------------*/
|
|
/*--Special stuff for the new NT5 Print Dialog------------------------------------------------------*/
|
|
/*--------------------------------------------------------------------------------------------------*/
|
|
|
|
WAB_PRINTDIALOGCALLBACK_Vtbl vtblWABPRINTDIALOGCALLBACK = {
|
|
VTABLE_FILL
|
|
WAB_PRINTDIALOGCALLBACK_QueryInterface,
|
|
WAB_PRINTDIALOGCALLBACK_AddRef,
|
|
WAB_PRINTDIALOGCALLBACK_Release,
|
|
WAB_PRINTDIALOGCALLBACK_InitDone,
|
|
WAB_PRINTDIALOGCALLBACK_SelectionChange,
|
|
WAB_PRINTDIALOGCALLBACK_HandleMessage
|
|
};
|
|
|
|
/*
|
|
- HrCreatePrintCallbackObject
|
|
-
|
|
*
|
|
* This callback object is needed so the new NT5 print dialog can provide send messages back to
|
|
* us for the customization we do for the print dialog ..
|
|
*
|
|
*/
|
|
HRESULT HrCreatePrintCallbackObject(LPIAB lpIAB, LPWABPRINTDIALOGCALLBACK * lppWABPCO, DWORD dwSelectedStyle)
|
|
{
|
|
LPWABPRINTDIALOGCALLBACK lpWABPCO = NULL;
|
|
SCODE sc;
|
|
HRESULT hr = hrSuccess;
|
|
|
|
//
|
|
// Allocate space for the IAB structure
|
|
//
|
|
if (FAILED(sc = MAPIAllocateBuffer(sizeof(WABPRINTDIALOGCALLBACK), (LPVOID *) &lpWABPCO)))
|
|
{
|
|
hr = ResultFromScode(sc);
|
|
goto err;
|
|
}
|
|
|
|
MAPISetBufferName(lpWABPCO, TEXT("WAB Print Dialog Callback Object"));
|
|
|
|
ZeroMemory(lpWABPCO, sizeof(WABPRINTDIALOGCALLBACK));
|
|
|
|
lpWABPCO->lpVtbl = &vtblWABPRINTDIALOGCALLBACK;
|
|
|
|
lpWABPCO->lpIAB = lpIAB;
|
|
|
|
lpWABPCO->dwSelectedStyle = dwSelectedStyle;
|
|
|
|
lpWABPCO->lpVtbl->AddRef(lpWABPCO);
|
|
|
|
*lppWABPCO = lpWABPCO;
|
|
|
|
return(hrSuccess);
|
|
|
|
err:
|
|
|
|
FreeBufferAndNull(&lpWABPCO);
|
|
return(hr);
|
|
}
|
|
|
|
|
|
void ReleaseWABPrintCallbackObject(LPWABPRINTDIALOGCALLBACK lpWABPCO)
|
|
{
|
|
MAPIFreeBuffer(lpWABPCO);
|
|
}
|
|
|
|
|
|
STDMETHODIMP_(ULONG)
|
|
WAB_PRINTDIALOGCALLBACK_AddRef(LPWABPRINTDIALOGCALLBACK lpWABPCO)
|
|
{
|
|
return(++(lpWABPCO->lcInit));
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP_(ULONG)
|
|
WAB_PRINTDIALOGCALLBACK_Release(LPWABPRINTDIALOGCALLBACK lpWABPCO)
|
|
{
|
|
ULONG ulc = (--(lpWABPCO->lcInit));
|
|
if(ulc==0)
|
|
ReleaseWABPrintCallbackObject(lpWABPCO);
|
|
return(ulc);
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
WAB_PRINTDIALOGCALLBACK_QueryInterface(LPWABPRINTDIALOGCALLBACK lpWABPCO,
|
|
REFIID lpiid,
|
|
LPVOID * lppNewObj)
|
|
{
|
|
LPVOID lp = NULL;
|
|
|
|
if(!lppNewObj)
|
|
return MAPI_E_INVALID_PARAMETER;
|
|
|
|
*lppNewObj = NULL;
|
|
|
|
if(IsEqualIID(lpiid, &IID_IUnknown))
|
|
lp = (LPVOID) lpWABPCO;
|
|
|
|
if(IsEqualIID(lpiid, &IID_IPrintDialogCallback))
|
|
lp = (LPVOID) lpWABPCO;
|
|
|
|
if(!lp)
|
|
return E_NOINTERFACE;
|
|
|
|
((LPWABPRINTDIALOGCALLBACK) lp)->lpVtbl->AddRef((LPWABPRINTDIALOGCALLBACK) lp);
|
|
|
|
*lppNewObj = lp;
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
STDMETHODIMP
|
|
WAB_PRINTDIALOGCALLBACK_InitDone(LPWABPRINTDIALOGCALLBACK lpWABPCO)
|
|
{
|
|
HRESULT hr = S_FALSE;
|
|
DebugTrace( TEXT("WAB_PRINTDIALOGCALLBACK_InitDone\n"));
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
WAB_PRINTDIALOGCALLBACK_SelectionChange(LPWABPRINTDIALOGCALLBACK lpWABPCO)
|
|
{
|
|
HRESULT hr = S_FALSE;
|
|
DebugTrace( TEXT("WAB_PRINTDIALOGCALLBACK_SelectionChange\n"));
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
WAB_PRINTDIALOGCALLBACK_HandleMessage(LPWABPRINTDIALOGCALLBACK lpWABPCO,
|
|
HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, LRESULT *pResult)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
LPDWORD lpdwStyle = &lpWABPCO->dwSelectedStyle;
|
|
|
|
DebugTrace( TEXT("WAB_PRINTDIALOGCALLBACK_HandleMessage: 0x%.8x\n"), message);
|
|
|
|
switch(message)
|
|
{
|
|
case WM_INITDIALOG:
|
|
bRet = bHandleWMInitDialog(hDlg,message,wParam,lParam,lpdwStyle);
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
bRet = bHandleWMCommand(hDlg,message,wParam,lParam,lpdwStyle);
|
|
break;
|
|
|
|
case WM_HELP:
|
|
bRet = bHandleWMHelp(hDlg,message,wParam,lParam,lpdwStyle);
|
|
break;
|
|
|
|
case WM_CONTEXTMENU:
|
|
bRet = bHandleWMContextMenu(hDlg,message,wParam,lParam,lpdwStyle);
|
|
break;
|
|
|
|
default:
|
|
bRet = FALSE;
|
|
break;
|
|
}
|
|
|
|
return (bRet ? S_OK : S_FALSE);
|
|
}
|
|
|
|
|
|
/******************************************************************************************/
|
|
|
|
|
|
/*
|
|
- bCheckForPrintExtensions
|
|
-
|
|
* In case any app has implemented a Print Extension to the WAB, we should hook into
|
|
* that print extension
|
|
*
|
|
* lpDLLPath can be NULL or should point to a buffer big enough to receive the module Path
|
|
*
|
|
*/
|
|
static const LPTSTR szExtDisplayMailUser = TEXT("Software\\Microsoft\\WAB\\WAB4\\ExtPrint");
|
|
extern HrGetActionAdrList(LPADRBOOK lpAdrBook,HWND hWndLV,LPADRLIST * lppAdrList,LPTSTR * lppURL, BOOL * lpbIsNTDSEntry);
|
|
|
|
BOOL bCheckForPrintExtensions(LPTSTR lpDLLPath, DWORD cchSize)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
HKEY hKey = NULL;
|
|
|
|
if(ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE,szExtDisplayMailUser,0, KEY_READ,&hKey))
|
|
{
|
|
goto out;
|
|
}
|
|
|
|
{
|
|
TCHAR szExt[MAX_PATH];
|
|
DWORD dwIndex = 0, dwSize = ARRAYSIZE(szExt), dwType = 0;
|
|
*szExt = '\0';
|
|
|
|
while(ERROR_SUCCESS == RegEnumValue(hKey, dwIndex, szExt, &dwSize,
|
|
0, &dwType, NULL, NULL))
|
|
{
|
|
// we found some entry in here .. the value name will be the full path
|
|
// to the module containing the print function
|
|
// Double-check that this module actually exists
|
|
if (szExt && lstrlen(szExt) && (GetFileAttributes(szExt) != 0xFFFFFFFF))
|
|
{
|
|
if(lpDLLPath)
|
|
StrCpyN(lpDLLPath, szExt, cchSize);
|
|
bRet = TRUE;
|
|
goto out;
|
|
}
|
|
}
|
|
}
|
|
|
|
out:
|
|
if(hKey)
|
|
RegCloseKey(hKey);
|
|
return bRet;
|
|
}
|
|
|
|
/*
|
|
-
|
|
- HrUseWABPrintExtension()
|
|
-
|
|
* Loads the WAB Print Extension from the extension DLL
|
|
* and calls into it
|
|
*
|
|
* hWnd - Handle of WAB parent
|
|
* lpAdrBook - lpAdrBook pointer
|
|
* hWndLV - listview from which a user may have chosen selections
|
|
*
|
|
*/
|
|
HRESULT HrUseWABPrintExtension(HWND hWnd, LPADRBOOK lpAdrBook, HWND hWndLV)
|
|
{
|
|
TCHAR szExt[MAX_PATH];
|
|
HRESULT hr = E_FAIL;
|
|
HINSTANCE hInstPrint = NULL;
|
|
LPWABPRINTEXT lpfnWABPrintExt = NULL;
|
|
LPADRLIST lpAdrList = NULL;
|
|
LPWABOBJECT lpWABObject = (LPWABOBJECT)((LPIAB)lpAdrBook)->lpWABObject;
|
|
|
|
*szExt = '\0';
|
|
if(!bCheckForPrintExtensions(szExt, ARRAYSIZE(szExt)) || !lstrlen(szExt))
|
|
goto out;
|
|
|
|
if(!(hInstPrint = LoadLibrary(szExt)))
|
|
goto out;
|
|
|
|
lpfnWABPrintExt = (LPWABPRINTEXT) GetProcAddress(hInstPrint, "WABPrintExt");
|
|
if(!lpfnWABPrintExt)
|
|
goto out;
|
|
|
|
// Get the currently selected data from the list view
|
|
if(HR_FAILED(hr = HrGetActionAdrList(lpAdrBook,hWndLV,&lpAdrList,NULL,NULL)))
|
|
goto out;
|
|
|
|
hr = lpfnWABPrintExt(lpAdrBook, lpWABObject, hWnd, lpAdrList);
|
|
|
|
out:
|
|
if(lpAdrList)
|
|
FreePadrlist(lpAdrList);
|
|
if(hInstPrint)
|
|
FreeLibrary(hInstPrint);
|
|
return hr;
|
|
}
|