home *** CD-ROM | disk | FTP | other *** search
/ ftp.wwiv.com / ftp.wwiv.com.zip / ftp.wwiv.com / pub / MISC / LSW270SR.ZIP / hook / lswhook.c next >
Text File  |  2004-04-11  |  16KB  |  443 lines

  1. /*
  2.  *      Copyright (C) 1997-2004 Andrei Los.
  3.  *      This file is part of the lSwitcher source package.
  4.  *      lSwitcher is free software; you can redistribute it and/or modify
  5.  *      it under the terms of the GNU General Public License as published
  6.  *      by the Free Software Foundation, in version 2 as it comes in the
  7.  *      "COPYING" file of the lSwitcher main distribution.
  8.  *      This program is distributed in the hope that it will be useful,
  9.  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11.  *      GNU General Public License for more details.
  12.  */
  13.  
  14.  
  15. #define INCL_DOSMEMMGR
  16. #define INCL_DOSMODULEMGR
  17. #define INCL_WIN
  18.  
  19. #include "lswitch.h"
  20. #include "taskbar.h"
  21. #include <string.h>
  22. #include <stdio.h>
  23.  
  24. /*
  25.    Since the hooks may be called in the context of any thead having a message
  26.    queue, we must use shared memory to access the globals of lSwitcher daemon.
  27.    For the same reason the shared mem must be freed upon exiting the hook procs,
  28.    otherwise the caller will retain a reference to it and the shared mem object
  29.    will not be destroyed when lSwitcher exits
  30.    IMPORTANT !!! Don't use DosGetNamedSharedMed/DosFreeMem before it's REALLY
  31.    needed, check all other conditions first. These functions turn out to be
  32.    expensive performance wise
  33.  
  34.    With version 2.6 this DLL, if compiled with Watcom C, does not use C RTL
  35.    (since Watcom RTL does not support multiple processes attached to a DLL
  36.    with a single data segment, which we need). Because of this stack overflow
  37.    is not checked for, and we want to reduce stack usage to a minimum
  38. */
  39.  
  40. HWND hwndMenuUp=NULLHANDLE;
  41.  
  42. //simple and dirty string to integer conversion
  43. ULONG __atol(UCHAR *s)
  44. { SHORT k;
  45.   ULONG r,base;
  46.  
  47.   for (k=0;s[k]!='\0';k++);
  48.   for (--k,base=1,r=0;k>=0;k--,base*=10)
  49.     r+=(s[k]-48)*base;
  50.  
  51.   return r;
  52. }
  53. /*
  54. void int2str(unsigned long value, int hex,char *string)
  55. { unsigned long count, i,k, sign;
  56.   static char *ptr, temp[12];
  57.  
  58.   count = 0;
  59.   if ((sign = value) < 0) {
  60.     value = -value;
  61.     count++;
  62.   }
  63.  
  64.   for (i=0;i<12;i++) { temp[i]=0; string[i]=0; }
  65.  
  66.   ptr = string;
  67.   i=0;
  68.   do {
  69.     temp[i++] = value % (hex?16:10)+'0';
  70.     temp[i-1]+= (temp[i-1]>'9'?7:0);
  71.     count++;
  72.   }  while (( value /= (hex?16:10)) >0);
  73.  
  74.   if (sign < 0)
  75.     temp[i++] = '-';
  76.  
  77.   temp[i--] = '\0';
  78.  
  79.   for (k = 0; k < count; k++, i--, ptr++)
  80.  
  81.   *ptr=temp[i];
  82. }
  83. */
  84. BOOL IsWindowClass(HWND hwnd,UCHAR *pszClassName)
  85. { static UCHAR ucBuf[32]; //reduce stack usage to minimum since we don't use stack probes
  86.   USHORT k;
  87.   BOOL bEqual;
  88.  
  89.   WinQueryClassName(hwnd,sizeof(ucBuf)-1,ucBuf);
  90. /* equivalent of strcmp, but we don't want to use the RTL */
  91.   for (k=0, bEqual=TRUE; ucBuf[k]!='\0' && pszClassName[k]!='\0'; k++)
  92.     if (ucBuf[k]!=pszClassName[k]) {
  93.        bEqual = FALSE;
  94.        break;
  95.     }
  96.  
  97.   return (bEqual && ucBuf[k]=='\0' && pszClassName[k]=='\0');
  98. }
  99.  
  100. BOOL IsDesktop(HWND hwnd)
  101. {
  102.   return (hwnd==WinQueryWindow(HWND_DESKTOP,QW_BOTTOM) &&
  103.           (IsWindowClass(hwnd,"wpFolder window")));
  104. }
  105.  
  106. BOOL GetSharedMem(LSWDATA **plswData)
  107. {
  108.   return
  109.    (DosGetNamedSharedMem((PVOID*)plswData,SHAREMEM_NAME,PAG_READ | PAG_WRITE)==0 &&
  110.     plswData!=NULL);
  111. }
  112.  
  113. BOOL SetPrty(ULONG pid,USHORT usPrty,USHORT usMagic)
  114. { SHORT sPrtyC, sPrtyD;
  115.   BOOL bDesc;
  116.  
  117.   if (usMagic==PRTY_MAGIC) {
  118.     bDesc = (usPrty & 0x8000); usPrty &= ~0x8000;
  119.     sPrtyC = (usPrty+PRTYD_MAXIMUM)>>8;
  120.     sPrtyD = usPrty-(sPrtyC<<8);
  121.     DosSetPriority(bDesc?PRTYS_PROCESSTREE:PRTYS_PROCESS,sPrtyC,sPrtyD,pid);
  122.     return TRUE;
  123.   } else
  124.     return FALSE;
  125. }
  126.  
  127. BOOL EXPENTRY lswInputHookWidg(HAB hab, PQMSG pQmsg, ULONG fs)
  128. { LSWDATA *plswData;
  129.   static HWND hwndTskBar=0,hwndBtn=0;
  130.  
  131.   if (pQmsg->msg==WM_NULL && pQmsg->hwnd==0 && GetSharedMem(&plswData)) {
  132.     hwndTskBar = plswData->hwndTaskBarClient;
  133.     DosFreeMem(plswData);
  134.   }
  135.  
  136.   if (pQmsg->msg==WM_MOUSEMOVE && pQmsg->hwnd!=hwndBtn) {
  137.     if (hwndBtn!=0) {
  138.       WinPostMsg(hwndTskBar,LSWM_MOUSEOVERBTN,MPFROMHWND(hwndBtn),MPFROMSHORT(FALSE));
  139.       hwndBtn = 0;
  140.     }
  141.     if (WinQueryWindow(pQmsg->hwnd,QW_PARENT)==hwndTskBar && IsWindowClass(pQmsg->hwnd,"#3")) {
  142.       hwndBtn = pQmsg->hwnd;
  143.       WinPostMsg(hwndTskBar,LSWM_MOUSEOVERBTN,MPFROMHWND(hwndBtn),MPFROMSHORT(TRUE));
  144.     }
  145.   } else if (pQmsg->msg==LSWM_WPSGETOBJID && LONGFROMMP(pQmsg->mp1)==WPSGETOBJIDMAGIC && GetSharedMem(&plswData)) {
  146.     UCHAR *ucHandle;
  147.     USHORT usHandle=0;
  148.     if (DosScanEnv("WP_OBJHANDLE",&ucHandle)==0 && ucHandle!=NULL)
  149.       usHandle=(USHORT)__atol(ucHandle);
  150.     WinPostMsg(plswData->hwndTaskBarClient,WM_USER+1000,MPFROMSHORT(usHandle),pQmsg->mp2);
  151.     DosFreeMem(plswData);
  152.   } else if (pQmsg->msg==LSWM_SETPRIORITY)
  153.     return SetPrty(LONGFROMMP(pQmsg->mp2),SHORT1FROMMP(pQmsg->mp1),SHORT2FROMMP(pQmsg->mp1));
  154.  
  155.   return FALSE;
  156. }
  157.  
  158. BOOL EXPENTRY lswInputHook(HAB hab, PQMSG pQmsg, ULONG fs)
  159. { LSWDATA *plswData;
  160.   POINTL ptl;
  161.   static BOOL bOnTop=FALSE;
  162.   static USHORT usOldY=0xFFFF,cyScreen=0,cyTskBar=0; // this and the previous lines need to be static
  163.   static RECTL rcl; //reduce stack usage to minimum since we don't use stack probes
  164.   static HWND hwndTskBar=0,hwndBtn=0;
  165.  
  166.   if (cyScreen==0 || pQmsg->msg==WM_SYSVALUECHANGED)
  167.     cyScreen=WinQuerySysValue(HWND_DESKTOP,SV_CYSCREEN);
  168.  
  169.   if (pQmsg->msg==WM_NULL && pQmsg->hwnd==0 && GetSharedMem(&plswData)) {
  170.     hwndTskBar = plswData->hwndTaskBarClient;
  171.     DosFreeMem(plswData);
  172.   }
  173.  
  174.   if (pQmsg->msg==WM_MOUSEMOVE) {
  175.     if (pQmsg->hwnd!=hwndBtn) {
  176.       if (hwndBtn!=0) {
  177.         WinPostMsg(hwndTskBar,LSWM_MOUSEOVERBTN,MPFROMHWND(hwndBtn),MPFROMSHORT(FALSE));
  178.         hwndBtn = 0;
  179.       }
  180.       if (WinQueryWindow(pQmsg->hwnd,QW_PARENT)==hwndTskBar && IsWindowClass(pQmsg->hwnd,"#3")) {
  181.         hwndBtn = pQmsg->hwnd;
  182.         WinPostMsg(hwndTskBar,LSWM_MOUSEOVERBTN,MPFROMHWND(hwndBtn),MPFROMSHORT(TRUE));
  183.       }
  184.     }
  185.  
  186.     if (hwndMenuUp==NULLHANDLE && (WinQueryPointerPos(HWND_DESKTOP,&ptl),ptl.y!=usOldY)) {
  187.       usOldY=ptl.y;
  188.       if ((!bOnTop && (ptl.y==0 || ptl.y==cyScreen-1)) ||
  189.           (bOnTop && ptl.y>2*cyTskBar && ptl.y<cyScreen-2*cyTskBar)) {
  190.  
  191.         if (!GetSharedMem(&plswData)) return FALSE;
  192.  
  193.         if ((!bOnTop && plswData->Settings.bTaskBarTopScr ^ ptl.y==0) ||
  194.             (bOnTop && !WinIsWindowVisible(plswData->hwndMenu))) {
  195.           if (!bOnTop) {
  196.             WinQueryWindowRect(plswData->hwndTaskBar,&rcl);
  197.             cyTskBar = rcl.yTop;
  198.           }
  199.           WinSetWindowPos(plswData->hwndTaskBar,bOnTop?HWND_BOTTOM:HWND_TOP,0,0,0,0,
  200.                           SWP_ZORDER|(plswData->Settings.bTaskBarAlwaysVisible?0:
  201.                                       (bOnTop?SWP_HIDE:SWP_SHOW)));
  202.           bOnTop^=TRUE;
  203.         }
  204.         DosFreeMem(plswData);
  205.       }
  206.     }
  207.   }
  208.  
  209.   if (pQmsg->msg==LSWM_WPSGETOBJID && LONGFROMMP(pQmsg->mp1)==WPSGETOBJIDMAGIC && GetSharedMem(&plswData)) {
  210.     UCHAR *ucHandle;
  211.     //  static *substr,buf[128];
  212.  
  213.     USHORT usHandle=0;
  214.     /*  PIB *ppib;TIB *ptib;
  215.      UCHAR *env;
  216.  
  217.      if (DosGetInfoBlocks(&ptib,&ppib)==0 *//*&&
  218.      (substr=strstr(ppib->pib_pchenv,"WP_OBJHANDLE="))!=NULL*///){
  219.     //    strncpy(ucHandle,substr+13,sizeof(ucHandle)-1);
  220.     //while (*ppib->pib_pchenv=='\0'&&ppib->pib_pchenv!=&ppib->pib_flstatus)ppib->pib_pchenv++;
  221.     /*    if (*ppib->pib_pchenv!='\0') DosBeep(1000,100);
  222.      env=ppib->pib_pchenv;
  223.      plswData->buf[0]='\0';
  224.      int2str(ppib->pib_ulpid,1,plswData->buf);
  225.      int2str(pQmsg->hwnd,1,buf);
  226.      strcat(plswData->buf," "); strcat(plswData->buf,buf); strcat(plswData->buf," ");
  227.      strcat(plswData->buf,ppib->pib_pchcmd);
  228.      strcat(plswData->buf,"\n");
  229.  
  230.      for (;*env!='\0';env+=strlen(buf)+1) {
  231.      strncpy(buf,env,sizeof(buf)-1);
  232.      strcat(plswData->buf,buf);strcat(plswData->buf,"\n");
  233.      }
  234.      strcat(plswData->buf,"\n");
  235.      }
  236.      */
  237.     if (DosScanEnv("WP_OBJHANDLE",&ucHandle)==0 && ucHandle!=NULL)
  238.       usHandle=(USHORT)__atol(ucHandle);
  239.  
  240.     WinPostMsg(plswData->hwndTaskBarClient,WM_USER+1000,MPFROMSHORT(usHandle),pQmsg->mp2);
  241.     DosFreeMem(plswData);
  242.   }
  243.  
  244.   if (pQmsg->msg==LSWM_SETPRIORITY)
  245.     return SetPrty(LONGFROMMP(pQmsg->mp2),SHORT1FROMMP(pQmsg->mp1),SHORT2FROMMP(pQmsg->mp1));
  246.   else
  247.     return FALSE;
  248. }
  249.  
  250.  
  251. /* we install this function as a pre-accelerator hook (undocumented). This hook
  252.  is called even before an application accelerator table is translated, which helps
  253.  to avoid compatibility problems with Ctrl-Tab hotkey */
  254. BOOL EXPENTRY lswPreAccHook(HAB hab, PQMSG pQmsg, ULONG fs)
  255. { USHORT usFlags;
  256.   UCHAR ucScan;
  257.   LSWDATA *plswData;
  258.   BOOL bRet;
  259.  
  260.   if (pQmsg->msg!=WM_CHAR ||
  261.       (usFlags=SHORT1FROMMP(pQmsg->mp1), ucScan=CHAR4FROMMP(pQmsg->mp1),
  262.        (usFlags & KC_SCANCODE))==0)
  263.     return FALSE;
  264.  
  265.   bRet = FALSE;
  266. /* tab w/ left Ctrl down. Trap the key either it's pressed or released,
  267.  so that it does not reach other applications and trigger something*/
  268. /* Alt-Tab might work in alternative shells */
  269.   if (ucScan==SCAN_TAB && (((usFlags & KC_CTRL)!=0 ^ (usFlags & KC_ALT)!=0) ^
  270.                            (WinGetPhysKeyState(HWND_DESKTOP,SCAN_WINLEFT)&0x8000)!=0) &&
  271.       GetSharedMem(&plswData)) {
  272.     if ((plswData->Settings.ucPopupHotKey==0 && (usFlags & KC_ALT)) ||
  273.         (plswData->Settings.ucPopupHotKey==1 && (usFlags & KC_CTRL)) ||
  274.         (plswData->Settings.ucPopupHotKey==2 && (WinGetPhysKeyState(HWND_DESKTOP,SCAN_WINLEFT)&0x8000))) {
  275.       if (usFlags & KC_KEYUP)
  276.         WinPostMsg(plswData->hwndPopClient,WM_COMMAND,MPFROMSHORT
  277.                    ((usFlags & KC_SHIFT) ? CMD_SCROLLLEFT : CMD_SCROLLRIGHT),
  278.                    MPFROM2SHORT(CMDSRC_OTHER,FALSE));
  279.       bRet = TRUE;
  280.     }
  281.     DosFreeMem(plswData);
  282.   }
  283.  
  284. /* Show settings */
  285.   if (!(usFlags & KC_KEYUP) && (usFlags & KC_ALT) && (usFlags & KC_CTRL) && GetSharedMem(&plswData)) {
  286.     if (ucScan == plswData->Settings.ucSettingsScan) {
  287.       WinPostMsg(plswData->hwndPopClient,WM_COMMAND,MPFROMSHORT(CMD_SHOWSETTINGS),MPFROM2SHORT(CMDSRC_OTHER,FALSE));
  288.       bRet = TRUE;
  289.     }
  290.     DosFreeMem(plswData);
  291.   }
  292.  
  293.   return bRet;
  294. }
  295.  
  296.  
  297. VOID EXPENTRY lswSendHook(HAB hab, PSMHSTRUCT psmh, BOOL fInterTask)
  298. { LSWDATA *plswData;
  299.   HSWITCH hsw;
  300.   static SWCNTRL swctl; //reduce stack usage to minimum since we don't use stack probes
  301.   static SWP swp;
  302.   ULONG ulFlags;
  303.  
  304. // make sure the taskbar does not show up and cover desktop menu
  305.   if (psmh->msg==WM_INITMENU && GetSharedMem(&plswData)) {
  306.     PID pid1,pid2; TID tid1,tid2;
  307.  
  308.     if (IsDesktop(psmh->hwnd) || (WinQueryWindowProcess(psmh->hwnd,&pid1,&tid1),
  309.                                   WinQueryWindowProcess(plswData->hwndPopup,&pid2,&tid2),pid1==pid2))
  310.       hwndMenuUp=HWNDFROMMP(psmh->mp2);
  311.     DosFreeMem(plswData);
  312.   }
  313.  
  314.   if (psmh->msg==WM_MENUEND && HWNDFROMMP(psmh->mp2)==hwndMenuUp)
  315.     hwndMenuUp=NULLHANDLE;
  316.  
  317.   if (psmh->msg==WM_MINMAXFRAME &&
  318.       (ulFlags=((PSWP)PVOIDFROMMP(psmh->mp1))->fl, ulFlags & SWP_MAXIMIZE) &&
  319.       WinQueryWindow(psmh->hwnd,QW_PARENT)==WinQueryDesktopWindow(0,0) &&
  320.       GetSharedMem(&plswData)) {
  321.  
  322.     if (!plswData->bWidget && plswData->Settings.bTaskBarOn && plswData->Settings.bReduceDsk &&
  323.         plswData->Settings.bTaskBarAlwaysVisible) {
  324.       SHORT sHgt,sY,sCY,sCYScr;
  325.  
  326.       sCYScr=WinQuerySysValue(HWND_DESKTOP,SV_CYSCREEN);
  327.  
  328.       WinQueryWindowPos(plswData->hwndTaskBar, &swp);
  329.       sHgt=(plswData->Settings.bTaskBarTopScr?sCYScr-swp.y:swp.y+swp.cy)-1;
  330.  
  331.       sY=((PSWP)PVOIDFROMMP(psmh->mp1))->y; sCY=((PSWP)PVOIDFROMMP(psmh->mp1))->cy;
  332.  
  333.       if ((plswData->Settings.bTaskBarTopScr && sY+sCY > sCYScr-sHgt) ||
  334.           (!plswData->Settings.bTaskBarTopScr && sY < sHgt)) {
  335.         ((PSWP)PVOIDFROMMP(psmh->mp1))->cy-=plswData->Settings.bTaskBarTopScr?sY+sCY-(sCYScr-sHgt):sHgt-sY;
  336.         ((PSWP)PVOIDFROMMP(psmh->mp1))->y=plswData->Settings.bTaskBarTopScr?sY:sHgt;
  337.       }
  338.     }
  339.     DosFreeMem(plswData);
  340.     return;
  341.   }
  342.  
  343.   if (psmh->msg==WM_ACTIVATE && GetSharedMem(&plswData)) {
  344.     if (plswData->Settings.bTaskBarOn)
  345.       WinPostMsg(plswData->hwndTaskBarClient,LSWM_ACTIVEWNDCHANGED,psmh->mp1,MPFROMHWND(psmh->hwnd));
  346.     DosFreeMem(plswData);
  347.     return;
  348.   }
  349.  
  350.   if (psmh->msg==WM_WINDOWPOSCHANGED &&
  351.       (ulFlags=((PSWP)PVOIDFROMMP(psmh->mp1))->fl,
  352.        ulFlags & (SWP_HIDE|SWP_SHOW|SWP_MINIMIZE|SWP_MAXIMIZE|SWP_RESTORE)) &&
  353.       (hsw=WinQuerySwitchHandle(psmh->hwnd,0))!=0 &&
  354.       (WinQuerySwitchEntry(hsw,&swctl),swctl.hwnd==psmh->hwnd) &&
  355.       GetSharedMem(&plswData)) {
  356.  
  357.       if (plswData->Settings.bTaskBarOn)
  358.         WinPostMsg(plswData->hwndTaskBarClient, LSWM_WNDSTATECHANGED,
  359.                    MPFROM2SHORT(hsw&0xFFFF,(SHORT)(ulFlags&0xFFFF)), MPFROMHWND(psmh->hwnd));
  360.  
  361.       WinPostMsg(plswData->hwndPopClient, LSWM_WNDSTATECHANGED,
  362.                  MPFROM2SHORT(hsw&0xFFFF,(SHORT)(ulFlags&0xFFFF)), MPFROMHWND(psmh->hwnd));
  363.  
  364.     DosFreeMem(plswData);
  365.     return;
  366.   }
  367.  
  368.   if ((psmh->msg==WM_SETICON || (psmh->msg==SH_SWITCHLIST &&
  369.         (((LONG)psmh->mp1>=1&&(LONG)psmh->mp1<=3)||(LONG)psmh->mp1==0x10001))) &&
  370.       GetSharedMem(&plswData)) {
  371.  
  372.     if (plswData->bNowActive)
  373.       WinPostMsg(plswData->hwndPopClient,
  374.         psmh->msg==WM_SETICON?LSWM_WNDICONCHANGED:LSWM_SWITCHLISTCHANGED,
  375.         psmh->mp1, psmh->msg==WM_SETICON?MPFROMHWND(psmh->hwnd):psmh->mp2);
  376.  
  377.     if (plswData->Settings.bTaskBarOn)
  378.       WinPostMsg(plswData->hwndTaskBarClient,
  379.         psmh->msg==WM_SETICON?LSWM_WNDICONCHANGED:LSWM_SWITCHLISTCHANGED,
  380.         psmh->mp1, psmh->msg==WM_SETICON?MPFROMHWND(psmh->hwnd):psmh->mp2);
  381.  
  382.     DosFreeMem(plswData);
  383.     return;
  384.   }
  385.  
  386.   /* make the just minimized or hidden window appear after the current one in
  387.    the switch list */
  388.   if (psmh->msg==WM_ADJUSTWINDOWPOS &&
  389.       (((PSWP)PVOIDFROMMP(psmh->mp1))->fl & (SWP_HIDE|SWP_MINIMIZE)) &&
  390.       !(WinGetPhysKeyState(HWND_DESKTOP,0x38) & 0x8000) &&
  391.       (hsw=WinQuerySwitchHandle(psmh->hwnd,0))!=0 &&
  392.       IsWindowClass(psmh->hwnd,"#1") && GetSharedMem(&plswData)) {
  393.  
  394.     if (plswData->Settings.bChangeZOrder)
  395.       ((PSWP)PVOIDFROMMP(psmh->mp1))->hwndInsertBehind = HWND_TOP;
  396.  
  397.     DosFreeMem(plswData);
  398.     return;
  399.   }
  400.  
  401.   if (psmh->msg==WM_COMMAND && IsWindowClass(psmh->hwnd,"AltTabWindow") &&
  402.       (WinGetPhysKeyState(HWND_DESKTOP,0x5e) & 0x8000)==0 && // right Alt up
  403.       GetSharedMem(&plswData)) {
  404.  
  405.     BOOL bShift;
  406.  
  407.     if (plswData->Settings.ucPopupHotKey==0 && plswData->Settings.bPMSwitcher) {
  408.       bShift = (WinGetPhysKeyState(HWND_DESKTOP,0x2a) & 0x8000) || // either Shift down
  409.                (WinGetPhysKeyState(HWND_DESKTOP,0x36) & 0x8000);
  410.       WinPostMsg(plswData->hwndPopClient,WM_COMMAND,MPFROMSHORT
  411.                  (bShift ? CMD_SCROLLLEFT : CMD_SCROLLRIGHT),
  412.                  MPFROM2SHORT(CMDSRC_OTHER,FALSE));
  413.       psmh->msg = WM_NULL;
  414.     }
  415.     DosFreeMem(plswData);
  416.   }
  417. }
  418.  
  419. LONG EXPENTRY lswHookInit(LSWDATA *plswData)
  420. {
  421.   if (DosQueryModuleHandle(DLL_NAME,&plswData->hmodHook)) return -1;
  422.  
  423.   if (!WinSetHook(plswData->hab,NULLHANDLE,HK_SENDMSG,(PFN)lswSendHook,plswData->hmodHook)) return -2;
  424.   if (!WinSetHook(plswData->hab,NULLHANDLE,HK_PREACCEL,(PFN)lswPreAccHook,plswData->hmodHook)) return -3;
  425.   if (!WinSetHook(plswData->hab,NULLHANDLE,HK_INPUT,plswData->bWidget?(PFN)lswInputHookWidg:(PFN)lswInputHook,plswData->hmodHook)) return -4;
  426.  
  427.   if (plswData->bWidget) WinPostMsg(0,WM_NULL,0,0); //reset the hook
  428.  
  429.   return MAKEULONG(MAKEUSHORT(VERSIONMAJOR,VERSIONMINOR),MAKEUSHORT(REVISION,0));
  430. }
  431.  
  432. VOID EXPENTRY lswHookTerm(LSWDATA *plswData)
  433. {
  434.   WinReleaseHook(plswData->hab,NULLHANDLE,HK_INPUT,plswData->bWidget?(PFN)lswInputHookWidg:(PFN)lswInputHook,plswData->hmodHook);
  435.   WinReleaseHook(plswData->hab,NULLHANDLE,HK_PREACCEL,(PFN)lswPreAccHook,plswData->hmodHook);
  436.   WinReleaseHook(plswData->hab,NULLHANDLE,HK_SENDMSG,(PFN)lswSendHook,plswData->hmodHook);
  437. }
  438.  
  439. ULONG EXPENTRY lswHookGetVersion(void)
  440. {
  441.   return MAKEULONG(MAKEUSHORT(VERSIONMAJOR,VERSIONMINOR),MAKEUSHORT(REVISION,0));
  442. }
  443.