mirror of https://github.com/tongzx/nt5src
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.
716 lines
15 KiB
716 lines
15 KiB
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
faxcpl.c
|
|
|
|
Abstract:
|
|
|
|
Implementation of the control panel applet entry point
|
|
|
|
Environment:
|
|
|
|
Windows NT fax configuration applet
|
|
|
|
Revision History:
|
|
|
|
02/27/96 -davidx-
|
|
Created it.
|
|
|
|
mm/dd/yy -author-
|
|
description
|
|
|
|
--*/
|
|
|
|
#include "faxcpl.h"
|
|
|
|
#include <tapi.h>
|
|
#include "faxdev.h"
|
|
|
|
//
|
|
// Global variable definitions
|
|
//
|
|
|
|
HANDLE ghInstance = NULL; // Fax monitor DLL instance handle
|
|
PCONFIGDATA gConfigData = NULL; // Fax configuration data structure
|
|
INT _debugLevel = 1; // Control the amount of debug messages generated
|
|
|
|
//
|
|
// Setup API for determining whether the user has admin privilege on a machine
|
|
//
|
|
|
|
BOOL
|
|
IsUserAdmin(
|
|
VOID
|
|
);
|
|
|
|
|
|
|
|
extern BOOL WINAPI _CRT_INIT(HANDLE, ULONG, PVOID);
|
|
|
|
BOOL
|
|
DllEntryPoint(
|
|
HANDLE hModule,
|
|
ULONG ulReason,
|
|
PCONTEXT pContext
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
DLL initialization procedure.
|
|
|
|
Arguments:
|
|
|
|
hModule - DLL instance handle
|
|
ulReason - Reason for the call
|
|
pContext - Pointer to context (not used by us)
|
|
|
|
Return Value:
|
|
|
|
TRUE if DLL is initialized successfully, FALSE otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
switch (ulReason) {
|
|
|
|
case DLL_PROCESS_ATTACH:
|
|
#if DBG
|
|
_CRT_INIT(hModule, ulReason, pContext);
|
|
#endif
|
|
|
|
ghInstance = hModule;
|
|
break;
|
|
|
|
case DLL_PROCESS_DETACH:
|
|
|
|
FaxConfigCleanup();
|
|
#if DBG
|
|
_CRT_INIT(hModule, ulReason, pContext);
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
INT
|
|
DetermineFaxConfigType(
|
|
BOOL CplInit
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determine the type of fax installation
|
|
|
|
Arguments:
|
|
|
|
CplInit - if this is TRUE then don't display the message box
|
|
|
|
Return Value:
|
|
|
|
FAXCONFIG_CLIENT - client installation
|
|
FAXCONFIG_WORKSTATION - workstation installation
|
|
FAXCONFIG_SERVER - server installation
|
|
|
|
-1 if there is an error
|
|
|
|
--*/
|
|
|
|
{
|
|
HANDLE FaxHandle = NULL;
|
|
DWORD InstallType;
|
|
DWORD InstalledPlatforms;
|
|
DWORD ProductType;
|
|
HKEY hKey;
|
|
DWORD Size;
|
|
DWORD Type;
|
|
|
|
|
|
//
|
|
// look at the machine registry for an install type
|
|
// if the install type is for a network client, then
|
|
// that is the cpl that we present. if there is a
|
|
// network client and a server installed on this machine
|
|
// then the install type will contain a mask of those
|
|
// two values and this check will fail. this check
|
|
// is here so that on a network client only install
|
|
// we don't go off and try to talk to a server.
|
|
//
|
|
|
|
if (RegOpenKey( HKEY_LOCAL_MACHINE, REGKEY_FAX_SETUP, &hKey ) != ERROR_SUCCESS) {
|
|
return -1;
|
|
}
|
|
|
|
Size = sizeof(InstallType);
|
|
if (RegQueryValueEx( hKey, REGVAL_FAXINSTALL_TYPE, NULL, &Type, (LPBYTE) &InstallType, &Size ) != ERROR_SUCCESS) {
|
|
RegCloseKey( hKey );
|
|
return -1;
|
|
}
|
|
|
|
RegCloseKey( hKey );
|
|
|
|
if (InstallType == FAX_INSTALL_NETWORK_CLIENT ) {
|
|
return FAXCONFIG_CLIENT;
|
|
}
|
|
|
|
if (CplInit) {
|
|
goto noconnect;
|
|
}
|
|
//
|
|
// ask the server for the install type
|
|
//
|
|
|
|
if ((!FaxConnectFaxServer( gConfigData->pServerName, &FaxHandle)) ||
|
|
(!FaxGetInstallType( FaxHandle, &InstallType, &InstalledPlatforms, &ProductType )))
|
|
{
|
|
if (FaxHandle) {
|
|
FaxClose( FaxHandle );
|
|
}
|
|
|
|
DisplayMessageDialog( NULL, 0, 0, IDS_NULL_SERVICE_HANDLE );
|
|
|
|
return -1;
|
|
}
|
|
|
|
FaxClose( FaxHandle );
|
|
|
|
noconnect:
|
|
Verbose(("Fax installation type: 0x%x\n", InstallType));
|
|
|
|
if (InstallType & FAX_INSTALL_SERVER)
|
|
InstallType = FAXCONFIG_SERVER;
|
|
else if (InstallType & FAX_INSTALL_WORKSTATION)
|
|
InstallType = FAXCONFIG_WORKSTATION;
|
|
else
|
|
InstallType = FAXCONFIG_CLIENT;
|
|
|
|
return InstallType;
|
|
}
|
|
|
|
|
|
|
|
LPTSTR
|
|
VerifyServerName(
|
|
LPTSTR pServerName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Verify the server name is well-formed
|
|
|
|
Arguments:
|
|
|
|
pServerName - Specifies the input server name
|
|
|
|
Return Value:
|
|
|
|
Pointer to a copy of the verified server name
|
|
NULL if there is an error
|
|
|
|
--*/
|
|
|
|
{
|
|
LPTSTR pVerifiedName;
|
|
|
|
Assert(pServerName != NULL);
|
|
|
|
if (pVerifiedName = MemAlloc(SizeOfString(pServerName) + 2*sizeof(TCHAR))) {
|
|
|
|
//
|
|
// Make sure the server name always starts with double backslash (\\)
|
|
//
|
|
|
|
pVerifiedName[0] = pVerifiedName[1] = TEXT(PATH_SEPARATOR);
|
|
|
|
while (*pServerName == TEXT(PATH_SEPARATOR))
|
|
pServerName++;
|
|
|
|
_tcscpy(pVerifiedName+2, pServerName);
|
|
}
|
|
|
|
return pVerifiedName;
|
|
}
|
|
|
|
|
|
|
|
INT
|
|
FaxConfigInit(
|
|
LPTSTR pServerName,
|
|
BOOL CplInit
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialize fax configuration DLL
|
|
|
|
Arguments:
|
|
|
|
pServerName - Specifies the name of the fax server machine.
|
|
Pass NULL for local machine.
|
|
|
|
CplInit - TRUE if called due to CPL_INIT message
|
|
|
|
Return Value:
|
|
|
|
-1 - An error has occurred
|
|
FAXCONFIG_CLIENT -
|
|
FAXCONFIG_SERVER -
|
|
FAXCONFIG_WORKSTATION - Indicates the type of configuration the user can run
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// Allocate memory for the fax configuration data structure
|
|
//
|
|
|
|
Assert(gConfigData == NULL);
|
|
|
|
if (! (gConfigData = MemAllocZ(sizeof(CONFIGDATA)))) {
|
|
|
|
Error(("Memory allocation failed\n"));
|
|
return -1;
|
|
}
|
|
|
|
gConfigData->startSign = gConfigData->endSign = gConfigData;
|
|
|
|
//
|
|
// Make sure the server name is well-formed
|
|
// Determine the type of fax configuration to be run
|
|
//
|
|
|
|
if ((pServerName && !(gConfigData->pServerName = VerifyServerName(pServerName))) ||
|
|
(gConfigData->configType = DetermineFaxConfigType(CplInit)) < 0)
|
|
{
|
|
FaxConfigCleanup();
|
|
return -1;
|
|
}
|
|
|
|
return gConfigData->configType;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
FaxConfigCleanup(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Deinitialize fax configuration DLL
|
|
|
|
Arguments:
|
|
|
|
NONE
|
|
|
|
Return Value:
|
|
|
|
NONE
|
|
|
|
--*/
|
|
|
|
{
|
|
if (gConfigData != NULL) {
|
|
|
|
Assert(ValidConfigData(gConfigData));
|
|
|
|
//
|
|
// Disconnect from the fax service if we're currently connected
|
|
//
|
|
|
|
if (gConfigData->hFaxSvc)
|
|
FaxClose(gConfigData->hFaxSvc);
|
|
|
|
//
|
|
// Free up memory used to hold various information:
|
|
// printer information
|
|
// form information
|
|
// port information
|
|
//
|
|
|
|
FreeFaxDeviceAndConfigInfo();
|
|
|
|
FreeCoverPageInfo(gConfigData->pCPInfo);
|
|
MemFree(gConfigData->pServerName);
|
|
MemFree(gConfigData);
|
|
gConfigData = NULL;
|
|
|
|
DeinitTapiService();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Information about each fax configuration page
|
|
//
|
|
|
|
typedef struct _FAXCFG_PAGEINFO {
|
|
|
|
INT dialogId;
|
|
DLGPROC dialogProc;
|
|
|
|
} FAXCFG_PAGEINFO, *PFAXCFG_PAGEINFO;
|
|
|
|
static FAXCFG_PAGEINFO ClientConfigPageInfo[] = {
|
|
|
|
{ IDD_CLIENT_COVERPG, ClientCoverPageProc },
|
|
{ IDD_USER_INFO, UserInfoProc }
|
|
};
|
|
|
|
static FAXCFG_PAGEINFO ServerConfigPageInfo[] = {
|
|
|
|
{ IDD_SERVER_OPTIONS, ServerOptionsProc },
|
|
{ IDD_SERVER_COVERPG, ServerCoverPageProc },
|
|
{ IDD_SEND_OPTIONS, SendOptionsProc },
|
|
{ IDD_RECEIVE_OPTIONS, ReceiveOptionsProc },
|
|
{ IDD_DEVICE_PRIORITY, DevicePriorityProc },
|
|
{ IDD_DEVICE_STATUS, DeviceStatusProc },
|
|
{ IDD_LOGGING, DiagLogProc },
|
|
{ IDD_SERVER_GENERAL, GeneralProc }
|
|
};
|
|
|
|
static FAXCFG_PAGEINFO WorkstationConfigPageInfo[] = {
|
|
|
|
{ IDD_CLIENT_COVERPG, ClientCoverPageProc },
|
|
{ IDD_USER_INFO, UserInfoProc },
|
|
|
|
{ IDD_SERVER_OPTIONS, ServerOptionsProc },
|
|
{ IDD_SEND_OPTIONS, SendOptionsProc },
|
|
{ IDD_RECEIVE_OPTIONS, ReceiveOptionsProc },
|
|
{ IDD_LOGGING, DiagLogProc },
|
|
{ IDD_STATUS_OPTIONS, StatusOptionsProc }
|
|
};
|
|
|
|
#define MAX_CLIENT_PAGES (sizeof(ClientConfigPageInfo) / sizeof(FAXCFG_PAGEINFO))
|
|
#define MAX_SERVER_PAGES (sizeof(ServerConfigPageInfo) / sizeof(FAXCFG_PAGEINFO))
|
|
#define MAX_WORKSTATION_PAGES (sizeof(WorkstationConfigPageInfo) / sizeof(FAXCFG_PAGEINFO))
|
|
|
|
|
|
|
|
INT
|
|
FaxConfigGetPageHandles(
|
|
HPROPSHEETPAGE *phPropSheetPages,
|
|
INT count,
|
|
PFAXCFG_PAGEINFO pPageInfo,
|
|
INT nPages
|
|
)
|
|
|
|
{
|
|
//
|
|
// Zero-initialize the input buffer
|
|
//
|
|
|
|
if (count > 0) {
|
|
|
|
if (phPropSheetPages == NULL) {
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return -1;
|
|
}
|
|
|
|
ZeroMemory(phPropSheetPages, sizeof(HPROPSHEETPAGE) * count);
|
|
}
|
|
|
|
//
|
|
// Make sure the input buffer is large enough to hold all available pages
|
|
//
|
|
|
|
if (count >= nPages) {
|
|
|
|
PROPSHEETPAGE psp;
|
|
INT index;
|
|
|
|
|
|
ZeroMemory(&psp, sizeof(psp));
|
|
psp.dwSize = sizeof(PROPSHEETPAGE);
|
|
psp.hInstance = ghInstance;
|
|
psp.lParam = (LPARAM) gConfigData;
|
|
|
|
for (index=0; index < nPages; index++) {
|
|
|
|
//
|
|
// Create property page handles
|
|
//
|
|
|
|
psp.pszTemplate = MAKEINTRESOURCE(pPageInfo[index].dialogId);
|
|
psp.pfnDlgProc = pPageInfo[index].dialogProc;
|
|
|
|
if (! (phPropSheetPages[index] = CreatePropertySheetPage(&psp))) {
|
|
|
|
Error(("CreatePropertySheetPage failed: %d\n", GetLastError()));
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we failed to create handles for all property pages,
|
|
// we must destroy any handles we already created.
|
|
//
|
|
|
|
if (index < nPages) {
|
|
|
|
while (--index >= 0)
|
|
DestroyPropertySheetPage(phPropSheetPages[index]);
|
|
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return nPages;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
DoConnectFaxService(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Connect to the fax service if necessary
|
|
|
|
Arguments:
|
|
|
|
NONE
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, FALSE otherwise
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD InstallType;
|
|
DWORD InstalledPlatforms;
|
|
DWORD ProductType;
|
|
|
|
Assert(ValidConfigData(gConfigData));
|
|
Assert(gConfigData->configType == FAXCONFIG_SERVER ||
|
|
gConfigData->configType == FAXCONFIG_WORKSTATION);
|
|
|
|
if ((! gConfigData->hFaxSvc &&
|
|
! FaxConnectFaxServer(gConfigData->pServerName, &gConfigData->hFaxSvc)) ||
|
|
! FaxGetInstallType( gConfigData->hFaxSvc, &InstallType, &InstalledPlatforms, &ProductType ))
|
|
{
|
|
DisplayMessageDialog(NULL, 0, 0, IDS_NO_FAX_SERVICE);
|
|
gConfigData->hFaxSvc = NULL;
|
|
}
|
|
|
|
return (gConfigData->hFaxSvc != NULL);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Get an array of handles to client/server/workstation configuration pages
|
|
//
|
|
// Parameters:
|
|
//
|
|
// phPropSheetPages - Specifies a buffer for storing property page handles
|
|
// count - Specifies the maximum number of handles the input buffer can hold
|
|
//
|
|
// Return value:
|
|
//
|
|
// -1 - An error has occurred
|
|
// >0 - Total number of configuration pages available
|
|
//
|
|
// Note:
|
|
//
|
|
// To figure out how large the input buffer should be, the caller can
|
|
// first call these functions with phPropSheetPages set to NULL and
|
|
// count set to 0.
|
|
//
|
|
|
|
INT
|
|
FaxConfigGetClientPages(
|
|
HPROPSHEETPAGE *phPropSheetPages,
|
|
INT count
|
|
)
|
|
|
|
{
|
|
//
|
|
// We can only display client pages for non-workstation configuration types
|
|
//
|
|
|
|
if (!ValidConfigData(gConfigData) || gConfigData->configType == FAXCONFIG_WORKSTATION) {
|
|
|
|
SetLastError(ERROR_INVALID_FUNCTION);
|
|
return -1;
|
|
}
|
|
|
|
return FaxConfigGetPageHandles(phPropSheetPages,
|
|
count,
|
|
ClientConfigPageInfo,
|
|
MAX_CLIENT_PAGES);
|
|
}
|
|
|
|
|
|
INT
|
|
GetDeviceProviderPages(
|
|
HPROPSHEETPAGE *phPropSheetPages,
|
|
INT count
|
|
)
|
|
{
|
|
HKEY hKey, hKeyDev;
|
|
DWORD PageCnt = 0;
|
|
DWORD Index = 0;
|
|
WCHAR KeyName[MAX_PATH+1];
|
|
WCHAR ImageName[MAX_PATH+1];
|
|
HMODULE hMod;
|
|
PFAXDEVCONFIGURE pFaxDevConfigure;
|
|
DWORD Size;
|
|
DWORD Type;
|
|
|
|
|
|
if (RegOpenKey( HKEY_LOCAL_MACHINE, REGKEY_DEVICE_PROVIDER_KEY, &hKey ) != ERROR_SUCCESS) {
|
|
return PageCnt;
|
|
}
|
|
|
|
while( RegEnumKey( hKey, Index, KeyName, sizeof(KeyName)/sizeof(WCHAR) ) == ERROR_SUCCESS) {
|
|
|
|
if (RegOpenKey( hKey, KeyName, &hKeyDev ) == ERROR_SUCCESS) {
|
|
|
|
Size = sizeof(KeyName);
|
|
if (RegQueryValueEx( hKeyDev, REGVAL_IMAGE_NAME, 0, &Type, (LPBYTE)KeyName, &Size ) == ERROR_SUCCESS) {
|
|
|
|
ExpandEnvironmentStrings( KeyName, ImageName, sizeof(ImageName)/sizeof(TCHAR) );
|
|
|
|
hMod = LoadLibrary( ImageName );
|
|
if (hMod) {
|
|
pFaxDevConfigure = (PFAXDEVCONFIGURE) GetProcAddress( hMod, "FaxDevConfigure" );
|
|
if (pFaxDevConfigure) {
|
|
//
|
|
// this device provider supports configuration
|
|
// lets call the dll and get the pages
|
|
//
|
|
if (pFaxDevConfigure( &phPropSheetPages[PageCnt] )) {
|
|
PageCnt += 1;
|
|
}
|
|
} else {
|
|
FreeLibrary( hMod );
|
|
}
|
|
}
|
|
}
|
|
RegCloseKey( hKeyDev );
|
|
}
|
|
if (PageCnt == (DWORD) count) {
|
|
break;
|
|
}
|
|
Index += 1;
|
|
}
|
|
|
|
RegCloseKey( hKey );
|
|
|
|
return PageCnt;
|
|
}
|
|
|
|
|
|
INT
|
|
FaxConfigGetServerPages(
|
|
HPROPSHEETPAGE *phPropSheetPages,
|
|
INT count
|
|
)
|
|
|
|
{
|
|
DWORD DevPages = 0;
|
|
DWORD SvrPages = 0;
|
|
|
|
|
|
//
|
|
// We can only display server pages for server configuration type
|
|
//
|
|
|
|
if (!ValidConfigData(gConfigData) || gConfigData->configType != FAXCONFIG_SERVER) {
|
|
|
|
SetLastError(ERROR_INVALID_FUNCTION);
|
|
return -1;
|
|
}
|
|
|
|
if (!DoConnectFaxService()) {
|
|
return -1;
|
|
}
|
|
|
|
SvrPages = FaxConfigGetPageHandles(
|
|
phPropSheetPages,
|
|
count,
|
|
ServerConfigPageInfo,
|
|
MAX_SERVER_PAGES
|
|
);
|
|
if (SvrPages) {
|
|
count -= SvrPages;
|
|
phPropSheetPages += SvrPages;
|
|
}
|
|
|
|
DevPages = GetDeviceProviderPages( phPropSheetPages, count );
|
|
if (DevPages) {
|
|
count -= DevPages;
|
|
phPropSheetPages += DevPages;
|
|
}
|
|
|
|
return SvrPages + DevPages;
|
|
}
|
|
|
|
|
|
INT
|
|
FaxConfigGetWorkstationPages(
|
|
HPROPSHEETPAGE *phPropSheetPages,
|
|
INT count
|
|
)
|
|
|
|
{
|
|
DWORD DevPages = 0;
|
|
DWORD WksPages = 0;
|
|
|
|
|
|
//
|
|
// We can only display workstation pages for workstation configuration type
|
|
//
|
|
|
|
if (!ValidConfigData(gConfigData) || gConfigData->configType != FAXCONFIG_WORKSTATION) {
|
|
|
|
SetLastError(ERROR_INVALID_FUNCTION);
|
|
return -1;
|
|
}
|
|
|
|
if (! DoConnectFaxService())
|
|
return -1;
|
|
|
|
WksPages = FaxConfigGetPageHandles(
|
|
phPropSheetPages,
|
|
count,
|
|
WorkstationConfigPageInfo,
|
|
MAX_WORKSTATION_PAGES
|
|
);
|
|
if (WksPages) {
|
|
count -= WksPages;
|
|
phPropSheetPages += WksPages;
|
|
}
|
|
|
|
DevPages = GetDeviceProviderPages( phPropSheetPages, count );
|
|
if (DevPages) {
|
|
count -= DevPages;
|
|
phPropSheetPages += DevPages;
|
|
}
|
|
|
|
return WksPages + DevPages;
|
|
}
|