windows-nt/Source/XPSP1/NT/printscan/fax/config/dll/util.c

1677 lines
36 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
util.c
Abstract:
Misc. utility functions used by the fax configuration applet
Environment:
Fax configuration applet
Revision History:
03/13/96 -davidx-
Created it.
mm/dd/yy -author-
description
--*/
#include "faxcpl.h"
#include "forms.h"
#include "cfghelp.h"
#include <shlobj.h>
#include <mapicode.h>
#include <winsprlp.h>
//
// A flag to indicate whether we're inside SetDlgItemText call.
// This is a kluge but we have no other way of telling whether
// an EN_CHANGE message is caused by user action or by us calling
// SetDlgItemText.
//
BOOL insideSetDlgItemText = FALSE;
VOID
SetChangedFlag(
HWND hDlg,
INT pageIndex,
BOOL changed
)
/*++
Routine Description:
Enable or disable the Apply button in the property sheet
depending on if any of the dialog contents was changed
Arguments:
hDlg - Handle to the property page window
pageIndex - Specifies the index of current property page
changed - Specifies whether the Apply button should be enabled
Return Value:
NONE
--*/
{
HWND hwndPropSheet;
INT pageMask = (1 << pageIndex);
//
// Enable or disable the Apply button as appropriate
//
hwndPropSheet = GetParent(hDlg);
if (changed) {
PropSheet_Changed(hwndPropSheet, hDlg);
gConfigData->changeFlag |= pageMask;
} else {
gConfigData->changeFlag &= ~pageMask;
if (gConfigData->changeFlag == 0) {
PropSheet_UnChanged(hwndPropSheet, hDlg);
}
}
}
BOOL
GetMapiProfiles(
VOID
)
/*++
Routine Description:
Connect to the server and get its MAPI profiles.
Arguments:
NONE
Return Value:
TRUE if successful, FALSE if not
--*/
{
if (gConfigData->pMapiProfiles)
return TRUE;
if (!FaxGetMapiProfiles(gConfigData->hFaxSvc, (LPBYTE*) &gConfigData->pMapiProfiles))
{
gConfigData->pMapiProfiles = NULL;
Error(("Cannot retrieve MapiProfiles: %d\n", GetLastError()));
return FALSE;
}
return TRUE;
}
PVOID
MyEnumPrinters(
LPTSTR pServerName,
DWORD level,
PDWORD pcPrinters,
DWORD dwFlags
)
/*++
Routine Description:
Wrapper function for spooler API EnumPrinters
Arguments:
pServerName - Specifies the name of the print server
level - Level of PRINTER_INFO_x structure
pcPrinters - Returns the number of printers enumerated
dwFlags - Flag bits passed to EnumPrinters
Return Value:
Pointer to an array of PRINTER_INFO_x structures
NULL if there is an error
--*/
{
PBYTE pPrinterInfo = NULL;
DWORD cb;
if (! EnumPrinters(dwFlags, pServerName, level, NULL, 0, &cb, pcPrinters) &&
GetLastError() == ERROR_INSUFFICIENT_BUFFER &&
(pPrinterInfo = MemAlloc(cb)) &&
EnumPrinters(dwFlags, pServerName, level, pPrinterInfo, cb, &cb, pcPrinters))
{
return pPrinterInfo;
}
Error(("EnumPrinters failed: %d\n", GetLastError()));
MemFree(pPrinterInfo);
return NULL;
}
LPTSTR
MakePortNameString(
VOID
)
/*++
Routine Description:
Compose a port name string consisting of all available fax devices
Arguments:
NONE
Return Value:
Pointer to a list of comma-separated port names
NULL if there is an error
--*/
{
LPTSTR pPortName, p;
INT index, cb;
//
// Connect to the fax service and retrieve the list of fax devices
//
GetFaxDeviceAndConfigInfo();
//
// Figure out the total size of port name string
//
for (index=cb=0; index < gConfigData->cDevices; index++)
cb += SizeOfString(gConfigData->pDevInfo[index].DeviceName);
if (cb == 0 || !(p = pPortName = MemAlloc(cb)))
return NULL;
//
// Compose the port name string
//
for (index=0; index < gConfigData->cDevices; index++) {
if (p != pPortName)
*p++ = PORTNAME_SEPARATOR;
_tcscpy(p, gConfigData->pDevInfo[index].DeviceName);
p += _tcslen(p);
}
return pPortName;
}
BOOL
CheckFaxServerType(
HWND hDlg,
LPTSTR pPrinterName
)
/*++
Routine Description:
Make sure the print server has fax server software installed
Arguments:
hDlg - Handle to the currently active property page
pPrinterName - Specifies the name of the shared printer
Return Value:
TRUE if the fax server software is installed
FALSE otherwise
--*/
{
HANDLE hServer;
LPTSTR p, pNoRemoteDrivers;
INT status = 0;
//
// Derived the server name from the share name
//
Assert(_tcsncmp(pPrinterName, TEXT("\\\\"), 2) == EQUAL_STRING);
p = pPrinterName + 2;
if (p = _tcschr(p, TEXT(PATH_SEPARATOR))) {
*p = NUL;
if (OpenPrinter(pPrinterName, &hServer, NULL)) {
if (pNoRemoteDrivers = GetPrinterDataStr(hServer, SPLREG_NO_REMOTE_PRINTER_DRIVERS)) {
if (_tcsstr(pNoRemoteDrivers, DRIVER_NAME) != NULL)
status = IDS_NO_FAXSERVER;
MemFree(pNoRemoteDrivers);
}
ClosePrinter(hServer);
} else
status = IDS_SERVER_NOTALIVE;
*p = TEXT(PATH_SEPARATOR);
} else
status = IDS_INVALID_SHARENAME;
if (status != 0)
DisplayMessageDialog(hDlg, 0, 0, status);
return (status == 0);
}
PVOID
FaxSvcEnumPorts(
HANDLE hFaxSvc,
PDWORD pcPorts
)
/*++
Routine Description:
Wrapper function for fax service API FaxEnumPorts
Arguments:
hFaxSvc - Specifies a coneection handle to the fax service
DWORD - Specifies the level of FAX_PORT_INFO structure desired
pcPorts - Returns the number of devices managed by the fax service
Return Value:
Pointer to an array of FAX_PORT_INFO_x structures
NULL if there is an error
--*/
{
PVOID pSvcPortInfo = NULL;
if (!FaxEnumPorts(hFaxSvc, (PFAX_PORT_INFO*) &pSvcPortInfo, pcPorts)) {
Error(("FaxEnumPorts failed: %d\n", GetLastError()));
return NULL;
}
return pSvcPortInfo;
}
BOOL
GetFaxDeviceAndConfigInfo(
VOID
)
/*++
Routine Description:
Get a list of fax devices available on the system and
retrieve fax configuration information from the service
Arguments:
NONE
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{
PFAX_PORT_INFO pSvcPortInfo;
PFAX_PORT_INFO pSvcPort;
PCONFIG_PORT_INFO_2 pDevInfo;
DWORD index;
DWORD cPorts;
DWORD cb;
HANDLE FaxPortHandle;
LPBYTE RoutingInfo;
Verbose(("Enumerating fax ports ...\n"));
Assert(ValidConfigData(gConfigData));
if (gConfigData->pDevInfo)
return TRUE;
//
// Allocate memory to hold information about fax devices
//
Assert(gConfigData->hFaxSvc != NULL);
Assert(gConfigData->cDevices == 0);
if (! (pSvcPortInfo = FaxSvcEnumPorts(gConfigData->hFaxSvc, &cPorts)) ||
! (gConfigData->pDevInfo = pDevInfo = MemAllocZ(sizeof(CONFIG_PORT_INFO_2) * cPorts)))
{
FaxFreeBuffer(pSvcPortInfo);
return FALSE;
}
//
// Collect information about each fax device. Here we're depending on the fact that
// fax devices are enumerated in reverse priority order, i.e. the lowest priority
// device is enumerated first.
//
Verbose(("Available fax devices:\n"));
for (index=0; index < cPorts; index++, pDevInfo++) {
pSvcPort = &pSvcPortInfo[cPorts - index - 1];
Verbose(( " %ws\n", pSvcPort->DeviceName ));
pDevInfo->SizeOfStruct = pSvcPort->SizeOfStruct;
pDevInfo->DeviceId = pSvcPort->DeviceId;
pDevInfo->State = pSvcPort->State;
pDevInfo->Flags = pSvcPort->Flags;
pDevInfo->Rings = pSvcPort->Rings;
pDevInfo->Priority = pSvcPort->Priority;
pDevInfo->DeviceName = DuplicateString( pSvcPort->DeviceName );
pDevInfo->CSID = DuplicateString( pSvcPort->Csid);
pDevInfo->TSID = DuplicateString( pSvcPort->Tsid);
pDevInfo->Mask = 0;
pDevInfo->ProfileName = NULL;
pDevInfo->PrinterName = NULL;
pDevInfo->DirStore = NULL;
//
// open the fax port for query so we can get the routing info
//
if (FaxOpenPort(gConfigData->hFaxSvc, pDevInfo->DeviceId, PORT_OPEN_QUERY, &FaxPortHandle )) {
//
// get the store dir
//
if (FaxGetRoutingInfo( FaxPortHandle, REGVAL_RM_FOLDER_GUID, &RoutingInfo, &cb )) {
if (*((LPDWORD)RoutingInfo)) {
pDevInfo->Mask |= LR_STORE;
pDevInfo->DirStore = DuplicateString( (LPWSTR)(RoutingInfo+sizeof(DWORD)) );
}
FaxFreeBuffer( RoutingInfo );
}
//
// get the printer name
//
if (FaxGetRoutingInfo( FaxPortHandle, REGVAL_RM_PRINTING_GUID, &RoutingInfo, &cb )) {
if (*((LPDWORD)RoutingInfo)) {
pDevInfo->Mask |= LR_PRINT;
pDevInfo->PrinterName = DuplicateString( (LPWSTR)(RoutingInfo+sizeof(DWORD)) );
}
FaxFreeBuffer( RoutingInfo );
}
//
// get the email profile name
//
if (FaxGetRoutingInfo( FaxPortHandle, REGVAL_RM_EMAIL_GUID, &RoutingInfo, &cb )) {
if (*((LPDWORD)RoutingInfo)) {
pDevInfo->Mask |= LR_EMAIL;
pDevInfo->ProfileName = DuplicateString( (LPWSTR)(RoutingInfo+sizeof(DWORD)) );
}
FaxFreeBuffer( RoutingInfo );
}
//
// get the inbox profile name
//
if (FaxGetRoutingInfo( FaxPortHandle, REGVAL_RM_INBOX_GUID, &RoutingInfo, &cb )) {
if (*((LPDWORD)RoutingInfo)) {
pDevInfo->Mask |= LR_INBOX;
MemFree( pDevInfo->ProfileName );
pDevInfo->ProfileName = DuplicateString( (LPWSTR)(RoutingInfo+sizeof(DWORD)) );
}
FaxFreeBuffer( RoutingInfo );
}
FaxClose( FaxPortHandle );
}
gConfigData->cDevices++;
}
//
// Retrieve fax configuration information from the service
//
Assert( gConfigData->pFaxConfig == NULL );
if (!FaxGetConfiguration(gConfigData->hFaxSvc, &gConfigData->pFaxConfig)) {
Error(("Cannot retrieve fax configuration information: %d\n", GetLastError()));
gConfigData->pFaxConfig = NULL;
}
//
// Retrieve the logging categories
//
Assert( gConfigData->pFaxLogging == NULL );
if (!FaxGetLoggingCategories( gConfigData->hFaxSvc, &gConfigData->pFaxLogging, &gConfigData->NumberCategories )) {
Error(("Cannot retrieve fax logging category information: %d\n", GetLastError()));
gConfigData->pFaxLogging = NULL;
}
}
BOOL
SaveFaxDeviceAndConfigInfo(
HWND hDlg,
INT pageIndex
)
/*++
Routine Description:
Save fax device and configuration information
Arguments:
hDlg - Handle to the currently active property page
pageIndex - Specifies the currently active page index
Return Value:
TRUE if successful, FALSE if there is an error
--*/
#define FAIL_SAVE_FAX_CONFIG(err) { errorId = err; goto ExitSaveFaxConfig; }
{
PCONFIG_PORT_INFO_2 pDevInfo;
FAX_PORT_INFO SvcPort;
DWORD ec;
INT index = 0;
INT errorId = 0;
DWORD cb;
//
// Check if we're on the last page that has settable fax configuration info
//
if ((gConfigData->changeFlag & CONFIGPAGE_MASK) != (1 << pageIndex)) {
return TRUE;
}
if (gConfigData->hFaxSvc == NULL) {
FAIL_SAVE_FAX_CONFIG(IDS_NULL_SERVICE_HANDLE);
}
//
// Save fax configuration information
//
if (gConfigData->pFaxConfig &&
! FaxSetConfiguration(gConfigData->hFaxSvc, gConfigData->pFaxConfig))
{
ec = GetLastError();
Error(("FaxSetConfiguration failed: %d\n", ec));
FAIL_SAVE_FAX_CONFIG((ec == ERROR_ACCESS_DENIED ? IDS_NO_AUTHORITY : IDS_FAXSETCONFIG_FAILED));
}
//
// Save fax device information
// NOTE: Here, we're calling FaxSetPort on every device which may be
// a little redundant. But it shouldn't hurt anything.
//
pDevInfo = gConfigData->pDevInfo;
for (index=0; index < gConfigData->cDevices; index++, pDevInfo++) {
HANDLE FaxPortHandle;
LPBYTE RoutingInfo;
if (!FaxOpenPort(gConfigData->hFaxSvc, pDevInfo->DeviceId, PORT_OPEN_MODIFY, &FaxPortHandle )) {
DisplayMessageDialog(hDlg, 0, 0, IDS_DEVICE_BUSY, pDevInfo->DeviceName);
return FALSE;
}
SvcPort.SizeOfStruct = pDevInfo->SizeOfStruct;
SvcPort.DeviceId = pDevInfo->DeviceId;
SvcPort.State = pDevInfo->State;
SvcPort.Flags = pDevInfo->Flags;
SvcPort.Rings = pDevInfo->Rings;
SvcPort.Priority = pDevInfo->Priority;
SvcPort.DeviceName = pDevInfo->DeviceName;
SvcPort.Tsid = pDevInfo->TSID;
SvcPort.Csid = pDevInfo->CSID;
if (! FaxSetPort(FaxPortHandle, &SvcPort)) {
ec = GetLastError();
Error(("FaxSetPort failed: %d\n", ec));
FAIL_SAVE_FAX_CONFIG((ec == ERROR_ACCESS_DENIED ? IDS_NO_AUTHORITY : IDS_FAXSETPORT_FAILED));
}
//
// change the routing information
//
cb = 4096;
RoutingInfo = (LPBYTE) MemAllocZ( cb );
if (!RoutingInfo) {
Error(("Memory allocation failed: %d\n", GetLastError()));
goto ExitSaveFaxConfig;
}
//
// set the store dir
//
*((LPDWORD)RoutingInfo) = (pDevInfo->Mask & LR_STORE) > 0;
if (pDevInfo->Mask & LR_STORE) {
_tcscpy( (LPTSTR) (RoutingInfo+sizeof(DWORD)), pDevInfo->DirStore );
}
if (!FaxSetRoutingInfo( FaxPortHandle, REGVAL_RM_FOLDER_GUID, RoutingInfo, cb )) {
Error(("FaxSetRoutingInfo failed: %d\n", GetLastError()));
}
//
// set the printer name
//
*((LPDWORD)RoutingInfo) = (pDevInfo->Mask & LR_PRINT) > 0;
if (pDevInfo->Mask & LR_PRINT) {
_tcscpy( (LPTSTR) (RoutingInfo+sizeof(DWORD)), pDevInfo->PrinterName ? pDevInfo->PrinterName : TEXT("") );
}
if (!FaxSetRoutingInfo( FaxPortHandle, REGVAL_RM_PRINTING_GUID, RoutingInfo, cb )) {
Error(("FaxSetRoutingInfo failed: %d\n", GetLastError()));
}
//
// set the email profile name
//
*((LPDWORD)RoutingInfo) = (pDevInfo->Mask & LR_EMAIL) > 0;
if (pDevInfo->Mask & LR_EMAIL) {
_tcscpy( (LPTSTR) (RoutingInfo+sizeof(DWORD)), pDevInfo->ProfileName ? pDevInfo->ProfileName : TEXT("") );
}
if (!FaxSetRoutingInfo( FaxPortHandle, REGVAL_RM_EMAIL_GUID, RoutingInfo, cb )) {
Error(("FaxSetRoutingInfo failed: %d\n", GetLastError()));
}
//
// set the inbox profile name
//
*((LPDWORD)RoutingInfo) = (pDevInfo->Mask & LR_INBOX) > 0;
if (pDevInfo->Mask & LR_INBOX) {
_tcscpy( (LPTSTR) (RoutingInfo+sizeof(DWORD)), pDevInfo->ProfileName ? pDevInfo->ProfileName : TEXT("") );
}
if (!FaxSetRoutingInfo( FaxPortHandle, REGVAL_RM_INBOX_GUID, RoutingInfo, cb )) {
Error(("FaxSetRoutingInfo failed: %d\n", GetLastError()));
}
MemFree( RoutingInfo );
FaxClose( FaxPortHandle );
}
//
// save the logging categories
//
if (!FaxSetLoggingCategories( gConfigData->hFaxSvc, gConfigData->pFaxLogging, gConfigData->NumberCategories )) {
Error(("Cannot change fax logging category information: %d\n", GetLastError()));
}
ExitSaveFaxConfig:
//
// If an error was encountered, display a message box and return FALSE.
// Otherwise, return TRUE to indicate success.
//
if (errorId != 0) {
DisplayMessageDialog(hDlg, 0, 0, errorId);
return FALSE;
}
if (gConfigData->priorityChanged) {
DisplayMessageDialog(hDlg,
MB_OK | MB_ICONINFORMATION,
IDS_PRIORITY_CHANGE_TITLE,
IDS_PRIORITY_CHANGE_MESSAGE);
gConfigData->priorityChanged = FALSE;
}
return TRUE;
}
VOID
FreeFaxDeviceAndConfigInfo(
VOID
)
/*++
Routine Description:
Dispose of fax device and configuration information
Arguments:
NONE
Return Value:
NONE
--*/
{
PCONFIG_PORT_INFO_2 pDevInfo = gConfigData->pDevInfo;
while (gConfigData->cDevices > 0) {
MemFree(pDevInfo->DeviceName);
MemFree(pDevInfo->TSID);
MemFree(pDevInfo->PrinterName);
MemFree(pDevInfo->DirStore);
MemFree(pDevInfo->ProfileName);
MemFree(pDevInfo->CSID);
gConfigData->cDevices--;
pDevInfo++;
}
MemFree(gConfigData->pDevInfo);
gConfigData->pDevInfo = NULL;
gConfigData->cDevices = 0;
FaxFreeBuffer(gConfigData->pFaxConfig);
gConfigData->pFaxConfig = NULL;
FaxFreeBuffer(gConfigData->pMapiProfiles);
gConfigData->pMapiProfiles = NULL;
}
LPTSTR
DuplicateString(
LPCTSTR pSrcStr
)
/*++
Routine Description:
Make a duplicate of the specified character string
Arguments:
pSrcStr - Specifies the source string to be duplicated
Return Value:
Pointer to the duplicated string, NULL if there is an error
--*/
{
LPTSTR pDestStr;
INT size;
if (pSrcStr == NULL)
return NULL;
size = SizeOfString(pSrcStr);
if (pDestStr = MemAlloc(size))
CopyMemory(pDestStr, pSrcStr, size);
else
Error(("Couldn't duplicate string: %ws\n", pSrcStr));
return pDestStr;
}
VOID
EnableControls(
HWND hDlg,
INT *pCtrlIds,
BOOL enabled
)
/*++
Routine Description:
Enable or disable a set of controls in a dialog
Arguments:
hwnd - Specifies the handle to the dialog window
pCtrlIds - Array of control IDs to be enabled or disabled (0 terminated)
enabled - Whether to enable or disable the specified controls
Return Value:
NONE
--*/
{
while (*pCtrlIds) {
EnableWindow(GetDlgItem(hDlg, *pCtrlIds), enabled);
pCtrlIds++;
}
}
VOID
ShowControls(
HWND hDlg,
INT *pCtrlIds,
BOOL visible
)
/*++
Routine Description:
Show or hide a set of controls in a dialog
Arguments:
hwnd - Specifies the handle to the dialog window
pCtrlIds - Array of control IDs to be shown or hidden (0 terminated)
visible - Whether to show or hide the specified controls
Return Value:
NONE
--*/
{
INT nCmdShow = visible ? SW_SHOW : SW_HIDE;
while (*pCtrlIds) {
ShowWindow(GetDlgItem(hDlg, *pCtrlIds), nCmdShow);
pCtrlIds++;
}
}
VOID
LimitTextFields(
HWND hDlg,
INT *pLimitInfo
)
/*++
Routine Description:
Limit the maximum length for a number of text fields
Arguments:
hDlg - Specifies the handle to the dialog window
pLimitInfo - Array of text field control IDs and their maximum length
ID for the 1st text field, maximum length for the 1st text field
ID for the 2nd text field, maximum length for the 2nd text field
...
0
Note: The maximum length counts the NUL-terminator.
Return Value:
NONE
--*/
{
while (*pLimitInfo != 0) {
SendDlgItemMessage(hDlg, pLimitInfo[0], EM_SETLIMITTEXT, pLimitInfo[1]-1, 0);
pLimitInfo += 2;
}
}
INT
DisplayMessageDialog(
HWND hwndParent,
UINT type,
INT titleStrId,
INT formatStrId,
...
)
/*++
Routine Description:
Display a message dialog box
Arguments:
hwndParent - Specifies a parent window for the error message dialog
type - Specifies the type of message box to be displayed
titleStrId - Title string (could be a string resource ID)
formatStrId - Message format string (could be a string resource ID)
...
Return Value:
Same as the return value from MessageBox
--*/
{
LPTSTR pTitle, pFormat, pMessage;
INT result;
va_list ap;
pTitle = pFormat = pMessage = NULL;
if ((pTitle = AllocStringZ(MAX_TITLE_LEN)) &&
(pFormat = AllocStringZ(MAX_STRING_LEN)) &&
(pMessage = AllocStringZ(MAX_MESSAGE_LEN)))
{
//
// Load dialog box title string resource
//
if (titleStrId == 0)
titleStrId = IDS_ERROR_DLGTITLE;
LoadString(ghInstance, titleStrId, pTitle, MAX_TITLE_LEN);
//
// Load message format string resource
//
LoadString(ghInstance, formatStrId, pFormat, MAX_STRING_LEN);
//
// Compose the message string
//
va_start(ap, formatStrId);
wvsprintf(pMessage, pFormat, ap);
va_end(ap);
//
// Display the message box
//
if (type == 0)
type = MB_OK | MB_ICONERROR;
result = MessageBox(hwndParent, pMessage, pTitle, type);
} else {
MessageBeep(MB_ICONHAND);
result = 0;
}
MemFree(pTitle);
MemFree(pFormat);
MemFree(pMessage);
return result;
}
VOID
ToggleListViewCheckbox(
HWND hwndLV,
INT index
)
/*++
Routine Description:
Toggle the checkbox associated with the specified list view item
Arguments:
hwndLV - Handle to the list view control
index - Specifies the index of the interested item
Return Value:
NONE
--*/
{
UINT state;
if (IsListViewItemChecked(hwndLV, index))
state = UNCHECKED_STATE;
else
state = CHECKED_STATE;
ListView_SetItemState(hwndLV, index, state, LVIS_STATEIMAGEMASK);
}
VOID
InitFaxDeviceListView(
HWND hwndLV,
DWORD flags,
PCOLUMNINFO pColumnInfo
)
/*++
Routine Description:
Initialize the fax device list view
Arguments:
hwndLV - Handle to the fax device list view
flags - Miscellaneous flag bits
pColumnInfo - Specifies columns to be displayed and their relative widths
ID for the 1st column, relative width for the 1st column
ID for the 2nd column, relative width for the 2nd column
...
0, 0
Return Value:
NONE
--*/
{
//
// Column header string resource IDs
//
static INT columnHeaderIDs[MAX_COLUMNS] = {
0,
IDS_DEVICE_NAME_COLUMN,
IDS_CSID_COLUMN,
IDS_TSID_COLUMN,
IDS_STATUS_COLUMN,
};
INT index, nColumns, widthDenom, lvWidth;
RECT rect;
LV_COLUMN lvc;
LV_ITEM lvi;
TCHAR buffer[MAX_TITLE_LEN];
//
// Count the number of columns
//
if (hwndLV == NULL)
return;
nColumns = widthDenom = 0;
while (pColumnInfo[nColumns].columnId) {
widthDenom += pColumnInfo[nColumns].columnWidth;
nColumns++;
}
Assert(nColumns > 0 && nColumns <= MAX_COLUMNS);
Assert(pColumnInfo[0].columnId == COLUMN_DEVICE_NAME);
lvc.mask = LVCF_TEXT;
lvc.pszText = buffer;
lvc.cchTextMax = MAX_TITLE_LEN;
if (ListView_GetColumn(hwndLV, 0, &lvc) && ! IsEmptyString(buffer)) {
//
// The columns have already be inserted
//
ListView_DeleteAllItems(hwndLV);
} else {
//
// This is the first time and the list view is not initialized
// Insert the specified columns into the list view
//
GetClientRect(hwndLV, &rect);
lvWidth = rect.right - rect.left;
//
// Insert a column of check boxes if requested
//
if (flags & LV_HASCHECKBOX) {
HBITMAP hbmp;
HIMAGELIST himl;
if (hbmp = LoadBitmap(ghInstance, MAKEINTRESOURCE(IDB_CHECKSTATES))) {
if (himl = ImageList_Create(16, 16, TRUE, 2, 0)) {
ImageList_AddMasked(himl, hbmp, RGB(255, 0, 0));
ListView_SetImageList(hwndLV, himl, LVSIL_STATE);
} else
Error(("LoadBitmap failed: %d\n", GetLastError()));
DeleteObject(hbmp);
} else
Error(("LoadBitmap failed: %d\n", GetLastError()));
}
//
// Insert list view columns
//
ZeroMemory(&lvc, sizeof(lvc));
lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
lvc.fmt = LVCFMT_LEFT;
lvc.pszText = buffer;
for (index=0; index < nColumns; index++) {
lvc.cx = lvWidth * pColumnInfo[index].columnWidth / widthDenom;
lvc.iSubItem = index;
if (index == nColumns-1)
lvc.cx -= GetSystemMetrics(SM_CXVSCROLL);
LoadString(ghInstance,
columnHeaderIDs[pColumnInfo[index].columnId],
buffer,
MAX_TITLE_LEN);
if (ListView_InsertColumn(hwndLV, index, &lvc) == -1)
Error(("ListView_InsertColumn failed\n"));
}
}
//
// Insert list view items list view content
//
ZeroMemory(&lvi, sizeof(lvi));
lvi.iSubItem = 0;
lvi.mask = LVIF_STATE | LVIF_TEXT;
if (flags & LV_HASCHECKBOX) {
lvi.state = UNCHECKED_STATE;
lvi.stateMask = LVIS_STATEIMAGEMASK;
}
for (index = 0; index < gConfigData->cDevices; index ++) {
//
// The first column is always the device name
//
lvi.iItem = index;
lvi.pszText = gConfigData->pDevInfo[index].DeviceName;
if (ListView_InsertItem(hwndLV, &lvi) == -1) {
Error(("ListView_InsertItem failed\n"));
break;
}
}
//
// Display the remaining columns
//
UpdateFaxDeviceListViewColumns(hwndLV, pColumnInfo, 1);
//
// The initial selection is the first fax device in the list
//
ListView_SetItemState(hwndLV, 0, LVIS_SELECTED|LVIS_FOCUSED, LVIS_SELECTED|LVIS_FOCUSED);
}
LPTSTR
MakeDeviceStatusString(
DWORD state
)
/*++
Routine Description:
Assemble fax device status string
Arguments:
state - Current state of the fax device
Return Value:
Pointer to the device status string, NULL if there is an error
--*/
{
static struct _STATEBITINFO {
DWORD bitFlag;
INT stringId;
} stateBitInfo[] = {
FPS_AVAILABLE, IDS_STATUS_AVAILABLE,
FPS_UNAVAILABLE, IDS_STATUS_UNAVAILABLE,
FPS_SENDING, IDS_STATUS_SENDING,
FPS_RECEIVING, IDS_STATUS_RECEIVING,
FPS_ABORTING, IDS_STATUS_ABORTING,
FPS_ROUTING, IDS_STATUS_ROUTING,
FPS_DIALING, IDS_STATUS_DIALING,
FPS_COMPLETED, IDS_STATUS_COMPLETED,
FPS_HANDLED, IDS_STATUS_HANDLED,
FPS_BUSY, IDS_STATUS_BUSY,
FPS_NO_ANSWER, IDS_STATUS_NO_ANSWER,
FPS_BAD_ADDRESS, IDS_STATUS_BAD_ADDRESS,
FPS_NO_DIAL_TONE, IDS_STATUS_NO_DIAL_TONE,
FPS_DISCONNECTED, IDS_STATUS_DISCONNECTED,
FPS_FATAL_ERROR, IDS_STATUS_FATAL_ERROR,
FPS_NOT_FAX_CALL, IDS_STATUS_NOT_FAX_CALL,
FPS_CALL_DELAYED, IDS_STATUS_CALL_DELAYED,
FPS_CALL_BLACKLISTED, IDS_STATUS_CALL_BLACKLISTED,
FPS_INITIALIZING, IDS_STATUS_INITIALIZING,
FPS_OFFLINE, IDS_STATUS_OFFLINE,
FPS_ANSWERED, IDS_STATUS_ANSWERED
};
LPTSTR pBuffer, p;
INT index, count, statusLen, separatorLen;
BOOL appendSeparator = FALSE;
TCHAR separator[MAX_TITLE_LEN];
//
// Load the string that's used separated status fields
//
if (! LoadString(ghInstance, IDS_STATUS_SEPARATOR, separator, MAX_TITLE_LEN))
_tcscpy(separator, TEXT(", "));
separatorLen = _tcslen(separator);
//
// Calculate how much space we need
//
count = sizeof(stateBitInfo) / sizeof(struct _STATEBITINFO);
for (index=statusLen=0; index < count; index++) {
if ((state & stateBitInfo[index].bitFlag) == stateBitInfo[index].bitFlag) {
TCHAR buffer[MAX_TITLE_LEN];
INT length;
length = LoadString(ghInstance,
stateBitInfo[index].stringId,
buffer,
MAX_TITLE_LEN);
if (length == 0) {
Error(("LoadString failed: %d\n", GetLastError()));
return NULL;
}
statusLen += (length + separatorLen);
}
}
//
// Assemble the status string
//
if (p = pBuffer = MemAllocZ((statusLen + 1) * sizeof(TCHAR))) {
for (index=0; index < count; index++) {
if ((state & stateBitInfo[index].bitFlag) == stateBitInfo[index].bitFlag) {
if (appendSeparator) {
_tcscpy(p, separator);
p += separatorLen;
appendSeparator = FALSE;
}
statusLen = LoadString(ghInstance,
stateBitInfo[index].stringId,
p,
MAX_TITLE_LEN);
if (statusLen > 0) {
p += statusLen;
appendSeparator = TRUE;
} else
Error(("LoadString failed: %d\n", GetLastError()));
}
}
}
return pBuffer;
}
VOID
UpdateFaxDeviceListViewColumns(
HWND hwndLV,
PCOLUMNINFO pColumnInfo,
INT startColumn
)
/*++
Routine Description:
Refresh columns in the fax device list view
Arguments:
hwndLV - Handle to the fax device list view
pColumnInfo - Specifies columns to be redisplayed
startColumn - Specifies the first column index
Return Value:
NONE
--*/
{
LPTSTR pBuffer, pColumnStr;
LV_ITEM lvi;
INT item, nItems, column, nColumns;
//
// Count the number of items in the list view
//
if ((hwndLV == NULL) ||
(nItems = ListView_GetItemCount(hwndLV)) < 0 ||
(nItems > gConfigData->cDevices))
{
return;
}
//
// Count the total number of columns
//
for (nColumns=0; pColumnInfo[nColumns].columnId; nColumns++)
NULL;
ZeroMemory(&lvi, sizeof(lvi));
lvi.mask = LVIF_TEXT;
//
// Go through each item in the list view
//
for (item=0; item < nItems; item++) {
PCONFIG_PORT_INFO_2 pDevInfo = gConfigData->pDevInfo + item;
lvi.iItem = item;
//
// Go through each column for every list view item
//
for (column=startColumn; column < nColumns; column++) {
pBuffer = pColumnStr = NULL;
switch (pColumnInfo[column].columnId) {
case COLUMN_CSID:
pColumnStr = pDevInfo->CSID;
break;
case COLUMN_TSID:
pColumnStr = pDevInfo->TSID;
break;
case COLUMN_STATUS:
pBuffer = pColumnStr = MakeDeviceStatusString(pDevInfo->State);
break;
default:
Assert(FALSE);
break;
}
lvi.iSubItem = column;
lvi.pszText = pColumnStr ? pColumnStr : TEXT("");
if (! ListView_SetItem(hwndLV, &lvi))
Error(("ListView_SetItem failed\n"));
MemFree(pBuffer);
}
}
}
INT
BrowseCallbackProc(
HWND hwnd,
UINT uMsg,
LPARAM lParam,
LPARAM lpData
)
/*++
Routine Description:
Callback function for SHBrowseForFolder
Arguments:
hwnd - Handle to the browse dialog box
uMsg - Identifying the reason for the callback
lParam - Message parameter
lpData - Application-defined value given in BROWSEINFO.lParam
Return Value:
0
--*/
{
if (uMsg == BFFM_INITIALIZED)
SendMessage(hwnd, BFFM_SETSELECTION, TRUE, lpData);
return 0;
}
BOOL
DoBrowseForDirectory(
HWND hDlg,
INT textFieldId,
INT titleStrId
)
/*++
Routine Description:
Browse for a directory
Arguments:
hDlg - Specifies the dialog window on which the Browse button is displayed
textFieldId - Specifies the text field adjacent to the Browse button
titleStrId - Specifies the title to be displayed in the browse window
Return Value:
TRUE if successful, FALSE if the user presses Cancel
--*/
{
LPITEMIDLIST pidl;
TCHAR buffer[MAX_PATH];
TCHAR title[MAX_TITLE_LEN];
VOID SHFree(LPVOID);
BOOL result = FALSE;
BROWSEINFO bi = {
hDlg,
NULL,
buffer,
title,
BIF_RETURNONLYFSDIRS,
BrowseCallbackProc,
(LPARAM) buffer,
};
if (! LoadString(ghInstance, titleStrId, title, MAX_TITLE_LEN))
title[0] = NUL;
if (! GetDlgItemText(hDlg, textFieldId, buffer, MAX_PATH))
buffer[0] = NUL;
if (pidl = SHBrowseForFolder(&bi)) {
if (SHGetPathFromIDList(pidl, buffer)) {
if (_tcslen(buffer) > MAX_ARCHIVE_DIR)
DisplayMessageDialog(hDlg, 0, 0, IDS_DIR_TOO_LONG);
else {
MySetDlgItemText(hDlg, textFieldId, buffer);
result = TRUE;
}
}
SHFree(pidl);
}
return result;
}
BOOL
HandleHelpPopup(
HWND hDlg,
UINT message,
UINT wParam,
LPARAM lParam,
INT pageIndex
)
/*++
Routine Description:
Handle context-sensitive help in property sheet pages
Arguments:
hDlg, message, wParam, lParam - Parameters passed to the dialog procedure
pageIndex - Specifies the index of the current property sheet page
Return Value:
TRUE if the message is handle, FALSE otherwise
--*/
{
static LPDWORD arrayHelpIDs[MAX_PAGES] = {
clientOptionsHelpIDs,
personalCoverPageHelpIDs,
userInfoHelpIDs,
serverOptionsHelpIDs,
serverCoverPageHelpIDs,
sendOptionsHelpIDs,
receiveOptionsHelpIDs,
devicePriorityHelpIDs,
deviceStatusHelpIDs,
loggingHelpIDs,
NULL,
statusMonitorHelpIDs
};
Assert(pageIndex >= 0 && pageIndex < MAX_PAGES);
if (message == WM_HELP) {
WinHelp(((LPHELPINFO) lParam)->hItemHandle,
FAXCFG_HELP_FILENAME,
HELP_WM_HELP,
(DWORD) arrayHelpIDs[pageIndex]);
} else {
WinHelp((HWND) wParam,
FAXCFG_HELP_FILENAME,
HELP_CONTEXTMENU,
(DWORD) arrayHelpIDs[pageIndex]);
}
return TRUE;
}
PFAX_DEVICE_STATUS
FaxSvcGetDeviceStatus(
HANDLE hFaxSvc,
DWORD DeviceId
)
/*++
Routine Description:
Wrapper function for fax service API FaxGetDeviceStatus
Arguments:
hFaxSvc - Specifies a coneection handle to the fax service
DeviceId - Specifies the ID of the interested device
Return Value:
Pointer to a FAX_DEVICE_STATUS structure,
NULL if there is an error
--*/
{
PBYTE pFaxStatus = NULL;
HANDLE FaxPortHandle = NULL;
if ((hFaxSvc == NULL) ||
FaxOpenPort(hFaxSvc, DeviceId, PORT_OPEN_QUERY, &FaxPortHandle) == FALSE ||
!FaxGetDeviceStatus(FaxPortHandle, (PFAX_DEVICE_STATUS*)&pFaxStatus))
{
Error(("FaxGetDeviceStatus failed: %d\n", GetLastError()));
pFaxStatus = NULL;
}
if (FaxPortHandle) {
FaxClose( FaxPortHandle );
}
return (PFAX_DEVICE_STATUS) pFaxStatus;
}