home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1995 November / PCWK1195.iso / inne / podstawy / os2 / nakladki / pc2v190.exe / SOURCE.ZIP / Source / PC2Spool.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-01  |  44.2 KB  |  809 lines

  1. /***********************************************************************\
  2.  *                             PC2Spool.c                              *
  3.  *              Copyright (C) by Stangl Roman, 1994, 1995              *
  4.  * This Code may be freely distributed, provided the Copyright isn't   *
  5.  * removed, under the conditions indicated in the documentation.       *
  6.  *                                                                     *
  7.  * PC2Spool.c   PC/2's spooler control, available when running PC/2    *
  8.  *              as a WPS replacement.                                  *
  9.  *                                                                     *
  10. \***********************************************************************/
  11.  
  12. static char RCSID[]="@(#) $Header: PC2Spool.c Version 1.90 05,1995 $ (LBL)";
  13.  
  14. #define         _FILE_  "PC/2 - PC2Spool.c V1.90"
  15.  
  16. #define         INCL_SPL
  17. #define         INCL_SPLDOSPRINT
  18.  
  19. #include        "PC2.h"                 /* User include files */
  20. #include        "Error.h"
  21.  
  22.                                         /* Function prototype of the undocumented Spl32QMInitialize()
  23.                                            OS/2 spooler start API. Thanks to Monte Copeland for
  24.                                            demonstrating its use in his MSHELL program */
  25. typedef BOOL    (APIENTRY SPL32QMINITIALIZE) (ULONG *pulError);
  26. SPL32QMINITIALIZE   *pSpl32QmInitialize;
  27.  
  28. FIELDINFO       ContainerFieldInfo[]=
  29.                     {
  30.                     { 0, CFA_STRING | CFA_HORZSEPARATOR | CFA_SEPARATOR, 0, "Queue"        , FIELDOFFSET(SPOOLERRECORD, pszQueue)       , NULL, NULL, 0 },
  31.                     { 0, CFA_STRING | CFA_HORZSEPARATOR | CFA_SEPARATOR, 0, "Queue\nStatus", FIELDOFFSET(SPOOLERRECORD, pszQueueStatus) , NULL, NULL, 0 },
  32.                     { 0, CFA_STRING | CFA_HORZSEPARATOR | CFA_SEPARATOR, 0, "Queue\nName"  , FIELDOFFSET(SPOOLERRECORD, pszQueueComment), NULL, NULL, 0 },
  33.                     { 0, CFA_STRING | CFA_HORZSEPARATOR | CFA_SEPARATOR, 0, "Queue\nDriver", FIELDOFFSET(SPOOLERRECORD, pszQueueDriver) , NULL, NULL, 0 },
  34.                     { 0, CFA_STRING | CFA_HORZSEPARATOR | CFA_SEPARATOR, 0, "Job"          , FIELDOFFSET(SPOOLERRECORD, pszJob)         , NULL, NULL, 0 },
  35.                     { 0, CFA_STRING | CFA_HORZSEPARATOR | CFA_SEPARATOR, 0, "Job\nNumber"  , FIELDOFFSET(SPOOLERRECORD, pszJobNumber)   , NULL, NULL, 0 },
  36.                     { 0, CFA_STRING | CFA_HORZSEPARATOR | CFA_SEPARATOR, 0, "Job\nStatus"  , FIELDOFFSET(SPOOLERRECORD, pszJobStatus)   , NULL, NULL, 0 },
  37.                     { 0, CFA_STRING | CFA_HORZSEPARATOR | CFA_SEPARATOR, 0, "Job\nComment" , FIELDOFFSET(SPOOLERRECORD, pszJobComment)  , NULL, NULL, 0 },
  38.                     };
  39.  
  40. HOOKPARAMETERS  *pHP;
  41. HWND            hwndSpoolerFrame;
  42. HWND            hwndSpoolerPopupMenu;
  43. PFNWP           pfnContainerWindowProc; /* Container window procedure for subclassing */
  44.  
  45. ULONG   SpoolerInitialize(HMODULE hDLLPc2Hook)
  46. {
  47. ULONG   flCreate=FCF_SPOOLERWINDOW;     /* Frame creation control flag */
  48. SWP     swp;                            /* According to a tip from members of OS/2 development in
  49.                                            an article in OS/2 Developer magazine, it is more
  50.                                            efficient to call WinSetMultWindowPos(), because
  51.                                            WinSetWindowPos() internally calls WinSetMultWindowPos()
  52.                                            (even if just one window is moved) */
  53. HMODULE hDLLPmSpl;                      /* DLL handle of PMSPL.DLL */
  54. UCHAR   ucBuffer[80];                   /* DosLoadModule() error buffer */
  55.                                         /* Parameter for Spl32QmInitialize */
  56. ULONG   ulSpoolerRc;
  57.  
  58.                                         /* Get access to the PC/2 control structure */
  59. if(DosQueryProcAddr(hDLLPc2Hook, 4, "HookParameters", (PFN *)(&pHP))!=NO_ERROR)
  60.     return(ERROR_FILE_NOT_FOUND);
  61. /*                                                                                      *\
  62.  * Initialize the spooler interface of PMSPL.DLL, if PC/2 is running as a WPS           *
  63.  * replacement, by loading SPL32QMINITIALIZE from PMSPL.DLL.                            *
  64. \*                                                                                      */
  65. if(DosLoadModule(ucBuffer, sizeof(ucBuffer)-1, "PMSPL", &hDLLPmSpl)!=NO_ERROR)
  66.     {                                   /* DLL couldn't be found in the current PC/2
  67.                                            directory or via the LIBPATH path */
  68.     return(ERROR_FILE_NOT_FOUND);
  69.     }
  70. if(DosQueryProcAddr(hDLLPmSpl, 0, "SPL32QMINITIALIZE", (PFN *)(&pSpl32QmInitialize))!=NO_ERROR)
  71.     {                                   /* An error occured */
  72.     DosFreeModule(hDLLPmSpl);
  73.     return(ERROR_FILE_NOT_FOUND);
  74.     }
  75.                                         /* Initialize the OS/2 2.x spooler */
  76. pSpl32QmInitialize(&ulSpoolerRc);
  77.                                         /* Return any error and disable Spooler Container, except for
  78.                                            error 0x4FFD which is returned when the OS/2 Spooler is
  79.                                            already running. Note, this error is not documented, so this
  80.                                            assumption comes from trial and error... */
  81. if(ulSpoolerRc==0x4FFD) ulSpoolerRc=NO_ERROR;
  82. if(ulSpoolerRc!=NO_ERROR)
  83.     return(ulSpoolerRc);
  84. /*                                                                                      *\
  85.  * If spooler could be initialized create PC/2 Spooler Control Window.                  *
  86. \*                                                                                      */
  87. if(!WinRegisterClass(                   /* Register window class */
  88.     pHP->habPc2,                        /* Handle of anchor block */
  89.     (PSZ)PC2_CLASSNAME_SPOOLER,         /* Window class name */
  90.     (PFNWP)PC2_SpoolerWindowProc,       /* Address of window procedure */
  91.                                         /* Class style */
  92.     CS_SIZEREDRAW | CS_SAVEBITS | CS_MOVENOTIFY,
  93.     0))                                 /* Extra window words */
  94.     return(1);
  95.                                         /* Create a standard window */
  96. if((hwndSpoolerFrame=WinCreateStdWindow(
  97.     HWND_DESKTOP,                       /* DESKTOP is parent */
  98.     0,                                  /* Standard window styles */
  99.     &flCreate,                          /* Frame control flags */
  100.     (PSZ)PC2_CLASSNAME_SPOOLER,         /* Client window class name */
  101.     "",                                 /* No window text */
  102.     0,                                  /* No special class style */
  103.     pHP->hDLLPc2Spooler,                /* Ressource is in PC2SPOOL.DLL file */
  104.     ID_PC2SPOOLERWINDOW,                /* Frame window identifier */
  105.     &pHP->hwndSpooler)                  /* Client window handle */
  106.     )==NULLHANDLE)
  107.     return(2);
  108. WinSetWindowText(hwndSpoolerFrame, PC2_SPOOLER_WINDOW);
  109. swp.fl=SWP_HIDE|SWP_MOVE|SWP_SIZE|SWP_DEACTIVATE;
  110. swp.x=pHP->swpPC2Spooler.x;
  111. swp.y=pHP->swpPC2Spooler.y;
  112. swp.cx=pHP->swpPC2Spooler.cx;
  113. swp.cy=pHP->swpPC2Spooler.cy;
  114. swp.hwndInsertBehind=NULLHANDLE;
  115. swp.hwnd=hwndSpoolerFrame;
  116. WinSetMultWindowPos(pHP->habPc2, &swp, 1);
  117. hwndSpoolerPopupMenu=WinLoadMenu(pHP->hwndSpooler, pHP->hDLLPc2Spooler, ID_SPOOLERPOPUPMENU);
  118. return(NO_ERROR);
  119. }
  120.  
  121. MRESULT EXPENTRY PC2_SpoolerWindowProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  122. {
  123. static CNRINFO      CnrInfo;            /* Container info structure */
  124. static PFIELDINFO   pFieldInfo;
  125. static PFIELDINFO   pFieldInfoFirst;
  126.  
  127. switch(msg)
  128. {
  129. case WM_CREATE:
  130. /*                                                                                      *\
  131.  * During spooler window creation, create a container class window as the child of the  *
  132.  * client area. Initialize the columns for the details view, the spooler container      *
  133.  * window will use. Then set the container info structure to details view with a        *
  134.  * splitbar.
  135. \*                                                                                      */
  136.     {
  137.     ULONG           ulColumn;
  138.     PFIELDINFO      pFieldInfoSplitbar; /* Pointer to a the FIELDINFO structure of the 4th column
  139.                                            to set splitbar afterwards */
  140.     FIELDINFOINSERT FieldInfoInsert;    /* Control structure for column insertation */
  141.  
  142.                                         /* Create the container to fill in spooler queue
  143.                                            and job data in details view. */
  144.     pHP->hwndSpoolerContainer=WinCreateWindow(hwnd, WC_CONTAINER, "",
  145.         WS_VISIBLE | CCS_READONLY | CCS_MINIRECORDCORE | CCS_MULTIPLESEL,
  146.         0, 0, 0, 0, hwnd, HWND_TOP, ID_PC2SPOOLERCONTAINER, NULL, NULL);
  147.                                         /* Set presentation parameters saved */
  148.     WinSetPresParam(pHP->hwndSpoolerContainer, PP_FONTNAMESIZE,
  149.         sizeof(pHP->ucPC2SpoolerFont), pHP->ucPC2SpoolerFont);
  150.                                         /* Subclass container window to get hold of presentation
  151.                                            parameter changes */
  152.     pfnContainerWindowProc=WinSubclassWindow(pHP->hwndSpoolerContainer, SubclassedContainerWindowProc);
  153.                                         /* Create fieldinfos for the columns in details view */
  154.     pFieldInfo=(PFIELDINFO)WinSendMsg(pHP->hwndSpoolerContainer, CM_ALLOCDETAILFIELDINFO,
  155.         MPFROMSHORT(sizeof(ContainerFieldInfo)/sizeof(ContainerFieldInfo[0])), NULL);
  156.                                         /* Fill the columns avaiable into container */
  157.     pFieldInfoFirst=pFieldInfo;
  158.     pFieldInfoSplitbar=NULL;
  159.     for(ulColumn=0; ulColumn<(sizeof(ContainerFieldInfo)/sizeof(ContainerFieldInfo[0])); ulColumn++)
  160.         {
  161.                                         /* Save 4th column to set splitbar afterwards */
  162.         if(ulColumn==3) pFieldInfoSplitbar=pFieldInfo;
  163.         pFieldInfo->flTitle=ContainerFieldInfo[ulColumn].flTitle;
  164.         pFieldInfo->pTitleData=strdup(ContainerFieldInfo[ulColumn].pTitleData);
  165.         pFieldInfo->flData=ContainerFieldInfo[ulColumn].flData;
  166.         pFieldInfo->offStruct=ContainerFieldInfo[ulColumn].offStruct;
  167.         pFieldInfo=pFieldInfo->pNextFieldInfo;
  168.         }
  169.                                         /* Fill column insertation control */
  170.     FieldInfoInsert.cb=sizeof(FieldInfoInsert);
  171.                                         /* Insert from first column */
  172.     FieldInfoInsert.pFieldInfoOrder=(PFIELDINFO)CMA_FIRST;
  173.                                         /* Update container display now */
  174.     FieldInfoInsert.fInvalidateFieldInfo=(ULONG)TRUE;
  175.                                         /* Number of columns to insert */
  176.     FieldInfoInsert.cFieldInfoInsert=sizeof(ContainerFieldInfo)/sizeof(ContainerFieldInfo[0]);
  177.                                         /* Insert column field info into container */
  178.     WinSendMsg(pHP->hwndSpoolerContainer, CM_INSERTDETAILFIELDINFO,
  179.         MPFROMP(pFieldInfoFirst), MPFROMP(&FieldInfoInsert));
  180.                                         /* Select details view */
  181.     CnrInfo.flWindowAttr=CV_DETAIL | CA_DETAILSVIEWTITLES;
  182.                                         /* Splitbar is set to last saved position */
  183.     CnrInfo.xVertSplitbar=pHP->lSplitbarPosition;
  184.                                         /* Splitbar occurs after the 4th column */
  185.     CnrInfo.pFieldInfoLast=pFieldInfoSplitbar;
  186.                                         /* Setup CNRINFO into container */
  187.     WinSendMsg(pHP->hwndSpoolerContainer, CM_SETCNRINFO,
  188.         MPFROMP(&CnrInfo), MPFROMLONG(CMA_FLWINDOWATTR|CMA_XVERTSPLITBAR|CMA_PFIELDINFOLAST));
  189.     RefreshSpooler();                   /* Fill spooler container from queue data */
  190.     WinSetFocus(HWND_DESKTOP, pHP->hwndSpoolerContainer);
  191.     }
  192.     break;
  193.  
  194. case WM_PAINT:
  195.     {
  196.     HPS     hpsClient;
  197.  
  198.                                         /* Get a cached presentation space */
  199.     hpsClient=WinBeginPaint(hwnd, NULLHANDLE, NULL);
  200.     WinEndPaint(hpsClient);
  201.     }
  202.     break;
  203.  
  204. case WM_SIZE:
  205. case WM_MOVE:
  206. /*                                                                                      *\
  207.  * During sizing (and moving) of the spooler window, ensure that the container always   *
  208.  * fills the complete client area.                                                      *
  209. \*                                                                                      */
  210.     {
  211.     LONG    lXBorder=WinQuerySysValue(HWND_DESKTOP, SV_CXSIZEBORDER);
  212.     LONG    lYBorder=WinQuerySysValue(HWND_DESKTOP, SV_CYSIZEBORDER);
  213.     SWP     swpPC2Spooler;
  214.     RECTL   rectlClient;
  215.     SWP     swp;
  216.  
  217.                                         /* Get the frame area size */
  218.     WinQueryWindowPos(hwndSpoolerFrame, &swpPC2Spooler);
  219.     if((swpPC2Spooler.cx>pHP->DesktopSize.x) || (pHP->swpPC2Spooler.cx<0))
  220.         pHP->swpPC2Spooler.cx=pHP->DesktopSize.x/2;
  221.     else
  222.         pHP->swpPC2Spooler.cx=swpPC2Spooler.cx;
  223.     if((swpPC2Spooler.cy>pHP->DesktopSize.y) || (pHP->swpPC2Spooler.cy<0))
  224.         pHP->swpPC2Spooler.cy=pHP->DesktopSize.y/5;
  225.     else
  226.         pHP->swpPC2Spooler.cy=swpPC2Spooler.cy;
  227.     if((swpPC2Spooler.x<(0-lXBorder)) ||
  228.         ((swpPC2Spooler.x+pHP->swpPC2Spooler.cx)>(pHP->DesktopSize.x+lXBorder)))
  229.         pHP->swpPC2Spooler.x=0;
  230.     else
  231.         pHP->swpPC2Spooler.x=swpPC2Spooler.x;
  232.     if((swpPC2Spooler.y<(0-lYBorder)) ||
  233.         ((swpPC2Spooler.y+pHP->swpPC2Spooler.cy)>(pHP->DesktopSize.y+lYBorder)))
  234.         pHP->swpPC2Spooler.y=0;
  235.     else
  236.         pHP->swpPC2Spooler.y=swpPC2Spooler.y;
  237.     WinSetWindowPos(hwndSpoolerFrame, NULLHANDLE, pHP->swpPC2Spooler.x, pHP->swpPC2Spooler.y,
  238.         pHP->swpPC2Spooler.cx, pHP->swpPC2Spooler.cy, SWP_SIZE | SWP_MOVE);
  239.                                         /* Size container to client area */
  240.     WinQueryWindowRect(hwnd, &rectlClient);
  241.     swp.fl=SWP_MOVE|SWP_SIZE|SWP_SHOW|SWP_ZORDER;
  242.     swp.x=swp.y=0;
  243.     swp.cx=rectlClient.xRight;
  244.     swp.cy=rectlClient.yTop;
  245.     swp.hwndInsertBehind=HWND_TOP;
  246.     swp.hwnd=pHP->hwndSpoolerContainer;
  247.     WinSetMultWindowPos(pHP->habPc2, &swp, 1);
  248.     }
  249.     break;
  250.  
  251. /*                                                                                      *\
  252.  * Syntax: WM_SHOWSPOOLER, NULL, NULL                                                   *
  253. \*                                                                                      */
  254. case WM_SHOWSPOOLER:
  255. /*                                                                                      *\
  256.  * The spooler window is initially created invisible. When the user selects the         *
  257.  * menuentry PC2 Spooler, this message is posted to set the spooler window visible.     *
  258. \*                                                                                      */
  259.     {
  260.     SWP     swp;
  261.  
  262.     swp.fl=SWP_SHOW|SWP_ACTIVATE|SWP_ZORDER;
  263.     swp.x=pHP->swpPC2Spooler.x;
  264.     swp.y=pHP->swpPC2Spooler.y;
  265.     swp.cx=pHP->swpPC2Spooler.cx;
  266.     swp.cy=pHP->swpPC2Spooler.cy;
  267.     swp.hwndInsertBehind=HWND_TOP;
  268.     swp.hwnd=hwndSpoolerFrame;
  269.     WinSetMultWindowPos(pHP->habPc2, &swp, 1);
  270.     }
  271.     break;
  272.  
  273. /*                                                                                      *\
  274.  * Syntax: WM_REFRESHSPOOLER, NULL, NULL                                                *
  275. \*                                                                                      */
  276. case WM_REFRESHSPOOLER:
  277. /*                                                                                      *\
  278.  * The spooler container regularily gets this message from a timer to update the        *
  279.  * container with the current printer queue data, to have a real-time status of the     *
  280.  * printer queue.                                                                       *
  281. \*                                                                                      */
  282.     RefreshSpooler();
  283.     break;
  284.  
  285. case WM_CONTROL:
  286. /*                                                                                      *\
  287.  * The child window of the client area sends its notification messages to its parent,   *
  288.  * so the client window procedure can expext container notification messages.           *
  289. \*                                                                                      */
  290.     switch(SHORT2FROMMP(mp1))
  291.     {
  292.     case CN_CONTEXTMENU:
  293.         {
  294.         SPOOLERRECORD   *pListSpoolerRecord;
  295.         POINTL          ptlMouse;       /* Mouse position during creation of notification */
  296.         USHORT          fsOptions=PU_NONE | PU_KEYBOARD | PU_MOUSEBUTTON1 |
  297.                                   PU_HCONSTRAIN | PU_VCONSTRAIN;
  298.  
  299.                                         /* Query selected records in container and return them,
  300.                                            or return the one below the mouse pointer if none is
  301.                                            selected. */
  302.         pListSpoolerRecord=QuerySelectedRecords((SPOOLERRECORD *)mp2);
  303.         if(pListSpoolerRecord==NULL)
  304.             pHP->pSpoolerObject=NULL;
  305.         else
  306.             pHP->pSpoolerObject=pListSpoolerRecord->pSpoolerObject;
  307.                                         /* Get the mouse position */
  308.         WinQueryMsgPos(pHP->habPc2, &ptlMouse);
  309.         WinPopupMenu(HWND_DESKTOP, hwnd, hwndSpoolerPopupMenu,
  310.             ptlMouse.x, ptlMouse.y, 0, fsOptions);
  311.         }
  312.         break;
  313.     }
  314.     break;
  315.  
  316. case WM_HELP:                           /* Help pressed */
  317.     WinSendMsg(pHP->hwndHelp, HM_DISPLAY_HELP,
  318.         MPFROMSHORT(ID_PC2SPOOLERWINDOW), HM_RESOURCEID);
  319.     break;
  320.  
  321. case WM_COMMAND:
  322. /*                                                                                      *\
  323.  * Process the messages generated by the menuentries of the spooler container popup     *
  324.  * menu.                                                                                *
  325. \*                                                                                      */
  326.     switch(SHORT1FROMMP(mp1))
  327.     {
  328.     case ID_SPOOLERREFRESH:             /* User requested to refresh the spooler container window
  329.                                            with the status of the actual spooler queue */
  330.         RefreshSpooler();
  331.         break;
  332.  
  333.     case ID_SPOOLERHOLDJOB:             /* The user selected to hold a job */
  334.     case ID_SPOOLERRELEASEJOB:          /* The user selected to release a job */
  335.     case ID_SPOOLERDELETEJOB:           /* The user selected to delete a job */
  336.     case ID_SPOOLERHOLDQUEUE:           /* The user selected to hold a queue */
  337.     case ID_SPOOLERRELEASEQUEUE:        /* The user selected to release a queue */
  338.                                         /* Perform the action on linked list of selected records */
  339.         NotifySelectedRecords((ULONG)SHORT1FROMMP(mp1));
  340.         break;
  341.  
  342.     case ID_SPOOLERHELP:                /* The user requested some help */
  343.         WinPostMsg(hwnd, WM_HELP, MPFROMLONG(ID_PC2SPOOLERWINDOW), MPFROM2SHORT(CMDSRC_MENU, TRUE));
  344.         break;
  345.     }
  346.     break;
  347.  
  348. case WM_DESTROY:
  349. /*                                                                                      *\
  350.  * Clear container structures and free control structures used by PC/2.                 *
  351. \*                                                                                      */
  352.     {
  353.     SPOOLERRECORD   *pSpoolerRecord;
  354.  
  355.                                         /* Query the actual container info structure */
  356.     WinSendMsg(pHP->hwndSpoolerContainer, CM_QUERYCNRINFO,
  357.         MPFROMP(&CnrInfo), MPFROMSHORT(sizeof(CnrInfo)));
  358.     pHP->lSplitbarPosition=CnrInfo.xVertSplitbar;
  359.                                         /* Prevent unnecessary container drawing */
  360.     WinEnableWindowUpdate(pHP->hwndSpoolerContainer, FALSE);
  361.                                         /* Get first container record to delete them sequentially */
  362.     pSpoolerRecord=(SPOOLERRECORD *)WinSendMsg(pHP->hwndSpoolerContainer, CM_QUERYRECORD,
  363.         NULL, MPFROM2SHORT(CMA_FIRST, CMA_ITEMORDER));
  364.     while(pSpoolerRecord)
  365.         {                               /* Delete and free records */
  366.         free(pSpoolerRecord->pszQueue);
  367.         free(pSpoolerRecord->pszQueueStatus);
  368.         free(pSpoolerRecord->pszQueueComment);
  369.         free(pSpoolerRecord->pszQueueDriver);
  370.         free(pSpoolerRecord->pszJob);
  371.         free(pSpoolerRecord->pszJobNumber);
  372.         free(pSpoolerRecord->pszJobStatus);
  373.         free(pSpoolerRecord->pszJobComment);
  374.         free(pSpoolerRecord->pSpoolerObject);
  375.                                         /* Delete record in container. Warning! as this function
  376.                                            expects an array, but we only delete one record, we
  377.                                            have to get the address of the pointer to the record. */
  378.         WinSendMsg(pHP->hwndSpoolerContainer, CM_REMOVERECORD,
  379.             MPFROMP(&pSpoolerRecord), MPFROM2SHORT(1, CMA_FREE|CMA_INVALIDATE));
  380.                                         /* Get next container record to delete them sequentially */
  381.         pSpoolerRecord=(SPOOLERRECORD *)WinSendMsg(pHP->hwndSpoolerContainer, CM_QUERYRECORD,
  382.             NULL, MPFROM2SHORT(CMA_FIRST, CMA_ITEMORDER));
  383.         }
  384.     }
  385.     break;
  386.  
  387. default:                                /* Default window procedure must be called */
  388.     return((MRESULT)WinDefWindowProc(hwnd, msg, mp1, mp2));
  389. }
  390. return((MRESULT)FALSE);                 /* We have handled the message */
  391. }
  392.  
  393. /*--------------------------------------------------------------------------------------*\
  394.  * This function applies the current selected menu identifiert from the container's     *
  395.  * context popup menu to the linked list of container records selected. E.g. if the     *
  396.  * user wants to hold some jobs, he marks the jobs and then selects the menuentry to    *
  397.  * hold a job on any selected job. All selected jobs (which are in the linked list      *
  398.  * pointed to by pHP->pSpoolerObject) get holded.                                       *
  399.  * Req:                                                                                 *
  400.  *      ulActionCode .. The menu identifier of the container window context menu.       *
  401.  * Returns:                                                                             *
  402. \*--------------------------------------------------------------------------------------*/
  403. void            NotifySelectedRecords(ULONG ulActionCode)
  404. {
  405. SPOOLERRECORD   *pCurrentSpoolerRecord;
  406.  
  407.                                         /* If linked list is empty just return */
  408. if(pHP->pSpoolerObject==NULL)
  409.     return;
  410. else
  411.     pCurrentSpoolerRecord=pHP->pSpoolerObject->pSpoolerRecord;
  412. while(pCurrentSpoolerRecord!=NULL)
  413.     {
  414.     switch(ulActionCode)
  415.     {
  416.     case ID_SPOOLERHOLDJOB:             /* The user selected to hold a job */
  417.         SplHoldJob(NULL, pCurrentSpoolerRecord->pszQueue, pCurrentSpoolerRecord->ulJob);
  418.         break;
  419.  
  420.     case ID_SPOOLERRELEASEJOB:          /* The user selected to release a job */
  421.         SplReleaseJob(NULL, pCurrentSpoolerRecord->pszQueue, pCurrentSpoolerRecord->ulJob);
  422.         break;
  423.  
  424.     case ID_SPOOLERDELETEJOB:           /* The user selected to delete a job */
  425.         SplDeleteJob(NULL, pCurrentSpoolerRecord->pszQueue, pCurrentSpoolerRecord->ulJob);
  426.         break;
  427.  
  428.     case ID_SPOOLERHOLDQUEUE:           /* The user selected to hold a queue */
  429.         SplHoldQueue(NULL, pCurrentSpoolerRecord->pszQueue);
  430.         break;
  431.  
  432.     case ID_SPOOLERRELEASEQUEUE:        /* The user selected to release a queue */
  433.         SplReleaseQueue(NULL, pCurrentSpoolerRecord->pszQueue);
  434.         break;
  435.     }
  436.                                         /* Advance linked list */
  437.     pCurrentSpoolerRecord=(SPOOLERRECORD *)pCurrentSpoolerRecord->MiniRec.preccNextRecord;
  438.     }
  439. RefreshSpooler();                       /* Update container records from spooler queue data */
  440. }
  441.  
  442. /*--------------------------------------------------------------------------------------*\
  443.  * This function queries the spooler container records that are selected. As an         *
  444.  * argument it gets the SPOOLERRECORD of the container record the user wants to display *
  445.  * the context menu. If this container records is not selected, this record is returned *
  446.  * as a linked list of just one record.                                                 *
  447.  * All selected container records are chained together in a linked list by updating     *
  448.  * the MINIRECORD.preccNextRecord structure element.                                    *
  449.  * Req:                                                                                 *
  450.  *      pSelectedSpoolerRecord                                                          *
  451.  *               ...... The SPOOLERRECORD the mouse pointer was used to activate the    *
  452.  *                      container's context menu.                                       *
  453.  * Returns:                                                                             *
  454.  *      pSpoolerRecord  The first SPOOLERRECORD of a linked list of SPOOLERRECORDS that *
  455.  *                      are all selected, or pSelectedSpoolerRecord if none is          *
  456.  *                      selected or NULL if the container is empty.                     *
  457. \*--------------------------------------------------------------------------------------*/
  458. SPOOLERRECORD   *QuerySelectedRecords(SPOOLERRECORD *pSelectedSpoolerRecord)
  459. {
  460. SPOOLERRECORD   *pSpoolerRecord;
  461. SPOOLERRECORD   *pCurrentSpoolerRecord;
  462. SPOOLERRECORD   *pLastSpoolerRecord;
  463.  
  464.                                         /* If container contains no record return NULL */
  465. if(pSelectedSpoolerRecord==NULL) return((SPOOLERRECORD *)NULL);
  466.                                         /* Test if record the menu was selected above is selected */
  467. if(pSelectedSpoolerRecord->MiniRec.flRecordAttr & CRA_SELECTED)
  468.     {
  469.                                         /* Query the first selected container record */
  470.     pCurrentSpoolerRecord=(SPOOLERRECORD *)WinSendMsg(pHP->hwndSpoolerContainer, CM_QUERYRECORDEMPHASIS,
  471.         (PRECORDCORE)CMA_FIRST, MPFROMSHORT(CRA_SELECTED));
  472.                                         /* Because this if clause is only executed if one record
  473.                                            is selected, we can safely save and return the first one,
  474.                                            even if its just the only one */
  475.     pSpoolerRecord=pCurrentSpoolerRecord;
  476.     pLastSpoolerRecord=NULL;            /* We haven't found any record before, the current one can
  477.                                            be appended */
  478.     while(pCurrentSpoolerRecord)
  479.         {
  480.         if(pLastSpoolerRecord)
  481.             {                           /* Append current record to linked list and advance linked list */
  482.             pLastSpoolerRecord->MiniRec.preccNextRecord=(MINIRECORDCORE *)pCurrentSpoolerRecord;
  483.             }
  484.         pLastSpoolerRecord=pCurrentSpoolerRecord;
  485.                                         /* Search next selected record starting with the current one */
  486.         pCurrentSpoolerRecord=(SPOOLERRECORD *)WinSendMsg(pHP->hwndSpoolerContainer, CM_QUERYRECORDEMPHASIS,
  487.             (PRECORDCORE)pCurrentSpoolerRecord, MPFROMSHORT(CRA_SELECTED));
  488.         }
  489.                                         /* After the last selected record found end linked list */
  490.     pLastSpoolerRecord->MiniRec.preccNextRecord=NULL;
  491.     }
  492. else
  493.     {                                   /* Because record under activation of the context menu
  494.                                            by the mouse pointer is not selected, return this
  495.                                            record, being a linked list of just one element */
  496.     pSelectedSpoolerRecord->MiniRec.preccNextRecord=NULL;
  497.     pSpoolerRecord=pSelectedSpoolerRecord;
  498.     }
  499. return(pSpoolerRecord);                 /* Return 1st element of linked list */
  500. }
  501.  
  502. /*--------------------------------------------------------------------------------------*\
  503.  * This function updates the spooler container, and the structures related to the       *
  504.  * queues and jobs on this local machine, according to the current real time spooler    *
  505.  * contents.                                                                            *
  506.  * Req:                                                                                 *
  507.  * Returns:                                                                             *
  508.  *      NO_ERROR ...... If called sucessfully                                           *
  509.  *      ulErrorCode ... If called unsucessfully                                         *
  510. \*--------------------------------------------------------------------------------------*/
  511. ULONG           RefreshSpooler(void)
  512. {
  513. ULONG           ulQueueCountReturned;   /* Number of queues returned in SplEnumQueue() */
  514. ULONG           ulQueueCountNeeded;     /* Number of queues available */
  515. ULONG           ulQueueSize;            /* Size of information returned */
  516. PRQINFO3        *pQueueInfo;            /* Points to all information returned */
  517. PRQINFO3        *pCurrentQueue;         /* Points to current queue within all queues available */
  518. PRQINFO3        *pLastQueue;            /* Points to the queue current job is inserted */
  519. ULONG           ulCurrentQueue;
  520. PRJINFO2        *pCurrentJob;           /* Points to current job within one queue */
  521. ULONG           ulCurrentJob;
  522. ULONG           ulJobCount;             /* Number of jobs within current queue */
  523. RECORDINSERT    RecordInsert;           /* RECORDINSERT structure to control record insertion */
  524. SPOOLERRECORD   *pSpoolerRecord;        /* Pointer to new SPOOLERRECORD created, when a new entry
  525.                                            was found in the queue */
  526. SPOOLEROBJECT   *pCurrentSpoolerObject; /* Pointer to current SPOOLEROBJECT added to list, when a new
  527.                                            entry was found in the queue */
  528. SPOOLEROBJECT   *pAppendSpoolerObject;  /* Pointer to the last element in the SPOOLEROBJECT list,
  529.                                            where the current queue entry is appended */
  530.  
  531. /*                                                                                      *\
  532.  * Fill RECORDINSERT structure, which will be used for inserting records.               *
  533. \*                                                                                      */
  534.                                         /* Initialize RECORDINSERT structure */
  535. RecordInsert.cb=sizeof(RecordInsert);
  536.                                         /* Insert record at end of existing records */
  537. RecordInsert.pRecordOrder=(PRECORDCORE)CMA_END;
  538. RecordInsert.pRecordParent=NULL;        /* There is no parent */
  539. RecordInsert.fInvalidateRecord=TRUE;    /* Update during insertation */
  540. RecordInsert.zOrder=CMA_TOP;            /* Insert at top of Z-Order */
  541. RecordInsert.cRecordsInsert=1;          /* Insert 1 record */
  542. /*                                                                                      *\
  543.  * Get first record from container, free SPOOLERRECORD structure and the corresponding  *
  544.  * SPOOLEROBJECT structure, and then remove record from container until all records are *
  545.  * removed from the spooler container.                                                  *
  546. \*                                                                                      */
  547.                                         /* Prevent unnecessary container drawing */
  548. WinEnableWindowUpdate(pHP->hwndSpoolerContainer, FALSE);
  549.                                         /* Get first container record to delete them sequentially */
  550. pSpoolerRecord=(SPOOLERRECORD *)WinSendMsg(pHP->hwndSpoolerContainer, CM_QUERYRECORD,
  551.     NULL, MPFROM2SHORT(CMA_FIRST, CMA_ITEMORDER));
  552. while(pSpoolerRecord)
  553.     {                                   /* Delete and free records */
  554.     free(pSpoolerRecord->pszQueue);
  555.     free(pSpoolerRecord->pszQueueStatus);
  556.     free(pSpoolerRecord->pszQueueComment);
  557.     free(pSpoolerRecord->pszQueueDriver);
  558.     free(pSpoolerRecord->pszJob);
  559.     free(pSpoolerRecord->pszJobNumber);
  560.     free(pSpoolerRecord->pszJobStatus);
  561.     free(pSpoolerRecord->pszJobComment);
  562.     free(pSpoolerRecord->pSpoolerObject);
  563.                                         /* Delete record in container. Warning! as this function
  564.                                            expects an array, but we only delete one record, we
  565.                                            have to get the address of the pointer to the record. */
  566.     WinSendMsg(pHP->hwndSpoolerContainer, CM_REMOVERECORD,
  567.         MPFROMP(&pSpoolerRecord), MPFROM2SHORT(1, CMA_FREE|CMA_INVALIDATE));
  568.                                         /* Get next container record to delete them sequentially */
  569.     pSpoolerRecord=(SPOOLERRECORD *)WinSendMsg(pHP->hwndSpoolerContainer, CM_QUERYRECORD,
  570.         NULL, MPFROM2SHORT(CMA_FIRST, CMA_ITEMORDER));
  571.     }
  572.                                         /* We have deleted all container object */
  573. pHP->pSpoolerObjectRoot=pAppendSpoolerObject=NULL;
  574. /*                                                                                      *\
  575.  * Now enumerate the printer queue of the local machine, and create container records   *
  576.  * for each queue and its jobs, even if the queue currently doesn't have any print job  *
  577.  * (the queue is inserted in this case to allow queue manipulation).                    *
  578. \*                                                                                      */
  579. SplEnumQueue(                           /* Get printer queue count of local machine */
  580.     NULL,                               /* Local machine */
  581.     4,                                  /* Detail level */
  582.     NULL,                               /* Output buffer */
  583.     0,                                  /* Output buffer size */
  584.     &ulQueueCountReturned,              /* Number of entries returned */
  585.     &ulQueueCountNeeded,                /* Number of entries available */
  586.     &ulQueueSize,                       /* Size of available information */
  587.     NULL);                              /* Reserved */
  588.                                         /* If no queue available return error */
  589. if(ulQueueCountNeeded==0) return(ERROR_INVALID_DATA);
  590.                                         /* Get all local printer queues */
  591. pQueueInfo=malloc(ulQueueSize);
  592. SplEnumQueue(NULL, 4, pQueueInfo, ulQueueSize,
  593.     &ulQueueCountReturned, &ulQueueCountNeeded, &ulQueueSize, NULL);
  594. pCurrentQueue=pQueueInfo;               /* Begin with first queue. For each queue a PRQINFO3
  595.                                            structure is available immediately followed by a
  596.                                            PRJINFO2 structure for each job in the queue. */
  597. for(ulCurrentQueue=0; ulCurrentQueue<ulQueueCountReturned; ulCurrentQueue++)
  598.     {
  599.     UCHAR   ucCurrentJob[256];
  600.     UCHAR   ucCurrentQueueStatus[256];
  601.     UCHAR   ucBuffer[256];
  602.  
  603.                                         /* Print queue status bitmask */
  604.     switch(pCurrentQueue->fsStatus & PRQ_STATUS_MASK)
  605.     {
  606.     case PRQ_ACTIVE:
  607.         strcpy(ucCurrentQueueStatus, "Active");
  608.         break;
  609.  
  610.     case PRQ_PAUSED:
  611.         strcpy(ucCurrentQueueStatus, "Paused");
  612.         break;
  613.  
  614.     case PRQ_ERROR:
  615.         strcpy(ucCurrentQueueStatus, "Error");
  616.         break;
  617.  
  618.     case PRQ_PENDING:
  619.         strcpy(ucCurrentQueueStatus, "Pending");
  620.         break;
  621.     }
  622.     ulJobCount=pCurrentQueue->cJobs;    /* Get number of jobs in current queue */
  623.     pLastQueue=pCurrentQueue;           /* Save the queue for the case it contains at least 1 job */
  624.     pCurrentQueue++;                    /* Point to next PRQINFO3 structure if current queue
  625.                                            has no jobs, or to a PRJINFO2 structure for a job */
  626.                                         /* Get all jobs within current queue */
  627.     for(ulCurrentJob=0, pCurrentJob=(PRJINFO2 *)pCurrentQueue; ulCurrentJob<ulJobCount;
  628.         ulCurrentJob++, pCurrentJob++)
  629.         {
  630.         ucCurrentJob[0]='\0';           /* Clear to get sure, but it would be a surprise if this
  631.                                            empty string doesn't get overwritten */
  632.         switch(pCurrentJob->fsStatus & PRJ_QSTATUS)
  633.         {
  634.         case PRJ_QS_QUEUED:
  635.             strcpy(ucCurrentJob, "Queued");
  636.             break;
  637.  
  638.         case PRJ_QS_PAUSED:
  639.             strcpy(ucCurrentJob, "Paused");
  640.             break;
  641.  
  642.         case PRJ_QS_SPOOLING:
  643.             strcpy(ucCurrentJob, "Spooling");
  644.             break;
  645.  
  646.         case PRJ_QS_PRINTING:
  647.             strcpy(ucCurrentJob, "Printing");
  648.             break;
  649.  
  650.         default:
  651.             strcpy(ucCurrentJob, "Unknown");
  652.             break;
  653.         }
  654.         if(!(pCurrentJob->fsStatus & PRJ_DEVSTATUS))
  655.             {
  656.             strcat(ucCurrentJob, ", Normal");
  657.             }
  658.         else
  659.             {
  660.             if(pCurrentJob->fsStatus & PRJ_COMPLETE)
  661.                 {
  662.                 strcat(ucCurrentJob, ", Complete");
  663.                 }
  664.             if(pCurrentJob->fsStatus & PRJ_INTERV)
  665.                 {
  666.                 strcat(ucCurrentJob, ", Intervention required");
  667.                 }
  668.             if(pCurrentJob->fsStatus & PRJ_DESTOFFLINE)
  669.                 {
  670.                 strcat(ucCurrentJob, ", Destination offline");
  671.                 }
  672.             if(pCurrentJob->fsStatus & PRJ_DESTPAUSED)
  673.                 {
  674.                 strcat(ucCurrentJob, ", Destination paused");
  675.                 }
  676.             if(pCurrentJob->fsStatus & PRJ_NOTIFY)
  677.                 {
  678.                 strcat(ucCurrentJob, ", Alert raised");
  679.                 }
  680.             if(pCurrentJob->fsStatus & PRJ_DESTNOPAPER)
  681.                 {
  682.                 strcat(ucCurrentJob, ", Out of paper");
  683.                 }
  684.             if(pCurrentJob->fsStatus & PRJ_DESTFORMCHG)
  685.                 {
  686.                 strcat(ucCurrentJob, ", Form change");
  687.                 }
  688.             if(pCurrentJob->fsStatus & PRJ_DESTCRTCHG)
  689.                 {
  690.                 strcat(ucCurrentJob, ", Cartridge change");
  691.                 }
  692.             if(pCurrentJob->fsStatus & PRJ_DESTPENCHG)
  693.                 {
  694.                 strcat(ucCurrentJob, ", Pen change");
  695.                 }
  696.             }
  697. /*                                                                                      *\
  698.  * Because we have found at least one job for the current queue, add one record to the  *
  699.  * container for each job.                                                              *
  700. \*                                                                                      */
  701.                                         /* Because we found a job, get queue data of current queue */
  702.                                         /* Allocate, setup and chain in a SPOOLEROBJECT structure */
  703.         pCurrentSpoolerObject=malloc(sizeof(SPOOLEROBJECT));
  704.         pCurrentSpoolerObject->pSpoolerObjectNext=NULL;
  705.         pCurrentSpoolerObject->pSpoolerObjectBack=pAppendSpoolerObject;
  706.         pCurrentSpoolerObject->bInQueue=TRUE;
  707.         if(pAppendSpoolerObject!=NULL)
  708.                                         /* Advance pointer to current record */
  709.             pAppendSpoolerObject->pSpoolerObjectNext=pCurrentSpoolerObject;
  710.         else
  711.             pAppendSpoolerObject=pCurrentSpoolerObject;
  712.                                         /* Save pointer to first record */
  713.         if(pHP->pSpoolerObjectRoot!=NULL) pHP->pSpoolerObjectRoot=pCurrentSpoolerObject;
  714.                                         /* Allocate one record to insert into container */
  715.         pSpoolerRecord=(SPOOLERRECORD *)WinSendMsg(pHP->hwndSpoolerContainer, CM_ALLOCRECORD,
  716.             MPFROMLONG(sizeof(SPOOLERRECORD)-sizeof(MINIRECORDCORE)), MPFROMLONG(1));
  717.                                         /* Chain SPOOLERRECORD and corresponding SPOOLEROBJECT together */
  718.         pSpoolerRecord->pSpoolerObject=pCurrentSpoolerObject;
  719.         pCurrentSpoolerObject->pSpoolerRecord=pSpoolerRecord;
  720.                                         /* Fill record */
  721.         pSpoolerRecord->pszQueue=strdup(pLastQueue->pszName);
  722.         pSpoolerRecord->pszQueueStatus=strdup(ucCurrentQueueStatus);
  723.         pSpoolerRecord->pszQueueComment=strdup(pLastQueue->pszComment);
  724.         pSpoolerRecord->pszQueueDriver=strdup(pLastQueue->pszDriverName);
  725.         pSpoolerRecord->pszJob=strdup(pCurrentJob->pszDocument);
  726.         sprintf(ucBuffer, "%4d", pCurrentJob->uJobId);
  727.         pSpoolerRecord->pszJobNumber=strdup(ucBuffer);
  728.         pSpoolerRecord->pszJobStatus=strdup(ucCurrentJob);
  729.         pSpoolerRecord->pszJobComment=strdup(pCurrentJob->pszComment);
  730.         pSpoolerRecord->ulJob=pCurrentJob->uJobId;
  731.                                         /* Insert record into container */
  732.         WinSendMsg(pHP->hwndSpoolerContainer, CM_INSERTRECORD,
  733.             MPFROMP(pSpoolerRecord), MPFROMP(&RecordInsert));
  734.         }
  735.     if(ulJobCount==0)
  736.         {
  737. /*                                                                                      *\
  738.  * Because the current queue doesn't have at least on job, create a container record    *
  739.  * anyway, even when there is no job data.                                              *
  740. \*                                                                                      */
  741.                                         /* Allocate, setup and chain in a SPOOLEROBJECT structure */
  742.         pCurrentSpoolerObject=malloc(sizeof(SPOOLEROBJECT));
  743.         pCurrentSpoolerObject->pSpoolerObjectNext=NULL;
  744.         pCurrentSpoolerObject->pSpoolerObjectBack=pAppendSpoolerObject;
  745.         pCurrentSpoolerObject->bInQueue=TRUE;
  746.         if(pAppendSpoolerObject!=NULL)
  747.                                         /* Advance pointer to current record */
  748.             pAppendSpoolerObject->pSpoolerObjectNext=pCurrentSpoolerObject;
  749.         else
  750.             pAppendSpoolerObject=pCurrentSpoolerObject;
  751.                                         /* Save pointer to first record */
  752.         if(pHP->pSpoolerObjectRoot!=NULL) pHP->pSpoolerObjectRoot=pCurrentSpoolerObject;
  753.                                         /* Allocate one record in container */
  754.         pSpoolerRecord=(SPOOLERRECORD *)WinSendMsg(pHP->hwndSpoolerContainer, CM_ALLOCRECORD,
  755.             MPFROMLONG(sizeof(SPOOLERRECORD)-sizeof(MINIRECORDCORE)), MPFROMLONG(1));
  756.                                         /* Chain SPOOLERRECORD and corresponding SPOOLEROBJECT together */
  757.         pSpoolerRecord->pSpoolerObject=pCurrentSpoolerObject;
  758.         pCurrentSpoolerObject->pSpoolerRecord=pSpoolerRecord;
  759.                                         /* Fill record */
  760.         pSpoolerRecord->pszQueue=strdup(pLastQueue->pszName);
  761.         pSpoolerRecord->pszQueueStatus=strdup(ucCurrentQueueStatus);
  762.         pSpoolerRecord->pszQueueComment=strdup(pLastQueue->pszComment);
  763.         pSpoolerRecord->pszQueueDriver=strdup(pLastQueue->pszDriverName);
  764.         pSpoolerRecord->pszJob=strdup("");
  765.         pSpoolerRecord->pszJobNumber=strdup("");
  766.         pSpoolerRecord->pszJobStatus=strdup("");
  767.         pSpoolerRecord->pszJobComment=strdup("");
  768.         pSpoolerRecord->ulJob=0;
  769.                                         /* Insert record into container */
  770.         WinSendMsg(pHP->hwndSpoolerContainer, CM_INSERTRECORD,
  771.             MPFROMP(pSpoolerRecord), MPFROMP(&RecordInsert));
  772.         }
  773.                                         /* Last job of current queue reached, so current job
  774.                                            points to next queue */
  775.     pCurrentQueue=(PRQINFO3 *)pCurrentJob;
  776.     }
  777. free(pQueueInfo);
  778.                                         /* Now draw changes in container window */
  779. WinEnableWindowUpdate(pHP->hwndSpoolerContainer, TRUE);
  780. return(NO_ERROR);
  781. }
  782.  
  783. /*--------------------------------------------------------------------------------------*\
  784.  * This subclassed window procedure handles the PC/2's Spooler container window.        *
  785.  * Req: none                                                                            *
  786. \*--------------------------------------------------------------------------------------*/
  787. MRESULT  EXPENTRY SubclassedContainerWindowProc(HWND hwndMenu, ULONG msg, MPARAM mp1, MPARAM mp2)
  788. {
  789. switch(msg)
  790. {
  791. case WM_PRESPARAMCHANGED:
  792.     switch((ULONG)mp1)
  793.     {
  794.     case PP_FONTNAMESIZE:
  795.         {
  796.         ULONG       ulAttrFound;
  797.  
  798.                                         /* Get font selected for PC/2's smart icon menu */
  799.         WinQueryPresParam(hwndMenu, PP_FONTNAMESIZE, 0, &ulAttrFound,
  800.             sizeof(pHP->ucPC2SpoolerFont), pHP->ucPC2SpoolerFont, 0);
  801.         }
  802.         break;
  803.     }
  804. }
  805.                                         /* Call default window procedure */
  806. return(pfnContainerWindowProc(hwndMenu, msg, mp1, mp2));
  807. }
  808.  
  809.