/*++ Copyright (c) 1998 Microsoft Corporation Module Name: faxqueue.cpp Abstract: This module implements the fax queue viewer Environment: WIN32 User Mode Author: Wesley Witt (wesw) 9-june-1997 Steven Kehrli (steveke) 30-oct-1998 - major rewrite --*/ #include "faxqueue.h" HINSTANCE g_hInstance; // g_hInstance is the handle to the instance HWND g_hWndMain; // g_hWndMain is the handle to the parent window HWND g_hWndListView; // g_hWndListView is the handle to the list view window HWND g_hWndToolbar; // g_hWndToolbar is the handle to the toolbar LPTSTR g_szTitleConnected; // g_szTitleConnected is the window title when connected LPTSTR g_szTitleNotConnected; // g_szTitleNotConnected is the window title when not connected LPTSTR g_szTitleConnecting; // g_szTitleConnecting is the window title when connecting LPTSTR g_szTitleRefreshing; // g_szTitleRefreshing is the window title when refreshing LPTSTR g_szTitlePaused; // g_szTitlePaused is the window title when paused LPTSTR g_szCurrentUserName; // g_szCurrentUserName is the name of the current user HANDLE g_hStartEvent; // g_hStartEvent is the handle to an event indicating the fax event queue exists HANDLE g_hExitEvent; // g_hExitEvent is the handle to an event indicating the application is exiting LPTSTR g_szMachineName; // g_szMachineName is the machine to connect to HANDLE g_hFaxSvcMutex; // g_hFaxSvcMutex is an object to synchronize access to the fax service routines HANDLE g_hFaxSvcHandle; // g_hFaxSvcHandle is the handle to the fax service LONG g_nNumConnections; // g_nNumConnections is the number of connections to the fax service HANDLE g_hCompletionPort; // g_hCompletionPort is the handle to the completion port WINPOSINFO WinPosInfo = { #ifdef DEBUG FALSE, #endif // DEBUG #ifdef TOOLBAR_ENABLED FALSE, // toolbar #endif // TOOLBAR_ENABLED TRUE, // status bar 200, // eDocumentName 80, // eJobType 80, // eStatus 80, // eOwner 60, // ePages 100, // eSize 140, // eScheduledTime 120, // ePort {sizeof(WINDOWPLACEMENT), 0, SW_SHOWNORMAL, {0, 0}, {0, 0}, {50, 100, 695, 300}} }; DWORD DocumentPropertiesHelpIDs[] = { IDC_FAX_DOCUMENTNAME, IDH_QUEUE_DOCUMENTNAME, IDC_FAX_RECIPIENTINFO, IDH_QUEUE_RECIPIENTINFO, IDC_FAX_RECIPIENTNAME_TEXT, IDH_QUEUE_RECIPIENTNAME, IDC_FAX_RECIPIENTNAME, IDH_QUEUE_RECIPIENTNAME, IDC_FAX_RECIPIENTNUMBER_TEXT, IDH_QUEUE_RECIPIENTNUMBER, IDC_FAX_RECIPIENTNUMBER, IDH_QUEUE_RECIPIENTNUMBER, IDC_FAX_SENDERINFO, IDH_QUEUE_SENDERINFO, IDC_FAX_SENDERNAME_TEXT, IDH_QUEUE_SENDERNAME, IDC_FAX_SENDERNAME, IDH_QUEUE_SENDERNAME, IDC_FAX_SENDERCOMPANY_TEXT, IDH_QUEUE_SENDERCOMPANY, IDC_FAX_SENDERCOMPANY, IDH_QUEUE_SENDERCOMPANY, IDC_FAX_SENDERDEPT_TEXT, IDH_QUEUE_SENDERDEPT, IDC_FAX_SENDERDEPT, IDH_QUEUE_SENDERDEPT, IDC_FAX_BILLINGCODE_TEXT, IDH_QUEUE_BILLINGCODE, IDC_FAX_BILLINGCODE, IDH_QUEUE_BILLINGCODE, IDC_FAX_FAXINFO, IDH_QUEUE_FAXINFO, IDC_FAX_JOBTYPE_TEXT, IDH_QUEUE_JOBTYPE, IDC_FAX_JOBTYPE, IDH_QUEUE_JOBTYPE, IDC_FAX_STATUS_TEXT, IDH_QUEUE_STATUS, IDC_FAX_STATUS, IDH_QUEUE_STATUS, IDC_FAX_PAGES_TEXT, IDH_QUEUE_PAGES, IDC_FAX_PAGES, IDH_QUEUE_PAGES, IDC_FAX_SIZE_TEXT, IDH_QUEUE_SIZE, IDC_FAX_SIZE, IDH_QUEUE_SIZE, IDC_FAX_SCHEDULEDTIME_TEXT, IDH_QUEUE_SCHEDULEDTIME, IDC_FAX_SCHEDULEDTIME, IDH_QUEUE_SCHEDULEDTIME, 0, 0 }; // MainWndProc is the parent window procedure LRESULT CALLBACK MainWndProc (HWND hWndMain, UINT iMsg, WPARAM wParam, LPARAM lParam); // SelectFaxPrinterDlgProc is the select fax printer dialog procedure INT_PTR CALLBACK SelectFaxPrinterDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam); // DocumentPropertiesDlgProc is the select fax printer dialog procedure INT_PTR CALLBACK DocumentPropertiesDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam); // EnumThreadWndProc is the callback function for the EnumThreadWindows call BOOL CALLBACK EnumThreadWndProc(HWND hWnd, LPARAM lParam); // PostEventToCompletionPort posts an exit packet to a completion port VOID PostEventToCompletionPort(HANDLE hCompletionPort, DWORD dwEventId, DWORD dwJobId); // FaxEventThread is the thread to handle the fax events DWORD FaxEventThread (LPVOID lpv); extern "C" int __cdecl _tmain( int argc, LPTSTR argv[] ) { WNDCLASSEX wndclass; MSG msg; // bStarted indicates if the application has started BOOL bStarted; // szFormat is a format string TCHAR szFormat[RESOURCE_STRING_LEN]; // szComputerName is the local computer name LPTSTR szComputerName; DWORD dwComputerNameSize; // hThread is the handle to a thread HANDLE hThread; // hAccel is the handle to the accelerators HACCEL hAccel; DWORD dwReturn; DWORD cb; // Set g_hInstance g_hInstance = GetModuleHandle(NULL); // Set bStarted to FALSE to indicate the application has not started bStarted = FALSE; // Get the machine name g_szMachineName = NULL; if (argc == 2) { // Allocate the memory for the machine name g_szMachineName = (LPTSTR) MemAlloc((lstrlen(argv[1]) + 1) * sizeof(TCHAR)); if (g_szMachineName) { // Copy the machine name lstrcpy(g_szMachineName, argv[1]); // Allocate the memory for the local computer name dwComputerNameSize = MAX_COMPUTERNAME_LENGTH + 1; szComputerName = (LPTSTR) MemAlloc((MAX_COMPUTERNAME_LENGTH + 1) * sizeof(TCHAR)); if (szComputerName) { // Get the local computer name if (GetComputerName(szComputerName, &dwComputerNameSize)) { // Compare the local computer name against the machine name if (!lstrcmpi(g_szMachineName, szComputerName)) { // Local computer name and machine name are the same, so set machine name to NULL MemFree(g_szMachineName); g_szMachineName = NULL; } } MemFree(szComputerName); } } } // Set the window title when connected if (g_szMachineName) { // Convert the machine name to uppercase g_szMachineName = CharUpper(g_szMachineName); LoadString(g_hInstance, IDS_FAXQUEUE_REMOTE_CAPTION, szFormat, RESOURCE_STRING_LEN); // Allocate the memory for the window title g_szTitleConnected = (LPTSTR) MemAlloc((lstrlen(szFormat) + lstrlen(g_szMachineName) + 1) * sizeof(TCHAR)); if (!g_szTitleConnected) { // Set the exit code dwReturn = GetLastError(); goto ExitLevel0; } wsprintf(g_szTitleConnected, szFormat, g_szMachineName); } else { LoadString(g_hInstance, IDS_FAXQUEUE_LOCAL_CAPTION, szFormat, RESOURCE_STRING_LEN); // Allocate the memory for the window title g_szTitleConnected = (LPTSTR) MemAlloc((lstrlen(szFormat) + 1) * sizeof(TCHAR)); if (!g_szTitleConnected) { // Set the exit code dwReturn = GetLastError(); goto ExitLevel0; } lstrcpy(g_szTitleConnected, szFormat); } // Set the window title when not connected LoadString(g_hInstance, IDS_FAXQUEUE_NOT_CONNECTED, szFormat, RESOURCE_STRING_LEN); // Allocate the memory for the window title g_szTitleNotConnected = (LPTSTR) MemAlloc((lstrlen(g_szTitleConnected) + lstrlen(szFormat) + 1) * sizeof(TCHAR)); if (!g_szTitleNotConnected) { // Set the exit code dwReturn = GetLastError(); goto ExitLevel1; } lstrcpy(g_szTitleNotConnected, g_szTitleConnected); lstrcat(g_szTitleNotConnected, szFormat); // Set the window title when connecting LoadString(g_hInstance, IDS_FAXQUEUE_CONNECTING, szFormat, RESOURCE_STRING_LEN); // Allocate the memory for the window title g_szTitleConnecting = (LPTSTR) MemAlloc((lstrlen(g_szTitleConnected) + lstrlen(szFormat) + 1) * sizeof(TCHAR)); if (!g_szTitleConnecting) { // Set the exit code dwReturn = GetLastError(); goto ExitLevel2; } lstrcpy(g_szTitleConnecting, g_szTitleConnected); lstrcat(g_szTitleConnecting, szFormat); // Set the window title when refreshing LoadString(g_hInstance, IDS_FAXQUEUE_REFRESHING, szFormat, RESOURCE_STRING_LEN); // Allocate the memory for the window title g_szTitleRefreshing = (LPTSTR) MemAlloc((lstrlen(g_szTitleConnected) + lstrlen(szFormat) + 1) * sizeof(TCHAR)); if (!g_szTitleRefreshing) { // Set the exit code dwReturn = GetLastError(); goto ExitLevel3; } lstrcpy(g_szTitleRefreshing, g_szTitleConnected); lstrcat(g_szTitleRefreshing, szFormat); // Set the window title when paused LoadString(g_hInstance, IDS_FAXQUEUE_PAUSED, szFormat, RESOURCE_STRING_LEN); // Allocate the memory for the window title g_szTitlePaused = (LPTSTR) MemAlloc((lstrlen(g_szTitleConnected) + lstrlen(szFormat) + 1) * sizeof(TCHAR)); if (!g_szTitlePaused) { // Set the exit code dwReturn = GetLastError(); goto ExitLevel4; } lstrcpy(g_szTitlePaused, g_szTitleConnected); lstrcat(g_szTitlePaused, szFormat); g_hWndMain = NULL; // Find the window g_hWndMain = FindWindow(FAXQUEUE_WINCLASS, g_szTitlePaused); if (g_hWndMain) { goto ExitLevel5; } // Find the window g_hWndMain = FindWindow(FAXQUEUE_WINCLASS, g_szTitleRefreshing); if (g_hWndMain) { goto ExitLevel5; } // Find the window g_hWndMain = FindWindow(FAXQUEUE_WINCLASS, g_szTitleConnecting); if (g_hWndMain) { goto ExitLevel5; } // Find the window g_hWndMain = FindWindow(FAXQUEUE_WINCLASS, g_szTitleNotConnected); if (g_hWndMain) { goto ExitLevel5; } // Find the window g_hWndMain = FindWindow(FAXQUEUE_WINCLASS, g_szTitleConnected); if (g_hWndMain) { goto ExitLevel5; } // Create the g_hStartEvent g_hStartEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (!g_hStartEvent) { // Set the exit code dwReturn = GetLastError(); goto ExitLevel5; } // Create the g_hExitEvent g_hExitEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (!g_hExitEvent) { // Set the exit code dwReturn = GetLastError(); goto ExitLevel6; } // Initialize the fax service g_hFaxSvcMutex = CreateMutex(NULL, FALSE, NULL); if (!g_hFaxSvcMutex) { // Set the exit code dwReturn = GetLastError(); goto ExitLevel7; } g_hFaxSvcHandle = NULL; g_nNumConnections = 0; hThread = CreateThread(NULL, 0, FaxEventThread, NULL, 0, NULL); if (!hThread) { // Set the exit code dwReturn = GetLastError(); goto ExitLevel8; } CloseHandle(hThread); // Load the accelerators hAccel = LoadAccelerators(g_hInstance, MAKEINTRESOURCE(IDR_ACCEL)); if (!hAccel) { // Set the exit code dwReturn = GetLastError(); goto ExitLevel9; } // Get the name of the current user cb = 0; GetUserName(NULL, &cb); g_szCurrentUserName = (LPTSTR) MemAlloc((cb + 1) * sizeof(TCHAR)); if (!GetUserName(g_szCurrentUserName, &cb)) { MemFree(g_szCurrentUserName); g_szCurrentUserName = NULL; } // Retrieve the persistent data GetFaxQueueRegistryData(&WinPosInfo); // Initialize the common controls InitCommonControls(); // Set bStarted to TRUE to indicate the application has started bStarted = TRUE; // Initialize the wndclass wndclass.cbSize = sizeof(wndclass); wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = MainWndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = g_hInstance; wndclass.hIcon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_FAXQUEUE_ICON)); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1); wndclass.lpszMenuName = MAKEINTRESOURCE(IDR_MENU); wndclass.lpszClassName = FAXQUEUE_WINCLASS; wndclass.hIconSm = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_FAXQUEUE_ICON)); RegisterClassEx(&wndclass); g_hWndMain = CreateWindow(FAXQUEUE_WINCLASS, g_szTitleConnecting, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, g_hInstance, NULL); // Move and show the window SetWindowPlacement(g_hWndMain, &WinPosInfo.WindowPlacement); ShowWindow(g_hWndMain, SW_SHOWNORMAL); UpdateWindow(g_hWndMain); // Set the start event SetEvent(g_hStartEvent); while (GetMessage(&msg, NULL, 0, 0)) { if (!TranslateAccelerator(g_hWndMain, hAccel, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } if (g_szCurrentUserName) { MemFree(g_szCurrentUserName); } ExitLevel9: SetEvent(g_hExitEvent); ExitLevel8: CloseHandle(g_hFaxSvcMutex); ExitLevel7: CloseHandle(g_hExitEvent); ExitLevel6: CloseHandle(g_hStartEvent); ExitLevel5: if ((g_hWndMain) && (!bStarted)) { // g_hWndMain is valid but the application has not started, so it must already be running // Switch to that window ShowWindow(g_hWndMain, SW_RESTORE); SetForegroundWindow(g_hWndMain); // Set the exit code dwReturn = 0; // Set bStarted to TRUE to indicate the application has started bStarted = TRUE; } MemFree(g_szTitlePaused); ExitLevel4: MemFree(g_szTitleRefreshing); ExitLevel3: MemFree(g_szTitleConnecting); ExitLevel2: MemFree(g_szTitleNotConnected); ExitLevel1: MemFree(g_szTitleConnected); ExitLevel0: if (g_szMachineName) { MemFree(g_szMachineName); } if (!bStarted) { // szErrorCaption is the error caption if the application cannot start TCHAR szErrorCaption[RESOURCE_STRING_LEN]; // szErrorFormat is the format of the error message if the application cannot start TCHAR szErrorFormat[RESOURCE_STRING_LEN]; // szErrorReason is the error reason if the application cannot start LPTSTR szErrorReason; // szErrorMessage is the error message if the application cannot start LPTSTR szErrorMessage; // The application did not start so display an error message // Load the error caption LoadString(g_hInstance, IDS_ERROR_CAPTION, szErrorCaption, RESOURCE_STRING_LEN); // Try to get the error message from the system message table szErrorMessage = NULL; if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwReturn, 0, (LPTSTR) &szErrorReason, 0, NULL)) { // Load the error format LoadString(g_hInstance, IDS_ERROR_APP_FAILED_FORMAT, szErrorFormat, RESOURCE_STRING_LEN); // Allocate the memory for the error message szErrorMessage = (LPTSTR) MemAlloc((lstrlen(szErrorReason) + RESOURCE_STRING_LEN + 1) * sizeof(TCHAR)); if (szErrorMessage) { // Set the error message wsprintf(szErrorMessage, szErrorFormat, szErrorReason); } LocalFree(szErrorReason); } if (!szErrorMessage) { // Allocate the memory for the error message szErrorMessage = (LPTSTR) MemAlloc((RESOURCE_STRING_LEN) * sizeof(TCHAR)); if (szErrorMessage) { // Load the error message LoadString(g_hInstance, IDS_ERROR_APP_FAILED, szErrorMessage, RESOURCE_STRING_LEN); } } if (szErrorMessage) { // Display the error message MessageBox(NULL, szErrorMessage, szErrorCaption, MB_OK | MB_ICONERROR | MB_APPLMODAL); MemFree(szErrorMessage); } } return dwReturn; } LRESULT CALLBACK MainWndProc (HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { // rcClient is the rectangle of the client area RECT rcClient; // hWndToolTips is the handle to the tool tips window static HWND hWndToolTips; // rcToolbar is the rectangle of the toolbar static RECT rcToolbar; // hWndStatusBar is the handle to the status bar static HWND hWndStatusBar; // rcStatusBar is the rectangle of the status bar static RECT rcStatusBar; // hFaxMenu is the handle to the fax menu static HMENU hFaxMenu; // hFaxSetAsDefaultMenu is the handle to the set as default printer menu static HMENU hFaxSetAsDefaultMenu; // hFaxSharingMenu is the handle to the sharing menu static HMENU hFaxSharingMenu; // hFaxPropertiesMenu is the handle to the properties menu static HMENU hFaxPropertiesMenu; // hDocumentMenu is the handle to the document menu static HMENU hDocumentMenu; // hViewMenu is the handle to the view menu static HMENU hViewMenu; // uCurrentMenu indicates the current menu selection static UINT uCurrentMenu; // pProcessInfoList is a pointer to the process info list static PLIST_ENTRY pProcessInfoList; switch (iMsg) { case WM_CREATE: // lvc specifies the attributes of a particular column of the list view LV_COLUMN lvc; // nColumnIndex is used to enumerate each column of the list view INT nColumnIndex; // szColumnHeader is the column header text TCHAR szColumnHeader[RESOURCE_STRING_LEN]; // Set pProcessInfoList to NULL pProcessInfoList = NULL; // Get the handle to the fax menu hFaxMenu = GetSubMenu(GetMenu(hWnd), 0); // Initialize the set as default printer menu hFaxSetAsDefaultMenu = NULL; // Initialize the sharing menu hFaxSharingMenu = NULL; // Initialize the properties menu hFaxPropertiesMenu = NULL; // Disable the pause faxing menu item and the cancel all faxes menu item EnableMenuItem(hFaxMenu, IDM_FAX_PAUSE_FAXING, MF_BYCOMMAND | MF_GRAYED); EnableMenuItem(hFaxMenu, IDM_FAX_CANCEL_ALL_FAXES, MF_BYCOMMAND | MF_GRAYED); #ifdef TOOLBAR_ENABLED // Disable the pause faxing toolbar menu item and the cancel all faxes toolbar menu item EnableToolbarMenuState(g_hWndToolbar, IDM_FAX_PAUSE_FAXING, FALSE); EnableToolbarMenuState(g_hWndToolbar, IDM_FAX_CANCEL_ALL_FAXES, FALSE); #endif // TOOLBAR_ENABLED #ifdef WIN95 // Disable the sharing menu item EnableMenuItem(hFaxMenu, 5, MF_BYPOSITION | MF_GRAYED); // Disable the properties menu item EnableMenuItem(hFaxMenu, 7, MF_BYPOSITION | MF_GRAYED); #endif // WIN95 // Get the handle to the document menu hDocumentMenu = GetSubMenu(GetMenu(hWnd), 1); // Get the handle to the view menu hViewMenu = GetSubMenu(GetMenu(hWnd), 2); #ifdef TOOLBAR_ENABLED // Set the toolbar if (WinPosInfo.bToolbarVisible) { // Show the toolbar hWndToolTips = CreateToolTips(hWnd); g_hWndToolbar = CreateToolbar(hWnd); // Get the rectangle of the status bar GetWindowRect(g_hWndToolbar, &rcToolbar); } else { ZeroMemory(&rcToolbar, sizeof(rcToolbar)); } // Check the menu item CheckMenuItem(hViewMenu, IDM_VIEW_TOOLBAR, MF_BYCOMMAND | (WinPosInfo.bToolbarVisible ? MF_CHECKED : MF_UNCHECKED)); #else ZeroMemory(&rcToolbar, sizeof(rcToolbar)); #endif // TOOLBAR_ENABLED // Set the status bar if (WinPosInfo.bStatusBarVisible) { // Show the status bar hWndStatusBar = CreateStatusWindow(WS_CHILD | WS_CLIPSIBLINGS | WS_TABSTOP | WS_VISIBLE | SBARS_SIZEGRIP, NULL, hWnd, IDM_STATUS_BAR); // Get the rectangle of the status bar GetWindowRect(hWndStatusBar, &rcStatusBar); } else { ZeroMemory(&rcStatusBar, sizeof(rcStatusBar)); } // Check the menu item CheckMenuItem(hViewMenu, IDM_VIEW_STATUS_BAR, MF_BYCOMMAND | (WinPosInfo.bStatusBarVisible ? MF_CHECKED : MF_UNCHECKED)); // Get the rectangle of the client area GetClientRect(hWnd, &rcClient); // Create the list view control g_hWndListView = CreateWindowEx(WS_EX_CLIENTEDGE, WC_LISTVIEW, NULL, WS_CHILD | WS_CLIPSIBLINGS | WS_TABSTOP | WS_VISIBLE | LVS_REPORT, 0, (rcToolbar.bottom - rcToolbar.top), rcClient.right, rcClient.bottom - (rcStatusBar.bottom - rcStatusBar.top) - (rcToolbar.bottom - rcToolbar.top), hWnd, NULL, g_hInstance, NULL); if (g_hWndListView) { ListView_SetExtendedListViewStyle(g_hWndListView, LVS_EX_FULLROWSELECT); // Set common attributes for each column lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; lvc.fmt = LVCFMT_LEFT; for (nColumnIndex = 0; nColumnIndex < (INT) eIllegalColumnIndex; nColumnIndex++) { // Get the column header text GetColumnHeaderText((eListViewColumnIndex) nColumnIndex, szColumnHeader); // Set the column header text lvc.pszText = szColumnHeader; // Set the column width lvc.cx = WinPosInfo.ColumnWidth[nColumnIndex]; // Set the column number lvc.iSubItem = nColumnIndex; // Insert column into list view ListView_InsertColumn(g_hWndListView, lvc.iSubItem, &lvc); } SetFocus(g_hWndListView); } break; case WM_MENUSELECT: UINT uBase; switch (LOWORD(wParam)) { case IDM_FAX_SET_AS_DEFAULT_PRINTER_1: case IDM_FAX_SET_AS_DEFAULT_PRINTER_2: case IDM_FAX_SET_AS_DEFAULT_PRINTER_3: case IDM_FAX_SET_AS_DEFAULT_PRINTER_4: wParam = MAKELONG(LOWORD(IDM_FAX_SET_AS_DEFAULT_PRINTER), HIWORD(wParam)); break; case IDM_FAX_SHARING_1: case IDM_FAX_SHARING_2: case IDM_FAX_SHARING_3: case IDM_FAX_SHARING_4: wParam = MAKELONG(LOWORD(IDM_FAX_SHARING), HIWORD(wParam)); break; case IDM_FAX_PROPERTIES_1: case IDM_FAX_PROPERTIES_2: case IDM_FAX_PROPERTIES_3: case IDM_FAX_PROPERTIES_4: wParam = MAKELONG(LOWORD(IDM_FAX_PROPERTIES), HIWORD(wParam)); break; case IDM_FAX_SET_AS_DEFAULT_PRINTER_MORE: case IDM_FAX_SHARING_MORE: case IDM_FAX_PROPERTIES_MORE: wParam = MAKELONG(LOWORD(IDM_FAX_SET_AS_DEFAULT_PRINTER_MORE), HIWORD(wParam)); break; } if (hWndStatusBar) { uBase = IDS_MENU_BASE; MenuHelp(iMsg, wParam, lParam, NULL, g_hInstance, hWndStatusBar, &uBase); } break; case WM_INITMENUPOPUP: if (((HMENU) wParam == hFaxMenu) && (LOWORD(lParam) == 0)) { // mii is the menu item info MENUITEMINFO mii; // szMenuString is a menu string TCHAR szMenuString[RESOURCE_STRING_LEN]; // dwNumOldMenuItems is the old number of menu items DWORD dwNumOldMenuItems; // dwNumNewMenuItems is the new number of menu items DWORD dwNumNewMenuItems; // pFaxPrintersConfig is the pointer to the fax printers LPPRINTER_INFO_2 pFaxPrintersConfig; // dwNumFaxPrinters is the number of fax printers DWORD dwNumFaxPrinters; // dwIndex is a counter to enumerate each menu and printer DWORD dwIndex; // dwDefaultIndex is the index of the default fax printer DWORD dwDefaultIndex; // szDefaultPrinterName is the default printer name LPTSTR szDefaultPrinterName; if ((WaitForSingleObject(g_hStartEvent, 0) != WAIT_TIMEOUT) && (ListView_GetItemCount(g_hWndListView))) { // Enable the cancel all faxes menu item EnableMenuItem(hFaxMenu, IDM_FAX_CANCEL_ALL_FAXES, MF_BYCOMMAND | MF_ENABLED); } else { // Disable the cancel all faxes menu item EnableMenuItem(hFaxMenu, IDM_FAX_CANCEL_ALL_FAXES, MF_BYCOMMAND | MF_GRAYED); } // Get the default printer szDefaultPrinterName = GetDefaultPrinterName(); // Get the fax printers pFaxPrintersConfig = (LPPRINTER_INFO_2) GetFaxPrinters(&dwNumFaxPrinters); if ((pFaxPrintersConfig) && (dwNumFaxPrinters > 1)) { // Many fax printers, so set menu items as sub-menus // Initialize the menu item info mii.cbSize = sizeof(mii); mii.fMask = MIIM_STATE | MIIM_SUBMENU; mii.fState = MFS_ENABLED; // Update the set as default printer menu item if (!hFaxSetAsDefaultMenu) { hFaxSetAsDefaultMenu = CreatePopupMenu(); mii.hSubMenu = hFaxSetAsDefaultMenu; SetMenuItemInfo(hFaxMenu, IDM_FAX_SET_AS_DEFAULT_PRINTER, FALSE, &mii); } // Update the sharing menu item if (!hFaxSharingMenu) { hFaxSharingMenu = CreatePopupMenu(); mii.hSubMenu = hFaxSharingMenu; SetMenuItemInfo(hFaxMenu, IDM_FAX_SHARING, FALSE, &mii); } // Update the properties menu item if (!hFaxPropertiesMenu) { hFaxPropertiesMenu = CreatePopupMenu(); mii.hSubMenu = hFaxPropertiesMenu; SetMenuItemInfo(hFaxMenu, IDM_FAX_PROPERTIES, FALSE, &mii); } // Initialize the menu item info mii.cbSize = sizeof(mii); mii.fMask = MIIM_ID | MIIM_STATE | MIIM_TYPE; mii.fType = MFT_STRING; // Get the number of menu items dwNumOldMenuItems = (DWORD) GetMenuItemCount(hFaxSetAsDefaultMenu); // Insert the default fax printer first into the menus for (dwDefaultIndex = dwNumFaxPrinters, dwNumNewMenuItems = 0; (szDefaultPrinterName) && (dwDefaultIndex > 0); dwDefaultIndex--) { if (!lstrcmpi(szDefaultPrinterName, pFaxPrintersConfig[dwDefaultIndex - 1].pPrinterName)) { // Set the menu string wsprintf(szMenuString, TEXT("&%d %s"), dwNumNewMenuItems + 1, pFaxPrintersConfig[dwDefaultIndex - 1].pPrinterName); mii.fState = MFS_CHECKED | MFS_ENABLED; mii.dwTypeData = szMenuString; // Insert the item into the set as default printer menu mii.wID = IDM_FAX_SET_AS_DEFAULT_PRINTER_1; InsertMenuItem(hFaxSetAsDefaultMenu, dwNumOldMenuItems, TRUE, &mii); // Insert the item into the sharing menu mii.wID = IDM_FAX_SHARING_1; InsertMenuItem(hFaxSharingMenu, dwNumOldMenuItems, TRUE, &mii); // Insert the item into the properties menu mii.wID = IDM_FAX_PROPERTIES_1; InsertMenuItem(hFaxPropertiesMenu, dwNumOldMenuItems, TRUE, &mii); // Increment the number of new menu items dwNumNewMenuItems++; break; } } // Propagate the menus with the list of fax printers mii.fState = MFS_ENABLED; for (dwIndex = 0; (dwIndex < dwNumFaxPrinters) && (dwNumNewMenuItems < (IDM_FAX_SET_AS_DEFAULT_PRINTER_MORE - IDM_FAX_SET_AS_DEFAULT_PRINTER_1)); dwIndex++) { if (dwIndex != (dwDefaultIndex - 1)) { // Set the menu string wsprintf(szMenuString, TEXT("&%d %s"), dwNumNewMenuItems + 1, pFaxPrintersConfig[dwIndex].pPrinterName); mii.dwTypeData = szMenuString; // Insert the item into the set as default printer menu mii.wID = (IDM_FAX_SET_AS_DEFAULT_PRINTER_1 + dwNumNewMenuItems); InsertMenuItem(hFaxSetAsDefaultMenu, (dwNumOldMenuItems + dwNumNewMenuItems), TRUE, &mii); // Insert the item into the sharing menu mii.wID = (IDM_FAX_SHARING_1 + dwNumNewMenuItems); InsertMenuItem(hFaxSharingMenu, (dwNumOldMenuItems + dwNumNewMenuItems), TRUE, &mii); // Insert the item into the properties menu mii.wID = (IDM_FAX_PROPERTIES_1 + dwNumNewMenuItems); InsertMenuItem(hFaxPropertiesMenu, (dwNumOldMenuItems + dwNumNewMenuItems), TRUE, &mii); // Increment the number of new menu items dwNumNewMenuItems++; } } if (dwNumFaxPrinters > (IDM_FAX_SET_AS_DEFAULT_PRINTER_MORE - IDM_FAX_SET_AS_DEFAULT_PRINTER_1)) { // Finish the menus with the printers string LoadString(g_hInstance, IDS_MENU_ITEM_FAX_PRINTERS, szMenuString, RESOURCE_STRING_LEN); mii.dwTypeData = szMenuString; // Insert the item into the set as default printer menu mii.wID = IDM_FAX_SET_AS_DEFAULT_PRINTER_MORE; InsertMenuItem(hFaxSetAsDefaultMenu, (dwNumOldMenuItems + dwNumNewMenuItems), TRUE, &mii); // Insert the item into the sharing menu mii.wID = IDM_FAX_SHARING_MORE; InsertMenuItem(hFaxSharingMenu, (dwNumOldMenuItems + dwNumNewMenuItems), TRUE, &mii); // Insert the item into the properties menu mii.wID = IDM_FAX_PROPERTIES_MORE; InsertMenuItem(hFaxPropertiesMenu, (dwNumOldMenuItems + dwNumNewMenuItems), TRUE, &mii); } // Remove the old items from the set as default printer menu for (dwIndex = 0; dwIndex < dwNumOldMenuItems; dwIndex++) { DeleteMenu(hFaxSetAsDefaultMenu, 0, MF_BYPOSITION); } // Remove the old items from the sharing menu for (dwIndex = 0; dwIndex < dwNumOldMenuItems; dwIndex++) { DeleteMenu(hFaxSharingMenu, 0, MF_BYPOSITION); } // Remove the old items from the properties menu for (dwIndex = 0; dwIndex < dwNumOldMenuItems; dwIndex++) { DeleteMenu(hFaxPropertiesMenu, 0, MF_BYPOSITION); } } else { // One or zero fax printers, so set sub-menus as menu items // Initialize the menu item info mii.cbSize = sizeof(mii); mii.fMask = MIIM_STATE | MIIM_SUBMENU; mii.hSubMenu = NULL; // Update the set as default printer menu item if (hFaxSetAsDefaultMenu) { DestroyMenu(hFaxSetAsDefaultMenu); hFaxSetAsDefaultMenu = NULL; } if ((pFaxPrintersConfig) && (dwNumFaxPrinters == 1) && (szDefaultPrinterName) && (!lstrcmpi(szDefaultPrinterName, pFaxPrintersConfig[0].pPrinterName))) { mii.fState = MFS_CHECKED | MFS_ENABLED; } else { mii.fState = (dwNumFaxPrinters == 1) ? MFS_ENABLED : MFS_GRAYED; } SetMenuItemInfo(hFaxMenu, IDM_FAX_SET_AS_DEFAULT_PRINTER, FALSE, &mii); // Update the sharing menu item if (hFaxSharingMenu) { DestroyMenu(hFaxSharingMenu); hFaxSharingMenu = NULL; } mii.fState = (dwNumFaxPrinters == 1) ? MFS_ENABLED : MFS_GRAYED; SetMenuItemInfo(hFaxMenu, IDM_FAX_SHARING, FALSE, &mii); // Update the properties menu item if (hFaxPropertiesMenu) { DestroyMenu(hFaxPropertiesMenu); hFaxPropertiesMenu = NULL; } mii.fState = (dwNumFaxPrinters == 1) ? MFS_ENABLED : MFS_GRAYED; SetMenuItemInfo(hFaxMenu, IDM_FAX_PROPERTIES, FALSE, &mii); } if (pFaxPrintersConfig) { MemFree(pFaxPrintersConfig); } if (szDefaultPrinterName) { MemFree(szDefaultPrinterName); } } else if (((HMENU) wParam == hDocumentMenu) && (LOWORD(lParam) == 1)) { if ((WaitForSingleObject(g_hStartEvent, 0) == WAIT_TIMEOUT) || (!ListView_GetSelectedCount(g_hWndListView))) { // Disconnected or no items selected, so disable all menu items // Disable the pause menu item EnableMenuItem(hDocumentMenu, IDM_DOCUMENT_PAUSE, MF_BYCOMMAND | MF_GRAYED); // Disable the resume menu item EnableMenuItem(hDocumentMenu, IDM_DOCUMENT_RESUME, MF_BYCOMMAND | MF_GRAYED); // Disable the restart menu item EnableMenuItem(hDocumentMenu, IDM_DOCUMENT_RESTART, MF_BYCOMMAND | MF_GRAYED); // Disable the cancel menu item EnableMenuItem(hDocumentMenu, IDM_DOCUMENT_CANCEL, MF_BYCOMMAND | MF_GRAYED); // Disable the properties menu item EnableMenuItem(hDocumentMenu, IDM_DOCUMENT_PROPERTIES, MF_BYCOMMAND | MF_GRAYED); } else { // uAndMask is the mask indicating the item attributes ANDed together UINT uAndMask; // uOrMask is the mask indicating the item attributes ORed together UINT uOrMask; // uState is the item's state UINT uState; // dwListIndex is the index of a particular item in the list view DWORD dwListIndex; // bUserHasAccess indicates the user has job manage access BOOL bUserHasAccess; // Initialize uAndMask uAndMask = LVIS_OVERLAYMASK; // Initialize uOrMask uOrMask = 0; // Enumerate each selected item in the list view dwListIndex = ListView_GetNextItem(g_hWndListView, -1, LVNI_ALL | LVNI_SELECTED); while (dwListIndex != -1) { // Get the item's attributes uState = ListView_GetItemState(g_hWndListView, dwListIndex, LVIS_OVERLAYMASK); // AND the item's attributes with uAndMask uAndMask &= uState; // OR the item's attributes with uOrMask uOrMask |= uState; dwListIndex = ListView_GetNextItem(g_hWndListView, dwListIndex, LVNI_ALL | LVNI_SELECTED); } if (uAndMask & ITEM_USEROWNSJOB_MASK) { // User owns all of the jobs bUserHasAccess = TRUE; } else { // User does not own all of the jobs, so determine if user has job manage permission // Initialize bUserHasAccess to FALSE bUserHasAccess = FALSE; // Connect to the fax service if (Connect()) { // Get the user's job manage access bUserHasAccess = FaxAccessCheck(g_hFaxSvcHandle, FAX_JOB_MANAGE); // Disconnect from the fax service Disconnect(); } } if (((uAndMask & ITEM_SEND_MASK) == 0) || ((uAndMask & ITEM_IDLE_MASK) == 0)) { // Not a send job or a send job in progress, so disable the pause, resume and restart menu items // Disable the pause menu item EnableMenuItem(hDocumentMenu, IDM_DOCUMENT_PAUSE, MF_BYCOMMAND | MF_GRAYED); // Disable the resume menu item EnableMenuItem(hDocumentMenu, IDM_DOCUMENT_RESUME, MF_BYCOMMAND | MF_GRAYED); // Disable the restart menu item EnableMenuItem(hDocumentMenu, IDM_DOCUMENT_RESTART, MF_BYCOMMAND | MF_GRAYED); } else if (uAndMask & ITEM_PAUSED_MASK) { // Idle send job that is paused, so enable the resume and restart menu items and disable the pause menu item // Disable the pause menu item EnableMenuItem(hDocumentMenu, IDM_DOCUMENT_PAUSE, MF_BYCOMMAND | MF_GRAYED); // Enable the resume menu item EnableMenuItem(hDocumentMenu, IDM_DOCUMENT_RESUME, MF_BYCOMMAND | (bUserHasAccess ? MF_ENABLED : MF_GRAYED)); // Enable the restart menu item EnableMenuItem(hDocumentMenu, IDM_DOCUMENT_RESTART, MF_BYCOMMAND | (bUserHasAccess ? MF_ENABLED : MF_GRAYED)); } else if ((uOrMask & ITEM_PAUSED_MASK) == 0) { // Idle send job that is not paused, so enable the pause and restart menu items and disable the resume menu item // Enable the pause menu item EnableMenuItem(hDocumentMenu, IDM_DOCUMENT_PAUSE, MF_BYCOMMAND | (bUserHasAccess ? MF_ENABLED : MF_GRAYED)); // Disable the resume menu item EnableMenuItem(hDocumentMenu, IDM_DOCUMENT_RESUME, MF_BYCOMMAND | MF_GRAYED); // Enable the restart menu item EnableMenuItem(hDocumentMenu, IDM_DOCUMENT_RESTART, MF_BYCOMMAND | (bUserHasAccess ? MF_ENABLED : MF_GRAYED)); } else { // Idle send job, so enable the restart menu item and disable the pause and resume menu items // Enable the pause menu item EnableMenuItem(hDocumentMenu, IDM_DOCUMENT_PAUSE, MF_BYCOMMAND | MF_GRAYED); // Disable the resume menu item EnableMenuItem(hDocumentMenu, IDM_DOCUMENT_RESUME, MF_BYCOMMAND | MF_GRAYED); // Enable the restart menu item EnableMenuItem(hDocumentMenu, IDM_DOCUMENT_RESTART, MF_BYCOMMAND | (bUserHasAccess ? MF_ENABLED : MF_GRAYED)); } // Enable the cancel menu item EnableMenuItem(hDocumentMenu, IDM_DOCUMENT_CANCEL, MF_BYCOMMAND | (bUserHasAccess ? MF_ENABLED : MF_GRAYED)); if (ListView_GetSelectedCount(g_hWndListView) == 1) { // Only one item selected, so enable the properties menu item EnableMenuItem(hDocumentMenu, IDM_DOCUMENT_PROPERTIES, MF_BYCOMMAND | MF_ENABLED); } else { // Multiple items selected, so disable the properties menu item EnableMenuItem(hDocumentMenu, IDM_DOCUMENT_PROPERTIES, MF_BYCOMMAND | MF_GRAYED); } } } break; case WM_NOTIFY: LPNMHDR pnmhdr; // dwMessagePos is the cursor position for the message DWORD dwMessagePos; pnmhdr = (LPNMHDR) lParam; if ((pnmhdr->hwndFrom == g_hWndListView) && (pnmhdr->code == NM_RCLICK)) { // User has right-clicked in the list view, so display the document context menu // Initialize the document menu SendMessage(g_hWndMain, WM_INITMENUPOPUP, (WPARAM) hDocumentMenu, MAKELPARAM(1, FALSE)); // Get the cursor position dwMessagePos = GetMessagePos(); // Display the document context menu TrackPopupMenu(hDocumentMenu, TPM_LEFTALIGN | TPM_LEFTBUTTON, LOWORD(dwMessagePos), HIWORD(dwMessagePos), 0, g_hWndMain, NULL); } else if ((pnmhdr->hwndFrom == g_hWndListView) && (pnmhdr->code == NM_DBLCLK)) { // rcItem is the rectangle of the item RECT rcItem; // User has double-clicked in the list view, so display the job properties if (ListView_GetSelectedCount(g_hWndListView) != 1) { break; } // Get the item's bounding rectangle if (ListView_GetItemRect(g_hWndListView, ListView_GetNextItem(g_hWndListView, -1, LVNI_ALL | LVNI_SELECTED), &rcItem, LVIR_BOUNDS)) { // Get the cursor position dwMessagePos = GetMessagePos(); // Get the window rectangle of the list view GetWindowRect(g_hWndListView, &rcClient); // Adjust dwMessagePos to indicate the cursor position within the list view dwMessagePos = MAKELONG(LOWORD(dwMessagePos) - rcClient.left, HIWORD(dwMessagePos) - rcClient.top); if ((LOWORD(dwMessagePos) >= rcItem.left) && (LOWORD(dwMessagePos) <= rcItem.right) && (HIWORD(dwMessagePos) >= rcItem.top) && (HIWORD(dwMessagePos) <= rcItem.bottom)) { // Display the job properties SendMessage(g_hWndMain, WM_COMMAND, MAKEWPARAM(IDM_DOCUMENT_PROPERTIES, 0), 0); } } } #ifdef TOOLBAR_ENABLED else if (pnmhdr->code == TTN_NEEDTEXT) { // pToolTipText is the pointer to the tool tip text structure LPTOOLTIPTEXT pToolTipText; // szToolTip is the tool tip text TCHAR szToolTip[RESOURCE_STRING_LEN]; pToolTipText = (LPTOOLTIPTEXT) lParam; switch (pToolTipText->hdr.idFrom) { case IDM_FAX_PAUSE_FAXING: LoadString(g_hInstance, IDS_MENU_FAX_PAUSE_FAXING, szToolTip, RESOURCE_STRING_LEN); break; case IDM_FAX_CANCEL_ALL_FAXES: LoadString(g_hInstance, IDS_MENU_FAX_CANCEL_ALL_FAXES, szToolTip, RESOURCE_STRING_LEN); break; case IDM_DOCUMENT_PAUSE: LoadString(g_hInstance, IDS_MENU_DOCUMENT_PAUSE, szToolTip, RESOURCE_STRING_LEN); break; case IDM_DOCUMENT_RESUME: LoadString(g_hInstance, IDS_MENU_DOCUMENT_PAUSE, szToolTip, RESOURCE_STRING_LEN); break; case IDM_DOCUMENT_RESTART: LoadString(g_hInstance, IDS_MENU_DOCUMENT_RESTART, szToolTip, RESOURCE_STRING_LEN); break; case IDM_DOCUMENT_CANCEL: LoadString(g_hInstance, IDS_MENU_DOCUMENT_CANCEL, szToolTip, RESOURCE_STRING_LEN); break; case IDM_DOCUMENT_PROPERTIES: LoadString(g_hInstance, IDS_MENU_DOCUMENT_PROPERTIES, szToolTip, RESOURCE_STRING_LEN); break; case IDM_VIEW_REFRESH: LoadString(g_hInstance, IDS_MENU_VIEW_REFRESH, szToolTip, RESOURCE_STRING_LEN); break; case IDM_HELP_TOPICS: LoadString(g_hInstance, IDS_MENU_HELP_TOPICS, szToolTip, RESOURCE_STRING_LEN); break; default: ZeroMemory(szToolTip, sizeof(szToolTip)); break; } pToolTipText->lpszText = szToolTip; } #endif // TOOLBAR_ENABLED break; case WM_SETFOCUS: SetFocus(g_hWndListView); break; case WM_SIZE: #ifdef TOOLBAR_ENABLED // Resize the toolbar if (WinPosInfo.bToolbarVisible) { SendMessage(g_hWndToolbar, iMsg, wParam, lParam); } #endif // TOOLBAR_ENABLED // Resize the status bar if (WinPosInfo.bStatusBarVisible) { SendMessage(hWndStatusBar, iMsg, wParam, lParam); } // Get the rectangle of the client area GetClientRect(hWnd, &rcClient); // Resize the list view MoveWindow(g_hWndListView, 0, (rcToolbar.bottom - rcToolbar.top), rcClient.right, rcClient.bottom - (rcStatusBar.bottom - rcStatusBar.top) - (rcToolbar.bottom - rcToolbar.top), TRUE); break; case UM_SELECT_FAX_PRINTER: // szCommandLine is the command line TCHAR szCommandLine[MAX_PATH]; // si is the startup info for the print ui STARTUPINFO si; // pi is the process info for the print ui PROCESS_INFORMATION pi; // hWndPrintUI is the handle to the print ui window HWND hWndPrintUI; // pProcessInfoItem is a pointer to a PROCESS_INFO_ITEM structure PPROCESS_INFO_ITEM pProcessInfoItem; // szErrorCaption is the error caption if CreateProcess() fails TCHAR szErrorCaption[RESOURCE_STRING_LEN]; // szErrorMessage is the error message if CreateProcess() fails LPTSTR szErrorMessage; if (uCurrentMenu == IDM_FAX_SET_AS_DEFAULT_PRINTER_MORE) { // Set the default printer SetDefaultPrinterName((LPTSTR) wParam); MemFree((LPBYTE) wParam); uCurrentMenu = 0; return 0; } if (pProcessInfoList) { // See if print ui is already open pProcessInfoItem = (PPROCESS_INFO_ITEM) pProcessInfoList; while (TRUE) { if (!lstrcmpi((LPTSTR) wParam, pProcessInfoItem->szPrinterName)) { // Printer name matches, so print ui may still be open if (WaitForSingleObject(pProcessInfoItem->hProcess, 0) != WAIT_OBJECT_0) { // Print ui is still open ShowWindow(pProcessInfoItem->hWnd, SW_SHOWNORMAL); SetForegroundWindow(pProcessInfoItem->hWnd); return 0; } if (pProcessInfoItem == (PPROCESS_INFO_ITEM) pProcessInfoList) { pProcessInfoList = pProcessInfoItem->ListEntry.Blink; } if (IsListEmpty(pProcessInfoList)) { // This is the last item in the list, so set the list head to NULL pProcessInfoList = NULL; } else { // Remove the process info item from the list RemoveEntryList(&pProcessInfoItem->ListEntry); } // Free the process info item MemFree(pProcessInfoItem); break; } // Step to the next process info item pProcessInfoItem = (PPROCESS_INFO_ITEM) pProcessInfoItem->ListEntry.Blink; if (pProcessInfoItem == (PPROCESS_INFO_ITEM) pProcessInfoList) { // The list has been traversed break; } } } switch (uCurrentMenu) { case IDM_FAX_SHARING_MORE: // Set the parameters wsprintf(szCommandLine, TEXT("rundll32 printui.dll,PrintUIEntry /p /t1 /n \"%s\""), (LPTSTR) wParam); break; case IDM_FAX_PROPERTIES_MORE: // Set the parameters wsprintf(szCommandLine, TEXT("rundll32 printui.dll,PrintUIEntry /p /t0 /n \"%s\""), (LPTSTR) wParam); break; } // Initialize si ZeroMemory(&si, sizeof(si)); GetStartupInfo(&si); si.dwFlags = STARTF_USESHOWWINDOW; si.wShowWindow = SW_NORMAL; // Initialize pi ZeroMemory(&pi, sizeof(pi)); // Launch the print ui hWndPrintUI = NULL; SetCursor(LoadCursor(NULL, IDC_WAIT)); if (CreateProcess(NULL, szCommandLine, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &si, &pi)) { // Find the print ui window do { Sleep(250); EnumThreadWindows(pi.dwThreadId, EnumThreadWndProc, (LPARAM) &hWndPrintUI); } while (hWndPrintUI == NULL); SetCursor(LoadCursor(NULL, IDC_ARROW)); // Add the process info item to the list pProcessInfoItem = (PPROCESS_INFO_ITEM) MemAlloc(sizeof(PROCESS_INFO_ITEM) + (lstrlen((LPTSTR) wParam) + 1) * sizeof(TCHAR)); if (pProcessInfoItem) { // Set szPrinterName pProcessInfoItem->szPrinterName = (LPTSTR) ((UINT_PTR) pProcessInfoItem + sizeof(PROCESS_INFO_ITEM)); // Copy szPrinterName lstrcpy(pProcessInfoItem->szPrinterName, (LPTSTR) wParam); // Copy hProcess pProcessInfoItem->hProcess = pi.hProcess; // Copy hWndPrintUI pProcessInfoItem->hWnd = hWndPrintUI; // Insert the process info item into the list if (pProcessInfoList) { InsertTailList(pProcessInfoList, &pProcessInfoItem->ListEntry); } else { pProcessInfoList = &pProcessInfoItem->ListEntry; InitializeListHead(pProcessInfoList); } } } else { // CreateProcess() failed, so display an error message SetCursor(LoadCursor(NULL, IDC_ARROW)); // Load the error caption LoadString(g_hInstance, IDS_ERROR_CAPTION, szErrorCaption, RESOURCE_STRING_LEN); // Try to get the error message from the system message table if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, (LPTSTR) &szErrorMessage, 0, NULL)) { // Display the error message MessageBox(hWnd, szErrorMessage, szErrorCaption, MB_OK | MB_ICONERROR | MB_APPLMODAL); LocalFree(szErrorMessage); } else { // Allocate the memory for the error message szErrorMessage = (LPTSTR) MemAlloc((RESOURCE_STRING_LEN) * sizeof(TCHAR)); if (szErrorMessage) { // Load the error message LoadString(g_hInstance, IDS_ERROR_PRINTER_PROPERTIES, szErrorMessage, RESOURCE_STRING_LEN); // Display the error message MessageBox(hWnd, szErrorMessage, szErrorCaption, MB_OK | MB_ICONERROR | MB_APPLMODAL); MemFree(szErrorMessage); } } } MemFree((LPBYTE) wParam); uCurrentMenu = 0; break; case WM_COMMAND: // mii is the menu item info MENUITEMINFO mii; // szPrinterName is the printer name LPTSTR szPrinterName; // pFaxJobEntry is the pointer to the fax jobs PFAX_JOB_ENTRY pFaxJobEntry; // lvi specifies the attributes of a particular item in the list view LV_ITEM lvi; // dwListIndex is the index of a particular item in the list view DWORD dwListIndex; switch (LOWORD(wParam)) { case IDM_FAX_PAUSE_FAXING: // pFaxConfig is the pointer to the fax configuration PFAX_CONFIGURATION pFaxConfig; // Initialize the menu item info mii.cbSize = sizeof(mii); mii.fMask = MIIM_STATE; mii.fState = 0; // Get the size of the menu item if (!GetMenuItemInfo(hFaxMenu, IDM_FAX_PAUSE_FAXING, FALSE, &mii)) { break; } SetCursor(LoadCursor(NULL, IDC_WAIT)); if (Connect()) { // Get the fax configuration if (FaxGetConfiguration(g_hFaxSvcHandle, &pFaxConfig)) { // Toggle the pause faxing status pFaxConfig->PauseServerQueue = mii.fState & MFS_CHECKED ? FALSE : TRUE; // Set the fax configuration if (FaxSetConfiguration(g_hFaxSvcHandle, pFaxConfig)) { // Check the menu item CheckMenuItem(hFaxMenu, IDM_FAX_PAUSE_FAXING, MF_BYCOMMAND | (pFaxConfig->PauseServerQueue ? MF_CHECKED : MF_UNCHECKED)); #ifdef TOOLBAR_ENABLED // Enable the pause faxing toolbar menu item EnableToolbarMenuState(g_hWndToolbar, IDM_FAX_PAUSE_FAXING, pFaxConfig->PauseServerQueue); #endif // TOOLBAR_ENABLED } FaxFreeBuffer(pFaxConfig); } Disconnect(); } // Set the window title to indicate connected or paused SetWindowText(hWnd, mii.fState & MFS_CHECKED ? g_szTitleConnected : g_szTitlePaused); SetCursor(LoadCursor(NULL, IDC_ARROW)); break; case IDM_FAX_CANCEL_ALL_FAXES: // dwNumFaxJobs is the number of fax jobs DWORD dwNumFaxJobs; // dwIndex is a counter to enumerate each fax job DWORD dwIndex; SetCursor(LoadCursor(NULL, IDC_WAIT)); if (Connect()) { // Enumerate the fax jobs if (FaxEnumJobs(g_hFaxSvcHandle, &pFaxJobEntry, &dwNumFaxJobs)) { // Enumerate and cancel each fax job for (dwIndex = 0; dwIndex < dwNumFaxJobs; dwIndex++) { FaxSetJob(g_hFaxSvcHandle, pFaxJobEntry[dwIndex].JobId, JC_DELETE, &pFaxJobEntry[dwIndex]); } FaxFreeBuffer(pFaxJobEntry); } Disconnect(); } SetCursor(LoadCursor(NULL, IDC_ARROW)); break; case IDM_FAX_CLOSE: SendMessage(hWnd, WM_CLOSE, 0, 0); break; case IDM_DOCUMENT_PAUSE: case IDM_DOCUMENT_RESUME: case IDM_DOCUMENT_RESTART: case IDM_DOCUMENT_CANCEL: // pJobIdList is a pointer to the job id list PLIST_ENTRY pJobIdList; // JobIdItem is a JOB_ID_ITEM structure PJOB_ID_ITEM pJobIdItem; // FaxJobEntry is the fax job FAX_JOB_ENTRY FaxJobEntry; // dwCommand is the command to set the fax job entry DWORD dwCommand; switch (LOWORD(wParam)) { case IDM_DOCUMENT_PAUSE: dwCommand = JC_PAUSE; break; case IDM_DOCUMENT_RESUME: dwCommand = JC_RESUME; break; case IDM_DOCUMENT_RESTART: dwCommand = JC_RESTART; break; case IDM_DOCUMENT_CANCEL: dwCommand = JC_DELETE; break; } // Set pJobIdList to NULL pJobIdList = NULL; SetCursor(LoadCursor(NULL, IDC_WAIT)); if (Connect()) { // Initialize FaxJobEntry ZeroMemory(&FaxJobEntry, sizeof(FaxJobEntry)); FaxJobEntry.SizeOfStruct = sizeof(FaxJobEntry); // Enumerate each selected item in the list view dwListIndex = ListView_GetNextItem(g_hWndListView, -1, LVNI_ALL | LVNI_SELECTED); while (dwListIndex != -1) { // Initialize lvi lvi.mask = LVIF_PARAM; // Set the item number lvi.iItem = dwListIndex; // Set the subitem number lvi.iSubItem = 0; // Set the lParam lvi.lParam = 0; // Get the selected item from the list view if (ListView_GetItem(g_hWndListView, &lvi)) { // Add the job id item to the list pJobIdItem = (PJOB_ID_ITEM) MemAlloc(sizeof(JOB_ID_ITEM)); if (pJobIdItem) { // Copy dwJobId pJobIdItem->dwJobId = (DWORD) lvi.lParam; // Insert the job id item into the list if (pJobIdList) { InsertTailList(pJobIdList, &pJobIdItem->ListEntry); } else { pJobIdList = &pJobIdItem->ListEntry; InitializeListHead(pJobIdList); } } } dwListIndex = ListView_GetNextItem(g_hWndListView, dwListIndex, LVNI_ALL | LVNI_SELECTED); } while (pJobIdList) { // Get the job id item from the list pJobIdItem = (PJOB_ID_ITEM) pJobIdList; // Set FaxJobEntry FaxJobEntry.JobId = pJobIdItem->dwJobId; // Set the fax job entry if (FaxSetJob(g_hFaxSvcHandle, FaxJobEntry.JobId, dwCommand, &FaxJobEntry)) { if (LOWORD(wParam) != IDM_DOCUMENT_CANCEL) { // Post an event to the completion port to indicate thread is to refresh PostEventToCompletionPort(g_hCompletionPort, (DWORD) -1, FaxJobEntry.JobId); } } // Set the head of the job id item list to the next job id item in the list pJobIdList = pJobIdItem->ListEntry.Blink; if (IsListEmpty(pJobIdList)) { // This is the last item in the list, so set the list head to NULL pJobIdList = NULL; } else { // Remove the job id item from the list RemoveEntryList(&pJobIdItem->ListEntry); } // Free the job id item MemFree(pJobIdItem); } Disconnect(); } SetCursor(LoadCursor(NULL, IDC_ARROW)); break; case IDM_DOCUMENT_PROPERTIES: // PropSheetHeader is the property sheet header PROPSHEETHEADER PropSheetHeader; // PropSheetPage is the property sheet page PROPSHEETPAGE PropSheetPage; // Set pJobIdList to NULL pJobIdList = NULL; // Initialize PropSheetHeader PropSheetHeader.dwSize = sizeof(PropSheetHeader); // Set the property sheet header flags PropSheetHeader.dwFlags = PSH_NOAPPLYNOW | PSH_PROPSHEETPAGE | PSH_PROPTITLE; // Set the property sheet header owner window PropSheetHeader.hwndParent = hWnd; // Set the property sheet header hInstance PropSheetHeader.hInstance = g_hInstance; // Set the number of property sheet pages PropSheetHeader.nPages = 1; // Set the start property sheet page PropSheetHeader.nStartPage = 0; PropSheetHeader.pStartPage = NULL; // Set the property sheet pages PropSheetHeader.ppsp = &PropSheetPage; // Initialize PropSheetPage PropSheetPage.dwSize = sizeof(PropSheetPage); // Set the property sheet page flags PropSheetPage.dwFlags = 0; // Set the property sheet page hInstance PropSheetPage.hInstance = g_hInstance; // Set the property sheet page dialog template PropSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_DOCUMENT_PROPERTIES); // Set the property sheet page dialog procedure PropSheetPage.pfnDlgProc = DocumentPropertiesDlgProc; SetCursor(LoadCursor(NULL, IDC_WAIT)); if (Connect()) { // Enumerate each selected item in the list view dwListIndex = ListView_GetNextItem(g_hWndListView, -1, LVNI_ALL | LVNI_SELECTED); while (dwListIndex != -1) { // Initialize lvi lvi.mask = LVIF_PARAM; // Set the item number lvi.iItem = dwListIndex; // Set the subitem number lvi.iSubItem = 0; // Set the lParam lvi.lParam = 0; // Get the selected item from the list view if (ListView_GetItem(g_hWndListView, &lvi)) { // Add the job id item to the list pJobIdItem = (PJOB_ID_ITEM) MemAlloc(sizeof(JOB_ID_ITEM)); if (pJobIdItem) { // Copy dwJobId pJobIdItem->dwJobId = (DWORD) lvi.lParam; // Insert the job id item into the list if (pJobIdList) { InsertTailList(pJobIdList, &pJobIdItem->ListEntry); } else { pJobIdList = &pJobIdItem->ListEntry; InitializeListHead(pJobIdList); } } } dwListIndex = ListView_GetNextItem(g_hWndListView, dwListIndex, LVNI_ALL | LVNI_SELECTED); } while (pJobIdList) { // Get the job id item from the list pJobIdItem = (PJOB_ID_ITEM) pJobIdList; if (FaxGetJob(g_hFaxSvcHandle, pJobIdItem->dwJobId, &pFaxJobEntry)) { // Set the property sheet header pszCaption PropSheetHeader.pszCaption = pFaxJobEntry->DocumentName; // Set the property sheet page lParam PropSheetPage.lParam = (LPARAM) pFaxJobEntry; // Create the property sheet PropertySheet(&PropSheetHeader); } // Set the head of the job id item list to the next job id item in the list pJobIdList = pJobIdItem->ListEntry.Blink; if (IsListEmpty(pJobIdList)) { // This is the last item in the list, so set the list head to NULL pJobIdList = NULL; } else { // Remove the job id item from the list RemoveEntryList(&pJobIdItem->ListEntry); } // Free the job id item MemFree(pJobIdItem); } Disconnect(); } SetCursor(LoadCursor(NULL, IDC_ARROW)); break; #ifdef TOOLBAR_ENABLED case IDM_VIEW_TOOLBAR: if (WinPosInfo.bToolbarVisible) { // Close the toolbar DestroyWindow(g_hWndToolbar); DestroyWindow(hWndToolTips); ZeroMemory(&rcToolbar, sizeof(rcToolbar)); } else { // Show the toolbar hWndToolTips = CreateToolTips(hWnd); g_hWndToolbar = CreateToolbar(hWnd); // Get the rectangle of the toolbar GetWindowRect(g_hWndToolbar, &rcToolbar); } WinPosInfo.bToolbarVisible = !WinPosInfo.bToolbarVisible; // Check the menu item CheckMenuItem(hViewMenu, IDM_VIEW_TOOLBAR, MF_BYCOMMAND | (WinPosInfo.bToolbarVisible ? MF_CHECKED : MF_UNCHECKED)); // Get the rectangle of the client area GetClientRect(hWnd, &rcClient); // Resize the list view MoveWindow(g_hWndListView, 0, (rcToolbar.bottom - rcToolbar.top), rcClient.right, rcClient.bottom - (rcStatusBar.bottom - rcStatusBar.top) - (rcToolbar.bottom - rcToolbar.top), TRUE); break; #endif // TOOLBAR_ENABLED case IDM_VIEW_STATUS_BAR: if (WinPosInfo.bStatusBarVisible) { // Close the status bar DestroyWindow(hWndStatusBar); ZeroMemory(&rcStatusBar, sizeof(rcStatusBar)); } else { // Show the status bar hWndStatusBar = CreateStatusWindow(WS_CHILD | WS_CLIPSIBLINGS | WS_TABSTOP | WS_VISIBLE | SBARS_SIZEGRIP, NULL, hWnd, IDM_STATUS_BAR); // Get the rectangle of the status bar GetWindowRect(hWndStatusBar, &rcStatusBar); } WinPosInfo.bStatusBarVisible = !WinPosInfo.bStatusBarVisible; // Check the menu item CheckMenuItem(hViewMenu, IDM_VIEW_STATUS_BAR, MF_BYCOMMAND | (WinPosInfo.bStatusBarVisible ? MF_CHECKED : MF_UNCHECKED)); // Get the rectangle of the client area GetClientRect(hWnd, &rcClient); // Resize the list view MoveWindow(g_hWndListView, 0, (rcToolbar.bottom - rcToolbar.top), rcClient.right, rcClient.bottom - (rcStatusBar.bottom - rcStatusBar.top) - (rcToolbar.bottom - rcToolbar.top), TRUE); break; case IDM_VIEW_REFRESH: if (WaitForSingleObject(g_hStartEvent, 0) == WAIT_OBJECT_0) { // Post an event to the completion port to indicate thread is to refresh PostEventToCompletionPort(g_hCompletionPort, FEI_FAXSVC_STARTED, (DWORD) -1); } else { // Set the start event SetEvent(g_hStartEvent); } break; case IDM_HELP_TOPICS: HtmlHelp(GetDesktopWindow(), FAXQUEUE_HTMLHELP_FILENAME, HH_DISPLAY_TOPIC, 0L); break; case IDM_HELP_ABOUT: // szCaption is the caption for the shell about dialog box TCHAR szCaption[RESOURCE_STRING_LEN]; LoadString(g_hInstance, IDS_FAXQUEUE_LOCAL_CAPTION, szCaption, RESOURCE_STRING_LEN); ShellAbout(hWnd, szCaption, NULL, NULL); break; case IDM_FAX_SET_AS_DEFAULT_PRINTER: case IDM_FAX_SHARING: case IDM_FAX_PROPERTIES: // pFaxPrintersConfig is the pointer to the fax printers LPPRINTER_INFO_2 pFaxPrintersConfig; // dwNumFaxPrinters is the number of fax printers DWORD dwNumFaxPrinters; // Set the current menu selection if (LOWORD(wParam) == IDM_FAX_SET_AS_DEFAULT_PRINTER) { uCurrentMenu = IDM_FAX_SET_AS_DEFAULT_PRINTER_MORE; } else if (LOWORD(wParam) == IDM_FAX_SHARING) { uCurrentMenu = IDM_FAX_SHARING_MORE; } else if (LOWORD(wParam) == IDM_FAX_PROPERTIES) { uCurrentMenu = IDM_FAX_PROPERTIES_MORE; } else { break; } // Get the fax printers pFaxPrintersConfig = (LPPRINTER_INFO_2) GetFaxPrinters(&dwNumFaxPrinters); if (pFaxPrintersConfig) { // Allocate the memory for the printer name szPrinterName = (LPTSTR) MemAlloc((lstrlen(pFaxPrintersConfig[0].pPrinterName) + 1) * sizeof(TCHAR)); if (szPrinterName) { // Copy the printer name lstrcpy(szPrinterName, pFaxPrintersConfig[0].pPrinterName); // Post a message that a printer has been selected PostMessage(hWnd, UM_SELECT_FAX_PRINTER, (UINT_PTR) szPrinterName, 0); } MemFree(pFaxPrintersConfig); } break; case IDM_FAX_SET_AS_DEFAULT_PRINTER_1: case IDM_FAX_SET_AS_DEFAULT_PRINTER_2: case IDM_FAX_SET_AS_DEFAULT_PRINTER_3: case IDM_FAX_SET_AS_DEFAULT_PRINTER_4: case IDM_FAX_SHARING_1: case IDM_FAX_SHARING_2: case IDM_FAX_SHARING_3: case IDM_FAX_SHARING_4: case IDM_FAX_PROPERTIES_1: case IDM_FAX_PROPERTIES_2: case IDM_FAX_PROPERTIES_3: case IDM_FAX_PROPERTIES_4: // hMenu is the handle to the menu HMENU hMenu; // szMenuString is a menu string TCHAR szMenuString[RESOURCE_STRING_LEN]; // szMenuItemName is the menu item name LPTSTR szMenuItemName; // Get the handle to the menu, set the current menu selection, and set the menu string if ((LOWORD(wParam) >= IDM_FAX_SET_AS_DEFAULT_PRINTER_1) && (LOWORD(wParam) < IDM_FAX_SET_AS_DEFAULT_PRINTER_MORE)) { hMenu = hFaxSetAsDefaultMenu; uCurrentMenu = IDM_FAX_SET_AS_DEFAULT_PRINTER_MORE; wsprintf(szMenuString, TEXT("&%d "), LOWORD(wParam) - IDM_FAX_SET_AS_DEFAULT_PRINTER_1 + 1); } else if ((LOWORD(wParam) >= IDM_FAX_SHARING_1) && (LOWORD(wParam) < IDM_FAX_SHARING_MORE)) { hMenu = hFaxSharingMenu; uCurrentMenu = IDM_FAX_SHARING_MORE; wsprintf(szMenuString, TEXT("&%d "), LOWORD(wParam) - IDM_FAX_SHARING_1 + 1); } else if ((LOWORD(wParam) >= IDM_FAX_PROPERTIES_1) && (LOWORD(wParam) < IDM_FAX_PROPERTIES_MORE)) { hMenu = hFaxPropertiesMenu; uCurrentMenu = IDM_FAX_PROPERTIES_MORE; wsprintf(szMenuString, TEXT("&%d "), LOWORD(wParam) - IDM_FAX_PROPERTIES_1 + 1); } else { break; } // Initialize the menu item info mii.cbSize = sizeof(mii); mii.fMask = MIIM_TYPE; mii.fType = MFT_STRING; mii.dwTypeData = NULL; mii.cch = 0; // Get the size of the menu item if (GetMenuItemInfo(hMenu, LOWORD(wParam), FALSE, &mii)) { mii.cch++; // Allocate the memory for the menu item szMenuItemName = (LPTSTR) MemAlloc(mii.cch * sizeof(TCHAR)); if (szMenuItemName) { mii.dwTypeData = szMenuItemName; // Get the menu item if (GetMenuItemInfo(hMenu, LOWORD(wParam), FALSE, &mii)) { // Allocate the memory for the printer name szPrinterName = (LPTSTR) MemAlloc((lstrlen(szMenuItemName) - lstrlen(szMenuString) + 1) * sizeof(TCHAR)); if (szPrinterName) { // Copy the printer name lstrcpy(szPrinterName, (LPTSTR) ((UINT_PTR) szMenuItemName + lstrlen(szMenuString) * sizeof(TCHAR))); // Post a message that a printer has been selected PostMessage(hWnd, UM_SELECT_FAX_PRINTER, (UINT_PTR) szPrinterName, 0); } } MemFree(szMenuItemName); } } break; case IDM_FAX_SET_AS_DEFAULT_PRINTER_MORE: case IDM_FAX_SHARING_MORE: case IDM_FAX_PROPERTIES_MORE: uCurrentMenu = LOWORD(wParam); DialogBox(g_hInstance, MAKEINTRESOURCE(IDD_SELECT_FAX_PRINTER), hWnd, SelectFaxPrinterDlgProc); break; } break; case WM_CLOSE: // Set the exit event SetEvent(g_hExitEvent); if (WaitForSingleObject(g_hStartEvent, 0) == WAIT_OBJECT_0) { // Post an event to the completion port to indicate thread is to exit PostEventToCompletionPort(g_hCompletionPort, FEI_FAXSVC_ENDED, (DWORD) -1); } #ifdef TOOLBAR_ENABLED // Set the persistent data SetFaxQueueRegistryData(WinPosInfo.bToolbarVisible, WinPosInfo.bStatusBarVisible, g_hWndListView, hWnd); #else // Set the persistent data SetFaxQueueRegistryData(WinPosInfo.bStatusBarVisible, g_hWndListView, hWnd); #endif // TOOLBAR_ENABLED // Free the process info list while (pProcessInfoList) { // Get the head of the process info list pProcessInfoItem = (PPROCESS_INFO_ITEM) pProcessInfoList; // Set the head of process info list to the next process info item in the list pProcessInfoList = pProcessInfoItem->ListEntry.Blink; if (IsListEmpty(pProcessInfoList)) { // This is the last item in the list, so set the list head to NULL pProcessInfoList = NULL; } else { // Remove the process info item from the list RemoveEntryList(&pProcessInfoItem->ListEntry); } // Free the process info item MemFree(pProcessInfoItem); } break; case WM_DESTROY: #ifdef TOOLBAR_ENABLED if (WinPosInfo.bToolbarVisible) { // Close the toolbar DestroyWindow(g_hWndToolbar); DestroyWindow(hWndToolTips); } #endif // TOOLBAR_ENABLED if (WinPosInfo.bStatusBarVisible) { // Close the status bar DestroyWindow(hWndStatusBar); } // Close the list view DestroyWindow(g_hWndListView); PostQuitMessage(0); break; } return DefWindowProc(hWnd, iMsg, wParam, lParam); } INT_PTR CALLBACK SelectFaxPrinterDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam) { // hWndPrinterList is the handle to the fax printer list box static HWND hWndPrinterList; switch(iMsg) { case WM_INITDIALOG: // pFaxPrintersConfig is the pointer to the fax printers LPPRINTER_INFO_2 pFaxPrintersConfig; // dwNumFaxPrinters is the number of fax printers DWORD dwNumFaxPrinters; // dwIndex is a counter to enumerate each printer DWORD dwIndex; // Get the handle to the fax printer list box hWndPrinterList = GetDlgItem(hDlg, IDC_FAX_PRINTER_LIST); // Get the fax printers pFaxPrintersConfig = (LPPRINTER_INFO_2) GetFaxPrinters(&dwNumFaxPrinters); if ((pFaxPrintersConfig) && (dwNumFaxPrinters)) { // Propagate the list box with the list of fax printers for (dwIndex = 0; dwIndex < dwNumFaxPrinters; dwIndex++) { SendMessage(hWndPrinterList, LB_ADDSTRING, 0, (UINT_PTR) pFaxPrintersConfig[dwIndex].pPrinterName); } } if (pFaxPrintersConfig) { MemFree(pFaxPrintersConfig); } return TRUE; case WM_COMMAND: switch(HIWORD(wParam)) { case LBN_DBLCLK: SendMessage(GetDlgItem(hDlg, IDOK), BM_CLICK, 0, 0); break; } switch(LOWORD(wParam)) { case IDOK: // szPrinterName is the printer name LPTSTR szPrinterName; // ulpIndex is the index of the currently selected item in the list box ULONG_PTR ulpIndex; DWORD cb; // Get the current selection of the list box ulpIndex = SendMessage(hWndPrinterList, LB_GETCURSEL, 0, 0); if (ulpIndex != LB_ERR) { // Get the size of the current selection of the list box cb = (DWORD) SendMessage(hWndPrinterList, LB_GETTEXTLEN, ulpIndex, NULL); if (cb != LB_ERR) { // Allocate the memory for the current selection szPrinterName = (LPTSTR) MemAlloc((cb + 1) * sizeof(TCHAR)); if (szPrinterName) { // Get the current selection of the list box if (SendMessage(hWndPrinterList, LB_GETTEXT, ulpIndex, (UINT_PTR) szPrinterName) != LB_ERR) { // Post a message that a printer has been selected PostMessage(g_hWndMain, UM_SELECT_FAX_PRINTER, (UINT_PTR) szPrinterName, 0); } } } } case IDCANCEL: EndDialog(hDlg, LOWORD(wParam)); return TRUE; } break; } return FALSE; } INT_PTR CALLBACK DocumentPropertiesDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam) { switch(iMsg) { case WM_INITDIALOG: // pFaxJobEntry is the pointer to the fax job PFAX_JOB_ENTRY pFaxJobEntry; // szColumnItem is text of a column item for those items that are equivalent to a column item LPTSTR szColumnItem; // Get the pointer to the fax job from the property sheet page pFaxJobEntry = (PFAX_JOB_ENTRY) ((LPPROPSHEETPAGE) lParam)->lParam; // Get the column item text for the document name szColumnItem = GetColumnItemText(eDocumentName, pFaxJobEntry, NULL); // Set the job type static text if (szColumnItem) { SetDlgItemText(hDlg, IDC_FAX_DOCUMENTNAME, szColumnItem); MemFree(szColumnItem); } // Set the recipient's name static text if (pFaxJobEntry->RecipientName) { SetDlgItemText(hDlg, IDC_FAX_RECIPIENTNAME, pFaxJobEntry->RecipientName); } // Set the recipient's fax number static text if (pFaxJobEntry->RecipientNumber) { SetDlgItemText(hDlg, IDC_FAX_RECIPIENTNUMBER, pFaxJobEntry->RecipientNumber); } // Set the sender's name static text if (pFaxJobEntry->SenderName) { SetDlgItemText(hDlg, IDC_FAX_SENDERNAME, pFaxJobEntry->SenderName); } // Set the sender's company static text if (pFaxJobEntry->SenderCompany) { SetDlgItemText(hDlg, IDC_FAX_SENDERCOMPANY, pFaxJobEntry->SenderCompany); } // Set the sender's department static text if (pFaxJobEntry->SenderDept) { SetDlgItemText(hDlg, IDC_FAX_SENDERDEPT, pFaxJobEntry->SenderDept); } // Set the billing code static text if (pFaxJobEntry->BillingCode) { SetDlgItemText(hDlg, IDC_FAX_BILLINGCODE, pFaxJobEntry->BillingCode); } // Get the column item text for the job type szColumnItem = GetColumnItemText(eJobType, pFaxJobEntry, NULL); // Set the job type static text if (szColumnItem) { SetDlgItemText(hDlg, IDC_FAX_JOBTYPE, szColumnItem); MemFree(szColumnItem); } // Get the column item text for the status szColumnItem = GetColumnItemText(eStatus, pFaxJobEntry, NULL); // Set the status static text if (szColumnItem) { SetDlgItemText(hDlg, IDC_FAX_STATUS, szColumnItem); MemFree(szColumnItem); } // Get the column item text for the pages szColumnItem = GetColumnItemText(ePages, pFaxJobEntry, NULL); // Set the pages static text if (szColumnItem) { SetDlgItemText(hDlg, IDC_FAX_PAGES, szColumnItem); MemFree(szColumnItem); } // Get the column item text for the size szColumnItem = GetColumnItemText(eSize, pFaxJobEntry, NULL); // Set the size static text if (szColumnItem) { SetDlgItemText(hDlg, IDC_FAX_SIZE, szColumnItem); MemFree(szColumnItem); } // Get the column item text for the scheduled time szColumnItem = GetColumnItemText(eScheduledTime, pFaxJobEntry, NULL); // Set the scheduled time static text if (szColumnItem) { SetDlgItemText(hDlg, IDC_FAX_SCHEDULEDTIME, szColumnItem); MemFree(szColumnItem); } FaxFreeBuffer(pFaxJobEntry); return TRUE; case WM_HELP: case WM_CONTEXTMENU: FAXWINHELP(iMsg, wParam, lParam, DocumentPropertiesHelpIDs); break; } return FALSE; } BOOL CALLBACK EnumThreadWndProc(HWND hWnd, LPARAM lParam) { if (GetWindowLong(hWnd, GWL_STYLE) & WS_VISIBLE) { CopyMemory((LPBYTE) lParam, &hWnd, sizeof(hWnd)); return FALSE; } return TRUE; } VOID PostEventToCompletionPort(HANDLE hCompletionPort, DWORD dwEventId, DWORD dwJobId) { PFAX_EVENT pFaxEvent; pFaxEvent = (PFAX_EVENT) LocalAlloc(LPTR, sizeof(FAX_EVENT)); pFaxEvent->EventId = dwEventId; pFaxEvent->JobId = dwJobId; PostQueuedCompletionStatus(hCompletionPort, sizeof(FAX_EVENT), 0, (LPOVERLAPPED) pFaxEvent); } DWORD FaxEventThread (LPVOID lpv) { // hExitStartEvents is a pointer to the g_hExitEvent and g_hStartEvent HANDLE hExitStartEvents[2]; // mii is the menu item info MENUITEMINFO mii; // hFaxMenu is a handle to the fax menu HMENU hFaxMenu; // pFaxConfig is the pointer to the fax configuration PFAX_CONFIGURATION pFaxConfig; // pPortJobInfoList is a pointer to the port job info list PLIST_ENTRY pPortJobInfoList; // pPortJobInfo is a pointer to a PORT_JOB_INFO_ITEM structure PPORT_JOB_INFO_ITEM pPortJobInfoItem; // pFaxPortInfo is the pointer to the fax ports PFAX_PORT_INFO pFaxPortInfo; // dwNumFaxPorts is the number of fax ports DWORD dwNumFaxPorts; // szDeviceName is the device name of the current fax port LPTSTR szDeviceName; // dwJobId is the fax job id on the current fax port DWORD dwJobId; // pFaxJobEntry is the pointer to the fax jobs PFAX_JOB_ENTRY pFaxJobEntry; // dwNumFaxJobs is the number of fax jobs DWORD dwNumFaxJobs; // lvfi specifies the attributes of a particular item to find in the list view LV_FINDINFO lvfi; // dwListIndex is the index of a particular item in the list view DWORD dwListIndex; // nColumnIndex is used to enumerate each column of the list view INT nColumnIndex; // szColumnItem is the text of a column item LPTSTR szColumnItem; // uState is the state of a particular item in the list view UINT uState; // dwOldFocusIndex is the old item in the list view with the focus DWORD dwOldFocusIndex; // dwNewFocusIndex is the new item in the list view with the focus DWORD dwNewFocusIndex; // pFaxEvent is a pointer to the port event PFAX_EVENT pFaxEvent; DWORD dwBytes; ULONG_PTR ulpCompletionKey; // dwIndex is a counter to enumerate each fax port and fax job DWORD dwIndex; DWORD dwRslt; // Set hExitStartEvents // g_hExitEvent hExitStartEvents[0] = g_hExitEvent; // g_hStartEvent hExitStartEvents[1] = g_hStartEvent; // Initialize hFaxMenu hFaxMenu = NULL; // Set pPortJobInfo to NULL pPortJobInfoList = NULL; while (TRUE) { // Wait for Exit, or Start event dwRslt = WaitForMultipleObjects(2, hExitStartEvents, FALSE, INFINITE); if (dwRslt == WAIT_OBJECT_0) { // Exit event was signaled, so exit return 0; } // Set the window title to indicate connecting SetWindowText(g_hWndMain, g_szTitleConnecting); // Get the handle to the fax menu if (!hFaxMenu) { hFaxMenu = GetSubMenu(GetMenu(g_hWndMain), 0); } // Create the completion port g_hCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0); if (!g_hCompletionPort) { goto ExitLevel0; } // Connect to the fax service if (!Connect()) { goto ExitLevel1; } // Initialize the fax event queue if (!FaxInitializeEventQueue(g_hFaxSvcHandle, g_hCompletionPort, 0, NULL, 0)) { // Disconnect from the fax service Disconnect(); goto ExitLevel1; } // Determine if faxing is paused if (FaxGetConfiguration(g_hFaxSvcHandle, &pFaxConfig)) { // Check the menu item CheckMenuItem(hFaxMenu, IDM_FAX_PAUSE_FAXING, MF_BYCOMMAND | (pFaxConfig->PauseServerQueue ? MF_CHECKED : MF_UNCHECKED)); #ifdef TOOLBAR_ENABLED // Enable the pause faxing toolbar menu item EnableToolbarMenuState(g_hWndToolbar, IDM_FAX_PAUSE_FAXING, pFaxConfig->PauseServerQueue); #endif // TOOLBAR_ENABLED FaxFreeBuffer(pFaxConfig); } // Enumerate the fax ports if (FaxEnumPorts(g_hFaxSvcHandle, &pFaxPortInfo, &dwNumFaxPorts)) { for (dwIndex = 0; dwIndex < dwNumFaxPorts; dwIndex++) { // Add each port job info into the list pPortJobInfoItem = (PPORT_JOB_INFO_ITEM) MemAlloc(sizeof(PORT_JOB_INFO_ITEM) + (lstrlen(pFaxPortInfo[dwIndex].DeviceName) + 1) * sizeof(TCHAR)); if (pPortJobInfoItem) { // Copy dwDeviceId pPortJobInfoItem->dwDeviceId = pFaxPortInfo[dwIndex].DeviceId; // Set szDeviceName pPortJobInfoItem->szDeviceName = (LPTSTR) ((UINT_PTR) pPortJobInfoItem + sizeof(PORT_JOB_INFO_ITEM)); // Copy szDeviceName lstrcpy(pPortJobInfoItem->szDeviceName, pFaxPortInfo[dwIndex].DeviceName); // Set dwJobId pPortJobInfoItem->dwJobId = (DWORD) -1; // Insert the port job info into the list if (pPortJobInfoList) { InsertTailList(pPortJobInfoList, &pPortJobInfoItem->ListEntry); } else { pPortJobInfoList = &pPortJobInfoItem->ListEntry; InitializeListHead(pPortJobInfoList); } } } FaxFreeBuffer(pFaxPortInfo); } // Enable the pause faxing menu item and the cancel all faxes menu item EnableMenuItem(hFaxMenu, IDM_FAX_PAUSE_FAXING, MF_BYCOMMAND | MF_ENABLED); EnableMenuItem(hFaxMenu, IDM_FAX_CANCEL_ALL_FAXES, MF_BYCOMMAND | MF_ENABLED); #ifdef TOOLBAR_ENABLED // Enable the pause faxing toolbar menu item and the cancel all faxes toolbar menu item EnableToolbarMenuState(g_hWndToolbar, IDM_FAX_PAUSE_FAXING, TRUE); EnableToolbarMenuState(g_hWndToolbar, IDM_FAX_CANCEL_ALL_FAXES, TRUE); #endif // TOOLBAR_ENABLED // Disconnect from the fax service Disconnect(); // Wait for fax events while (GetQueuedCompletionStatus(g_hCompletionPort, &dwBytes, &ulpCompletionKey, (LPOVERLAPPED *) &pFaxEvent, INFINITE)) { if (pFaxEvent->EventId == FEI_FAXSVC_ENDED) { // Thread should stop listening for fax events LocalFree(pFaxEvent); break; } switch (pFaxEvent->EventId) { case FEI_MODEM_POWERED_ON: case FEI_MODEM_POWERED_OFF: case FEI_RINGING: case FEI_ABORTING: // Ignore these fax events break; case FEI_FAXSVC_STARTED: // Set the window title to indicate refreshing SetWindowText(g_hWndMain, g_szTitleRefreshing); // Initialize the menu item info mii.cbSize = sizeof(mii); mii.fMask = MIIM_STATE; mii.fState = 0; // Get the state of the menu item GetMenuItemInfo(hFaxMenu, IDM_FAX_PAUSE_FAXING, FALSE, &mii); // Connect to the fax service if (Connect()) { // Enumerate the fax jobs if (FaxEnumJobs(g_hFaxSvcHandle, &pFaxJobEntry, &dwNumFaxJobs)) { // Initialize lvfi lvfi.flags = LVFI_PARAM; // Get the old item with the focus dwOldFocusIndex = ListView_GetNextItem(g_hWndListView, -1, LVNI_ALL | LVNI_FOCUSED); // Add new fax jobs and move existing fax jobs to their correct position for (dwIndex = 0; dwIndex < dwNumFaxJobs; dwIndex++) { // Set the search criteria lvfi.lParam = pFaxJobEntry[dwIndex].JobId; // Initialize the item's state uState = 0; // Initialize the device name szDeviceName = NULL; if (pPortJobInfoList) { // Find the appropriate job pPortJobInfoItem = (PPORT_JOB_INFO_ITEM) pPortJobInfoList; while (TRUE) { if (pFaxJobEntry[dwIndex].JobId == pPortJobInfoItem->dwJobId) { // Job id matches, so this is the appropriate port // Get the device name szDeviceName = pPortJobInfoItem->szDeviceName; break; } // Step to the next port job info item pPortJobInfoItem = (PPORT_JOB_INFO_ITEM) pPortJobInfoItem->ListEntry.Blink; if (pPortJobInfoItem == (PPORT_JOB_INFO_ITEM) pPortJobInfoList) { // The list has been traversed break; } } } // Find the job in the list view dwListIndex = ListView_FindItem(g_hWndListView, -1, &lvfi); if ((dwListIndex != -1) && (dwListIndex != dwIndex)) { // Job exists in the list view but is in the wrong position, so get the item // Get the item's state uState = ListView_GetItemState(g_hWndListView, dwListIndex, LVIS_FOCUSED | LVIS_SELECTED); // Delete the item from its current position ListView_DeleteItem(g_hWndListView, dwListIndex); // Set dwListIndex to -1 so item will be inserted into the list view dwListIndex = -1; } for (nColumnIndex = 0; nColumnIndex < (INT) eIllegalColumnIndex; nColumnIndex++) { // Get the column item text szColumnItem = GetColumnItemText((eListViewColumnIndex) nColumnIndex, &pFaxJobEntry[dwIndex], szDeviceName); // Insert item into the list view SetColumnItem(g_hWndListView, (dwListIndex == -1) ? TRUE : FALSE, dwIndex, nColumnIndex, szColumnItem, uState, &pFaxJobEntry[dwIndex]); if (szColumnItem) { MemFree(szColumnItem); } } } // Get the new item with the focus dwNewFocusIndex = ListView_GetNextItem(g_hWndListView, -1, LVNI_ALL | LVNI_FOCUSED); if ((dwOldFocusIndex != -1) && (dwNewFocusIndex != -1) && (dwNewFocusIndex >= dwNumFaxJobs)) { // Job will no longer exist in the list view, so set the focus to the item occupying that index // Get the state of the item occupying that index uState = ListView_GetItemState(g_hWndListView, dwOldFocusIndex, LVIS_FOCUSED | LVIS_SELECTED | LVIS_OVERLAYMASK); // Set the focus to the new item ListView_SetItemState(g_hWndListView, dwOldFocusIndex, uState | LVIS_FOCUSED, uState | LVIS_FOCUSED); } // Remove old fax jobs dwListIndex = ListView_GetItemCount(g_hWndListView); for (dwIndex = dwNumFaxJobs; dwIndex < dwListIndex; dwIndex++) { ListView_DeleteItem(g_hWndListView, dwNumFaxJobs); } FaxFreeBuffer(pFaxJobEntry); } // Disconnect from the fax service Disconnect(); } // Set the window title to indicate connected or paused SetWindowText(g_hWndMain, mii.fState & MFS_CHECKED ? g_szTitlePaused : g_szTitleConnected); continue; case FEI_JOB_QUEUED: case FEI_ANSWERED: // Initialize the device name szDeviceName = NULL; if ((pFaxEvent->EventId == FEI_ANSWERED) && (pPortJobInfoList)) { // Find the appropriate port pPortJobInfoItem = (PPORT_JOB_INFO_ITEM) pPortJobInfoList; while (TRUE) { if (pFaxEvent->DeviceId == pPortJobInfoItem->dwDeviceId) { // Device id matches, so this is the appropriate port // Set the job id pPortJobInfoItem->dwJobId = pFaxEvent->JobId; // Get the device name szDeviceName = pPortJobInfoItem->szDeviceName; break; } // Step to the next port job info item pPortJobInfoItem = (PPORT_JOB_INFO_ITEM) pPortJobInfoItem->ListEntry.Blink; if (pPortJobInfoItem == (PPORT_JOB_INFO_ITEM) pPortJobInfoList) { // The list has been traversed break; } } } // Connect to the fax service if (Connect()) { // Enumerate the fax jobs if (FaxEnumJobs(g_hFaxSvcHandle, &pFaxJobEntry, &dwNumFaxJobs)) { // Initialize lvfi lvfi.flags = LVFI_PARAM; // Add the new fax job to its correct position for (dwIndex = 0; dwIndex < dwNumFaxJobs; dwIndex++) { // Check if the current fax job matches the new fax job if (pFaxJobEntry[dwIndex].JobId != pFaxEvent->JobId) { continue; } // Set the search criteria lvfi.lParam = pFaxJobEntry[dwIndex].JobId; // Find the job in the list view dwListIndex = ListView_FindItem(g_hWndListView, -1, &lvfi); if (dwListIndex != -1) { // Job exists in the list view but is in the wrong position, so get the item // Delete the item from its current position ListView_DeleteItem(g_hWndListView, dwListIndex); } for (nColumnIndex = 0; nColumnIndex < (INT) eIllegalColumnIndex; nColumnIndex++) { // Get the column item text szColumnItem = GetColumnItemText((eListViewColumnIndex) nColumnIndex, &pFaxJobEntry[dwIndex], szDeviceName); // Insert item into the list view SetColumnItem(g_hWndListView, TRUE, dwIndex, nColumnIndex, szColumnItem, 0, &pFaxJobEntry[dwIndex]); if (szColumnItem) { MemFree(szColumnItem); } } break; } FaxFreeBuffer(pFaxJobEntry); } // Disconnect from the fax service Disconnect(); } continue; case FEI_DELETED: // Initialize lvfi lvfi.flags = LVFI_PARAM; // Set the search criteria lvfi.lParam = pFaxEvent->JobId; // Find the job in the list view dwListIndex = ListView_FindItem(g_hWndListView, -1, &lvfi); if (dwListIndex != -1) { // Delete the item from the list view ListView_DeleteItem(g_hWndListView, dwListIndex); } continue; default: // Initialize the device name szDeviceName = NULL; // Initialize the fax job id dwJobId = (DWORD) -1; // Set the port job info item if ((pFaxEvent->EventId != (DWORD) -1) && (pPortJobInfoList)) { // Find the appropriate port pPortJobInfoItem = (PPORT_JOB_INFO_ITEM) pPortJobInfoList; while (TRUE) { if (pFaxEvent->DeviceId == pPortJobInfoItem->dwDeviceId) { // Device id matches, so this is the appropriate port // Get the fax job id if (pFaxEvent->EventId == FEI_IDLE) { dwJobId = pPortJobInfoItem->dwJobId; } else { dwJobId = pFaxEvent->JobId; // Set the device name szDeviceName = pPortJobInfoItem->szDeviceName; } // Update the job id pPortJobInfoItem->dwJobId = pFaxEvent->JobId; break; } // Step to the next port job info item pPortJobInfoItem = (PPORT_JOB_INFO_ITEM) pPortJobInfoItem->ListEntry.Blink; if (pPortJobInfoItem == (PPORT_JOB_INFO_ITEM) pPortJobInfoList) { // The list has been traversed break; } } } else if (pFaxEvent->EventId == (DWORD) -1) { // Set the fax job id dwJobId = pFaxEvent->JobId; } // Initialize lvfi lvfi.flags = LVFI_PARAM; // Set the search criteria lvfi.lParam = dwJobId; // Find the job in the list view dwListIndex = ListView_FindItem(g_hWndListView, -1, &lvfi); if (dwListIndex != -1) { // Connect to the fax service if (Connect()) { // Get the fax job pFaxJobEntry = NULL; while ((FaxGetJob(g_hFaxSvcHandle, dwJobId, &pFaxJobEntry)) && (pFaxJobEntry->Status == FPS_AVAILABLE) && ((pFaxJobEntry->JobType == JT_SEND) || (pFaxJobEntry->JobType == JT_RECEIVE))) { FaxFreeBuffer(pFaxJobEntry); pFaxJobEntry = NULL; Sleep(250); } if (pFaxJobEntry) { // Job exists in the list view, so set the item for (nColumnIndex = 0; nColumnIndex < (INT) eIllegalColumnIndex; nColumnIndex++) { // Get the column item text szColumnItem = GetColumnItemText((eListViewColumnIndex) nColumnIndex, pFaxJobEntry, szDeviceName); // Set item in the list view SetColumnItem(g_hWndListView, FALSE, dwListIndex, nColumnIndex, szColumnItem, 0, pFaxJobEntry); if (szColumnItem) { MemFree(szColumnItem); } } FaxFreeBuffer(pFaxJobEntry); } // Disconnect from the fax service Disconnect(); } } break; } LocalFree(pFaxEvent); } // Disable the pause faxing menu item and the cancel all faxes menu item EnableMenuItem(hFaxMenu, IDM_FAX_PAUSE_FAXING, MF_BYCOMMAND | MF_GRAYED); EnableMenuItem(hFaxMenu, IDM_FAX_CANCEL_ALL_FAXES, MF_BYCOMMAND | MF_GRAYED); #ifdef TOOLBAR_ENABLED // Disable the pause faxing toolbar menu item and the cancel all faxes toolbar menu item EnableToolbarMenuState(g_hWndToolbar, IDM_FAX_PAUSE_FAXING, FALSE); EnableToolbarMenuState(g_hWndToolbar, IDM_FAX_CANCEL_ALL_FAXES, FALSE); #endif // TOOLBAR_ENABLED // Free the port job info list while (pPortJobInfoList) { // Get the head of the port job info list pPortJobInfoItem = (PPORT_JOB_INFO_ITEM) pPortJobInfoList; // Set the head of port job info list to the next port job info item in the list pPortJobInfoList = pPortJobInfoItem->ListEntry.Blink; if (IsListEmpty(pPortJobInfoList)) { // This is the last item in the list, so set the list head to NULL pPortJobInfoList = NULL; } else { // Remove the port job info item from the list RemoveEntryList(&pPortJobInfoItem->ListEntry); } // Free the port job info item MemFree(pPortJobInfoItem); } ExitLevel1: CloseHandle(g_hCompletionPort); ExitLevel0: // Reset the start event ResetEvent(g_hStartEvent); // Set the window title to indicate not connected SetWindowText(g_hWndMain, g_szTitleNotConnected); } return 0; }