Twain_DSM  1.0
hook.cpp
1 /*
2 * [Overview]
3 * The contents of this module allow the new TWAINDSM.DLL (tied to the 2.x version
4 * of the TWAIN Specifiction) to hook functions that might try to access the 1.x
5 * TWAIN_32.DLL. We need this because the DG_CONTROL/DAT_NULL/MSG_* triplets are
6 * sent from the data source (driver) to the application through the data source
7 * manager (DSM). The technique used was for a driver to issue a LoadLibrary or
8 * a GetModuleHandle, which would result in it attaching to the same TWAIN_32.DLL
9 * first loaded by the application. We have to force the driver to attach to the
10 * new TWAINDSM.DLL instead.
11 *
12 *
13 * [Diagram]
14 * This is the problem we have...
15 * +-----+ +--------------+ +--------------+
16 * | app | <-------> | TWAINDSM.DLL | --------> | |
17 * +-----+ +--------------+ | |
18 * | driver (1.x) |
19 * +--------------+ | |
20 * error <----- | TWAIN_32.DLL | <-------- | |
21 * +--------------+ +--------------+
22 *
23 * By hooking the appropriate function, we change the driver's request to get
24 * the DSM_Entry function from TWAIN_32.DLL into the DSM_Entry function from
25 * DSM_ TWAINDSM.DLL
26 * +-----+ +--------------+ +--------------+
27 * | app | <-------> | TWAINDSM.DLL | <-------> | |
28 * +-----+ +--------------+ | |
29 * | driver (1.x) |
30 * +--------------+ | |
31 * | TWAIN_32.DLL | | |
32 * +--------------+ +--------------+
33 *
34 * Note that TWAIN_32.DLL is still in the picture. This is intentional,
35 * because we're (indirectly) hooking GetProcAddress. The driver still
36 * does a LoadLibrary or GetModuleHandle on TWAIN_32.DLL. This design
37 * was selected because it results in the smallest possible hook code,
38 * and makes the smallest possible change to the 1.x driver. Everything
39 * runs the same as a TWAIN_32.DLL session, we just return a pointer to
40 * a different DSM_Entry function.
41 *
42 *
43 * [Hooked Functions]
44 * This is the ntdll.dll function we're hooking from kernel32.dll...
45 * LdrGetProcedureAddress (or LdrGetProcedureAddressForCaller)
46 * This gives us full coverage for the following function...
47 * GetProcAddress
48 *
49 *
50 * [Solution]
51 * The hook code is derived from the BugSlayer HookImportedFunctionByName function
52 * described in the August 1998 MSJ. The code has been considerably simplified to
53 * meet the limited needs of the DSM.
54 *
55 *
56 * [Risks]
57 * 32-bit Windows applications using TWAINDSM.DLL will never be able to access
58 * the TWAIN_32.DLL DSM_Entry function. Since this is by design, it's not so
59 * much a risk as "the plan", but it still deserves to be mentioned.
60 *
61 * We're not fully loading the TWAIN_32.DLL, because we don't have control over
62 * it, and we can't be sure what it's doing in DllMain. This could be a problem
63 * with a very badly behaved application. The scenerio is so convoluted, though,
64 * that it seems a good risk to keep TWAIN_32.DLL as uninvolved as possible.
65 *
66 * The application will crash if it does a FreeLibrary() on the DSM without first
67 * doing all the necessary MSG_CLOSEDS and MSG_CLOSEDSM calls. This can be
68 * mitigated by hooking LdrUnloadDll() and watching for an attempt to unload the
69 * DSM. But this adds complexity that rewards extremely bad coding behavior, so
70 * it's not going to be added unless we have a lot of bad actors we have to deal
71 * with.
72 *
73 * Hooks should be avoided whenever possible. Therefore the DSM code only installs
74 * the hook if the application attempts to DG_CONTROL/DAT_IDENTITY/MSG_OPENDS a 1.x
75 * driver on a 32-bit Windows system.
76 *
77 * This system is only designed to work with Window 2000 and higher, there is no
78 * intention of supporting either Windows NT or any of the Windows 9x platforms.
79 * Nor is there a reason to, since they don't have a file protection scheme (save for
80 * WinME, but hopefully nobody is still using that)...
81 */
82 
83 #include "dsm.h"
84 
85 
90 #if TWNDSM_OS_64BIT
91 #pragma message( "hook code disabled for 64-bit builds..." )
92 #elif TWNDSM_OS_32BIT
93 #pragma message( "hook code enabled for 32-bit builds..." )
94 
95 
96 
101 #define MakePtr(cast,ptr,AddValue) (cast)((DWORD_PTR)(ptr)+(DWORD_PTR)(AddValue))
102 
103 
107 enum EHOOK
108 {
109  HOOK_ATTACH = 0,
110  HOOK_DETACH = 1
111 };
112 
113 
117 typedef struct _ANSI_STRING {
118  USHORT Length;
119  USHORT MaximumLength;
120  PSTR Buffer;
122 
123 
128 typedef NTSYSAPI DWORD (NTAPI *LdrGetProcedureAddress_t)
129 (
130  __in HMODULE ModuleHandle,
131  __in_opt PANSI_STRING FunctionName,
132  __in_opt WORD Oridinal,
133  __out PVOID *FunctionAddress
134 );
135 typedef NTSYSAPI DWORD (NTAPI *LdrGetProcedureAddressForCaller_t)
136 (
137  __in HMODULE ModuleHandle,
138  __in_opt PANSI_STRING FunctionName,
139  __in_opt WORD Oridinal,
140  __out PVOID *FunctionAddress,
141  __in BOOL bValue,
142  __in PVOID *CallbackAddress
143 );
144 
148 DWORD NTAPI LocalLdrGetProcedureAddress
149 (
150  __in HMODULE ModuleHandle,
151  __in_opt PANSI_STRING FunctionName,
152  __in_opt WORD Oridinal,
153  __out PVOID *FunctionAddress
154 );
155 DWORD NTAPI LocalLdrGetProcedureAddressForCaller
156 (
157  __in HMODULE ModuleHandle,
158  __in_opt PANSI_STRING FunctionName,
159  __in_opt WORD Oridinal,
160  __out PVOID *FunctionAddress,
161  __in BOOL bValue,
162  __in PVOID *CallbackAddress
163 );
164 
169 extern DSMENTRY DSM_Entry
170 (
171  TW_IDENTITY *_pOrigin,
172  TW_IDENTITY *_pDest,
173  TW_UINT32 _DG,
174  TW_UINT16 _DAT,
175  TW_UINT16 _MSG,
176  TW_MEMREF _pData
177 );
178 
179 
183 class CTwHook
184 {
185  public:
186 
187  // Initialize our piece-of-data...
188  CTwHook()
189  {
190  memset(&pod,0,sizeof(pod));
191  }
192 
193  // The destructor cleans us all up (but Hook does the real work)...
194  ~CTwHook()
195  {
196  Hook(HOOK_DETACH);
197  memset(&pod,0,sizeof(pod));
198  }
199 
200  // The workhorse, this is where the hooking fun really takes place...
201  bool Hook
202  (
203  EHOOK _ehook
204  );
205 
206  // Determine if this DS ID has been hooked
207  bool DSID_Is_Hooked
208  (
209  TW_UINT32 DSID
210  );
211 
212  // Add this DS ID as being hooked
213  void Hook_Add_DSID
214  (
215  TW_UINT32 DSID
216  );
217 
218  // Remove this DS ID as being hooked
219  bool Hook_Remove_DSID
220  (
221  TW_UINT32 DSID
222  );
223 
224  private:
225 
226  // We use a pod so that we don't have to worry about initialization
227  // issues...
228  struct Pod
229  {
230  PROC pOriginal; // The original procedure we found
231  TW_UINT32 HookedDSs[MAX_NUM_DS];
232  } pod;
233 };
234 
235 
242 static int s_iHookCount = 0;
243 static CTwHook *s_ptwhook = (CTwHook*)NULL;
244 
245 
252 static LdrGetProcedureAddress_t OriginalLdrGetProcedureAddress = 0;
253 static LdrGetProcedureAddressForCaller_t OriginalLdrGetProcedureAddressForCaller = 0;
254 
255 
260 static HMODULE s_hmoduleTWAIN32 = 0;
261 
267 static DSMENTRYPROC TWAIN32_DSMEntry = 0;
268 
269 
270 
275 DSMENTRY DSM_HookedEntry
276 (
277  TW_IDENTITY *_pOrigin,
278  TW_IDENTITY *_pDest,
279  TW_UINT32 _DG,
280  TW_UINT16 _DAT,
281  TW_UINT16 _MSG,
282  TW_MEMREF _pData
283 )
284 {
285  if ( ((_DAT == DAT_NULL)
286  || (_DAT == DAT_CALLBACK && _MSG == MSG_INVOKE_CALLBACK))
287  && _pOrigin
288  && s_ptwhook
289  && s_ptwhook->DSID_Is_Hooked(_pOrigin->Id))
290  {
291  return (DSM_Entry(_pOrigin,_pDest,_DG,_DAT,_MSG,_pData));
292  }
293 
294  return (TWAIN32_DSMEntry(_pOrigin,_pDest,_DG,_DAT,_MSG,_pData));
295 }
296 
297 
298 
309 (
310  EHOOK _ehook
311 )
312 {
313  UINT uResult;
314  BOOL boolResult;
315  PIMAGE_IMPORT_DESCRIPTOR pImportDesc;
316  PIMAGE_THUNK_DATA pOrigThunk;
317  PIMAGE_THUNK_DATA pRealThunk;
318  PIMAGE_IMPORT_BY_NAME pByName;
319  bool bDoHook;
320  MEMORY_BASIC_INFORMATION mbi_thunk;
321  DWORD_PTR *pTemp;
322  DWORD dwOldProtect;
323  PIMAGE_DOS_HEADER pDOSHeader;
324  PIMAGE_NT_HEADERS pNTHeader;
325  PSTR szCurrMod;
326  HMODULE hmodule;
327  char szTwain32[MAX_PATH];
328  const char *szFunctionName;
329 
330  // Initialize stuff when we're doing an attach...
331  if (_ehook == HOOK_ATTACH)
332  {
333  // If we don't find TWAIN_32.DLL, then we're not going to
334  // make life any better by doing the hooks, so bail. Also,
335  // We're not going to allow any flavor of GetProcAddress
336  // to access this library, which is why we're using the
337  // extra flag, to keep TWAIN_32.DLL from loading anything
338  // other than itself.
339  //
340  // BUG ALERT
341  // ~~~~~~~~~
342  // There is a potential bug here, but one that depends
343  // on really bad behavior. If the application loads
344  // TWAINDSM.DLL, then loads TWAIN_32.DLL, then unloads
345  // TWAINDSM.DLL, then does a GetProcAddress for DSM_Entry
346  // with TWAIN_32.DLL, it's going to go ka-boom. If this
347  // is a problem, then go back to using ::LoadLibrary()...
348  memset(szTwain32,0,sizeof(szTwain32));
349  uResult = ::GetWindowsDirectory(szTwain32,sizeof(szTwain32)-1);
350  if (!uResult)
351  {
352  return(false);
353  }
354  SSTRCAT(szTwain32,sizeof(szTwain32)-1,"\\TWAIN_32.DLL");
355  s_hmoduleTWAIN32 = ::LoadLibraryEx(szTwain32,NULL,DONT_RESOLVE_DLL_REFERENCES);
356  if (0 == s_hmoduleTWAIN32)
357  {
358  return(false);
359  }
360 
361  // Load the undocumented routine, we're going for both, if we find
362  // LdrGetProcedureAddressForCaller, then we'll prefer it over LdrGetProcedureAddress...
363  szFunctionName = "";
364  OriginalLdrGetProcedureAddress = 0;
365  OriginalLdrGetProcedureAddressForCaller = 0;
366  hmodule = GetModuleHandle("ntdll.dll");
367  if (hmodule)
368  {
369  szFunctionName = "LdrGetProcedureAddressForCaller";
370  OriginalLdrGetProcedureAddressForCaller = (LdrGetProcedureAddressForCaller_t)GetProcAddress(hmodule,szFunctionName);
371  if (!OriginalLdrGetProcedureAddressForCaller)
372  {
373  szFunctionName = "LdrGetProcedureAddress";
374  OriginalLdrGetProcedureAddress = (LdrGetProcedureAddress_t)GetProcAddress(hmodule,szFunctionName);
375  }
376  }
377  }
378 
379  // If we're detaching, then make sure our reference to TWAIN_32.DLL is gone...
380  else
381  {
382  if (s_hmoduleTWAIN32)
383  {
384  ::FreeLibrary(s_hmoduleTWAIN32);
385  s_hmoduleTWAIN32 = 0;
386  }
387 
388  // If we don't have an old pointer, then we're done...
389  if (NULL == pod.pOriginal)
390  {
391  return (true);
392  }
393 
394  // Pick the name...
395  if (OriginalLdrGetProcedureAddressForCaller)
396  {
397  szFunctionName = "LdrGetProcedureAddressForCaller";
398  }
399  else
400  {
401  szFunctionName = "LdrGetProcedureAddress";
402  }
403  }
404 
405  // This is where we'll be hooking into Ldr functions, the calls
406  // themselves are in ntdll.dll. Kernel32 calls them, and that's
407  // where we can take advantage of the DLL indirection to do this
408  // spiffy DLL injection thingy...
409  // Starting with Windows7 the hooking has moved from kernel32.dll
410  // to a new library kernelbase.dll. Atempt kernelbase first
411  // if it fails then we are not Windows7 and try kernel32
412  hmodule = GetModuleHandle("kernelbase.dll");
413  if ( NULL == hmodule )
414  {
415  hmodule = GetModuleHandle("kernel32.dll");
416  }
417 
418  // Get the DOS header...
419  pDOSHeader = (PIMAGE_DOS_HEADER)hmodule;
420 
421  // Is this the MZ header?
422  if ( !pDOSHeader
423  || (TRUE == IsBadReadPtr(pDOSHeader,sizeof(IMAGE_DOS_HEADER)))
424  || (IMAGE_DOS_SIGNATURE != pDOSHeader->e_magic))
425  {
426  return (false);
427  }
428 
429  // Get the PE header.
430  pNTHeader = MakePtr(PIMAGE_NT_HEADERS,pDOSHeader,pDOSHeader->e_lfanew);
431 
432  // Is this a real PE image?
433  if ( (TRUE == IsBadReadPtr(pNTHeader,sizeof(IMAGE_NT_HEADERS)))
434  || (IMAGE_NT_SIGNATURE != pNTHeader->Signature))
435  {
436  return (false);
437  }
438 
439  // If there is no imports section, leave now.
440  if (0 == pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)
441  {
442  return (false);
443  }
444 
445  // Get the pointer to the imports section.
446  pImportDesc = MakePtr(PIMAGE_IMPORT_DESCRIPTOR,pDOSHeader,pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
447 
448  // Loop through the import module descriptors looking for the
449  // ntdll.dll module, which is where the Ldr functions live...
450  while (NULL != pImportDesc->Name)
451  {
452  szCurrMod = MakePtr(PSTR,pDOSHeader,pImportDesc->Name);
453  if (0 == _stricmp(szCurrMod,"ntdll.dll"))
454  {
455  // Found it.
456  break;
457  }
458  // Look at the next one.
459  pImportDesc++ ;
460  }
461 
462  // If the name is NULL, then the module is not imported.
463  if (NULL == pImportDesc->Name)
464  {
465  return (false);
466  }
467 
468  // Get the original thunk information for this DLL. I can't use
469  // the thunk information stored in pImportDesc->FirstThunk
470  // because the loader has already changed that array to fix up
471  // all the imports. The original thunk gives me access to the
472  // function names.
473  pOrigThunk = MakePtr(PIMAGE_THUNK_DATA,hmodule,pImportDesc->OriginalFirstThunk);
474 
475  // Get the array the pImportDesc->FirstThunk points to because
476  // I'll do the actual bashing and hooking there.
477  pRealThunk = MakePtr(PIMAGE_THUNK_DATA,hmodule,pImportDesc->FirstThunk);
478 
479  // Determines whether I hook the function
480  bDoHook = false;
481 
482  // Loop through and find the function to hook.
483  while (NULL != pOrigThunk->u1.Function)
484  {
485  // Look only at functions that are imported by name, not those
486  // that are imported by ordinal value.
487  if (IMAGE_ORDINAL_FLAG != (pOrigThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG))
488  {
489  // Look at the name of this imported function.
490  pByName = MakePtr(PIMAGE_IMPORT_BY_NAME,hmodule,pOrigThunk->u1.AddressOfData);
491 
492  // We found it, so scoot...
493  if ( pByName->Name
494  && ('\0' != pByName->Name[0])
495  && (0 == _stricmp(szFunctionName,(char*)pByName->Name)))
496  {
497  bDoHook = true;
498  break;
499  }
500 
501  // Increment both tables, and continue...
502  pOrigThunk++;
503  pRealThunk++;
504  }
505  }
506 
507  // If we found something, then hook or unhook it, as appropriate...
508  if (true == bDoHook)
509  {
510  // I found a function to hook. Now I need to change
511  // the memory protection to writable before I overwrite
512  // the function pointer. Note that I'm now writing into
513  // the real thunk area!
514  VirtualQuery(pRealThunk,&mbi_thunk,sizeof(MEMORY_BASIC_INFORMATION));
515  if (FALSE == VirtualProtect(mbi_thunk.BaseAddress,mbi_thunk.RegionSize,PAGE_EXECUTE_READWRITE,&mbi_thunk.Protect))
516  {
517  return(false);
518  }
519 
520  // Save the original address, if we're hooking...
521  if (_ehook == HOOK_ATTACH)
522  {
523  // This cast should make the compiler happy about the change in the word size...
524  pod.pOriginal = (PROC)(INT_PTR)pRealThunk->u1.Function;
525  if (OriginalLdrGetProcedureAddressForCaller)
526  {
527  OriginalLdrGetProcedureAddressForCaller = (LdrGetProcedureAddressForCaller_t)pod.pOriginal;
528  }
529  else
530  {
531  OriginalLdrGetProcedureAddress = (LdrGetProcedureAddress_t)pod.pOriginal;
532  }
533  }
534 
535  // Microsoft has two different definitions of the
536  // PIMAGE_THUNK_DATA fields as they are moving to
537  // support Win64. The W2K RC2 Platform SDK is the
538  // latest header, so I'll use that one and force the
539  // Visual C++ 6 Service Pack 3 headers to deal with it.
540 
541  // Hook the new function if we're hooking, or the original function
542  // if we're closing...
543  if (_ehook == HOOK_ATTACH)
544  {
545  pTemp = (DWORD_PTR*)&pRealThunk->u1.Function;
546  if (OriginalLdrGetProcedureAddressForCaller)
547  {
548  *pTemp = (DWORD_PTR)LocalLdrGetProcedureAddressForCaller;
549  }
550  else
551  {
552  *pTemp = (DWORD_PTR)LocalLdrGetProcedureAddress;
553  }
554  }
555  else
556  {
557  pTemp = (DWORD_PTR*)&pRealThunk->u1.Function;
558  *pTemp = (DWORD_PTR)(pod.pOriginal);
559  }
560 
561  // Change the protection back to what it was before I
562  // overwrote the function pointer.
563  boolResult = VirtualProtect(mbi_thunk.BaseAddress,mbi_thunk.RegionSize,mbi_thunk.Protect,&dwOldProtect);
564  if (boolResult == FALSE)
565  {
566  // Okay, this isn't good, but we're not going to do
567  // anything about it, because presumably this isn't
568  // the end of the world...
569  }
570  }
571 
572  // All done...
573  return(true);
574 }
575 
581 bool CTwHook::DSID_Is_Hooked(TW_UINT32 DSID)
582 {
583  int count = min(MAX_NUM_DS,s_iHookCount);
584  for (int i=0; i<count; i++)
585  {
586  if (pod.HookedDSs[i] == DSID)
587  {
588  return (true);
589  }
590  }
591  return (false);
592 }
593 
604 void CTwHook::Hook_Add_DSID(TW_UINT32 DSID)
605 {
606  pod.HookedDSs[s_iHookCount] = DSID;
607  s_iHookCount++;
608 }
609 
615 bool CTwHook::Hook_Remove_DSID(TW_UINT32 DSID)
616 {
617  int count = min(MAX_NUM_DS, s_iHookCount);
618 
619  for(int i=0; i<count; i++)
620  {
621  if(pod.HookedDSs[i] == DSID)
622  {
623  while(i+1<count)
624  {
625  pod.HookedDSs[i] = pod.HookedDSs[i+1];
626  }
627  pod.HookedDSs[i] = 0;
628  s_iHookCount--;
629  return true;
630  }
631  }
632 
633  // Should never get here. It means we are trying to
634  // remove a DS that was never hooked.
635  kLOG((kLOGERR,"Trying to removing a hook for a DSID (%d) that was never added.", DSID ));
636  return false;
637 }
638 
639 
640 
649 DWORD NTAPI LocalLdrGetProcedureAddress
650 (
651  __in HMODULE ModuleHandle,
652  __in_opt PANSI_STRING FunctionName,
653  __in_opt WORD Ordinal,
654  __out PVOID *FunctionAddress
655 )
656 {
657  // See if the caller is asking for TWAIN_32.DLL, and if so, then dive in
658  // and return our DSM_Entry. This works because attempts to load the
659  // same DLL more than once just bump up the reference count. Or put
660  // another way, if function A does a LoadLibrary("xyz") and then function
661  // B does a LoadLibrary("xzy") the HMODULE values returned will be found
662  // to be the same.
663  //
664  // We don't have to check the FunctionName or the Ordinal, there's only
665  // one possible return from TWAIN_32.DLL (thank you initial designers),
666  // and I haven't throught of a good security reason why I need to bother
667  // checking...
668  if (ModuleHandle == s_hmoduleTWAIN32)
669  {
670  // Get and store the original address in case we need it
671  (OriginalLdrGetProcedureAddress(ModuleHandle,FunctionName,Ordinal,(PVOID*)&TWAIN32_DSMEntry));
672  // Return the address to our own function
673  *FunctionAddress = ::DSM_HookedEntry;
674  return (ERROR_SUCCESS);
675  }
676 
677  // Otherwise let the call continue unmolested...
678  return (OriginalLdrGetProcedureAddress(ModuleHandle,FunctionName,Ordinal,FunctionAddress));
679 }
680 
681 
682 
693 DWORD NTAPI LocalLdrGetProcedureAddressForCaller
694 (
695  __in HMODULE ModuleHandle,
696  __in_opt PANSI_STRING FunctionName,
697  __in_opt WORD Ordinal,
698  __out PVOID *FunctionAddress,
699  __in BOOL bValue,
700  __in PVOID *CallbackAddress
701 )
702 {
703  // See if the caller is asking for TWAIN_32.DLL, and if so, then dive in
704  // and return our DSM_Entry. This works because attempts to load the
705  // same DLL more than once just bump up the reference count. Or put
706  // another way, if function A does a LoadLibrary("xyz") and then function
707  // B does a LoadLibrary("xzy") the HMODULE values returned will be found
708  // to be the same.
709  //
710  // We don't have to check the FunctionName or the Ordinal, there's only
711  // one possible return from TWAIN_32.DLL (thank you initial designers),
712  // and I haven't throught of a good security reason why I need to bother
713  // checking...
714  if (ModuleHandle == s_hmoduleTWAIN32)
715  {
716  // Get and store the original address in case we need it
717  (OriginalLdrGetProcedureAddressForCaller(ModuleHandle,FunctionName,Ordinal,(PVOID*)&TWAIN32_DSMEntry,bValue,CallbackAddress));
718  // Return the address to our own function
719  *FunctionAddress = ::DSM_HookedEntry;
720  return (ERROR_SUCCESS);
721  }
722 
723  // Otherwise let the call continue unmolested...
724  return (OriginalLdrGetProcedureAddressForCaller(ModuleHandle,FunctionName,Ordinal,FunctionAddress,bValue,CallbackAddress));
725 }
726 
727 
728 
733 HMODULE InstallTwain32DllHooks
734 (
735  const char* const _lib,
736  const bool _hook,
737  const TW_UINT32 _DSID
738 )
739 {
740  HMODULE hmodule;
741  CTwHook *ptwhook;
742  DWORD dwResult;
743 
744  // Init stuff...
745  ptwhook = (CTwHook*)NULL;
746 
747  // We hook before we load the library so that we can intercept calls
748  // to the Ldr functions during DllMain. But we only do the hook if
749  // it's the first time we've been here, and we've been asked to do
750  // hooking (which we won't be if the DSM is doing GetFirst/GetNext to
751  // enumerate the drivers)...
752  if (_hook)
753  {
754  // If we already have a hook in place, then bump up our
755  // reference counter...
756  if ( (s_iHookCount > 0)
757  && ((CTwHook*)NULL != s_ptwhook))
758  {
759  s_ptwhook->Hook_Add_DSID(_DSID);
760  }
761 
762  // Otherwise load the beastie...
763  else
764  {
765  // Allocate our object...
766  s_iHookCount = 0;
767  ptwhook = new CTwHook();
768  if (ptwhook)
769  {
770  // Do the hook...
771  if (ptwhook->Hook(HOOK_ATTACH))
772  {
773  // This activates our hooking functions to look for
774  // attempts to get DSM_Entry...
775  s_ptwhook = ptwhook;
776  s_ptwhook->Hook_Add_DSID(_DSID);
777  }
778  // No joy, cleanup...
779  else
780  {
781  delete ptwhook;
782  ptwhook = (CTwHook*)NULL;
783  s_ptwhook = (CTwHook*)NULL;
784  }
785  }
786  }
787  }
788 
789  // Load the library the caller asked for...
790  hmodule = ::LoadLibrary(_lib);
791 
792  // If we hooked for this module, and the LoadLibrary failed, then
793  // undo the hook...
794  if ( (NULL == hmodule)
795  && ((CTwHook*)NULL != ptwhook)
796  && _hook)
797  {
798  dwResult = ::GetLastError();
799  s_ptwhook->Hook_Remove_DSID(_DSID);
800  if (s_iHookCount <= 0)
801  {
802  s_ptwhook = (CTwHook*)NULL;
803  delete ptwhook;
804  s_iHookCount = 0;
805  }
806  ::SetLastError(dwResult);
807  }
808 
809  // All done...
810  return(hmodule);
811 }
812 
813 
814 
819 BOOL UninstallTwain32DllHooks
820 (
821  const HMODULE _hmodule,
822  const bool _unhook,
823  const TW_UINT32 _DSID
824 )
825 {
826  if(_unhook)
827  {
828  if (s_ptwhook)
829  {
830  // Remove the DS from the list and decrement the count...
831  s_ptwhook->Hook_Remove_DSID(_DSID);
832 
833  // If we're at zero, then cleanup. I'm probably being a bit
834  // paranoid about the cleanup scheme, but I like being paranoid
835  // when it comes to hooks...
836  if (s_iHookCount <= 0)
837  {
838  CTwHook *ptwhook = s_ptwhook;
839  s_ptwhook = (CTwHook*)NULL;
840  delete ptwhook;
841  s_iHookCount = 0;
842  }
843  }
844  }
845  // Free the library...
846  return(::FreeLibrary(_hmodule));
847 }
848 
849 
850 
851 // TWDSM_OS_64BIT/TWNDSM_OS_32BIT
852 #else
853 #error error, we need to be either 32-bit or 64-bit...
854 #endif
CTwHook::Hook_Remove_DSID
bool Hook_Remove_DSID(TW_UINT32 DSID)
Remove this DS from the list of being hooked.
Definition: hook.cpp:615
dsm.h
Everything we need to make our .cpp files happy.
CTwHook
The hook class...
Definition: hook.cpp:184
kLOGERR
#define kLOGERR
write error messages to LogFile.
Definition: dsm.h:490
TW_IDENTITY
Definition: twain.h:443
__in
#define __in
We use resource.h to specify version info on all platforms...
Definition: dsm.h:181
CTwHook::Hook_Add_DSID
void Hook_Add_DSID(TW_UINT32 DSID)
Add this DS to the list of being hooked.
Definition: hook.cpp:604
kLOG
#define kLOG(a)
Define to write messages to LogFile.
Definition: dsm.h:496
CTwHook::Pod
Definition: hook.cpp:229
_ANSI_STRING
Need this for our Ldr functions...
Definition: hook.cpp:117
DSMENTRY
#define DSMENTRY
the DSM entry point type
Definition: dsm.h:298
DSM_Entry
DSMENTRY DSM_Entry(TW_IDENTITY *_pOrigin, TW_IDENTITY *_pDest, TW_UINT32 _DG, TW_UINT16 _DAT, TW_UINT16 _MSG, TW_MEMREF _pData)
The entry point we want to return to the caller, instead of the one they thought they were getting fr...
Definition: dsm.cpp:314
SSTRCAT
#define SSTRCAT(d, z, s)
Secure String catinate.
Definition: dsm.h:402
CTwHook::Hook
bool Hook(EHOOK _ehook)
Derived from John Robbins' BugSlayer code in MSJ (so the 'I' in the comments in this function refers ...
Definition: hook.cpp:309
CTwHook::DSID_Is_Hooked
bool DSID_Is_Hooked(TW_UINT32 DSID)
Determine if the DS has been hooked by checking the ID.
Definition: hook.cpp:581
MAX_NUM_DS
#define MAX_NUM_DS
Maximum number of Data Sources that can be opened under one application.
Definition: dsm.h:521