home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft-Programers-Library-v1.3.iso / sampcode / c / msc51 / example / snap.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-08-11  |  12.8 KB  |  458 lines

  1. /* Snap    - An OS/2 screen capture utility
  2.  *
  3.  * Snap    starts a background process containing a keyboard monitor. The
  4.  * monitor checks for a    hot key    (ALT-PRTSCR). If found,    a thread is
  5.  * launched to write the screen    to a file. Various command line    options
  6.  * allow you to    specify    capture    behavior or to deinstall the program.
  7.  *
  8.  * To make a statically    linked version,    use these command lines:
  9.  *
  10.  *  cl /c /AL /G2s /Zp /X /I\include\mt    snap.c
  11.  *  link /NOD /NOI snap,,,llibcmt doscalls;
  12.  *
  13.  * To creat a dynamically linked version, create the dynamic linked
  14.  * library CRTLIB.DLL (as explained in MTDYNA.DOC file)    and place it in
  15.  * your    LIBPATH    directory. Create the imports library CRTLIB.LIB in your
  16.  * LIB directory. Make sure you    have the objec file CRTEXE.OBJ in your
  17.  * LIB directory. Then use these command lines:
  18.  *
  19.  *  cl /c /AL /G2s /Zp /X /I\include\mt    snap.c
  20.  *  link /NOD /NOI snap    \lib\crtexe,,,crtlib doscalls;
  21.  */
  22.  
  23. /* Function prototypes */
  24. int main (int argc, char * *argv);
  25. int Monitor (void);
  26. void Snap (unsigned long far *arg);
  27. void BackError (char *msgErr);
  28. void Syntax (void);
  29. void OptionEval    (int argc, char    * *argv);
  30.  
  31. /* Define constants to enable function groups in OS2 include files */
  32. #define    INCL_NOCOMMON
  33. #define    INCL_SUB
  34. #define    INCL_DOSMEMMGR
  35. #define    INCL_DOSMONITORS
  36. #define    INCL_DOSMISC
  37. #define    INCL_DOSSEMAPHORES
  38. #define    INCL_DOSPROCESS
  39. #define    INCL_DOSINFOSEG
  40. #include <os2.h>
  41.  
  42. #include <malloc.h>
  43. #include <process.h>
  44. #include <string.h>
  45. #include <stdlib.h>
  46. #include <stdio.h>
  47.  
  48. #define    FALSE    0
  49. #define    TRUE    1
  50.  
  51. #define    CON    0        /* Handle for the console device    */
  52. #define    FAIL    -1        /* Fail    to start thread            */
  53.  
  54. #define    NOCARE    0        /* DosMonReg constants specifying   */
  55. #define    FRONT    1        /* where to install in the monitor  */
  56. #define    BACK    2        /* chain */
  57.  
  58. #define    PRTSCR    0x37        /* Scan    code for PtrScr            */
  59. #define    ALT    0x8        /* Shift mask for either ALT        */
  60.  
  61. #define    RELEASE    0x40        /* Bit mask for    key release        */
  62.  
  63. #define    BUFSIZE    128        /* Size    for monitor buffers:
  64.                  * 64 minimum, 128 recommended        */
  65.  
  66. #define    STACKSIZE 2048        /* 2K minimum for any system call   */
  67.  
  68. #define    MAXSPEC     (2 + 66 + 12)    /* Drive - 2, directory    - 66, file name    - 12 */
  69.  
  70. static    char namShrSeg[] = { "\\SHAREMEM\\SNAP.DAT" };
  71.  
  72. struct SNAPDATA    {
  73.     int    sound;
  74.     int    append;
  75.     int    count;
  76.     unsigned long wait;
  77.     int    install;
  78.     char name[MAXSPEC];
  79. } far *pdatShrSnap = 0;        /* Initialize offset of    pointer    to 0. Segment
  80.                  * will    be initialized by system call.         */
  81.  
  82. #define    SHRSEGSIZE  sizeof(struct SNAPDATA)
  83.  
  84. main (int argc,    char * *argv)
  85. {
  86.     char namFail[MAXSPEC];    /* Dummies for DosExecPgm  */
  87.     RESULTCODES    resChild;
  88.  
  89.     char *namSnapExe = 0;    /* Name    of executable file */
  90.     unsigned offCmd;        /* Dummy used by DosGetEnv */
  91.  
  92.     /* Try to get shared segment (note how selector value is placed
  93.      * directly    in the segment word of the pointer address).
  94.      */
  95.     if (DosGetShrSeg (namShrSeg, (PSEL)&pdatShrSnap + 1)) {
  96.  
  97.     /* Segment doesn't exist, so try to allocate it. */
  98.     if (DosAllocShrSeg (SHRSEGSIZE,    namShrSeg, (PSEL)&pdatShrSnap +    1)) {
  99.  
  100.         puts ("Can't allocate shared memory");
  101.         exit (1);
  102.  
  103.     } else {
  104.  
  105.         /* This is the first time through, so we must execute
  106.          * ourself to do installation.
  107.          *
  108.          * First set defaults, then    modify for options.
  109.          */
  110.         pdatShrSnap->sound = TRUE;
  111.         pdatShrSnap->append    = TRUE;
  112.         pdatShrSnap->count = 0;
  113.         pdatShrSnap->install = FALSE;
  114.         strcpy (pdatShrSnap->name, "SNAP.IMG");
  115.         DosSemSet (&pdatShrSnap->wait);
  116.         OptionEval (argc, argv);
  117.  
  118.         /* Get our own path    name from the end of the environment
  119.          * segment.    This is    the most reliable way to get the full
  120.          * path name of the    current    file, since the    extension is
  121.          * ommitted    from argv[0].
  122.          */
  123.         DosGetEnv((PUSHORT)&namSnapExe + 1,    &offCmd);
  124.         while (*namSnapExe++ || *namSnapExe)    /* Adjust forward until  */
  125.         ;                    /* we point    to full    path */
  126.         ++namSnapExe;                /* name of .EXE file.    */
  127.  
  128.         if (DosExecPgm (namFail,
  129.                 MAXSPEC,
  130.                 EXEC_BACKGROUND,
  131.                 NULL,
  132.                 0,
  133.                 &resChild,
  134.                 namSnapExe)) {
  135.  
  136.         puts ("Can't start background process");
  137.         exit (1);
  138.         }
  139.  
  140.         puts ("Snap installed");
  141.         Syntax ();
  142.  
  143.         /* Wait for    child to report    receiving shared data */
  144.         DosSemWait (&pdatShrSnap->wait, -1L);
  145.     }
  146.  
  147.     } else {
  148.  
  149.     /* Shared segment already existed.
  150.      *
  151.      * If installed, just evaluate options.
  152.      */
  153.     if (pdatShrSnap->install)
  154.  
  155.         if (argc ==    1)
  156.         puts ("Snap already installed");
  157.         else
  158.         OptionEval (argc, argv);
  159.  
  160.     else {
  161.  
  162.         /* Not installed, so install now.
  163.          *
  164.          * Tell parent we have received data
  165.          */
  166.         DosSemClear    (&pdatShrSnap->wait);
  167.  
  168.         /* Flag as installed and start monitor */
  169.         pdatShrSnap->install = TRUE;
  170.         return (Monitor());
  171.  
  172.     }
  173.     }
  174. }
  175.  
  176. /* Monitor routine checks keystrokes as    they occur and calls
  177.  * the Snap thread if the hot key is pressed.
  178.  *
  179.  * Input: none
  180.  * Return: 1 if    error, 0 if deinstalled
  181.  * Uses: Shared    memory structure - pdatShrSnap
  182.  */
  183.  
  184. int Monitor ()
  185. {
  186.     /* The first 16 bytes of a monitor buffer are devoted to the
  187.      * header, as shown    in the MONBUFF structure below.    Prior to
  188.      * registering, the    first word (lBuff) must    be set to the size
  189.      * of the buffer.
  190.      */
  191.     struct MONBUFF {            /* Generic monitor buffer header       */
  192.     unsigned    lBuff;
  193.     unsigned    lBuffDD;
  194.     unsigned char dispatch[12];
  195.     } *inBuff, *outBuff;
  196.  
  197.     struct KEYPACKET {            /* KBD monitor data    record           */
  198.     unsigned    flgMn;
  199.     KBDKEYINFO  k;
  200.     unsigned    flgDD;
  201.     } keyBuff;
  202.  
  203.     HMONITOR    hKeybrd;        /* Keyboard    handle from monitor open   */
  204.     unsigned    cntMonChar;        /* Chars in    monitor    read/write buffer  */
  205.  
  206.     PGINFOSEG pGIS = 0,    pLIS = 0;   /* Information segment structures       */
  207.  
  208.     char stkSnap[STACKSIZE];        /* Stack and semaphore for Snap thread */
  209.     ULONG flgSnap = FALSE;
  210.  
  211.     int    ret;
  212.  
  213.     /* Allocate    space for monitor read/write buffers. */
  214.     inBuff = (struct MONBUFF *)malloc(BUFSIZE);
  215.     outBuff = (struct MONBUFF *)malloc(BUFSIZE);
  216.  
  217.     /* Prepare buffer headers for registration.    */
  218.     inBuff->lBuff = BUFSIZE;
  219.     outBuff->lBuff = BUFSIZE;
  220.  
  221.     /* Register    monitor    to the keyboard    device (KBD$). */
  222.     if (DosMonOpen ("KBD$", &hKeybrd)) {
  223.     BackError ("Can't open monitor");
  224.     return (1);
  225.     }
  226.  
  227.     /* Get information segments    (all we    really need is ID of current
  228.      * screen group from Global    Information Segment).
  229.      */
  230.     DosGetInfoSeg((PSEL)&pGIS +1, (PSEL)&pLIS +    1);
  231.  
  232.     /* Register    the monitor buffers to the current screen group    */
  233.     if (DosMonReg (hKeybrd,
  234.            (PBYTE)inBuff,
  235.            (PBYTE)outBuff,
  236.            NOCARE,
  237.            pGIS->sgCurrent)) {
  238.     BackError ("Can't register monitor");
  239.     return (1);
  240.     }
  241.  
  242.     /* Make process time critical so keys are interpreted without delay. */
  243.     DosSetPrty (PRTYS_PROCESS, PRTYC_TIMECRITICAL, 0, 0);
  244.  
  245.     /* Monitor loop - read into    monitor    buffer and examine. Take action
  246.      * if hot key, otherwise pass on to    device driver.
  247.      */
  248.     while (pdatShrSnap->install) {
  249.     cntMonChar = sizeof(keyBuff);
  250.     DosMonRead ((PBYTE)inBuff, IO_WAIT, (PBYTE)&keyBuff, &cntMonChar);
  251.     if ((keyBuff.k.chScan == PRTSCR) &&
  252.         (keyBuff.k.fsState & ALT) &&
  253.         (!(keyBuff.flgDD & RELEASE))) {
  254.  
  255.         /* Make sure last thread is    finished */
  256.         DosSemWait (&flgSnap, -1L);
  257.         ret    = _beginthread (Snap,
  258.                 (void far *)stkSnap,
  259.                 STACKSIZE,
  260.                 (void far *)&flgSnap);
  261.         if (ret == FAIL)
  262.         BackError ("Can't start screen capture thread");
  263.         else
  264.         DosSemSet (&flgSnap);
  265.     } else
  266.  
  267.         /* Pass the    key through if it is not the hot key */
  268.         DosMonWrite    ((PBYTE)outBuff, (PBYTE)&keyBuff, cntMonChar);
  269.     }
  270.  
  271.     /* Close monitor */
  272.     DosMonClose    (hKeybrd);
  273.     return (0);
  274. }
  275.  
  276. /* Screen capture routine (run as a thread). Does a pop-up to get access
  277.  * to the current screen. Reads    characters from    the screen into    a buffer.
  278.  * Then    filters    trailing spaces    as it writes buffer to a file.
  279.  *
  280.  * Input: pointer to flag indicated snap status    - pflgSnap
  281.  * Return: none
  282.  * Uses: Shared    memory structure - pdatShrSnap
  283.  */
  284.  
  285. void Snap (unsigned long far *pflgSnap)
  286. {
  287.     VIOMODEINFO    modScreen;    /* Variables for VioGetMode and    VioPopUp */
  288.     unsigned flgPopUp =    VP_WAIT    | VP_TRANSPARENT;
  289.  
  290.     char    *bufScreen;        /* Buffer for captured screen         */
  291.     unsigned lbufScreen;
  292.  
  293.     FILE    *sFile;        /* File    stream                 */
  294.  
  295.     int        line, pos, width;
  296.     char    num[5];
  297.  
  298.     if (pdatShrSnap->sound)
  299.     DosBeep    (698, 500);
  300.  
  301.     /* Pop up to current screen    */
  302.     VioPopUp (&flgPopUp, CON);
  303.  
  304.     /* Check screen */
  305.     modScreen.cb = sizeof(modScreen);
  306.     VioGetMode (&modScreen, CON);
  307.  
  308.     /* Allocate    memory for a full screen plus one byte */
  309.     lbufScreen = (modScreen.col    * modScreen.row);
  310.     bufScreen =    malloc (lbufScreen + 1);
  311.  
  312.     /* Read screen and end popup */
  313.     VioReadCharStr (bufScreen, &lbufScreen, 0, 0, CON);
  314.     VioEndPopUp    (0);
  315.  
  316.     /* Increment screen    count (four digits or less) and    convert    to string */
  317.     pdatShrSnap->count = (pdatShrSnap->count + 1) % 9999;
  318.     itoa (pdatShrSnap->count, num, 10);
  319.  
  320.     if (!pdatShrSnap->append)
  321.     /* Make    numbered file name */
  322.     strcat (strcat (strcpy (pdatShrSnap->name, "SNAP"), num), ".IMG");
  323.  
  324.     /* Open file and write buffer to it    a line at a time */
  325.     if ((sFile = fopen (pdatShrSnap->name, "at")) == NULL ) {
  326.  
  327.     BackError ("Can't open file");
  328.     --pdatShrSnap->count;
  329.  
  330.     } else {
  331.  
  332.     if (pdatShrSnap->append) {
  333.         /* Not using fprintf saves a few K */
  334.         fputs ("**** Screen ", sFile);
  335.         fputs (num,    sFile);
  336.         fputs (" ****\n", sFile);
  337.     }
  338.  
  339.     for (line = 0, pos = 0;    line < modScreen.row; line++) {
  340.  
  341.         /* Throw away trailing spaces */
  342.         for    (width = modScreen.col;
  343.          (bufScreen[pos    + width    - 1] == ' ') &&    width;
  344.          width--)
  345.          ;
  346.         /* Write line and newline */
  347.         fwrite (bufScreen +    pos, 1,    width, sFile);
  348.         fputc ('\n', sFile);
  349.         pos    += modScreen.col;
  350.     }
  351.  
  352.     fclose (sFile);
  353.     }
  354.     if (pdatShrSnap->sound)
  355.     DosBeep    (523, 500);
  356.  
  357.     /* Free memory and let parent know we are done */
  358.     free (bufScreen);
  359.     DosSemClear    (pflgSnap);
  360. }
  361.  
  362. /* Displays an error message from within a background process or thread.
  363.  * The monitor is in the background and    has no screen group, so    it must
  364.  * use VioPopUp    to get access to the screen.
  365.  *
  366.  * Input: error    message    string - msgErr
  367.  * Return: none
  368.  */
  369. void BackError (char *msgErr)
  370. {
  371.     unsigned flgPopUp =    VP_WAIT    | VP_TRANSPARENT;
  372.  
  373.     VioPopUp (&flgPopUp, CON);
  374.     puts (msgErr);
  375.     puts ("Press any key to continue . . .");
  376.     while (!kbhit ())
  377.     ;
  378.     VioEndPopUp    (CON);
  379. }
  380.  
  381. /* Displays syntax.
  382.  *
  383.  * Input: none
  384.  * Return: none
  385.  */
  386. void Syntax ()
  387. {
  388.     puts ("\nOptions: ");
  389.     puts ("\t/H\t  Display help.");
  390.     puts ("\t/S\t  Turn sound on (default).");
  391.     puts ("\t/Q\t  Turn sound off.");
  392.     puts ("\t/D\t  Deinstall.");
  393.     puts ("\t/A [path] Append each screen to a file (complete path allowed).");
  394.     puts ("\t\t  If no file given, default is SNAP.IMG in current directory");
  395.     puts ("\t\t  Resets screen number to 1.");
  396.     puts ("\t/N [num]  Create numbered file for each screen.");
  397.     puts ("\t\t  Example: SNAP1.IMG, SNAP2.IMG in current directory.");
  398.     puts ("\t\t  Resets screen number to 1 or to num if given.");
  399. }
  400.  
  401. /* Evaluated command-line options.
  402.  *
  403.  * Input: Number of arguments -    argv
  404.  *      Pointer to argument list - argv
  405.  * Return: none
  406.  * Uses: Shared    memory structure - pdatShrSnap
  407.  */
  408. void OptionEval    (int argc, char    * *argv)
  409. {
  410.     int    i;
  411.  
  412.     /* Look for    and handle arguments */
  413.     for    (i = 1;    i < argc; i++) {
  414.     if (argv[i][0] == '/' || argv[i][0] == '-') {
  415.         switch (toupper (argv[i][1])) {
  416.         case 'A' :
  417.             pdatShrSnap->append    = TRUE;
  418.             pdatShrSnap->count = 0;
  419.             if ((argv[++i]) && (argv[i][0] != '/') &&
  420.                        (argv[i][0] != '-')) {
  421.             strcpy (pdatShrSnap->name, argv[i]);
  422.             puts ("Append mode - name set");
  423.             } else
  424.             puts ("Append mode");
  425.             break;
  426.         case 'N' :
  427.             pdatShrSnap->append    = FALSE;
  428.             puts ("Numbered file mode");
  429.             if ((argv[++i]) && (argv[i][0] != '/') &&
  430.                        (argv[i][0] != '-'))
  431.             pdatShrSnap->count = ((atoi (argv[i])) % 9999) - 1;
  432.             else
  433.             pdatShrSnap->count = 0;
  434.             break;
  435.         case 'Q' :
  436.             pdatShrSnap->sound = FALSE;
  437.             puts ("Sound off");
  438.             break;
  439.         case 'S' :
  440.             pdatShrSnap->sound = TRUE;
  441.             puts ("Sound on");
  442.             break;
  443.         case 'D' :
  444.             if (pdatShrSnap->install) {
  445.             pdatShrSnap->install = FALSE;
  446.             puts ("Deinstalling");
  447.             } else
  448.             exit (0);
  449.             break;
  450.         case 'H' :
  451.             if (pdatShrSnap->install)
  452.             Syntax ();
  453.             break;
  454.         }
  455.     }
  456.     }
  457. }
  458.