/*++ 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 #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; }