Source code of Windows XP (NT5)
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.

2522 lines
109 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. faxqueue.cpp
  5. Abstract:
  6. This module implements the fax queue viewer
  7. Environment:
  8. WIN32 User Mode
  9. Author:
  10. Wesley Witt (wesw) 9-june-1997
  11. Steven Kehrli (steveke) 30-oct-1998 - major rewrite
  12. --*/
  13. #include "faxqueue.h"
  14. HINSTANCE g_hInstance; // g_hInstance is the handle to the instance
  15. HWND g_hWndMain; // g_hWndMain is the handle to the parent window
  16. HWND g_hWndListView; // g_hWndListView is the handle to the list view window
  17. HWND g_hWndToolbar; // g_hWndToolbar is the handle to the toolbar
  18. LPTSTR g_szTitleConnected; // g_szTitleConnected is the window title when connected
  19. LPTSTR g_szTitleNotConnected; // g_szTitleNotConnected is the window title when not connected
  20. LPTSTR g_szTitleConnecting; // g_szTitleConnecting is the window title when connecting
  21. LPTSTR g_szTitleRefreshing; // g_szTitleRefreshing is the window title when refreshing
  22. LPTSTR g_szTitlePaused; // g_szTitlePaused is the window title when paused
  23. LPTSTR g_szCurrentUserName; // g_szCurrentUserName is the name of the current user
  24. HANDLE g_hStartEvent; // g_hStartEvent is the handle to an event indicating the fax event queue exists
  25. HANDLE g_hExitEvent; // g_hExitEvent is the handle to an event indicating the application is exiting
  26. LPTSTR g_szMachineName; // g_szMachineName is the machine to connect to
  27. HANDLE g_hFaxSvcMutex; // g_hFaxSvcMutex is an object to synchronize access to the fax service routines
  28. HANDLE g_hFaxSvcHandle; // g_hFaxSvcHandle is the handle to the fax service
  29. LONG g_nNumConnections; // g_nNumConnections is the number of connections to the fax service
  30. HANDLE g_hCompletionPort; // g_hCompletionPort is the handle to the completion port
  31. WINPOSINFO WinPosInfo =
  32. {
  33. #ifdef DEBUG
  34. FALSE,
  35. #endif // DEBUG
  36. #ifdef TOOLBAR_ENABLED
  37. FALSE, // toolbar
  38. #endif // TOOLBAR_ENABLED
  39. TRUE, // status bar
  40. 200, // eDocumentName
  41. 80, // eJobType
  42. 80, // eStatus
  43. 80, // eOwner
  44. 60, // ePages
  45. 100, // eSize
  46. 140, // eScheduledTime
  47. 120, // ePort
  48. {sizeof(WINDOWPLACEMENT), 0, SW_SHOWNORMAL, {0, 0}, {0, 0}, {50, 100, 695, 300}}
  49. };
  50. DWORD DocumentPropertiesHelpIDs[] =
  51. {
  52. IDC_FAX_DOCUMENTNAME, IDH_QUEUE_DOCUMENTNAME,
  53. IDC_FAX_RECIPIENTINFO, IDH_QUEUE_RECIPIENTINFO,
  54. IDC_FAX_RECIPIENTNAME_TEXT, IDH_QUEUE_RECIPIENTNAME,
  55. IDC_FAX_RECIPIENTNAME, IDH_QUEUE_RECIPIENTNAME,
  56. IDC_FAX_RECIPIENTNUMBER_TEXT, IDH_QUEUE_RECIPIENTNUMBER,
  57. IDC_FAX_RECIPIENTNUMBER, IDH_QUEUE_RECIPIENTNUMBER,
  58. IDC_FAX_SENDERINFO, IDH_QUEUE_SENDERINFO,
  59. IDC_FAX_SENDERNAME_TEXT, IDH_QUEUE_SENDERNAME,
  60. IDC_FAX_SENDERNAME, IDH_QUEUE_SENDERNAME,
  61. IDC_FAX_SENDERCOMPANY_TEXT, IDH_QUEUE_SENDERCOMPANY,
  62. IDC_FAX_SENDERCOMPANY, IDH_QUEUE_SENDERCOMPANY,
  63. IDC_FAX_SENDERDEPT_TEXT, IDH_QUEUE_SENDERDEPT,
  64. IDC_FAX_SENDERDEPT, IDH_QUEUE_SENDERDEPT,
  65. IDC_FAX_BILLINGCODE_TEXT, IDH_QUEUE_BILLINGCODE,
  66. IDC_FAX_BILLINGCODE, IDH_QUEUE_BILLINGCODE,
  67. IDC_FAX_FAXINFO, IDH_QUEUE_FAXINFO,
  68. IDC_FAX_JOBTYPE_TEXT, IDH_QUEUE_JOBTYPE,
  69. IDC_FAX_JOBTYPE, IDH_QUEUE_JOBTYPE,
  70. IDC_FAX_STATUS_TEXT, IDH_QUEUE_STATUS,
  71. IDC_FAX_STATUS, IDH_QUEUE_STATUS,
  72. IDC_FAX_PAGES_TEXT, IDH_QUEUE_PAGES,
  73. IDC_FAX_PAGES, IDH_QUEUE_PAGES,
  74. IDC_FAX_SIZE_TEXT, IDH_QUEUE_SIZE,
  75. IDC_FAX_SIZE, IDH_QUEUE_SIZE,
  76. IDC_FAX_SCHEDULEDTIME_TEXT, IDH_QUEUE_SCHEDULEDTIME,
  77. IDC_FAX_SCHEDULEDTIME, IDH_QUEUE_SCHEDULEDTIME,
  78. 0, 0
  79. };
  80. // MainWndProc is the parent window procedure
  81. LRESULT CALLBACK MainWndProc (HWND hWndMain, UINT iMsg, WPARAM wParam, LPARAM lParam);
  82. // SelectFaxPrinterDlgProc is the select fax printer dialog procedure
  83. INT_PTR CALLBACK SelectFaxPrinterDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam);
  84. // DocumentPropertiesDlgProc is the select fax printer dialog procedure
  85. INT_PTR CALLBACK DocumentPropertiesDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam);
  86. // EnumThreadWndProc is the callback function for the EnumThreadWindows call
  87. BOOL CALLBACK EnumThreadWndProc(HWND hWnd, LPARAM lParam);
  88. // PostEventToCompletionPort posts an exit packet to a completion port
  89. VOID PostEventToCompletionPort(HANDLE hCompletionPort, DWORD dwEventId, DWORD dwJobId);
  90. // FaxEventThread is the thread to handle the fax events
  91. DWORD FaxEventThread (LPVOID lpv);
  92. extern "C"
  93. int __cdecl
  94. _tmain(
  95. int argc,
  96. LPTSTR argv[]
  97. )
  98. {
  99. WNDCLASSEX wndclass;
  100. MSG msg;
  101. // bStarted indicates if the application has started
  102. BOOL bStarted;
  103. // szFormat is a format string
  104. TCHAR szFormat[RESOURCE_STRING_LEN];
  105. // szComputerName is the local computer name
  106. LPTSTR szComputerName;
  107. DWORD dwComputerNameSize;
  108. // hThread is the handle to a thread
  109. HANDLE hThread;
  110. // hAccel is the handle to the accelerators
  111. HACCEL hAccel;
  112. DWORD dwReturn;
  113. DWORD cb;
  114. // Set g_hInstance
  115. g_hInstance = GetModuleHandle(NULL);
  116. // Set bStarted to FALSE to indicate the application has not started
  117. bStarted = FALSE;
  118. // Get the machine name
  119. g_szMachineName = NULL;
  120. if (argc == 2) {
  121. // Allocate the memory for the machine name
  122. g_szMachineName = (LPTSTR) MemAlloc((lstrlen(argv[1]) + 1) * sizeof(TCHAR));
  123. if (g_szMachineName) {
  124. // Copy the machine name
  125. lstrcpy(g_szMachineName, argv[1]);
  126. // Allocate the memory for the local computer name
  127. dwComputerNameSize = MAX_COMPUTERNAME_LENGTH + 1;
  128. szComputerName = (LPTSTR) MemAlloc((MAX_COMPUTERNAME_LENGTH + 1) * sizeof(TCHAR));
  129. if (szComputerName) {
  130. // Get the local computer name
  131. if (GetComputerName(szComputerName, &dwComputerNameSize)) {
  132. // Compare the local computer name against the machine name
  133. if (!lstrcmpi(g_szMachineName, szComputerName)) {
  134. // Local computer name and machine name are the same, so set machine name to NULL
  135. MemFree(g_szMachineName);
  136. g_szMachineName = NULL;
  137. }
  138. }
  139. MemFree(szComputerName);
  140. }
  141. }
  142. }
  143. // Set the window title when connected
  144. if (g_szMachineName) {
  145. // Convert the machine name to uppercase
  146. g_szMachineName = CharUpper(g_szMachineName);
  147. LoadString(g_hInstance, IDS_FAXQUEUE_REMOTE_CAPTION, szFormat, RESOURCE_STRING_LEN);
  148. // Allocate the memory for the window title
  149. g_szTitleConnected = (LPTSTR) MemAlloc((lstrlen(szFormat) + lstrlen(g_szMachineName) + 1) * sizeof(TCHAR));
  150. if (!g_szTitleConnected) {
  151. // Set the exit code
  152. dwReturn = GetLastError();
  153. goto ExitLevel0;
  154. }
  155. wsprintf(g_szTitleConnected, szFormat, g_szMachineName);
  156. }
  157. else {
  158. LoadString(g_hInstance, IDS_FAXQUEUE_LOCAL_CAPTION, szFormat, RESOURCE_STRING_LEN);
  159. // Allocate the memory for the window title
  160. g_szTitleConnected = (LPTSTR) MemAlloc((lstrlen(szFormat) + 1) * sizeof(TCHAR));
  161. if (!g_szTitleConnected) {
  162. // Set the exit code
  163. dwReturn = GetLastError();
  164. goto ExitLevel0;
  165. }
  166. lstrcpy(g_szTitleConnected, szFormat);
  167. }
  168. // Set the window title when not connected
  169. LoadString(g_hInstance, IDS_FAXQUEUE_NOT_CONNECTED, szFormat, RESOURCE_STRING_LEN);
  170. // Allocate the memory for the window title
  171. g_szTitleNotConnected = (LPTSTR) MemAlloc((lstrlen(g_szTitleConnected) + lstrlen(szFormat) + 1) * sizeof(TCHAR));
  172. if (!g_szTitleNotConnected) {
  173. // Set the exit code
  174. dwReturn = GetLastError();
  175. goto ExitLevel1;
  176. }
  177. lstrcpy(g_szTitleNotConnected, g_szTitleConnected);
  178. lstrcat(g_szTitleNotConnected, szFormat);
  179. // Set the window title when connecting
  180. LoadString(g_hInstance, IDS_FAXQUEUE_CONNECTING, szFormat, RESOURCE_STRING_LEN);
  181. // Allocate the memory for the window title
  182. g_szTitleConnecting = (LPTSTR) MemAlloc((lstrlen(g_szTitleConnected) + lstrlen(szFormat) + 1) * sizeof(TCHAR));
  183. if (!g_szTitleConnecting) {
  184. // Set the exit code
  185. dwReturn = GetLastError();
  186. goto ExitLevel2;
  187. }
  188. lstrcpy(g_szTitleConnecting, g_szTitleConnected);
  189. lstrcat(g_szTitleConnecting, szFormat);
  190. // Set the window title when refreshing
  191. LoadString(g_hInstance, IDS_FAXQUEUE_REFRESHING, szFormat, RESOURCE_STRING_LEN);
  192. // Allocate the memory for the window title
  193. g_szTitleRefreshing = (LPTSTR) MemAlloc((lstrlen(g_szTitleConnected) + lstrlen(szFormat) + 1) * sizeof(TCHAR));
  194. if (!g_szTitleRefreshing) {
  195. // Set the exit code
  196. dwReturn = GetLastError();
  197. goto ExitLevel3;
  198. }
  199. lstrcpy(g_szTitleRefreshing, g_szTitleConnected);
  200. lstrcat(g_szTitleRefreshing, szFormat);
  201. // Set the window title when paused
  202. LoadString(g_hInstance, IDS_FAXQUEUE_PAUSED, szFormat, RESOURCE_STRING_LEN);
  203. // Allocate the memory for the window title
  204. g_szTitlePaused = (LPTSTR) MemAlloc((lstrlen(g_szTitleConnected) + lstrlen(szFormat) + 1) * sizeof(TCHAR));
  205. if (!g_szTitlePaused) {
  206. // Set the exit code
  207. dwReturn = GetLastError();
  208. goto ExitLevel4;
  209. }
  210. lstrcpy(g_szTitlePaused, g_szTitleConnected);
  211. lstrcat(g_szTitlePaused, szFormat);
  212. g_hWndMain = NULL;
  213. // Find the window
  214. g_hWndMain = FindWindow(FAXQUEUE_WINCLASS, g_szTitlePaused);
  215. if (g_hWndMain) {
  216. goto ExitLevel5;
  217. }
  218. // Find the window
  219. g_hWndMain = FindWindow(FAXQUEUE_WINCLASS, g_szTitleRefreshing);
  220. if (g_hWndMain) {
  221. goto ExitLevel5;
  222. }
  223. // Find the window
  224. g_hWndMain = FindWindow(FAXQUEUE_WINCLASS, g_szTitleConnecting);
  225. if (g_hWndMain) {
  226. goto ExitLevel5;
  227. }
  228. // Find the window
  229. g_hWndMain = FindWindow(FAXQUEUE_WINCLASS, g_szTitleNotConnected);
  230. if (g_hWndMain) {
  231. goto ExitLevel5;
  232. }
  233. // Find the window
  234. g_hWndMain = FindWindow(FAXQUEUE_WINCLASS, g_szTitleConnected);
  235. if (g_hWndMain) {
  236. goto ExitLevel5;
  237. }
  238. // Create the g_hStartEvent
  239. g_hStartEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  240. if (!g_hStartEvent) {
  241. // Set the exit code
  242. dwReturn = GetLastError();
  243. goto ExitLevel5;
  244. }
  245. // Create the g_hExitEvent
  246. g_hExitEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  247. if (!g_hExitEvent) {
  248. // Set the exit code
  249. dwReturn = GetLastError();
  250. goto ExitLevel6;
  251. }
  252. // Initialize the fax service
  253. g_hFaxSvcMutex = CreateMutex(NULL, FALSE, NULL);
  254. if (!g_hFaxSvcMutex) {
  255. // Set the exit code
  256. dwReturn = GetLastError();
  257. goto ExitLevel7;
  258. }
  259. g_hFaxSvcHandle = NULL;
  260. g_nNumConnections = 0;
  261. hThread = CreateThread(NULL, 0, FaxEventThread, NULL, 0, NULL);
  262. if (!hThread) {
  263. // Set the exit code
  264. dwReturn = GetLastError();
  265. goto ExitLevel8;
  266. }
  267. CloseHandle(hThread);
  268. // Load the accelerators
  269. hAccel = LoadAccelerators(g_hInstance, MAKEINTRESOURCE(IDR_ACCEL));
  270. if (!hAccel) {
  271. // Set the exit code
  272. dwReturn = GetLastError();
  273. goto ExitLevel9;
  274. }
  275. // Get the name of the current user
  276. cb = 0;
  277. GetUserName(NULL, &cb);
  278. g_szCurrentUserName = (LPTSTR) MemAlloc((cb + 1) * sizeof(TCHAR));
  279. if (!GetUserName(g_szCurrentUserName, &cb)) {
  280. MemFree(g_szCurrentUserName);
  281. g_szCurrentUserName = NULL;
  282. }
  283. // Retrieve the persistent data
  284. GetFaxQueueRegistryData(&WinPosInfo);
  285. // Initialize the common controls
  286. InitCommonControls();
  287. // Set bStarted to TRUE to indicate the application has started
  288. bStarted = TRUE;
  289. // Initialize the wndclass
  290. wndclass.cbSize = sizeof(wndclass);
  291. wndclass.style = CS_HREDRAW | CS_VREDRAW;
  292. wndclass.lpfnWndProc = MainWndProc;
  293. wndclass.cbClsExtra = 0;
  294. wndclass.cbWndExtra = 0;
  295. wndclass.hInstance = g_hInstance;
  296. wndclass.hIcon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_FAXQUEUE_ICON));
  297. wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
  298. wndclass.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
  299. wndclass.lpszMenuName = MAKEINTRESOURCE(IDR_MENU);
  300. wndclass.lpszClassName = FAXQUEUE_WINCLASS;
  301. wndclass.hIconSm = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_FAXQUEUE_ICON));
  302. RegisterClassEx(&wndclass);
  303. g_hWndMain = CreateWindow(FAXQUEUE_WINCLASS, g_szTitleConnecting, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, g_hInstance, NULL);
  304. // Move and show the window
  305. SetWindowPlacement(g_hWndMain, &WinPosInfo.WindowPlacement);
  306. ShowWindow(g_hWndMain, SW_SHOWNORMAL);
  307. UpdateWindow(g_hWndMain);
  308. // Set the start event
  309. SetEvent(g_hStartEvent);
  310. while (GetMessage(&msg, NULL, 0, 0)) {
  311. if (!TranslateAccelerator(g_hWndMain, hAccel, &msg)) {
  312. TranslateMessage(&msg);
  313. DispatchMessage(&msg);
  314. }
  315. }
  316. if (g_szCurrentUserName) {
  317. MemFree(g_szCurrentUserName);
  318. }
  319. ExitLevel9:
  320. SetEvent(g_hExitEvent);
  321. ExitLevel8:
  322. CloseHandle(g_hFaxSvcMutex);
  323. ExitLevel7:
  324. CloseHandle(g_hExitEvent);
  325. ExitLevel6:
  326. CloseHandle(g_hStartEvent);
  327. ExitLevel5:
  328. if ((g_hWndMain) && (!bStarted)) {
  329. // g_hWndMain is valid but the application has not started, so it must already be running
  330. // Switch to that window
  331. ShowWindow(g_hWndMain, SW_RESTORE);
  332. SetForegroundWindow(g_hWndMain);
  333. // Set the exit code
  334. dwReturn = 0;
  335. // Set bStarted to TRUE to indicate the application has started
  336. bStarted = TRUE;
  337. }
  338. MemFree(g_szTitlePaused);
  339. ExitLevel4:
  340. MemFree(g_szTitleRefreshing);
  341. ExitLevel3:
  342. MemFree(g_szTitleConnecting);
  343. ExitLevel2:
  344. MemFree(g_szTitleNotConnected);
  345. ExitLevel1:
  346. MemFree(g_szTitleConnected);
  347. ExitLevel0:
  348. if (g_szMachineName) {
  349. MemFree(g_szMachineName);
  350. }
  351. if (!bStarted) {
  352. // szErrorCaption is the error caption if the application cannot start
  353. TCHAR szErrorCaption[RESOURCE_STRING_LEN];
  354. // szErrorFormat is the format of the error message if the application cannot start
  355. TCHAR szErrorFormat[RESOURCE_STRING_LEN];
  356. // szErrorReason is the error reason if the application cannot start
  357. LPTSTR szErrorReason;
  358. // szErrorMessage is the error message if the application cannot start
  359. LPTSTR szErrorMessage;
  360. // The application did not start so display an error message
  361. // Load the error caption
  362. LoadString(g_hInstance, IDS_ERROR_CAPTION, szErrorCaption, RESOURCE_STRING_LEN);
  363. // Try to get the error message from the system message table
  364. szErrorMessage = NULL;
  365. if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwReturn, 0, (LPTSTR) &szErrorReason, 0, NULL)) {
  366. // Load the error format
  367. LoadString(g_hInstance, IDS_ERROR_APP_FAILED_FORMAT, szErrorFormat, RESOURCE_STRING_LEN);
  368. // Allocate the memory for the error message
  369. szErrorMessage = (LPTSTR) MemAlloc((lstrlen(szErrorReason) + RESOURCE_STRING_LEN + 1) * sizeof(TCHAR));
  370. if (szErrorMessage) {
  371. // Set the error message
  372. wsprintf(szErrorMessage, szErrorFormat, szErrorReason);
  373. }
  374. LocalFree(szErrorReason);
  375. }
  376. if (!szErrorMessage) {
  377. // Allocate the memory for the error message
  378. szErrorMessage = (LPTSTR) MemAlloc((RESOURCE_STRING_LEN) * sizeof(TCHAR));
  379. if (szErrorMessage) {
  380. // Load the error message
  381. LoadString(g_hInstance, IDS_ERROR_APP_FAILED, szErrorMessage, RESOURCE_STRING_LEN);
  382. }
  383. }
  384. if (szErrorMessage) {
  385. // Display the error message
  386. MessageBox(NULL, szErrorMessage, szErrorCaption, MB_OK | MB_ICONERROR | MB_APPLMODAL);
  387. MemFree(szErrorMessage);
  388. }
  389. }
  390. return dwReturn;
  391. }
  392. LRESULT CALLBACK MainWndProc (HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
  393. {
  394. // rcClient is the rectangle of the client area
  395. RECT rcClient;
  396. // hWndToolTips is the handle to the tool tips window
  397. static HWND hWndToolTips;
  398. // rcToolbar is the rectangle of the toolbar
  399. static RECT rcToolbar;
  400. // hWndStatusBar is the handle to the status bar
  401. static HWND hWndStatusBar;
  402. // rcStatusBar is the rectangle of the status bar
  403. static RECT rcStatusBar;
  404. // hFaxMenu is the handle to the fax menu
  405. static HMENU hFaxMenu;
  406. // hFaxSetAsDefaultMenu is the handle to the set as default printer menu
  407. static HMENU hFaxSetAsDefaultMenu;
  408. // hFaxSharingMenu is the handle to the sharing menu
  409. static HMENU hFaxSharingMenu;
  410. // hFaxPropertiesMenu is the handle to the properties menu
  411. static HMENU hFaxPropertiesMenu;
  412. // hDocumentMenu is the handle to the document menu
  413. static HMENU hDocumentMenu;
  414. // hViewMenu is the handle to the view menu
  415. static HMENU hViewMenu;
  416. // uCurrentMenu indicates the current menu selection
  417. static UINT uCurrentMenu;
  418. // pProcessInfoList is a pointer to the process info list
  419. static PLIST_ENTRY pProcessInfoList;
  420. switch (iMsg) {
  421. case WM_CREATE:
  422. // lvc specifies the attributes of a particular column of the list view
  423. LV_COLUMN lvc;
  424. // nColumnIndex is used to enumerate each column of the list view
  425. INT nColumnIndex;
  426. // szColumnHeader is the column header text
  427. TCHAR szColumnHeader[RESOURCE_STRING_LEN];
  428. // Set pProcessInfoList to NULL
  429. pProcessInfoList = NULL;
  430. // Get the handle to the fax menu
  431. hFaxMenu = GetSubMenu(GetMenu(hWnd), 0);
  432. // Initialize the set as default printer menu
  433. hFaxSetAsDefaultMenu = NULL;
  434. // Initialize the sharing menu
  435. hFaxSharingMenu = NULL;
  436. // Initialize the properties menu
  437. hFaxPropertiesMenu = NULL;
  438. // Disable the pause faxing menu item and the cancel all faxes menu item
  439. EnableMenuItem(hFaxMenu, IDM_FAX_PAUSE_FAXING, MF_BYCOMMAND | MF_GRAYED);
  440. EnableMenuItem(hFaxMenu, IDM_FAX_CANCEL_ALL_FAXES, MF_BYCOMMAND | MF_GRAYED);
  441. #ifdef TOOLBAR_ENABLED
  442. // Disable the pause faxing toolbar menu item and the cancel all faxes toolbar menu item
  443. EnableToolbarMenuState(g_hWndToolbar, IDM_FAX_PAUSE_FAXING, FALSE);
  444. EnableToolbarMenuState(g_hWndToolbar, IDM_FAX_CANCEL_ALL_FAXES, FALSE);
  445. #endif // TOOLBAR_ENABLED
  446. #ifdef WIN95
  447. // Disable the sharing menu item
  448. EnableMenuItem(hFaxMenu, 5, MF_BYPOSITION | MF_GRAYED);
  449. // Disable the properties menu item
  450. EnableMenuItem(hFaxMenu, 7, MF_BYPOSITION | MF_GRAYED);
  451. #endif // WIN95
  452. // Get the handle to the document menu
  453. hDocumentMenu = GetSubMenu(GetMenu(hWnd), 1);
  454. // Get the handle to the view menu
  455. hViewMenu = GetSubMenu(GetMenu(hWnd), 2);
  456. #ifdef TOOLBAR_ENABLED
  457. // Set the toolbar
  458. if (WinPosInfo.bToolbarVisible) {
  459. // Show the toolbar
  460. hWndToolTips = CreateToolTips(hWnd);
  461. g_hWndToolbar = CreateToolbar(hWnd);
  462. // Get the rectangle of the status bar
  463. GetWindowRect(g_hWndToolbar, &rcToolbar);
  464. }
  465. else {
  466. ZeroMemory(&rcToolbar, sizeof(rcToolbar));
  467. }
  468. // Check the menu item
  469. CheckMenuItem(hViewMenu, IDM_VIEW_TOOLBAR, MF_BYCOMMAND | (WinPosInfo.bToolbarVisible ? MF_CHECKED : MF_UNCHECKED));
  470. #else
  471. ZeroMemory(&rcToolbar, sizeof(rcToolbar));
  472. #endif // TOOLBAR_ENABLED
  473. // Set the status bar
  474. if (WinPosInfo.bStatusBarVisible) {
  475. // Show the status bar
  476. hWndStatusBar = CreateStatusWindow(WS_CHILD | WS_CLIPSIBLINGS | WS_TABSTOP | WS_VISIBLE | SBARS_SIZEGRIP, NULL, hWnd, IDM_STATUS_BAR);
  477. // Get the rectangle of the status bar
  478. GetWindowRect(hWndStatusBar, &rcStatusBar);
  479. }
  480. else {
  481. ZeroMemory(&rcStatusBar, sizeof(rcStatusBar));
  482. }
  483. // Check the menu item
  484. CheckMenuItem(hViewMenu, IDM_VIEW_STATUS_BAR, MF_BYCOMMAND | (WinPosInfo.bStatusBarVisible ? MF_CHECKED : MF_UNCHECKED));
  485. // Get the rectangle of the client area
  486. GetClientRect(hWnd, &rcClient);
  487. // Create the list view control
  488. 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);
  489. if (g_hWndListView) {
  490. ListView_SetExtendedListViewStyle(g_hWndListView, LVS_EX_FULLROWSELECT);
  491. // Set common attributes for each column
  492. lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
  493. lvc.fmt = LVCFMT_LEFT;
  494. for (nColumnIndex = 0; nColumnIndex < (INT) eIllegalColumnIndex; nColumnIndex++) {
  495. // Get the column header text
  496. GetColumnHeaderText((eListViewColumnIndex) nColumnIndex, szColumnHeader);
  497. // Set the column header text
  498. lvc.pszText = szColumnHeader;
  499. // Set the column width
  500. lvc.cx = WinPosInfo.ColumnWidth[nColumnIndex];
  501. // Set the column number
  502. lvc.iSubItem = nColumnIndex;
  503. // Insert column into list view
  504. ListView_InsertColumn(g_hWndListView, lvc.iSubItem, &lvc);
  505. }
  506. SetFocus(g_hWndListView);
  507. }
  508. break;
  509. case WM_MENUSELECT:
  510. UINT uBase;
  511. switch (LOWORD(wParam)) {
  512. case IDM_FAX_SET_AS_DEFAULT_PRINTER_1:
  513. case IDM_FAX_SET_AS_DEFAULT_PRINTER_2:
  514. case IDM_FAX_SET_AS_DEFAULT_PRINTER_3:
  515. case IDM_FAX_SET_AS_DEFAULT_PRINTER_4:
  516. wParam = MAKELONG(LOWORD(IDM_FAX_SET_AS_DEFAULT_PRINTER), HIWORD(wParam));
  517. break;
  518. case IDM_FAX_SHARING_1:
  519. case IDM_FAX_SHARING_2:
  520. case IDM_FAX_SHARING_3:
  521. case IDM_FAX_SHARING_4:
  522. wParam = MAKELONG(LOWORD(IDM_FAX_SHARING), HIWORD(wParam));
  523. break;
  524. case IDM_FAX_PROPERTIES_1:
  525. case IDM_FAX_PROPERTIES_2:
  526. case IDM_FAX_PROPERTIES_3:
  527. case IDM_FAX_PROPERTIES_4:
  528. wParam = MAKELONG(LOWORD(IDM_FAX_PROPERTIES), HIWORD(wParam));
  529. break;
  530. case IDM_FAX_SET_AS_DEFAULT_PRINTER_MORE:
  531. case IDM_FAX_SHARING_MORE:
  532. case IDM_FAX_PROPERTIES_MORE:
  533. wParam = MAKELONG(LOWORD(IDM_FAX_SET_AS_DEFAULT_PRINTER_MORE), HIWORD(wParam));
  534. break;
  535. }
  536. if (hWndStatusBar) {
  537. uBase = IDS_MENU_BASE;
  538. MenuHelp(iMsg, wParam, lParam, NULL, g_hInstance, hWndStatusBar, &uBase);
  539. }
  540. break;
  541. case WM_INITMENUPOPUP:
  542. if (((HMENU) wParam == hFaxMenu) && (LOWORD(lParam) == 0)) {
  543. // mii is the menu item info
  544. MENUITEMINFO mii;
  545. // szMenuString is a menu string
  546. TCHAR szMenuString[RESOURCE_STRING_LEN];
  547. // dwNumOldMenuItems is the old number of menu items
  548. DWORD dwNumOldMenuItems;
  549. // dwNumNewMenuItems is the new number of menu items
  550. DWORD dwNumNewMenuItems;
  551. // pFaxPrintersConfig is the pointer to the fax printers
  552. LPPRINTER_INFO_2 pFaxPrintersConfig;
  553. // dwNumFaxPrinters is the number of fax printers
  554. DWORD dwNumFaxPrinters;
  555. // dwIndex is a counter to enumerate each menu and printer
  556. DWORD dwIndex;
  557. // dwDefaultIndex is the index of the default fax printer
  558. DWORD dwDefaultIndex;
  559. // szDefaultPrinterName is the default printer name
  560. LPTSTR szDefaultPrinterName;
  561. if ((WaitForSingleObject(g_hStartEvent, 0) != WAIT_TIMEOUT) && (ListView_GetItemCount(g_hWndListView))) {
  562. // Enable the cancel all faxes menu item
  563. EnableMenuItem(hFaxMenu, IDM_FAX_CANCEL_ALL_FAXES, MF_BYCOMMAND | MF_ENABLED);
  564. }
  565. else {
  566. // Disable the cancel all faxes menu item
  567. EnableMenuItem(hFaxMenu, IDM_FAX_CANCEL_ALL_FAXES, MF_BYCOMMAND | MF_GRAYED);
  568. }
  569. // Get the default printer
  570. szDefaultPrinterName = GetDefaultPrinterName();
  571. // Get the fax printers
  572. pFaxPrintersConfig = (LPPRINTER_INFO_2) GetFaxPrinters(&dwNumFaxPrinters);
  573. if ((pFaxPrintersConfig) && (dwNumFaxPrinters > 1)) {
  574. // Many fax printers, so set menu items as sub-menus
  575. // Initialize the menu item info
  576. mii.cbSize = sizeof(mii);
  577. mii.fMask = MIIM_STATE | MIIM_SUBMENU;
  578. mii.fState = MFS_ENABLED;
  579. // Update the set as default printer menu item
  580. if (!hFaxSetAsDefaultMenu) {
  581. hFaxSetAsDefaultMenu = CreatePopupMenu();
  582. mii.hSubMenu = hFaxSetAsDefaultMenu;
  583. SetMenuItemInfo(hFaxMenu, IDM_FAX_SET_AS_DEFAULT_PRINTER, FALSE, &mii);
  584. }
  585. // Update the sharing menu item
  586. if (!hFaxSharingMenu) {
  587. hFaxSharingMenu = CreatePopupMenu();
  588. mii.hSubMenu = hFaxSharingMenu;
  589. SetMenuItemInfo(hFaxMenu, IDM_FAX_SHARING, FALSE, &mii);
  590. }
  591. // Update the properties menu item
  592. if (!hFaxPropertiesMenu) {
  593. hFaxPropertiesMenu = CreatePopupMenu();
  594. mii.hSubMenu = hFaxPropertiesMenu;
  595. SetMenuItemInfo(hFaxMenu, IDM_FAX_PROPERTIES, FALSE, &mii);
  596. }
  597. // Initialize the menu item info
  598. mii.cbSize = sizeof(mii);
  599. mii.fMask = MIIM_ID | MIIM_STATE | MIIM_TYPE;
  600. mii.fType = MFT_STRING;
  601. // Get the number of menu items
  602. dwNumOldMenuItems = (DWORD) GetMenuItemCount(hFaxSetAsDefaultMenu);
  603. // Insert the default fax printer first into the menus
  604. for (dwDefaultIndex = dwNumFaxPrinters, dwNumNewMenuItems = 0; (szDefaultPrinterName) && (dwDefaultIndex > 0); dwDefaultIndex--) {
  605. if (!lstrcmpi(szDefaultPrinterName, pFaxPrintersConfig[dwDefaultIndex - 1].pPrinterName)) {
  606. // Set the menu string
  607. wsprintf(szMenuString, TEXT("&%d %s"), dwNumNewMenuItems + 1, pFaxPrintersConfig[dwDefaultIndex - 1].pPrinterName);
  608. mii.fState = MFS_CHECKED | MFS_ENABLED;
  609. mii.dwTypeData = szMenuString;
  610. // Insert the item into the set as default printer menu
  611. mii.wID = IDM_FAX_SET_AS_DEFAULT_PRINTER_1;
  612. InsertMenuItem(hFaxSetAsDefaultMenu, dwNumOldMenuItems, TRUE, &mii);
  613. // Insert the item into the sharing menu
  614. mii.wID = IDM_FAX_SHARING_1;
  615. InsertMenuItem(hFaxSharingMenu, dwNumOldMenuItems, TRUE, &mii);
  616. // Insert the item into the properties menu
  617. mii.wID = IDM_FAX_PROPERTIES_1;
  618. InsertMenuItem(hFaxPropertiesMenu, dwNumOldMenuItems, TRUE, &mii);
  619. // Increment the number of new menu items
  620. dwNumNewMenuItems++;
  621. break;
  622. }
  623. }
  624. // Propagate the menus with the list of fax printers
  625. mii.fState = MFS_ENABLED;
  626. for (dwIndex = 0; (dwIndex < dwNumFaxPrinters) && (dwNumNewMenuItems < (IDM_FAX_SET_AS_DEFAULT_PRINTER_MORE - IDM_FAX_SET_AS_DEFAULT_PRINTER_1)); dwIndex++) {
  627. if (dwIndex != (dwDefaultIndex - 1)) {
  628. // Set the menu string
  629. wsprintf(szMenuString, TEXT("&%d %s"), dwNumNewMenuItems + 1, pFaxPrintersConfig[dwIndex].pPrinterName);
  630. mii.dwTypeData = szMenuString;
  631. // Insert the item into the set as default printer menu
  632. mii.wID = (IDM_FAX_SET_AS_DEFAULT_PRINTER_1 + dwNumNewMenuItems);
  633. InsertMenuItem(hFaxSetAsDefaultMenu, (dwNumOldMenuItems + dwNumNewMenuItems), TRUE, &mii);
  634. // Insert the item into the sharing menu
  635. mii.wID = (IDM_FAX_SHARING_1 + dwNumNewMenuItems);
  636. InsertMenuItem(hFaxSharingMenu, (dwNumOldMenuItems + dwNumNewMenuItems), TRUE, &mii);
  637. // Insert the item into the properties menu
  638. mii.wID = (IDM_FAX_PROPERTIES_1 + dwNumNewMenuItems);
  639. InsertMenuItem(hFaxPropertiesMenu, (dwNumOldMenuItems + dwNumNewMenuItems), TRUE, &mii);
  640. // Increment the number of new menu items
  641. dwNumNewMenuItems++;
  642. }
  643. }
  644. if (dwNumFaxPrinters > (IDM_FAX_SET_AS_DEFAULT_PRINTER_MORE - IDM_FAX_SET_AS_DEFAULT_PRINTER_1)) {
  645. // Finish the menus with the printers string
  646. LoadString(g_hInstance, IDS_MENU_ITEM_FAX_PRINTERS, szMenuString, RESOURCE_STRING_LEN);
  647. mii.dwTypeData = szMenuString;
  648. // Insert the item into the set as default printer menu
  649. mii.wID = IDM_FAX_SET_AS_DEFAULT_PRINTER_MORE;
  650. InsertMenuItem(hFaxSetAsDefaultMenu, (dwNumOldMenuItems + dwNumNewMenuItems), TRUE, &mii);
  651. // Insert the item into the sharing menu
  652. mii.wID = IDM_FAX_SHARING_MORE;
  653. InsertMenuItem(hFaxSharingMenu, (dwNumOldMenuItems + dwNumNewMenuItems), TRUE, &mii);
  654. // Insert the item into the properties menu
  655. mii.wID = IDM_FAX_PROPERTIES_MORE;
  656. InsertMenuItem(hFaxPropertiesMenu, (dwNumOldMenuItems + dwNumNewMenuItems), TRUE, &mii);
  657. }
  658. // Remove the old items from the set as default printer menu
  659. for (dwIndex = 0; dwIndex < dwNumOldMenuItems; dwIndex++) {
  660. DeleteMenu(hFaxSetAsDefaultMenu, 0, MF_BYPOSITION);
  661. }
  662. // Remove the old items from the sharing menu
  663. for (dwIndex = 0; dwIndex < dwNumOldMenuItems; dwIndex++) {
  664. DeleteMenu(hFaxSharingMenu, 0, MF_BYPOSITION);
  665. }
  666. // Remove the old items from the properties menu
  667. for (dwIndex = 0; dwIndex < dwNumOldMenuItems; dwIndex++) {
  668. DeleteMenu(hFaxPropertiesMenu, 0, MF_BYPOSITION);
  669. }
  670. }
  671. else {
  672. // One or zero fax printers, so set sub-menus as menu items
  673. // Initialize the menu item info
  674. mii.cbSize = sizeof(mii);
  675. mii.fMask = MIIM_STATE | MIIM_SUBMENU;
  676. mii.hSubMenu = NULL;
  677. // Update the set as default printer menu item
  678. if (hFaxSetAsDefaultMenu) {
  679. DestroyMenu(hFaxSetAsDefaultMenu);
  680. hFaxSetAsDefaultMenu = NULL;
  681. }
  682. if ((pFaxPrintersConfig) && (dwNumFaxPrinters == 1) && (szDefaultPrinterName) && (!lstrcmpi(szDefaultPrinterName, pFaxPrintersConfig[0].pPrinterName))) {
  683. mii.fState = MFS_CHECKED | MFS_ENABLED;
  684. }
  685. else {
  686. mii.fState = (dwNumFaxPrinters == 1) ? MFS_ENABLED : MFS_GRAYED;
  687. }
  688. SetMenuItemInfo(hFaxMenu, IDM_FAX_SET_AS_DEFAULT_PRINTER, FALSE, &mii);
  689. // Update the sharing menu item
  690. if (hFaxSharingMenu) {
  691. DestroyMenu(hFaxSharingMenu);
  692. hFaxSharingMenu = NULL;
  693. }
  694. mii.fState = (dwNumFaxPrinters == 1) ? MFS_ENABLED : MFS_GRAYED;
  695. SetMenuItemInfo(hFaxMenu, IDM_FAX_SHARING, FALSE, &mii);
  696. // Update the properties menu item
  697. if (hFaxPropertiesMenu) {
  698. DestroyMenu(hFaxPropertiesMenu);
  699. hFaxPropertiesMenu = NULL;
  700. }
  701. mii.fState = (dwNumFaxPrinters == 1) ? MFS_ENABLED : MFS_GRAYED;
  702. SetMenuItemInfo(hFaxMenu, IDM_FAX_PROPERTIES, FALSE, &mii);
  703. }
  704. if (pFaxPrintersConfig) {
  705. MemFree(pFaxPrintersConfig);
  706. }
  707. if (szDefaultPrinterName) {
  708. MemFree(szDefaultPrinterName);
  709. }
  710. }
  711. else if (((HMENU) wParam == hDocumentMenu) && (LOWORD(lParam) == 1)) {
  712. if ((WaitForSingleObject(g_hStartEvent, 0) == WAIT_TIMEOUT) || (!ListView_GetSelectedCount(g_hWndListView))) {
  713. // Disconnected or no items selected, so disable all menu items
  714. // Disable the pause menu item
  715. EnableMenuItem(hDocumentMenu, IDM_DOCUMENT_PAUSE, MF_BYCOMMAND | MF_GRAYED);
  716. // Disable the resume menu item
  717. EnableMenuItem(hDocumentMenu, IDM_DOCUMENT_RESUME, MF_BYCOMMAND | MF_GRAYED);
  718. // Disable the restart menu item
  719. EnableMenuItem(hDocumentMenu, IDM_DOCUMENT_RESTART, MF_BYCOMMAND | MF_GRAYED);
  720. // Disable the cancel menu item
  721. EnableMenuItem(hDocumentMenu, IDM_DOCUMENT_CANCEL, MF_BYCOMMAND | MF_GRAYED);
  722. // Disable the properties menu item
  723. EnableMenuItem(hDocumentMenu, IDM_DOCUMENT_PROPERTIES, MF_BYCOMMAND | MF_GRAYED);
  724. }
  725. else {
  726. // uAndMask is the mask indicating the item attributes ANDed together
  727. UINT uAndMask;
  728. // uOrMask is the mask indicating the item attributes ORed together
  729. UINT uOrMask;
  730. // uState is the item's state
  731. UINT uState;
  732. // dwListIndex is the index of a particular item in the list view
  733. DWORD dwListIndex;
  734. // bUserHasAccess indicates the user has job manage access
  735. BOOL bUserHasAccess;
  736. // Initialize uAndMask
  737. uAndMask = LVIS_OVERLAYMASK;
  738. // Initialize uOrMask
  739. uOrMask = 0;
  740. // Enumerate each selected item in the list view
  741. dwListIndex = ListView_GetNextItem(g_hWndListView, -1, LVNI_ALL | LVNI_SELECTED);
  742. while (dwListIndex != -1) {
  743. // Get the item's attributes
  744. uState = ListView_GetItemState(g_hWndListView, dwListIndex, LVIS_OVERLAYMASK);
  745. // AND the item's attributes with uAndMask
  746. uAndMask &= uState;
  747. // OR the item's attributes with uOrMask
  748. uOrMask |= uState;
  749. dwListIndex = ListView_GetNextItem(g_hWndListView, dwListIndex, LVNI_ALL | LVNI_SELECTED);
  750. }
  751. if (uAndMask & ITEM_USEROWNSJOB_MASK) {
  752. // User owns all of the jobs
  753. bUserHasAccess = TRUE;
  754. }
  755. else {
  756. // User does not own all of the jobs, so determine if user has job manage permission
  757. // Initialize bUserHasAccess to FALSE
  758. bUserHasAccess = FALSE;
  759. // Connect to the fax service
  760. if (Connect()) {
  761. // Get the user's job manage access
  762. bUserHasAccess = FaxAccessCheck(g_hFaxSvcHandle, FAX_JOB_MANAGE);
  763. // Disconnect from the fax service
  764. Disconnect();
  765. }
  766. }
  767. if (((uAndMask & ITEM_SEND_MASK) == 0) || ((uAndMask & ITEM_IDLE_MASK) == 0)) {
  768. // Not a send job or a send job in progress, so disable the pause, resume and restart menu items
  769. // Disable the pause menu item
  770. EnableMenuItem(hDocumentMenu, IDM_DOCUMENT_PAUSE, MF_BYCOMMAND | MF_GRAYED);
  771. // Disable the resume menu item
  772. EnableMenuItem(hDocumentMenu, IDM_DOCUMENT_RESUME, MF_BYCOMMAND | MF_GRAYED);
  773. // Disable the restart menu item
  774. EnableMenuItem(hDocumentMenu, IDM_DOCUMENT_RESTART, MF_BYCOMMAND | MF_GRAYED);
  775. }
  776. else if (uAndMask & ITEM_PAUSED_MASK) {
  777. // Idle send job that is paused, so enable the resume and restart menu items and disable the pause menu item
  778. // Disable the pause menu item
  779. EnableMenuItem(hDocumentMenu, IDM_DOCUMENT_PAUSE, MF_BYCOMMAND | MF_GRAYED);
  780. // Enable the resume menu item
  781. EnableMenuItem(hDocumentMenu, IDM_DOCUMENT_RESUME, MF_BYCOMMAND | (bUserHasAccess ? MF_ENABLED : MF_GRAYED));
  782. // Enable the restart menu item
  783. EnableMenuItem(hDocumentMenu, IDM_DOCUMENT_RESTART, MF_BYCOMMAND | (bUserHasAccess ? MF_ENABLED : MF_GRAYED));
  784. }
  785. else if ((uOrMask & ITEM_PAUSED_MASK) == 0) {
  786. // Idle send job that is not paused, so enable the pause and restart menu items and disable the resume menu item
  787. // Enable the pause menu item
  788. EnableMenuItem(hDocumentMenu, IDM_DOCUMENT_PAUSE, MF_BYCOMMAND | (bUserHasAccess ? MF_ENABLED : MF_GRAYED));
  789. // Disable the resume menu item
  790. EnableMenuItem(hDocumentMenu, IDM_DOCUMENT_RESUME, MF_BYCOMMAND | MF_GRAYED);
  791. // Enable the restart menu item
  792. EnableMenuItem(hDocumentMenu, IDM_DOCUMENT_RESTART, MF_BYCOMMAND | (bUserHasAccess ? MF_ENABLED : MF_GRAYED));
  793. }
  794. else {
  795. // Idle send job, so enable the restart menu item and disable the pause and resume menu items
  796. // Enable the pause menu item
  797. EnableMenuItem(hDocumentMenu, IDM_DOCUMENT_PAUSE, MF_BYCOMMAND | MF_GRAYED);
  798. // Disable the resume menu item
  799. EnableMenuItem(hDocumentMenu, IDM_DOCUMENT_RESUME, MF_BYCOMMAND | MF_GRAYED);
  800. // Enable the restart menu item
  801. EnableMenuItem(hDocumentMenu, IDM_DOCUMENT_RESTART, MF_BYCOMMAND | (bUserHasAccess ? MF_ENABLED : MF_GRAYED));
  802. }
  803. // Enable the cancel menu item
  804. EnableMenuItem(hDocumentMenu, IDM_DOCUMENT_CANCEL, MF_BYCOMMAND | (bUserHasAccess ? MF_ENABLED : MF_GRAYED));
  805. if (ListView_GetSelectedCount(g_hWndListView) == 1) {
  806. // Only one item selected, so enable the properties menu item
  807. EnableMenuItem(hDocumentMenu, IDM_DOCUMENT_PROPERTIES, MF_BYCOMMAND | MF_ENABLED);
  808. }
  809. else {
  810. // Multiple items selected, so disable the properties menu item
  811. EnableMenuItem(hDocumentMenu, IDM_DOCUMENT_PROPERTIES, MF_BYCOMMAND | MF_GRAYED);
  812. }
  813. }
  814. }
  815. break;
  816. case WM_NOTIFY:
  817. LPNMHDR pnmhdr;
  818. // dwMessagePos is the cursor position for the message
  819. DWORD dwMessagePos;
  820. pnmhdr = (LPNMHDR) lParam;
  821. if ((pnmhdr->hwndFrom == g_hWndListView) && (pnmhdr->code == NM_RCLICK)) {
  822. // User has right-clicked in the list view, so display the document context menu
  823. // Initialize the document menu
  824. SendMessage(g_hWndMain, WM_INITMENUPOPUP, (WPARAM) hDocumentMenu, MAKELPARAM(1, FALSE));
  825. // Get the cursor position
  826. dwMessagePos = GetMessagePos();
  827. // Display the document context menu
  828. TrackPopupMenu(hDocumentMenu, TPM_LEFTALIGN | TPM_LEFTBUTTON, LOWORD(dwMessagePos), HIWORD(dwMessagePos), 0, g_hWndMain, NULL);
  829. }
  830. else if ((pnmhdr->hwndFrom == g_hWndListView) && (pnmhdr->code == NM_DBLCLK)) {
  831. // rcItem is the rectangle of the item
  832. RECT rcItem;
  833. // User has double-clicked in the list view, so display the job properties
  834. if (ListView_GetSelectedCount(g_hWndListView) != 1) {
  835. break;
  836. }
  837. // Get the item's bounding rectangle
  838. if (ListView_GetItemRect(g_hWndListView, ListView_GetNextItem(g_hWndListView, -1, LVNI_ALL | LVNI_SELECTED), &rcItem, LVIR_BOUNDS)) {
  839. // Get the cursor position
  840. dwMessagePos = GetMessagePos();
  841. // Get the window rectangle of the list view
  842. GetWindowRect(g_hWndListView, &rcClient);
  843. // Adjust dwMessagePos to indicate the cursor position within the list view
  844. dwMessagePos = MAKELONG(LOWORD(dwMessagePos) - rcClient.left, HIWORD(dwMessagePos) - rcClient.top);
  845. if ((LOWORD(dwMessagePos) >= rcItem.left) && (LOWORD(dwMessagePos) <= rcItem.right) && (HIWORD(dwMessagePos) >= rcItem.top) && (HIWORD(dwMessagePos) <= rcItem.bottom)) {
  846. // Display the job properties
  847. SendMessage(g_hWndMain, WM_COMMAND, MAKEWPARAM(IDM_DOCUMENT_PROPERTIES, 0), 0);
  848. }
  849. }
  850. }
  851. #ifdef TOOLBAR_ENABLED
  852. else if (pnmhdr->code == TTN_NEEDTEXT) {
  853. // pToolTipText is the pointer to the tool tip text structure
  854. LPTOOLTIPTEXT pToolTipText;
  855. // szToolTip is the tool tip text
  856. TCHAR szToolTip[RESOURCE_STRING_LEN];
  857. pToolTipText = (LPTOOLTIPTEXT) lParam;
  858. switch (pToolTipText->hdr.idFrom) {
  859. case IDM_FAX_PAUSE_FAXING:
  860. LoadString(g_hInstance, IDS_MENU_FAX_PAUSE_FAXING, szToolTip, RESOURCE_STRING_LEN);
  861. break;
  862. case IDM_FAX_CANCEL_ALL_FAXES:
  863. LoadString(g_hInstance, IDS_MENU_FAX_CANCEL_ALL_FAXES, szToolTip, RESOURCE_STRING_LEN);
  864. break;
  865. case IDM_DOCUMENT_PAUSE:
  866. LoadString(g_hInstance, IDS_MENU_DOCUMENT_PAUSE, szToolTip, RESOURCE_STRING_LEN);
  867. break;
  868. case IDM_DOCUMENT_RESUME:
  869. LoadString(g_hInstance, IDS_MENU_DOCUMENT_PAUSE, szToolTip, RESOURCE_STRING_LEN);
  870. break;
  871. case IDM_DOCUMENT_RESTART:
  872. LoadString(g_hInstance, IDS_MENU_DOCUMENT_RESTART, szToolTip, RESOURCE_STRING_LEN);
  873. break;
  874. case IDM_DOCUMENT_CANCEL:
  875. LoadString(g_hInstance, IDS_MENU_DOCUMENT_CANCEL, szToolTip, RESOURCE_STRING_LEN);
  876. break;
  877. case IDM_DOCUMENT_PROPERTIES:
  878. LoadString(g_hInstance, IDS_MENU_DOCUMENT_PROPERTIES, szToolTip, RESOURCE_STRING_LEN);
  879. break;
  880. case IDM_VIEW_REFRESH:
  881. LoadString(g_hInstance, IDS_MENU_VIEW_REFRESH, szToolTip, RESOURCE_STRING_LEN);
  882. break;
  883. case IDM_HELP_TOPICS:
  884. LoadString(g_hInstance, IDS_MENU_HELP_TOPICS, szToolTip, RESOURCE_STRING_LEN);
  885. break;
  886. default:
  887. ZeroMemory(szToolTip, sizeof(szToolTip));
  888. break;
  889. }
  890. pToolTipText->lpszText = szToolTip;
  891. }
  892. #endif // TOOLBAR_ENABLED
  893. break;
  894. case WM_SETFOCUS:
  895. SetFocus(g_hWndListView);
  896. break;
  897. case WM_SIZE:
  898. #ifdef TOOLBAR_ENABLED
  899. // Resize the toolbar
  900. if (WinPosInfo.bToolbarVisible) {
  901. SendMessage(g_hWndToolbar, iMsg, wParam, lParam);
  902. }
  903. #endif // TOOLBAR_ENABLED
  904. // Resize the status bar
  905. if (WinPosInfo.bStatusBarVisible) {
  906. SendMessage(hWndStatusBar, iMsg, wParam, lParam);
  907. }
  908. // Get the rectangle of the client area
  909. GetClientRect(hWnd, &rcClient);
  910. // Resize the list view
  911. MoveWindow(g_hWndListView, 0, (rcToolbar.bottom - rcToolbar.top), rcClient.right, rcClient.bottom - (rcStatusBar.bottom - rcStatusBar.top) - (rcToolbar.bottom - rcToolbar.top), TRUE);
  912. break;
  913. case UM_SELECT_FAX_PRINTER:
  914. // szCommandLine is the command line
  915. TCHAR szCommandLine[MAX_PATH];
  916. // si is the startup info for the print ui
  917. STARTUPINFO si;
  918. // pi is the process info for the print ui
  919. PROCESS_INFORMATION pi;
  920. // hWndPrintUI is the handle to the print ui window
  921. HWND hWndPrintUI;
  922. // pProcessInfoItem is a pointer to a PROCESS_INFO_ITEM structure
  923. PPROCESS_INFO_ITEM pProcessInfoItem;
  924. // szErrorCaption is the error caption if CreateProcess() fails
  925. TCHAR szErrorCaption[RESOURCE_STRING_LEN];
  926. // szErrorMessage is the error message if CreateProcess() fails
  927. LPTSTR szErrorMessage;
  928. if (uCurrentMenu == IDM_FAX_SET_AS_DEFAULT_PRINTER_MORE) {
  929. // Set the default printer
  930. SetDefaultPrinterName((LPTSTR) wParam);
  931. MemFree((LPBYTE) wParam);
  932. uCurrentMenu = 0;
  933. return 0;
  934. }
  935. if (pProcessInfoList) {
  936. // See if print ui is already open
  937. pProcessInfoItem = (PPROCESS_INFO_ITEM) pProcessInfoList;
  938. while (TRUE) {
  939. if (!lstrcmpi((LPTSTR) wParam, pProcessInfoItem->szPrinterName)) {
  940. // Printer name matches, so print ui may still be open
  941. if (WaitForSingleObject(pProcessInfoItem->hProcess, 0) != WAIT_OBJECT_0) {
  942. // Print ui is still open
  943. ShowWindow(pProcessInfoItem->hWnd, SW_SHOWNORMAL);
  944. SetForegroundWindow(pProcessInfoItem->hWnd);
  945. return 0;
  946. }
  947. if (pProcessInfoItem == (PPROCESS_INFO_ITEM) pProcessInfoList) {
  948. pProcessInfoList = pProcessInfoItem->ListEntry.Blink;
  949. }
  950. if (IsListEmpty(pProcessInfoList)) {
  951. // This is the last item in the list, so set the list head to NULL
  952. pProcessInfoList = NULL;
  953. }
  954. else {
  955. // Remove the process info item from the list
  956. RemoveEntryList(&pProcessInfoItem->ListEntry);
  957. }
  958. // Free the process info item
  959. MemFree(pProcessInfoItem);
  960. break;
  961. }
  962. // Step to the next process info item
  963. pProcessInfoItem = (PPROCESS_INFO_ITEM) pProcessInfoItem->ListEntry.Blink;
  964. if (pProcessInfoItem == (PPROCESS_INFO_ITEM) pProcessInfoList) {
  965. // The list has been traversed
  966. break;
  967. }
  968. }
  969. }
  970. switch (uCurrentMenu) {
  971. case IDM_FAX_SHARING_MORE:
  972. // Set the parameters
  973. wsprintf(szCommandLine, TEXT("rundll32 printui.dll,PrintUIEntry /p /t1 /n \"%s\""), (LPTSTR) wParam);
  974. break;
  975. case IDM_FAX_PROPERTIES_MORE:
  976. // Set the parameters
  977. wsprintf(szCommandLine, TEXT("rundll32 printui.dll,PrintUIEntry /p /t0 /n \"%s\""), (LPTSTR) wParam);
  978. break;
  979. }
  980. // Initialize si
  981. ZeroMemory(&si, sizeof(si));
  982. GetStartupInfo(&si);
  983. si.dwFlags = STARTF_USESHOWWINDOW;
  984. si.wShowWindow = SW_NORMAL;
  985. // Initialize pi
  986. ZeroMemory(&pi, sizeof(pi));
  987. // Launch the print ui
  988. hWndPrintUI = NULL;
  989. SetCursor(LoadCursor(NULL, IDC_WAIT));
  990. if (CreateProcess(NULL, szCommandLine, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &si, &pi)) {
  991. // Find the print ui window
  992. do {
  993. Sleep(250);
  994. EnumThreadWindows(pi.dwThreadId, EnumThreadWndProc, (LPARAM) &hWndPrintUI);
  995. } while (hWndPrintUI == NULL);
  996. SetCursor(LoadCursor(NULL, IDC_ARROW));
  997. // Add the process info item to the list
  998. pProcessInfoItem = (PPROCESS_INFO_ITEM) MemAlloc(sizeof(PROCESS_INFO_ITEM) + (lstrlen((LPTSTR) wParam) + 1) * sizeof(TCHAR));
  999. if (pProcessInfoItem) {
  1000. // Set szPrinterName
  1001. pProcessInfoItem->szPrinterName = (LPTSTR) ((UINT_PTR) pProcessInfoItem + sizeof(PROCESS_INFO_ITEM));
  1002. // Copy szPrinterName
  1003. lstrcpy(pProcessInfoItem->szPrinterName, (LPTSTR) wParam);
  1004. // Copy hProcess
  1005. pProcessInfoItem->hProcess = pi.hProcess;
  1006. // Copy hWndPrintUI
  1007. pProcessInfoItem->hWnd = hWndPrintUI;
  1008. // Insert the process info item into the list
  1009. if (pProcessInfoList) {
  1010. InsertTailList(pProcessInfoList, &pProcessInfoItem->ListEntry);
  1011. }
  1012. else {
  1013. pProcessInfoList = &pProcessInfoItem->ListEntry;
  1014. InitializeListHead(pProcessInfoList);
  1015. }
  1016. }
  1017. }
  1018. else {
  1019. // CreateProcess() failed, so display an error message
  1020. SetCursor(LoadCursor(NULL, IDC_ARROW));
  1021. // Load the error caption
  1022. LoadString(g_hInstance, IDS_ERROR_CAPTION, szErrorCaption, RESOURCE_STRING_LEN);
  1023. // Try to get the error message from the system message table
  1024. if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, (LPTSTR) &szErrorMessage, 0, NULL)) {
  1025. // Display the error message
  1026. MessageBox(hWnd, szErrorMessage, szErrorCaption, MB_OK | MB_ICONERROR | MB_APPLMODAL);
  1027. LocalFree(szErrorMessage);
  1028. }
  1029. else {
  1030. // Allocate the memory for the error message
  1031. szErrorMessage = (LPTSTR) MemAlloc((RESOURCE_STRING_LEN) * sizeof(TCHAR));
  1032. if (szErrorMessage) {
  1033. // Load the error message
  1034. LoadString(g_hInstance, IDS_ERROR_PRINTER_PROPERTIES, szErrorMessage, RESOURCE_STRING_LEN);
  1035. // Display the error message
  1036. MessageBox(hWnd, szErrorMessage, szErrorCaption, MB_OK | MB_ICONERROR | MB_APPLMODAL);
  1037. MemFree(szErrorMessage);
  1038. }
  1039. }
  1040. }
  1041. MemFree((LPBYTE) wParam);
  1042. uCurrentMenu = 0;
  1043. break;
  1044. case WM_COMMAND:
  1045. // mii is the menu item info
  1046. MENUITEMINFO mii;
  1047. // szPrinterName is the printer name
  1048. LPTSTR szPrinterName;
  1049. // pFaxJobEntry is the pointer to the fax jobs
  1050. PFAX_JOB_ENTRY pFaxJobEntry;
  1051. // lvi specifies the attributes of a particular item in the list view
  1052. LV_ITEM lvi;
  1053. // dwListIndex is the index of a particular item in the list view
  1054. DWORD dwListIndex;
  1055. switch (LOWORD(wParam)) {
  1056. case IDM_FAX_PAUSE_FAXING:
  1057. // pFaxConfig is the pointer to the fax configuration
  1058. PFAX_CONFIGURATION pFaxConfig;
  1059. // Initialize the menu item info
  1060. mii.cbSize = sizeof(mii);
  1061. mii.fMask = MIIM_STATE;
  1062. mii.fState = 0;
  1063. // Get the size of the menu item
  1064. if (!GetMenuItemInfo(hFaxMenu, IDM_FAX_PAUSE_FAXING, FALSE, &mii)) {
  1065. break;
  1066. }
  1067. SetCursor(LoadCursor(NULL, IDC_WAIT));
  1068. if (Connect()) {
  1069. // Get the fax configuration
  1070. if (FaxGetConfiguration(g_hFaxSvcHandle, &pFaxConfig)) {
  1071. // Toggle the pause faxing status
  1072. pFaxConfig->PauseServerQueue = mii.fState & MFS_CHECKED ? FALSE : TRUE;
  1073. // Set the fax configuration
  1074. if (FaxSetConfiguration(g_hFaxSvcHandle, pFaxConfig)) {
  1075. // Check the menu item
  1076. CheckMenuItem(hFaxMenu, IDM_FAX_PAUSE_FAXING, MF_BYCOMMAND | (pFaxConfig->PauseServerQueue ? MF_CHECKED : MF_UNCHECKED));
  1077. #ifdef TOOLBAR_ENABLED
  1078. // Enable the pause faxing toolbar menu item
  1079. EnableToolbarMenuState(g_hWndToolbar, IDM_FAX_PAUSE_FAXING, pFaxConfig->PauseServerQueue);
  1080. #endif // TOOLBAR_ENABLED
  1081. }
  1082. FaxFreeBuffer(pFaxConfig);
  1083. }
  1084. Disconnect();
  1085. }
  1086. // Set the window title to indicate connected or paused
  1087. SetWindowText(hWnd, mii.fState & MFS_CHECKED ? g_szTitleConnected : g_szTitlePaused);
  1088. SetCursor(LoadCursor(NULL, IDC_ARROW));
  1089. break;
  1090. case IDM_FAX_CANCEL_ALL_FAXES:
  1091. // dwNumFaxJobs is the number of fax jobs
  1092. DWORD dwNumFaxJobs;
  1093. // dwIndex is a counter to enumerate each fax job
  1094. DWORD dwIndex;
  1095. SetCursor(LoadCursor(NULL, IDC_WAIT));
  1096. if (Connect()) {
  1097. // Enumerate the fax jobs
  1098. if (FaxEnumJobs(g_hFaxSvcHandle, &pFaxJobEntry, &dwNumFaxJobs)) {
  1099. // Enumerate and cancel each fax job
  1100. for (dwIndex = 0; dwIndex < dwNumFaxJobs; dwIndex++) {
  1101. FaxSetJob(g_hFaxSvcHandle, pFaxJobEntry[dwIndex].JobId, JC_DELETE, &pFaxJobEntry[dwIndex]);
  1102. }
  1103. FaxFreeBuffer(pFaxJobEntry);
  1104. }
  1105. Disconnect();
  1106. }
  1107. SetCursor(LoadCursor(NULL, IDC_ARROW));
  1108. break;
  1109. case IDM_FAX_CLOSE:
  1110. SendMessage(hWnd, WM_CLOSE, 0, 0);
  1111. break;
  1112. case IDM_DOCUMENT_PAUSE:
  1113. case IDM_DOCUMENT_RESUME:
  1114. case IDM_DOCUMENT_RESTART:
  1115. case IDM_DOCUMENT_CANCEL:
  1116. // pJobIdList is a pointer to the job id list
  1117. PLIST_ENTRY pJobIdList;
  1118. // JobIdItem is a JOB_ID_ITEM structure
  1119. PJOB_ID_ITEM pJobIdItem;
  1120. // FaxJobEntry is the fax job
  1121. FAX_JOB_ENTRY FaxJobEntry;
  1122. // dwCommand is the command to set the fax job entry
  1123. DWORD dwCommand;
  1124. switch (LOWORD(wParam)) {
  1125. case IDM_DOCUMENT_PAUSE:
  1126. dwCommand = JC_PAUSE;
  1127. break;
  1128. case IDM_DOCUMENT_RESUME:
  1129. dwCommand = JC_RESUME;
  1130. break;
  1131. case IDM_DOCUMENT_RESTART:
  1132. dwCommand = JC_RESTART;
  1133. break;
  1134. case IDM_DOCUMENT_CANCEL:
  1135. dwCommand = JC_DELETE;
  1136. break;
  1137. }
  1138. // Set pJobIdList to NULL
  1139. pJobIdList = NULL;
  1140. SetCursor(LoadCursor(NULL, IDC_WAIT));
  1141. if (Connect()) {
  1142. // Initialize FaxJobEntry
  1143. ZeroMemory(&FaxJobEntry, sizeof(FaxJobEntry));
  1144. FaxJobEntry.SizeOfStruct = sizeof(FaxJobEntry);
  1145. // Enumerate each selected item in the list view
  1146. dwListIndex = ListView_GetNextItem(g_hWndListView, -1, LVNI_ALL | LVNI_SELECTED);
  1147. while (dwListIndex != -1) {
  1148. // Initialize lvi
  1149. lvi.mask = LVIF_PARAM;
  1150. // Set the item number
  1151. lvi.iItem = dwListIndex;
  1152. // Set the subitem number
  1153. lvi.iSubItem = 0;
  1154. // Set the lParam
  1155. lvi.lParam = 0;
  1156. // Get the selected item from the list view
  1157. if (ListView_GetItem(g_hWndListView, &lvi)) {
  1158. // Add the job id item to the list
  1159. pJobIdItem = (PJOB_ID_ITEM) MemAlloc(sizeof(JOB_ID_ITEM));
  1160. if (pJobIdItem) {
  1161. // Copy dwJobId
  1162. pJobIdItem->dwJobId = (DWORD) lvi.lParam;
  1163. // Insert the job id item into the list
  1164. if (pJobIdList) {
  1165. InsertTailList(pJobIdList, &pJobIdItem->ListEntry);
  1166. }
  1167. else {
  1168. pJobIdList = &pJobIdItem->ListEntry;
  1169. InitializeListHead(pJobIdList);
  1170. }
  1171. }
  1172. }
  1173. dwListIndex = ListView_GetNextItem(g_hWndListView, dwListIndex, LVNI_ALL | LVNI_SELECTED);
  1174. }
  1175. while (pJobIdList) {
  1176. // Get the job id item from the list
  1177. pJobIdItem = (PJOB_ID_ITEM) pJobIdList;
  1178. // Set FaxJobEntry
  1179. FaxJobEntry.JobId = pJobIdItem->dwJobId;
  1180. // Set the fax job entry
  1181. if (FaxSetJob(g_hFaxSvcHandle, FaxJobEntry.JobId, dwCommand, &FaxJobEntry)) {
  1182. if (LOWORD(wParam) != IDM_DOCUMENT_CANCEL) {
  1183. // Post an event to the completion port to indicate thread is to refresh
  1184. PostEventToCompletionPort(g_hCompletionPort, (DWORD) -1, FaxJobEntry.JobId);
  1185. }
  1186. }
  1187. // Set the head of the job id item list to the next job id item in the list
  1188. pJobIdList = pJobIdItem->ListEntry.Blink;
  1189. if (IsListEmpty(pJobIdList)) {
  1190. // This is the last item in the list, so set the list head to NULL
  1191. pJobIdList = NULL;
  1192. }
  1193. else {
  1194. // Remove the job id item from the list
  1195. RemoveEntryList(&pJobIdItem->ListEntry);
  1196. }
  1197. // Free the job id item
  1198. MemFree(pJobIdItem);
  1199. }
  1200. Disconnect();
  1201. }
  1202. SetCursor(LoadCursor(NULL, IDC_ARROW));
  1203. break;
  1204. case IDM_DOCUMENT_PROPERTIES:
  1205. // PropSheetHeader is the property sheet header
  1206. PROPSHEETHEADER PropSheetHeader;
  1207. // PropSheetPage is the property sheet page
  1208. PROPSHEETPAGE PropSheetPage;
  1209. // Set pJobIdList to NULL
  1210. pJobIdList = NULL;
  1211. // Initialize PropSheetHeader
  1212. PropSheetHeader.dwSize = sizeof(PropSheetHeader);
  1213. // Set the property sheet header flags
  1214. PropSheetHeader.dwFlags = PSH_NOAPPLYNOW | PSH_PROPSHEETPAGE | PSH_PROPTITLE;
  1215. // Set the property sheet header owner window
  1216. PropSheetHeader.hwndParent = hWnd;
  1217. // Set the property sheet header hInstance
  1218. PropSheetHeader.hInstance = g_hInstance;
  1219. // Set the number of property sheet pages
  1220. PropSheetHeader.nPages = 1;
  1221. // Set the start property sheet page
  1222. PropSheetHeader.nStartPage = 0;
  1223. PropSheetHeader.pStartPage = NULL;
  1224. // Set the property sheet pages
  1225. PropSheetHeader.ppsp = &PropSheetPage;
  1226. // Initialize PropSheetPage
  1227. PropSheetPage.dwSize = sizeof(PropSheetPage);
  1228. // Set the property sheet page flags
  1229. PropSheetPage.dwFlags = 0;
  1230. // Set the property sheet page hInstance
  1231. PropSheetPage.hInstance = g_hInstance;
  1232. // Set the property sheet page dialog template
  1233. PropSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_DOCUMENT_PROPERTIES);
  1234. // Set the property sheet page dialog procedure
  1235. PropSheetPage.pfnDlgProc = DocumentPropertiesDlgProc;
  1236. SetCursor(LoadCursor(NULL, IDC_WAIT));
  1237. if (Connect()) {
  1238. // Enumerate each selected item in the list view
  1239. dwListIndex = ListView_GetNextItem(g_hWndListView, -1, LVNI_ALL | LVNI_SELECTED);
  1240. while (dwListIndex != -1) {
  1241. // Initialize lvi
  1242. lvi.mask = LVIF_PARAM;
  1243. // Set the item number
  1244. lvi.iItem = dwListIndex;
  1245. // Set the subitem number
  1246. lvi.iSubItem = 0;
  1247. // Set the lParam
  1248. lvi.lParam = 0;
  1249. // Get the selected item from the list view
  1250. if (ListView_GetItem(g_hWndListView, &lvi)) {
  1251. // Add the job id item to the list
  1252. pJobIdItem = (PJOB_ID_ITEM) MemAlloc(sizeof(JOB_ID_ITEM));
  1253. if (pJobIdItem) {
  1254. // Copy dwJobId
  1255. pJobIdItem->dwJobId = (DWORD) lvi.lParam;
  1256. // Insert the job id item into the list
  1257. if (pJobIdList) {
  1258. InsertTailList(pJobIdList, &pJobIdItem->ListEntry);
  1259. }
  1260. else {
  1261. pJobIdList = &pJobIdItem->ListEntry;
  1262. InitializeListHead(pJobIdList);
  1263. }
  1264. }
  1265. }
  1266. dwListIndex = ListView_GetNextItem(g_hWndListView, dwListIndex, LVNI_ALL | LVNI_SELECTED);
  1267. }
  1268. while (pJobIdList) {
  1269. // Get the job id item from the list
  1270. pJobIdItem = (PJOB_ID_ITEM) pJobIdList;
  1271. if (FaxGetJob(g_hFaxSvcHandle, pJobIdItem->dwJobId, &pFaxJobEntry)) {
  1272. // Set the property sheet header pszCaption
  1273. PropSheetHeader.pszCaption = pFaxJobEntry->DocumentName;
  1274. // Set the property sheet page lParam
  1275. PropSheetPage.lParam = (LPARAM) pFaxJobEntry;
  1276. // Create the property sheet
  1277. PropertySheet(&PropSheetHeader);
  1278. }
  1279. // Set the head of the job id item list to the next job id item in the list
  1280. pJobIdList = pJobIdItem->ListEntry.Blink;
  1281. if (IsListEmpty(pJobIdList)) {
  1282. // This is the last item in the list, so set the list head to NULL
  1283. pJobIdList = NULL;
  1284. }
  1285. else {
  1286. // Remove the job id item from the list
  1287. RemoveEntryList(&pJobIdItem->ListEntry);
  1288. }
  1289. // Free the job id item
  1290. MemFree(pJobIdItem);
  1291. }
  1292. Disconnect();
  1293. }
  1294. SetCursor(LoadCursor(NULL, IDC_ARROW));
  1295. break;
  1296. #ifdef TOOLBAR_ENABLED
  1297. case IDM_VIEW_TOOLBAR:
  1298. if (WinPosInfo.bToolbarVisible) {
  1299. // Close the toolbar
  1300. DestroyWindow(g_hWndToolbar);
  1301. DestroyWindow(hWndToolTips);
  1302. ZeroMemory(&rcToolbar, sizeof(rcToolbar));
  1303. }
  1304. else {
  1305. // Show the toolbar
  1306. hWndToolTips = CreateToolTips(hWnd);
  1307. g_hWndToolbar = CreateToolbar(hWnd);
  1308. // Get the rectangle of the toolbar
  1309. GetWindowRect(g_hWndToolbar, &rcToolbar);
  1310. }
  1311. WinPosInfo.bToolbarVisible = !WinPosInfo.bToolbarVisible;
  1312. // Check the menu item
  1313. CheckMenuItem(hViewMenu, IDM_VIEW_TOOLBAR, MF_BYCOMMAND | (WinPosInfo.bToolbarVisible ? MF_CHECKED : MF_UNCHECKED));
  1314. // Get the rectangle of the client area
  1315. GetClientRect(hWnd, &rcClient);
  1316. // Resize the list view
  1317. MoveWindow(g_hWndListView, 0, (rcToolbar.bottom - rcToolbar.top), rcClient.right, rcClient.bottom - (rcStatusBar.bottom - rcStatusBar.top) - (rcToolbar.bottom - rcToolbar.top), TRUE);
  1318. break;
  1319. #endif // TOOLBAR_ENABLED
  1320. case IDM_VIEW_STATUS_BAR:
  1321. if (WinPosInfo.bStatusBarVisible) {
  1322. // Close the status bar
  1323. DestroyWindow(hWndStatusBar);
  1324. ZeroMemory(&rcStatusBar, sizeof(rcStatusBar));
  1325. }
  1326. else {
  1327. // Show the status bar
  1328. hWndStatusBar = CreateStatusWindow(WS_CHILD | WS_CLIPSIBLINGS | WS_TABSTOP | WS_VISIBLE | SBARS_SIZEGRIP, NULL, hWnd, IDM_STATUS_BAR);
  1329. // Get the rectangle of the status bar
  1330. GetWindowRect(hWndStatusBar, &rcStatusBar);
  1331. }
  1332. WinPosInfo.bStatusBarVisible = !WinPosInfo.bStatusBarVisible;
  1333. // Check the menu item
  1334. CheckMenuItem(hViewMenu, IDM_VIEW_STATUS_BAR, MF_BYCOMMAND | (WinPosInfo.bStatusBarVisible ? MF_CHECKED : MF_UNCHECKED));
  1335. // Get the rectangle of the client area
  1336. GetClientRect(hWnd, &rcClient);
  1337. // Resize the list view
  1338. MoveWindow(g_hWndListView, 0, (rcToolbar.bottom - rcToolbar.top), rcClient.right, rcClient.bottom - (rcStatusBar.bottom - rcStatusBar.top) - (rcToolbar.bottom - rcToolbar.top), TRUE);
  1339. break;
  1340. case IDM_VIEW_REFRESH:
  1341. if (WaitForSingleObject(g_hStartEvent, 0) == WAIT_OBJECT_0) {
  1342. // Post an event to the completion port to indicate thread is to refresh
  1343. PostEventToCompletionPort(g_hCompletionPort, FEI_FAXSVC_STARTED, (DWORD) -1);
  1344. }
  1345. else {
  1346. // Set the start event
  1347. SetEvent(g_hStartEvent);
  1348. }
  1349. break;
  1350. case IDM_HELP_TOPICS:
  1351. HtmlHelp(GetDesktopWindow(), FAXQUEUE_HTMLHELP_FILENAME, HH_DISPLAY_TOPIC, 0L);
  1352. break;
  1353. case IDM_HELP_ABOUT:
  1354. // szCaption is the caption for the shell about dialog box
  1355. TCHAR szCaption[RESOURCE_STRING_LEN];
  1356. LoadString(g_hInstance, IDS_FAXQUEUE_LOCAL_CAPTION, szCaption, RESOURCE_STRING_LEN);
  1357. ShellAbout(hWnd, szCaption, NULL, NULL);
  1358. break;
  1359. case IDM_FAX_SET_AS_DEFAULT_PRINTER:
  1360. case IDM_FAX_SHARING:
  1361. case IDM_FAX_PROPERTIES:
  1362. // pFaxPrintersConfig is the pointer to the fax printers
  1363. LPPRINTER_INFO_2 pFaxPrintersConfig;
  1364. // dwNumFaxPrinters is the number of fax printers
  1365. DWORD dwNumFaxPrinters;
  1366. // Set the current menu selection
  1367. if (LOWORD(wParam) == IDM_FAX_SET_AS_DEFAULT_PRINTER) {
  1368. uCurrentMenu = IDM_FAX_SET_AS_DEFAULT_PRINTER_MORE;
  1369. }
  1370. else if (LOWORD(wParam) == IDM_FAX_SHARING) {
  1371. uCurrentMenu = IDM_FAX_SHARING_MORE;
  1372. }
  1373. else if (LOWORD(wParam) == IDM_FAX_PROPERTIES) {
  1374. uCurrentMenu = IDM_FAX_PROPERTIES_MORE;
  1375. }
  1376. else {
  1377. break;
  1378. }
  1379. // Get the fax printers
  1380. pFaxPrintersConfig = (LPPRINTER_INFO_2) GetFaxPrinters(&dwNumFaxPrinters);
  1381. if (pFaxPrintersConfig) {
  1382. // Allocate the memory for the printer name
  1383. szPrinterName = (LPTSTR) MemAlloc((lstrlen(pFaxPrintersConfig[0].pPrinterName) + 1) * sizeof(TCHAR));
  1384. if (szPrinterName) {
  1385. // Copy the printer name
  1386. lstrcpy(szPrinterName, pFaxPrintersConfig[0].pPrinterName);
  1387. // Post a message that a printer has been selected
  1388. PostMessage(hWnd, UM_SELECT_FAX_PRINTER, (UINT_PTR) szPrinterName, 0);
  1389. }
  1390. MemFree(pFaxPrintersConfig);
  1391. }
  1392. break;
  1393. case IDM_FAX_SET_AS_DEFAULT_PRINTER_1:
  1394. case IDM_FAX_SET_AS_DEFAULT_PRINTER_2:
  1395. case IDM_FAX_SET_AS_DEFAULT_PRINTER_3:
  1396. case IDM_FAX_SET_AS_DEFAULT_PRINTER_4:
  1397. case IDM_FAX_SHARING_1:
  1398. case IDM_FAX_SHARING_2:
  1399. case IDM_FAX_SHARING_3:
  1400. case IDM_FAX_SHARING_4:
  1401. case IDM_FAX_PROPERTIES_1:
  1402. case IDM_FAX_PROPERTIES_2:
  1403. case IDM_FAX_PROPERTIES_3:
  1404. case IDM_FAX_PROPERTIES_4:
  1405. // hMenu is the handle to the menu
  1406. HMENU hMenu;
  1407. // szMenuString is a menu string
  1408. TCHAR szMenuString[RESOURCE_STRING_LEN];
  1409. // szMenuItemName is the menu item name
  1410. LPTSTR szMenuItemName;
  1411. // Get the handle to the menu, set the current menu selection, and set the menu string
  1412. if ((LOWORD(wParam) >= IDM_FAX_SET_AS_DEFAULT_PRINTER_1) && (LOWORD(wParam) < IDM_FAX_SET_AS_DEFAULT_PRINTER_MORE)) {
  1413. hMenu = hFaxSetAsDefaultMenu;
  1414. uCurrentMenu = IDM_FAX_SET_AS_DEFAULT_PRINTER_MORE;
  1415. wsprintf(szMenuString, TEXT("&%d "), LOWORD(wParam) - IDM_FAX_SET_AS_DEFAULT_PRINTER_1 + 1);
  1416. }
  1417. else if ((LOWORD(wParam) >= IDM_FAX_SHARING_1) && (LOWORD(wParam) < IDM_FAX_SHARING_MORE)) {
  1418. hMenu = hFaxSharingMenu;
  1419. uCurrentMenu = IDM_FAX_SHARING_MORE;
  1420. wsprintf(szMenuString, TEXT("&%d "), LOWORD(wParam) - IDM_FAX_SHARING_1 + 1);
  1421. }
  1422. else if ((LOWORD(wParam) >= IDM_FAX_PROPERTIES_1) && (LOWORD(wParam) < IDM_FAX_PROPERTIES_MORE)) {
  1423. hMenu = hFaxPropertiesMenu;
  1424. uCurrentMenu = IDM_FAX_PROPERTIES_MORE;
  1425. wsprintf(szMenuString, TEXT("&%d "), LOWORD(wParam) - IDM_FAX_PROPERTIES_1 + 1);
  1426. }
  1427. else {
  1428. break;
  1429. }
  1430. // Initialize the menu item info
  1431. mii.cbSize = sizeof(mii);
  1432. mii.fMask = MIIM_TYPE;
  1433. mii.fType = MFT_STRING;
  1434. mii.dwTypeData = NULL;
  1435. mii.cch = 0;
  1436. // Get the size of the menu item
  1437. if (GetMenuItemInfo(hMenu, LOWORD(wParam), FALSE, &mii)) {
  1438. mii.cch++;
  1439. // Allocate the memory for the menu item
  1440. szMenuItemName = (LPTSTR) MemAlloc(mii.cch * sizeof(TCHAR));
  1441. if (szMenuItemName) {
  1442. mii.dwTypeData = szMenuItemName;
  1443. // Get the menu item
  1444. if (GetMenuItemInfo(hMenu, LOWORD(wParam), FALSE, &mii)) {
  1445. // Allocate the memory for the printer name
  1446. szPrinterName = (LPTSTR) MemAlloc((lstrlen(szMenuItemName) - lstrlen(szMenuString) + 1) * sizeof(TCHAR));
  1447. if (szPrinterName) {
  1448. // Copy the printer name
  1449. lstrcpy(szPrinterName, (LPTSTR) ((UINT_PTR) szMenuItemName + lstrlen(szMenuString) * sizeof(TCHAR)));
  1450. // Post a message that a printer has been selected
  1451. PostMessage(hWnd, UM_SELECT_FAX_PRINTER, (UINT_PTR) szPrinterName, 0);
  1452. }
  1453. }
  1454. MemFree(szMenuItemName);
  1455. }
  1456. }
  1457. break;
  1458. case IDM_FAX_SET_AS_DEFAULT_PRINTER_MORE:
  1459. case IDM_FAX_SHARING_MORE:
  1460. case IDM_FAX_PROPERTIES_MORE:
  1461. uCurrentMenu = LOWORD(wParam);
  1462. DialogBox(g_hInstance, MAKEINTRESOURCE(IDD_SELECT_FAX_PRINTER), hWnd, SelectFaxPrinterDlgProc);
  1463. break;
  1464. }
  1465. break;
  1466. case WM_CLOSE:
  1467. // Set the exit event
  1468. SetEvent(g_hExitEvent);
  1469. if (WaitForSingleObject(g_hStartEvent, 0) == WAIT_OBJECT_0) {
  1470. // Post an event to the completion port to indicate thread is to exit
  1471. PostEventToCompletionPort(g_hCompletionPort, FEI_FAXSVC_ENDED, (DWORD) -1);
  1472. }
  1473. #ifdef TOOLBAR_ENABLED
  1474. // Set the persistent data
  1475. SetFaxQueueRegistryData(WinPosInfo.bToolbarVisible, WinPosInfo.bStatusBarVisible, g_hWndListView, hWnd);
  1476. #else
  1477. // Set the persistent data
  1478. SetFaxQueueRegistryData(WinPosInfo.bStatusBarVisible, g_hWndListView, hWnd);
  1479. #endif // TOOLBAR_ENABLED
  1480. // Free the process info list
  1481. while (pProcessInfoList) {
  1482. // Get the head of the process info list
  1483. pProcessInfoItem = (PPROCESS_INFO_ITEM) pProcessInfoList;
  1484. // Set the head of process info list to the next process info item in the list
  1485. pProcessInfoList = pProcessInfoItem->ListEntry.Blink;
  1486. if (IsListEmpty(pProcessInfoList)) {
  1487. // This is the last item in the list, so set the list head to NULL
  1488. pProcessInfoList = NULL;
  1489. }
  1490. else {
  1491. // Remove the process info item from the list
  1492. RemoveEntryList(&pProcessInfoItem->ListEntry);
  1493. }
  1494. // Free the process info item
  1495. MemFree(pProcessInfoItem);
  1496. }
  1497. break;
  1498. case WM_DESTROY:
  1499. #ifdef TOOLBAR_ENABLED
  1500. if (WinPosInfo.bToolbarVisible) {
  1501. // Close the toolbar
  1502. DestroyWindow(g_hWndToolbar);
  1503. DestroyWindow(hWndToolTips);
  1504. }
  1505. #endif // TOOLBAR_ENABLED
  1506. if (WinPosInfo.bStatusBarVisible) {
  1507. // Close the status bar
  1508. DestroyWindow(hWndStatusBar);
  1509. }
  1510. // Close the list view
  1511. DestroyWindow(g_hWndListView);
  1512. PostQuitMessage(0);
  1513. break;
  1514. }
  1515. return DefWindowProc(hWnd, iMsg, wParam, lParam);
  1516. }
  1517. INT_PTR CALLBACK SelectFaxPrinterDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
  1518. {
  1519. // hWndPrinterList is the handle to the fax printer list box
  1520. static HWND hWndPrinterList;
  1521. switch(iMsg) {
  1522. case WM_INITDIALOG:
  1523. // pFaxPrintersConfig is the pointer to the fax printers
  1524. LPPRINTER_INFO_2 pFaxPrintersConfig;
  1525. // dwNumFaxPrinters is the number of fax printers
  1526. DWORD dwNumFaxPrinters;
  1527. // dwIndex is a counter to enumerate each printer
  1528. DWORD dwIndex;
  1529. // Get the handle to the fax printer list box
  1530. hWndPrinterList = GetDlgItem(hDlg, IDC_FAX_PRINTER_LIST);
  1531. // Get the fax printers
  1532. pFaxPrintersConfig = (LPPRINTER_INFO_2) GetFaxPrinters(&dwNumFaxPrinters);
  1533. if ((pFaxPrintersConfig) && (dwNumFaxPrinters)) {
  1534. // Propagate the list box with the list of fax printers
  1535. for (dwIndex = 0; dwIndex < dwNumFaxPrinters; dwIndex++) {
  1536. SendMessage(hWndPrinterList, LB_ADDSTRING, 0, (UINT_PTR) pFaxPrintersConfig[dwIndex].pPrinterName);
  1537. }
  1538. }
  1539. if (pFaxPrintersConfig) {
  1540. MemFree(pFaxPrintersConfig);
  1541. }
  1542. return TRUE;
  1543. case WM_COMMAND:
  1544. switch(HIWORD(wParam)) {
  1545. case LBN_DBLCLK:
  1546. SendMessage(GetDlgItem(hDlg, IDOK), BM_CLICK, 0, 0);
  1547. break;
  1548. }
  1549. switch(LOWORD(wParam)) {
  1550. case IDOK:
  1551. // szPrinterName is the printer name
  1552. LPTSTR szPrinterName;
  1553. // ulpIndex is the index of the currently selected item in the list box
  1554. ULONG_PTR ulpIndex;
  1555. DWORD cb;
  1556. // Get the current selection of the list box
  1557. ulpIndex = SendMessage(hWndPrinterList, LB_GETCURSEL, 0, 0);
  1558. if (ulpIndex != LB_ERR) {
  1559. // Get the size of the current selection of the list box
  1560. cb = (DWORD) SendMessage(hWndPrinterList, LB_GETTEXTLEN, ulpIndex, NULL);
  1561. if (cb != LB_ERR) {
  1562. // Allocate the memory for the current selection
  1563. szPrinterName = (LPTSTR) MemAlloc((cb + 1) * sizeof(TCHAR));
  1564. if (szPrinterName) {
  1565. // Get the current selection of the list box
  1566. if (SendMessage(hWndPrinterList, LB_GETTEXT, ulpIndex, (UINT_PTR) szPrinterName) != LB_ERR) {
  1567. // Post a message that a printer has been selected
  1568. PostMessage(g_hWndMain, UM_SELECT_FAX_PRINTER, (UINT_PTR) szPrinterName, 0);
  1569. }
  1570. }
  1571. }
  1572. }
  1573. case IDCANCEL:
  1574. EndDialog(hDlg, LOWORD(wParam));
  1575. return TRUE;
  1576. }
  1577. break;
  1578. }
  1579. return FALSE;
  1580. }
  1581. INT_PTR CALLBACK DocumentPropertiesDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
  1582. {
  1583. switch(iMsg) {
  1584. case WM_INITDIALOG:
  1585. // pFaxJobEntry is the pointer to the fax job
  1586. PFAX_JOB_ENTRY pFaxJobEntry;
  1587. // szColumnItem is text of a column item for those items that are equivalent to a column item
  1588. LPTSTR szColumnItem;
  1589. // Get the pointer to the fax job from the property sheet page
  1590. pFaxJobEntry = (PFAX_JOB_ENTRY) ((LPPROPSHEETPAGE) lParam)->lParam;
  1591. // Get the column item text for the document name
  1592. szColumnItem = GetColumnItemText(eDocumentName, pFaxJobEntry, NULL);
  1593. // Set the job type static text
  1594. if (szColumnItem) {
  1595. SetDlgItemText(hDlg, IDC_FAX_DOCUMENTNAME, szColumnItem);
  1596. MemFree(szColumnItem);
  1597. }
  1598. // Set the recipient's name static text
  1599. if (pFaxJobEntry->RecipientName) {
  1600. SetDlgItemText(hDlg, IDC_FAX_RECIPIENTNAME, pFaxJobEntry->RecipientName);
  1601. }
  1602. // Set the recipient's fax number static text
  1603. if (pFaxJobEntry->RecipientNumber) {
  1604. SetDlgItemText(hDlg, IDC_FAX_RECIPIENTNUMBER, pFaxJobEntry->RecipientNumber);
  1605. }
  1606. // Set the sender's name static text
  1607. if (pFaxJobEntry->SenderName) {
  1608. SetDlgItemText(hDlg, IDC_FAX_SENDERNAME, pFaxJobEntry->SenderName);
  1609. }
  1610. // Set the sender's company static text
  1611. if (pFaxJobEntry->SenderCompany) {
  1612. SetDlgItemText(hDlg, IDC_FAX_SENDERCOMPANY, pFaxJobEntry->SenderCompany);
  1613. }
  1614. // Set the sender's department static text
  1615. if (pFaxJobEntry->SenderDept) {
  1616. SetDlgItemText(hDlg, IDC_FAX_SENDERDEPT, pFaxJobEntry->SenderDept);
  1617. }
  1618. // Set the billing code static text
  1619. if (pFaxJobEntry->BillingCode) {
  1620. SetDlgItemText(hDlg, IDC_FAX_BILLINGCODE, pFaxJobEntry->BillingCode);
  1621. }
  1622. // Get the column item text for the job type
  1623. szColumnItem = GetColumnItemText(eJobType, pFaxJobEntry, NULL);
  1624. // Set the job type static text
  1625. if (szColumnItem) {
  1626. SetDlgItemText(hDlg, IDC_FAX_JOBTYPE, szColumnItem);
  1627. MemFree(szColumnItem);
  1628. }
  1629. // Get the column item text for the status
  1630. szColumnItem = GetColumnItemText(eStatus, pFaxJobEntry, NULL);
  1631. // Set the status static text
  1632. if (szColumnItem) {
  1633. SetDlgItemText(hDlg, IDC_FAX_STATUS, szColumnItem);
  1634. MemFree(szColumnItem);
  1635. }
  1636. // Get the column item text for the pages
  1637. szColumnItem = GetColumnItemText(ePages, pFaxJobEntry, NULL);
  1638. // Set the pages static text
  1639. if (szColumnItem) {
  1640. SetDlgItemText(hDlg, IDC_FAX_PAGES, szColumnItem);
  1641. MemFree(szColumnItem);
  1642. }
  1643. // Get the column item text for the size
  1644. szColumnItem = GetColumnItemText(eSize, pFaxJobEntry, NULL);
  1645. // Set the size static text
  1646. if (szColumnItem) {
  1647. SetDlgItemText(hDlg, IDC_FAX_SIZE, szColumnItem);
  1648. MemFree(szColumnItem);
  1649. }
  1650. // Get the column item text for the scheduled time
  1651. szColumnItem = GetColumnItemText(eScheduledTime, pFaxJobEntry, NULL);
  1652. // Set the scheduled time static text
  1653. if (szColumnItem) {
  1654. SetDlgItemText(hDlg, IDC_FAX_SCHEDULEDTIME, szColumnItem);
  1655. MemFree(szColumnItem);
  1656. }
  1657. FaxFreeBuffer(pFaxJobEntry);
  1658. return TRUE;
  1659. case WM_HELP:
  1660. case WM_CONTEXTMENU:
  1661. FAXWINHELP(iMsg, wParam, lParam, DocumentPropertiesHelpIDs);
  1662. break;
  1663. }
  1664. return FALSE;
  1665. }
  1666. BOOL CALLBACK EnumThreadWndProc(HWND hWnd, LPARAM lParam)
  1667. {
  1668. if (GetWindowLong(hWnd, GWL_STYLE) & WS_VISIBLE) {
  1669. CopyMemory((LPBYTE) lParam, &hWnd, sizeof(hWnd));
  1670. return FALSE;
  1671. }
  1672. return TRUE;
  1673. }
  1674. VOID PostEventToCompletionPort(HANDLE hCompletionPort, DWORD dwEventId, DWORD dwJobId)
  1675. {
  1676. PFAX_EVENT pFaxEvent;
  1677. pFaxEvent = (PFAX_EVENT) LocalAlloc(LPTR, sizeof(FAX_EVENT));
  1678. pFaxEvent->EventId = dwEventId;
  1679. pFaxEvent->JobId = dwJobId;
  1680. PostQueuedCompletionStatus(hCompletionPort, sizeof(FAX_EVENT), 0, (LPOVERLAPPED) pFaxEvent);
  1681. }
  1682. DWORD FaxEventThread (LPVOID lpv)
  1683. {
  1684. // hExitStartEvents is a pointer to the g_hExitEvent and g_hStartEvent
  1685. HANDLE hExitStartEvents[2];
  1686. // mii is the menu item info
  1687. MENUITEMINFO mii;
  1688. // hFaxMenu is a handle to the fax menu
  1689. HMENU hFaxMenu;
  1690. // pFaxConfig is the pointer to the fax configuration
  1691. PFAX_CONFIGURATION pFaxConfig;
  1692. // pPortJobInfoList is a pointer to the port job info list
  1693. PLIST_ENTRY pPortJobInfoList;
  1694. // pPortJobInfo is a pointer to a PORT_JOB_INFO_ITEM structure
  1695. PPORT_JOB_INFO_ITEM pPortJobInfoItem;
  1696. // pFaxPortInfo is the pointer to the fax ports
  1697. PFAX_PORT_INFO pFaxPortInfo;
  1698. // dwNumFaxPorts is the number of fax ports
  1699. DWORD dwNumFaxPorts;
  1700. // szDeviceName is the device name of the current fax port
  1701. LPTSTR szDeviceName;
  1702. // dwJobId is the fax job id on the current fax port
  1703. DWORD dwJobId;
  1704. // pFaxJobEntry is the pointer to the fax jobs
  1705. PFAX_JOB_ENTRY pFaxJobEntry;
  1706. // dwNumFaxJobs is the number of fax jobs
  1707. DWORD dwNumFaxJobs;
  1708. // lvfi specifies the attributes of a particular item to find in the list view
  1709. LV_FINDINFO lvfi;
  1710. // dwListIndex is the index of a particular item in the list view
  1711. DWORD dwListIndex;
  1712. // nColumnIndex is used to enumerate each column of the list view
  1713. INT nColumnIndex;
  1714. // szColumnItem is the text of a column item
  1715. LPTSTR szColumnItem;
  1716. // uState is the state of a particular item in the list view
  1717. UINT uState;
  1718. // dwOldFocusIndex is the old item in the list view with the focus
  1719. DWORD dwOldFocusIndex;
  1720. // dwNewFocusIndex is the new item in the list view with the focus
  1721. DWORD dwNewFocusIndex;
  1722. // pFaxEvent is a pointer to the port event
  1723. PFAX_EVENT pFaxEvent;
  1724. DWORD dwBytes;
  1725. ULONG_PTR ulpCompletionKey;
  1726. // dwIndex is a counter to enumerate each fax port and fax job
  1727. DWORD dwIndex;
  1728. DWORD dwRslt;
  1729. // Set hExitStartEvents
  1730. // g_hExitEvent
  1731. hExitStartEvents[0] = g_hExitEvent;
  1732. // g_hStartEvent
  1733. hExitStartEvents[1] = g_hStartEvent;
  1734. // Initialize hFaxMenu
  1735. hFaxMenu = NULL;
  1736. // Set pPortJobInfo to NULL
  1737. pPortJobInfoList = NULL;
  1738. while (TRUE) {
  1739. // Wait for Exit, or Start event
  1740. dwRslt = WaitForMultipleObjects(2, hExitStartEvents, FALSE, INFINITE);
  1741. if (dwRslt == WAIT_OBJECT_0) {
  1742. // Exit event was signaled, so exit
  1743. return 0;
  1744. }
  1745. // Set the window title to indicate connecting
  1746. SetWindowText(g_hWndMain, g_szTitleConnecting);
  1747. // Get the handle to the fax menu
  1748. if (!hFaxMenu) {
  1749. hFaxMenu = GetSubMenu(GetMenu(g_hWndMain), 0);
  1750. }
  1751. // Create the completion port
  1752. g_hCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
  1753. if (!g_hCompletionPort) {
  1754. goto ExitLevel0;
  1755. }
  1756. // Connect to the fax service
  1757. if (!Connect()) {
  1758. goto ExitLevel1;
  1759. }
  1760. // Initialize the fax event queue
  1761. if (!FaxInitializeEventQueue(g_hFaxSvcHandle, g_hCompletionPort, 0, NULL, 0)) {
  1762. // Disconnect from the fax service
  1763. Disconnect();
  1764. goto ExitLevel1;
  1765. }
  1766. // Determine if faxing is paused
  1767. if (FaxGetConfiguration(g_hFaxSvcHandle, &pFaxConfig)) {
  1768. // Check the menu item
  1769. CheckMenuItem(hFaxMenu, IDM_FAX_PAUSE_FAXING, MF_BYCOMMAND | (pFaxConfig->PauseServerQueue ? MF_CHECKED : MF_UNCHECKED));
  1770. #ifdef TOOLBAR_ENABLED
  1771. // Enable the pause faxing toolbar menu item
  1772. EnableToolbarMenuState(g_hWndToolbar, IDM_FAX_PAUSE_FAXING, pFaxConfig->PauseServerQueue);
  1773. #endif // TOOLBAR_ENABLED
  1774. FaxFreeBuffer(pFaxConfig);
  1775. }
  1776. // Enumerate the fax ports
  1777. if (FaxEnumPorts(g_hFaxSvcHandle, &pFaxPortInfo, &dwNumFaxPorts)) {
  1778. for (dwIndex = 0; dwIndex < dwNumFaxPorts; dwIndex++) {
  1779. // Add each port job info into the list
  1780. pPortJobInfoItem = (PPORT_JOB_INFO_ITEM) MemAlloc(sizeof(PORT_JOB_INFO_ITEM) + (lstrlen(pFaxPortInfo[dwIndex].DeviceName) + 1) * sizeof(TCHAR));
  1781. if (pPortJobInfoItem) {
  1782. // Copy dwDeviceId
  1783. pPortJobInfoItem->dwDeviceId = pFaxPortInfo[dwIndex].DeviceId;
  1784. // Set szDeviceName
  1785. pPortJobInfoItem->szDeviceName = (LPTSTR) ((UINT_PTR) pPortJobInfoItem + sizeof(PORT_JOB_INFO_ITEM));
  1786. // Copy szDeviceName
  1787. lstrcpy(pPortJobInfoItem->szDeviceName, pFaxPortInfo[dwIndex].DeviceName);
  1788. // Set dwJobId
  1789. pPortJobInfoItem->dwJobId = (DWORD) -1;
  1790. // Insert the port job info into the list
  1791. if (pPortJobInfoList) {
  1792. InsertTailList(pPortJobInfoList, &pPortJobInfoItem->ListEntry);
  1793. }
  1794. else {
  1795. pPortJobInfoList = &pPortJobInfoItem->ListEntry;
  1796. InitializeListHead(pPortJobInfoList);
  1797. }
  1798. }
  1799. }
  1800. FaxFreeBuffer(pFaxPortInfo);
  1801. }
  1802. // Enable the pause faxing menu item and the cancel all faxes menu item
  1803. EnableMenuItem(hFaxMenu, IDM_FAX_PAUSE_FAXING, MF_BYCOMMAND | MF_ENABLED);
  1804. EnableMenuItem(hFaxMenu, IDM_FAX_CANCEL_ALL_FAXES, MF_BYCOMMAND | MF_ENABLED);
  1805. #ifdef TOOLBAR_ENABLED
  1806. // Enable the pause faxing toolbar menu item and the cancel all faxes toolbar menu item
  1807. EnableToolbarMenuState(g_hWndToolbar, IDM_FAX_PAUSE_FAXING, TRUE);
  1808. EnableToolbarMenuState(g_hWndToolbar, IDM_FAX_CANCEL_ALL_FAXES, TRUE);
  1809. #endif // TOOLBAR_ENABLED
  1810. // Disconnect from the fax service
  1811. Disconnect();
  1812. // Wait for fax events
  1813. while (GetQueuedCompletionStatus(g_hCompletionPort, &dwBytes, &ulpCompletionKey, (LPOVERLAPPED *) &pFaxEvent, INFINITE)) {
  1814. if (pFaxEvent->EventId == FEI_FAXSVC_ENDED) {
  1815. // Thread should stop listening for fax events
  1816. LocalFree(pFaxEvent);
  1817. break;
  1818. }
  1819. switch (pFaxEvent->EventId) {
  1820. case FEI_MODEM_POWERED_ON:
  1821. case FEI_MODEM_POWERED_OFF:
  1822. case FEI_RINGING:
  1823. case FEI_ABORTING:
  1824. // Ignore these fax events
  1825. break;
  1826. case FEI_FAXSVC_STARTED:
  1827. // Set the window title to indicate refreshing
  1828. SetWindowText(g_hWndMain, g_szTitleRefreshing);
  1829. // Initialize the menu item info
  1830. mii.cbSize = sizeof(mii);
  1831. mii.fMask = MIIM_STATE;
  1832. mii.fState = 0;
  1833. // Get the state of the menu item
  1834. GetMenuItemInfo(hFaxMenu, IDM_FAX_PAUSE_FAXING, FALSE, &mii);
  1835. // Connect to the fax service
  1836. if (Connect()) {
  1837. // Enumerate the fax jobs
  1838. if (FaxEnumJobs(g_hFaxSvcHandle, &pFaxJobEntry, &dwNumFaxJobs)) {
  1839. // Initialize lvfi
  1840. lvfi.flags = LVFI_PARAM;
  1841. // Get the old item with the focus
  1842. dwOldFocusIndex = ListView_GetNextItem(g_hWndListView, -1, LVNI_ALL | LVNI_FOCUSED);
  1843. // Add new fax jobs and move existing fax jobs to their correct position
  1844. for (dwIndex = 0; dwIndex < dwNumFaxJobs; dwIndex++) {
  1845. // Set the search criteria
  1846. lvfi.lParam = pFaxJobEntry[dwIndex].JobId;
  1847. // Initialize the item's state
  1848. uState = 0;
  1849. // Initialize the device name
  1850. szDeviceName = NULL;
  1851. if (pPortJobInfoList) {
  1852. // Find the appropriate job
  1853. pPortJobInfoItem = (PPORT_JOB_INFO_ITEM) pPortJobInfoList;
  1854. while (TRUE) {
  1855. if (pFaxJobEntry[dwIndex].JobId == pPortJobInfoItem->dwJobId) {
  1856. // Job id matches, so this is the appropriate port
  1857. // Get the device name
  1858. szDeviceName = pPortJobInfoItem->szDeviceName;
  1859. break;
  1860. }
  1861. // Step to the next port job info item
  1862. pPortJobInfoItem = (PPORT_JOB_INFO_ITEM) pPortJobInfoItem->ListEntry.Blink;
  1863. if (pPortJobInfoItem == (PPORT_JOB_INFO_ITEM) pPortJobInfoList) {
  1864. // The list has been traversed
  1865. break;
  1866. }
  1867. }
  1868. }
  1869. // Find the job in the list view
  1870. dwListIndex = ListView_FindItem(g_hWndListView, -1, &lvfi);
  1871. if ((dwListIndex != -1) && (dwListIndex != dwIndex)) {
  1872. // Job exists in the list view but is in the wrong position, so get the item
  1873. // Get the item's state
  1874. uState = ListView_GetItemState(g_hWndListView, dwListIndex, LVIS_FOCUSED | LVIS_SELECTED);
  1875. // Delete the item from its current position
  1876. ListView_DeleteItem(g_hWndListView, dwListIndex);
  1877. // Set dwListIndex to -1 so item will be inserted into the list view
  1878. dwListIndex = -1;
  1879. }
  1880. for (nColumnIndex = 0; nColumnIndex < (INT) eIllegalColumnIndex; nColumnIndex++) {
  1881. // Get the column item text
  1882. szColumnItem = GetColumnItemText((eListViewColumnIndex) nColumnIndex, &pFaxJobEntry[dwIndex], szDeviceName);
  1883. // Insert item into the list view
  1884. SetColumnItem(g_hWndListView, (dwListIndex == -1) ? TRUE : FALSE, dwIndex, nColumnIndex, szColumnItem, uState, &pFaxJobEntry[dwIndex]);
  1885. if (szColumnItem) {
  1886. MemFree(szColumnItem);
  1887. }
  1888. }
  1889. }
  1890. // Get the new item with the focus
  1891. dwNewFocusIndex = ListView_GetNextItem(g_hWndListView, -1, LVNI_ALL | LVNI_FOCUSED);
  1892. if ((dwOldFocusIndex != -1) && (dwNewFocusIndex != -1) && (dwNewFocusIndex >= dwNumFaxJobs)) {
  1893. // Job will no longer exist in the list view, so set the focus to the item occupying that index
  1894. // Get the state of the item occupying that index
  1895. uState = ListView_GetItemState(g_hWndListView, dwOldFocusIndex, LVIS_FOCUSED | LVIS_SELECTED | LVIS_OVERLAYMASK);
  1896. // Set the focus to the new item
  1897. ListView_SetItemState(g_hWndListView, dwOldFocusIndex, uState | LVIS_FOCUSED, uState | LVIS_FOCUSED);
  1898. }
  1899. // Remove old fax jobs
  1900. dwListIndex = ListView_GetItemCount(g_hWndListView);
  1901. for (dwIndex = dwNumFaxJobs; dwIndex < dwListIndex; dwIndex++) {
  1902. ListView_DeleteItem(g_hWndListView, dwNumFaxJobs);
  1903. }
  1904. FaxFreeBuffer(pFaxJobEntry);
  1905. }
  1906. // Disconnect from the fax service
  1907. Disconnect();
  1908. }
  1909. // Set the window title to indicate connected or paused
  1910. SetWindowText(g_hWndMain, mii.fState & MFS_CHECKED ? g_szTitlePaused : g_szTitleConnected);
  1911. continue;
  1912. case FEI_JOB_QUEUED:
  1913. case FEI_ANSWERED:
  1914. // Initialize the device name
  1915. szDeviceName = NULL;
  1916. if ((pFaxEvent->EventId == FEI_ANSWERED) && (pPortJobInfoList)) {
  1917. // Find the appropriate port
  1918. pPortJobInfoItem = (PPORT_JOB_INFO_ITEM) pPortJobInfoList;
  1919. while (TRUE) {
  1920. if (pFaxEvent->DeviceId == pPortJobInfoItem->dwDeviceId) {
  1921. // Device id matches, so this is the appropriate port
  1922. // Set the job id
  1923. pPortJobInfoItem->dwJobId = pFaxEvent->JobId;
  1924. // Get the device name
  1925. szDeviceName = pPortJobInfoItem->szDeviceName;
  1926. break;
  1927. }
  1928. // Step to the next port job info item
  1929. pPortJobInfoItem = (PPORT_JOB_INFO_ITEM) pPortJobInfoItem->ListEntry.Blink;
  1930. if (pPortJobInfoItem == (PPORT_JOB_INFO_ITEM) pPortJobInfoList) {
  1931. // The list has been traversed
  1932. break;
  1933. }
  1934. }
  1935. }
  1936. // Connect to the fax service
  1937. if (Connect()) {
  1938. // Enumerate the fax jobs
  1939. if (FaxEnumJobs(g_hFaxSvcHandle, &pFaxJobEntry, &dwNumFaxJobs)) {
  1940. // Initialize lvfi
  1941. lvfi.flags = LVFI_PARAM;
  1942. // Add the new fax job to its correct position
  1943. for (dwIndex = 0; dwIndex < dwNumFaxJobs; dwIndex++) {
  1944. // Check if the current fax job matches the new fax job
  1945. if (pFaxJobEntry[dwIndex].JobId != pFaxEvent->JobId) {
  1946. continue;
  1947. }
  1948. // Set the search criteria
  1949. lvfi.lParam = pFaxJobEntry[dwIndex].JobId;
  1950. // Find the job in the list view
  1951. dwListIndex = ListView_FindItem(g_hWndListView, -1, &lvfi);
  1952. if (dwListIndex != -1) {
  1953. // Job exists in the list view but is in the wrong position, so get the item
  1954. // Delete the item from its current position
  1955. ListView_DeleteItem(g_hWndListView, dwListIndex);
  1956. }
  1957. for (nColumnIndex = 0; nColumnIndex < (INT) eIllegalColumnIndex; nColumnIndex++) {
  1958. // Get the column item text
  1959. szColumnItem = GetColumnItemText((eListViewColumnIndex) nColumnIndex, &pFaxJobEntry[dwIndex], szDeviceName);
  1960. // Insert item into the list view
  1961. SetColumnItem(g_hWndListView, TRUE, dwIndex, nColumnIndex, szColumnItem, 0, &pFaxJobEntry[dwIndex]);
  1962. if (szColumnItem) {
  1963. MemFree(szColumnItem);
  1964. }
  1965. }
  1966. break;
  1967. }
  1968. FaxFreeBuffer(pFaxJobEntry);
  1969. }
  1970. // Disconnect from the fax service
  1971. Disconnect();
  1972. }
  1973. continue;
  1974. case FEI_DELETED:
  1975. // Initialize lvfi
  1976. lvfi.flags = LVFI_PARAM;
  1977. // Set the search criteria
  1978. lvfi.lParam = pFaxEvent->JobId;
  1979. // Find the job in the list view
  1980. dwListIndex = ListView_FindItem(g_hWndListView, -1, &lvfi);
  1981. if (dwListIndex != -1) {
  1982. // Delete the item from the list view
  1983. ListView_DeleteItem(g_hWndListView, dwListIndex);
  1984. }
  1985. continue;
  1986. default:
  1987. // Initialize the device name
  1988. szDeviceName = NULL;
  1989. // Initialize the fax job id
  1990. dwJobId = (DWORD) -1;
  1991. // Set the port job info item
  1992. if ((pFaxEvent->EventId != (DWORD) -1) && (pPortJobInfoList)) {
  1993. // Find the appropriate port
  1994. pPortJobInfoItem = (PPORT_JOB_INFO_ITEM) pPortJobInfoList;
  1995. while (TRUE) {
  1996. if (pFaxEvent->DeviceId == pPortJobInfoItem->dwDeviceId) {
  1997. // Device id matches, so this is the appropriate port
  1998. // Get the fax job id
  1999. if (pFaxEvent->EventId == FEI_IDLE) {
  2000. dwJobId = pPortJobInfoItem->dwJobId;
  2001. }
  2002. else {
  2003. dwJobId = pFaxEvent->JobId;
  2004. // Set the device name
  2005. szDeviceName = pPortJobInfoItem->szDeviceName;
  2006. }
  2007. // Update the job id
  2008. pPortJobInfoItem->dwJobId = pFaxEvent->JobId;
  2009. break;
  2010. }
  2011. // Step to the next port job info item
  2012. pPortJobInfoItem = (PPORT_JOB_INFO_ITEM) pPortJobInfoItem->ListEntry.Blink;
  2013. if (pPortJobInfoItem == (PPORT_JOB_INFO_ITEM) pPortJobInfoList) {
  2014. // The list has been traversed
  2015. break;
  2016. }
  2017. }
  2018. }
  2019. else if (pFaxEvent->EventId == (DWORD) -1) {
  2020. // Set the fax job id
  2021. dwJobId = pFaxEvent->JobId;
  2022. }
  2023. // Initialize lvfi
  2024. lvfi.flags = LVFI_PARAM;
  2025. // Set the search criteria
  2026. lvfi.lParam = dwJobId;
  2027. // Find the job in the list view
  2028. dwListIndex = ListView_FindItem(g_hWndListView, -1, &lvfi);
  2029. if (dwListIndex != -1) {
  2030. // Connect to the fax service
  2031. if (Connect()) {
  2032. // Get the fax job
  2033. pFaxJobEntry = NULL;
  2034. while ((FaxGetJob(g_hFaxSvcHandle, dwJobId, &pFaxJobEntry)) && (pFaxJobEntry->Status == FPS_AVAILABLE) && ((pFaxJobEntry->JobType == JT_SEND) || (pFaxJobEntry->JobType == JT_RECEIVE))) {
  2035. FaxFreeBuffer(pFaxJobEntry);
  2036. pFaxJobEntry = NULL;
  2037. Sleep(250);
  2038. }
  2039. if (pFaxJobEntry) {
  2040. // Job exists in the list view, so set the item
  2041. for (nColumnIndex = 0; nColumnIndex < (INT) eIllegalColumnIndex; nColumnIndex++) {
  2042. // Get the column item text
  2043. szColumnItem = GetColumnItemText((eListViewColumnIndex) nColumnIndex, pFaxJobEntry, szDeviceName);
  2044. // Set item in the list view
  2045. SetColumnItem(g_hWndListView, FALSE, dwListIndex, nColumnIndex, szColumnItem, 0, pFaxJobEntry);
  2046. if (szColumnItem) {
  2047. MemFree(szColumnItem);
  2048. }
  2049. }
  2050. FaxFreeBuffer(pFaxJobEntry);
  2051. }
  2052. // Disconnect from the fax service
  2053. Disconnect();
  2054. }
  2055. }
  2056. break;
  2057. }
  2058. LocalFree(pFaxEvent);
  2059. }
  2060. // Disable the pause faxing menu item and the cancel all faxes menu item
  2061. EnableMenuItem(hFaxMenu, IDM_FAX_PAUSE_FAXING, MF_BYCOMMAND | MF_GRAYED);
  2062. EnableMenuItem(hFaxMenu, IDM_FAX_CANCEL_ALL_FAXES, MF_BYCOMMAND | MF_GRAYED);
  2063. #ifdef TOOLBAR_ENABLED
  2064. // Disable the pause faxing toolbar menu item and the cancel all faxes toolbar menu item
  2065. EnableToolbarMenuState(g_hWndToolbar, IDM_FAX_PAUSE_FAXING, FALSE);
  2066. EnableToolbarMenuState(g_hWndToolbar, IDM_FAX_CANCEL_ALL_FAXES, FALSE);
  2067. #endif // TOOLBAR_ENABLED
  2068. // Free the port job info list
  2069. while (pPortJobInfoList) {
  2070. // Get the head of the port job info list
  2071. pPortJobInfoItem = (PPORT_JOB_INFO_ITEM) pPortJobInfoList;
  2072. // Set the head of port job info list to the next port job info item in the list
  2073. pPortJobInfoList = pPortJobInfoItem->ListEntry.Blink;
  2074. if (IsListEmpty(pPortJobInfoList)) {
  2075. // This is the last item in the list, so set the list head to NULL
  2076. pPortJobInfoList = NULL;
  2077. }
  2078. else {
  2079. // Remove the port job info item from the list
  2080. RemoveEntryList(&pPortJobInfoItem->ListEntry);
  2081. }
  2082. // Free the port job info item
  2083. MemFree(pPortJobInfoItem);
  2084. }
  2085. ExitLevel1:
  2086. CloseHandle(g_hCompletionPort);
  2087. ExitLevel0:
  2088. // Reset the start event
  2089. ResetEvent(g_hStartEvent);
  2090. // Set the window title to indicate not connected
  2091. SetWindowText(g_hWndMain, g_szTitleNotConnected);
  2092. }
  2093. return 0;
  2094. }