home *** CD-ROM | disk | FTP | other *** search
/ QBasic & Borland Pascal & C / Delphi5.iso / C / BC_502 / OWLSRC.PAK / OWL.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1997-05-06  |  7.6 KB  |  278 lines

  1. //----------------------------------------------------------------------------
  2. // ObjectWindows
  3. // Copyright (c) 1991, 1997 by Borland International, All Rights Reserved
  4. //
  5. //$Revision:   10.7  $
  6. //
  7. // Internal window object thunk creation & maintanance.
  8. //----------------------------------------------------------------------------
  9. #include <owl/pch.h>
  10. #if !defined(OWL_WINDOW_H)
  11. # include <owl/window.h>
  12. #endif
  13. #if !defined(SERVICES_MEMORY_H)
  14. # include <services/memory.h>
  15. #endif
  16. #include <dos.h>
  17. #if defined(BI_PLAT_WIN32)
  18. # include <stddef.h>
  19. #endif
  20.  
  21. OWL_DIAGINFO;
  22. DIAG_DECLARE_GROUP(OwlWin);
  23.  
  24. //
  25. // Creation window pointer for InitWndProc
  26. //
  27. TWindow* _OWLDATA CreationWindow = 0;
  28.  
  29. void _OWLFUNC
  30. SetCreationWindow(TWindow* w)
  31. {
  32.   // Theoretically, there should always be only one non-zero
  33.   // 'creationWindow' pointer. i.e. we never want to have a case where
  34.   // we're holding on to a pointer waiting to be thunked, and this function 
  35.   // is invoked with yet another valid pointer (Otherwise, we'll fail to 
  36.   // thunk a HWND<->TWindow* pair.
  37.   //
  38.   PRECONDITION(CreationWindow == 0 || w == 0);
  39.   TRACEX(OwlWin, 1, "SetCreationWindow: Old(" << (void*)CreationWindow <<\
  40.                     "), New(" << (void*)w << ')');
  41.   CreationWindow = w;
  42. }
  43.  
  44. //
  45. // Accessor of CreationWindow
  46. //
  47. TWindow* _OWLFUNC
  48. GetCreationWindow() 
  49. {
  50.   return CreationWindow;
  51. }
  52.  
  53. uint16 far _OWLFUNC
  54. OWLGetVersion()
  55. {
  56.   return OWLVersion;
  57. }
  58.  
  59. //
  60. // Initial WndProc called when an Owl window is first created.
  61. // Subclasses the window function by installing the thunk then calls the
  62. // thunk to get this first message to the window.
  63. //
  64. /*OWL_EXPORT*/ TResult CALLBACK OWL_EXPORT16
  65. TWindow::InitWndProc(TWindow::THandle hWnd, uint message, TParam1 param1,
  66.                      TParam2 param2)
  67. {
  68.   // If there's no creation window, i.e. we'll be aliasing a resource, then we
  69.   // can't do anything now.  Create() will take care of it later
  70.   //
  71.   if (!CreationWindow)
  72.     return ::DefWindowProc(hWnd, message, param1, param2);
  73.  
  74.   // Install "DefWindowProc" as the window function BEFORE we request the
  75.   // subclassings; otherwise it looks like we subclassed "InitWndProc"
  76.   //
  77.   CreationWindow->Handle = hWnd;
  78. #if defined(BI_PLAT_WIN32)
  79.   CreationWindow->DefaultProc = (WNDPROC)GetProcAddress(
  80.       (HINSTANCE)GetModuleHandle("USER32"), "DefWindowProcA");
  81. #else
  82.   CreationWindow->DefaultProc = ::DefWindowProc;
  83. #endif
  84.  
  85.   // Get the thunk & then zero out creation window so that it is not
  86.   // inadvertently used.
  87.   //
  88.   WNDPROC thunk = CreationWindow->GetThunk();
  89.   SetCreationWindow(0);
  90.  
  91.   // Set the thunk as the window proc, & call it with this first message.
  92.   //
  93.   ::SetWindowLong(hWnd, GWL_WNDPROC, uint32(thunk));
  94.   return (*(WNDPROC)(thunk))(hWnd, message, param1, param2);
  95. }
  96.  
  97. //
  98. // Win32 version of the instance thunking mechanism
  99. //
  100. #if defined(BI_PLAT_WIN32)
  101.  
  102. #include <pshpack1.h>     // This struct MUST be packed
  103.  
  104. struct TInstanceThunk {
  105.   uint8      Call;
  106.   int        Offset;
  107.   TThunkProc Proc;
  108.   TWindow*   Window;
  109.   uint8      Code[6];
  110. };
  111. #include <poppack.h>
  112.  
  113. static const int  CODEDISP = offsetof(TInstanceThunk, Code) -
  114.                              offsetof(TInstanceThunk, Proc);
  115.  
  116. WNDPROC
  117. CreateInstanceThunk(TWindow* w, TThunkProc thunkProc)
  118. {
  119.   TInstanceThunk*  thunk = new TInstanceThunk;
  120.  
  121.   thunk->Call = 0xE8u;        // CALL rel32
  122.   thunk->Offset = CODEDISP;   // relative displacement to Code[5]
  123.   thunk->Proc = thunkProc;
  124.   thunk->Window = w;
  125.  
  126.   // POP ECX
  127.   //
  128.   // pop return address of call into ecx (address of member "Proc")
  129.   //
  130.   thunk->Code[0] = 0x59u;
  131.  
  132.   // MOV EAX,[ECX+4]
  133.   //
  134.   // load "Window" into ebx
  135.   //
  136.   thunk->Code[1] = 0x8Bu;     // MOV r32,r/m32
  137.   thunk->Code[2] = 0x41u;     // eax,disp8[ECX]
  138.   thunk->Code[3] = 0x04u;     // +4
  139.  
  140.   // JMP [ECX]
  141.   //
  142.   // jump to window function provided
  143.   //
  144.   thunk->Code[4] = 0xFFu;     // JMP r/m32
  145.   thunk->Code[5] = 0x21u;     // [ECX]
  146.  
  147.   return (WNDPROC)thunk;
  148. }
  149.  
  150. void
  151. FreeInstanceThunk(WNDPROC proc)
  152. {
  153.   delete (TInstanceThunk*)proc;
  154. }
  155.  
  156. //
  157. // Win16 version of the instance thunking mechanism
  158. //
  159. #elif defined(BI_PLAT_WIN16)
  160.  
  161. //
  162. // AllocCSToDSAlias was not declared in windows.h
  163. //
  164. extern "C" uint16 FAR PASCAL AllocCSToDSAlias(uint16);
  165.  
  166. struct TInstanceThunk {
  167.   char   Code;
  168.   uint16 Offset;
  169.  
  170.   union Ptr {
  171.     struct TInstanceThunk far* Next;
  172.     TWindow far*               Window;
  173.   } ptr;
  174. };
  175.  
  176. struct TThunkBlock {
  177.   uint16    Next;
  178.   char      Code[5];
  179.   void far* Proc;
  180.   struct TInstanceThunk Thunks[34];
  181. };
  182.  
  183. static uint16              ThunkBlockList = 0;
  184. static TInstanceThunk far* ThunkFreeList = 0;
  185.  
  186. WNDPROC
  187. CreateInstanceThunk(TWindow* w, TThunkProc thunkProc)
  188. {
  189.   char                blockCode[5];
  190.   TThunkBlock far*    block;
  191.   TInstanceThunk far* thunk;
  192.   WNDPROC             objInstance;
  193.  
  194.   // POP BX
  195.   //
  196.   blockCode[0] = 0x5b;
  197.  
  198.   // LES BX, CS:[BX]
  199.   //
  200.   blockCode[1] = 0x2e;
  201.   blockCode[2] = 0xc4;
  202.   blockCode[3] = 0x1f;
  203.  
  204.   // JMP FAR StdWndProc
  205.   //
  206.   blockCode[4] = 0xea;
  207.  
  208.   if (!ThunkFreeList) {
  209.  
  210. #if 1
  211.     // Attempt to allocate the memory via an indirect call to 'GlobalAlloc'
  212.     // This allows us to bypass memory trackers which will report that the 
  213.     // memory was never freed. Indeed, the memory is never 'GlobalFree'ed
  214.     // but that's because the DATA is turned into a CODE selector via
  215.     // AllocCStoDSAlias and then cleaned up via a call to 'FreeSelector'.
  216.     //
  217.     typedef HGLOBAL   WINAPI (*pfnGblAlloc)(UINT, DWORD);
  218.     typedef VOID FAR* WINAPI (*pfnGblLock) (HGLOBAL);
  219.  
  220.     static pfnGblAlloc gblAlloc =(pfnGblAlloc)GetProcAddress(GetModuleHandle("KERNEL"), "GlobalAlloc");
  221.     static pfnGblLock  gblLock  =(pfnGblLock)GetProcAddress(GetModuleHandle("KERNEL"), "GlobalLock");
  222.  
  223.     CHECK(gblAlloc);
  224.     CHECK(gblLock);
  225.  
  226.     HGLOBAL hndl = gblAlloc ? (*gblAlloc)(GMEM_FIXED | GMEM_SHARE | GMEM_NOT_BANKED,
  227.                                           sizeof(TThunkBlock)) :
  228.                               GlobalAlloc(GMEM_FIXED | GMEM_SHARE | GMEM_NOT_BANKED,
  229.                                           sizeof(TThunkBlock));
  230.     block = (TThunkBlock far*)(gblLock ? (*gblLock)(hndl) : GlobalLock(hndl));
  231. #else
  232.  
  233.     block = (TThunkBlock far*)GlobalLock(GlobalAlloc(GMEM_FIXED | GMEM_SHARE | GMEM_NOT_BANKED,
  234.                                          sizeof(TThunkBlock)));
  235. #endif
  236.  
  237.     block->Next = ThunkBlockList;
  238.     memcpy(block->Code, blockCode, 5);
  239.     block->Proc = (void far*)thunkProc;
  240.     thunk = block->Thunks;
  241.  
  242.     do {
  243.       thunk->Code = 0xE8;
  244.       thunk->Offset = (2 - 3) - FP_OFF(thunk);
  245.       thunk->ptr.Next = ThunkFreeList;
  246.       ThunkFreeList = thunk;
  247.       thunk = (TInstanceThunk far*)MK_FP(
  248.                     FP_SEG(thunk),
  249.                     FP_OFF(thunk)+sizeof(TInstanceThunk)
  250.                  );
  251.     } while (FP_OFF(thunk) != sizeof(TThunkBlock));
  252.  
  253.     ThunkBlockList = FP_SEG(block);
  254.     PrestoChangoSelector(FP_SEG(block), FP_SEG(block));
  255.   }
  256.  
  257.   objInstance = (WNDPROC)ThunkFreeList;
  258.   thunk = (TInstanceThunk far*)MK_FP(AllocCSToDSAlias(FP_SEG(ThunkFreeList)),
  259.                                                       FP_OFF(ThunkFreeList));
  260.   ThunkFreeList = thunk->ptr.Next;
  261.   thunk->ptr.Window = (TWindow far*)w;
  262.   FreeSelector(FP_SEG(thunk));
  263.   return objInstance;
  264. }
  265.  
  266. void
  267. FreeInstanceThunk(WNDPROC proc)
  268. {
  269.   TInstanceThunk far* thunk =
  270.     (TInstanceThunk far*)MK_FP(AllocCSToDSAlias(FP_SEG(proc)), FP_OFF(proc));
  271.  
  272.   thunk->ptr.Next = ThunkFreeList;
  273.   FreeSelector(FP_SEG(thunk));
  274.   ThunkFreeList = (TInstanceThunk far*)proc;
  275. }
  276.  
  277. #endif  // BI_PLAT_XXX
  278.