Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

386 lines
11 KiB

  1. //*****************************************************************************
  2. //
  3. // SUBCLASSING -
  4. //
  5. // Support for subclassing of 32bit standard (predefined) classes by
  6. // WOW apps.
  7. //
  8. //
  9. // 01-10-92 NanduriR Created.
  10. //
  11. //*****************************************************************************
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. MODNAME(wsubcls.c);
  15. VPVOID vptwpFirst = (VPVOID)NULL;
  16. BOOL ConstructThunkWindowProc(
  17. LPTWPLIST lptwp,
  18. VPVOID vptwp
  19. ) {
  20. /*
  21. ** This is the code which would build a thunk window proc but since we already
  22. ** have code like this laying around (button window proc thunk) we can just
  23. ** copy it. This also saves us from having to know things like the DGROUP
  24. ** of USER16, or the address of the 16-bit CallWindowProc function.
  25. **
  26. ** lptwp->Code[0x00] = 0x45; inc bp
  27. ** lptwp->Code[0x01] = 0x55; push bp
  28. ** lptwp->Code[0x02] = 0x8B; mov bp,sp
  29. ** lptwp->Code[0x03] = 0xEC;
  30. ** lptwp->Code[0x04] = 0x1E; push ds
  31. ** lptwp->Code[0x05] = 0xB8; mov ax,DGROUP
  32. ** lptwp->Code[0x06] = LOBYTE(USER_DGROUP);
  33. ** lptwp->Code[0x07] = HIBYTE(USER_DGROUP);
  34. ** lptwp->Code[0x08] = 0x8E; mov ds,ax
  35. ** lptwp->Code[0x09] = 0xD8;
  36. ** lptwp->Code[0x0A] = 0xB8; mov ax,OFFSET BUTTONWNDPROC
  37. ** lptwp->Code[0x0B] = LOBYTE(LOWORD(ThunkProc16));
  38. ** lptwp->Code[0x0C] = HIBYTE(LOWORD(ThunkProc16));
  39. ** lptwp->Code[0x0D] = 0xBA; mov dx,SEG BUTTONWNDPROC
  40. ** lptwp->Code[0x0E] = LOBYTE(HIWORD(ThunkProc16));
  41. ** lptwp->Code[0x0F] = HIBYTE(HIWORD(ThunkProc16));
  42. ** lptwp->Code[0x10] = 0x52; push dx
  43. ** lptwp->Code[0x11] = 0x50; push ax
  44. ** lptwp->Code[0x12] = 0xFF; push WORD PTR [bp+14] ;hwnd
  45. ** lptwp->Code[0x13] = 0x76;
  46. ** lptwp->Code[0x14] = 0x0E;
  47. ** lptwp->Code[0x15] = 0xFF; push WORD PTR [bp+12] ;messag
  48. ** lptwp->Code[0x16] = 0x76;
  49. ** lptwp->Code[0x17] = 0x0C;
  50. ** lptwp->Code[0x18] = 0xFF; push WORD PTR [bp+10] ;wParam
  51. ** lptwp->Code[0x19] = 0x76;
  52. ** lptwp->Code[0x1A] = 0x0A;
  53. ** lptwp->Code[0x1B] = 0xFF; push WORD PTR [bp+8]
  54. ** lptwp->Code[0x1C] = 0x76;
  55. ** lptwp->Code[0x1D] = 0x08;
  56. ** lptwp->Code[0x1E] = 0xFF; push WORD PTR [bp+6] ;lParam
  57. ** lptwp->Code[0x1F] = 0x76;
  58. ** lptwp->Code[0x20] = 0x06;
  59. ** lptwp->Code[0x21] = 0x9A; call FAR PTR CALLWINDOWPROC
  60. ** lptwp->Code[0x22] = LOBYTE(LOWORD(CallWindowProc16));
  61. ** lptwp->Code[0x23] = HIBYTE(LOWORD(CallWindowProc16));
  62. ** lptwp->Code[0x24] = LOBYTE(HIWORD(CallWindowProc16));
  63. ** lptwp->Code[0x25] = HIBYTE(HIWORD(CallWindowProc16));
  64. ** lptwp->Code[0x26] = 0x4D; dec bp
  65. ** lptwp->Code[0x27] = 0x4D; dec bp
  66. ** lptwp->Code[0x28] = 0x8B; mov sp,bp
  67. ** lptwp->Code[0x29] = 0xE5; dec bp
  68. ** lptwp->Code[0x2A] = 0x1F; pop ds
  69. ** lptwp->Code[0x2B] = 0x5D; pop bp
  70. ** lptwp->Code[0x2C] = 0x4D; dec bp
  71. ** lptwp->Code[0x2D] = 0xCA; ret 10
  72. ** lptwp->Code[0x2E] = 0x0A;
  73. ** lptwp->Code[0x2F] = 0x00;
  74. */
  75. VPVOID vpfn;
  76. LPVOID lpfn;
  77. VPVOID vpProc16;
  78. /*
  79. ** Get the proc address of the Button Window Proc thunk
  80. */
  81. vpfn = GetStdClassThunkProc( WOWCLASS_BUTTON );
  82. if ( vpfn == (VPVOID)NULL ) {
  83. return( FALSE );
  84. }
  85. /*
  86. ** Now copy it into our thunk
  87. */
  88. GETVDMPTR( vpfn, THUNKWP_SIZE, lpfn);
  89. RtlCopyMemory( lptwp->Code, lpfn, THUNKWP_SIZE );
  90. FREEVDMPTR( lpfn );
  91. /*
  92. ** Patch the "our address" pointer
  93. */
  94. vpProc16 = (VPVOID)((DWORD)vptwp + FIELD_OFFSET(TWPLIST,Code[0]));
  95. lptwp->Code[0x0B] = LOBYTE(LOWORD(vpProc16));
  96. lptwp->Code[0x0C] = HIBYTE(LOWORD(vpProc16));
  97. lptwp->Code[0x0E] = LOBYTE(HIWORD(vpProc16));
  98. lptwp->Code[0x0F] = HIBYTE(HIWORD(vpProc16));
  99. /*
  100. ** Initialize the rest of the TWPLIST structure
  101. */
  102. lptwp->lpfn32 = 0;
  103. lptwp->vpfn16 = vpProc16;
  104. lptwp->vptwpNext = (VPVOID)NULL;
  105. lptwp->hwnd32 = (HWND)0;
  106. lptwp->dwMagic = SUBCLASS_MAGIC;
  107. return( TRUE );
  108. }
  109. DWORD GetThunkWindowProc(
  110. DWORD lpfn32,
  111. LPSTR lpszClass,
  112. PWW pww,
  113. HWND hwnd32
  114. ) {
  115. VPVOID vptwp;
  116. LPTWPLIST lptwp;
  117. INT count;
  118. DWORD dwResult;
  119. BOOL fOk;
  120. VPVOID vpAvail = (VPVOID)NULL;
  121. INT iClass;
  122. // Dont try to thunk a NULL 32-bit proc.
  123. if (!lpfn32) {
  124. LOGDEBUG(2, ("WOW:GetThunkWindowProc: attempt to thunk NULL proc\n"));
  125. return 0;
  126. }
  127. // the input is either lpstrClass or pww. One of them is always NULL.
  128. if (lpszClass != NULL) {
  129. iClass = GetStdClassNumber(lpszClass);
  130. }
  131. else {
  132. iClass = GETICLASS(pww, hwnd32);
  133. }
  134. if ( iClass == WOWCLASS_WIN16 ) {
  135. DWORD dwpid;
  136. // iClass == WOWCLASS_WIN16 implies that hwnd could either be a 32bit
  137. // window belonging to a WOW process (like Ole windows) or a window of
  138. // a different process. If it is the former return a stub proc
  139. // else return 0;
  140. if (!(GetWindowThreadProcessId(hwnd32,&dwpid) &&
  141. (dwpid == GetCurrentProcessId()))){
  142. LOGDEBUG(LOG_ALWAYS, ("WOW:GetThunkWindowProc: class unknown\n"));
  143. return 0;
  144. }
  145. } else {
  146. //
  147. // If they are subclassing one of the standard classes, and they
  148. // are doing it for the 1st time, then return the address of the
  149. // hardcoded thunk in USER16.
  150. //
  151. if ( lpfn32 == (DWORD)GetStdClassWndProc(iClass) ) {
  152. dwResult = GetStdClassThunkProc(iClass);
  153. return( dwResult );
  154. }
  155. }
  156. /*
  157. ** Scan the list for available TWPLIST entries or duplicates
  158. */
  159. vptwp = vptwpFirst;
  160. while ( vptwp != (VPVOID)NULL ) {
  161. GETVDMPTR( vptwp, sizeof(TWPLIST), lptwp );
  162. if ( lptwp->lpfn32 == 0 && vpAvail == (VPVOID)NULL ) {
  163. vpAvail = vptwp;
  164. }
  165. //
  166. // If we find that we've already subclassed this proc32
  167. // then return that thunk proc again.
  168. //
  169. if ( lptwp->lpfn32 == lpfn32 ) {
  170. dwResult = (DWORD)lptwp->vpfn16;
  171. FREEVDMPTR( lptwp );
  172. return( dwResult );
  173. }
  174. vptwp = lptwp->vptwpNext;
  175. FREEVDMPTR( lptwp );
  176. }
  177. // Obviously we didn't find any duplicate if we got here.
  178. // If we didn't find a slot to reuse, then allocate more.
  179. if ( vpAvail == (VPVOID)NULL ) {
  180. /*
  181. ** No more available slots, allocate some more
  182. */
  183. vptwp = GlobalAllocLock16( GMEM_MOVEABLE,
  184. THUNKWP_BLOCK * sizeof(TWPLIST),
  185. NULL );
  186. if ( vptwp == (VPVOID)NULL ) {
  187. LOGDEBUG( 1, ("GetThunkWindowProc: GlobalAllocLock16 failed to allocate memory\n"));
  188. return( (DWORD)NULL );
  189. }
  190. count = THUNKWP_BLOCK;
  191. while ( count ) {
  192. GETVDMPTR( vptwp, sizeof(TWPLIST), lptwp );
  193. fOk = ConstructThunkWindowProc( lptwp, vptwp );
  194. if ( fOk ) {
  195. /*
  196. ** Insert this thunk window proc into the list
  197. */
  198. lptwp->vptwpNext = vptwpFirst;
  199. vptwpFirst = vptwp;
  200. vpAvail = vptwp;
  201. }
  202. FLUSHVDMPTR( vptwp, sizeof(TWPLIST), lptwp );
  203. FREEVDMPTR( lptwp );
  204. vptwp = (VPVOID)((DWORD)vptwp + sizeof(TWPLIST));
  205. --count;
  206. }
  207. ChangeSelector16( HIWORD(vptwp) ); // Change into a code selector
  208. }
  209. if ( vpAvail != (VPVOID)NULL ) {
  210. /*
  211. ** Use that available slot
  212. */
  213. GETVDMPTR( vpAvail, sizeof(TWPLIST), lptwp );
  214. lptwp->lpfn32 = lpfn32;
  215. lptwp->hwnd32 = hwnd32;
  216. lptwp->iClass = iClass;
  217. dwResult = (DWORD)lptwp->vpfn16;
  218. FLUSHVDMCODEPTR(vpAvail, sizeof(TWPLIST), lptwp);
  219. FREEVDMPTR( lptwp );
  220. return( dwResult );
  221. }
  222. return( (DWORD)NULL );
  223. }
  224. #if 0 // Currently unused
  225. BOOL FreeThunkWindowProc(
  226. DWORD vpProc16
  227. ) {
  228. VPVOID vptwp;
  229. LPTWPLIST lptwp;
  230. /*
  231. ** Scan the list for available TWPLIST entries
  232. */
  233. vptwp = vptwpFirst;
  234. while ( vptwp != (VPVOID)NULL ) {
  235. GETVDMPTR( vptwp, sizeof(TWPLIST), lptwp );
  236. if ( lptwp->vpfn16 == vpProc16 ) {
  237. /*
  238. ** Found slot to free
  239. */
  240. lptwp->lpfn32 = 0;
  241. lptwp->hwnd32 = (HWND)0;
  242. lptwp->iClass = WOWCLASS_UNKNOWN;
  243. FREEVDMPTR( lptwp );
  244. return( TRUE );
  245. }
  246. vptwp = lptwp->vptwpNext;
  247. FREEVDMPTR( lptwp );
  248. }
  249. return( FALSE );
  250. }
  251. void W32FreeThunkWindowProc(
  252. DWORD lpfn32,
  253. DWORD lpfn16
  254. ) {
  255. VPVOID vptwp;
  256. LPTWPLIST lptwp;
  257. /*
  258. ** Scan the list for available TWPLIST entries
  259. */
  260. vptwp = vptwpFirst;
  261. while ( vptwp != (VPVOID)NULL ) {
  262. GETVDMPTR( vptwp, sizeof(TWPLIST), lptwp );
  263. if ( lptwp->lpfn32 == lpfn32 ) {
  264. /*
  265. ** Found slot to free
  266. */
  267. lptwp->lpfn32 = 0;
  268. lptwp->hwnd32 = (HWND)0;
  269. lptwp->iClass = WOWCLASS_UNKNOWN;
  270. FREEVDMPTR( lptwp );
  271. }
  272. vptwp = lptwp->vptwpNext;
  273. FREEVDMPTR( lptwp );
  274. }
  275. }
  276. #endif
  277. DWORD IsThunkWindowProc(
  278. DWORD vpProc16, // IN
  279. PINT piClass // OUT OPTIONAL
  280. ) {
  281. VPVOID vpdw;
  282. DWORD UNALIGNED * lpdw;
  283. DWORD dwResult;
  284. INT iClass;
  285. /* Screen for valid addresses... */
  286. if ( (HIWORD(vpProc16) == 0) || (LOWORD(vpProc16) < (sizeof(DWORD)*3)) ) {
  287. return( 0 );
  288. }
  289. /*
  290. ** If it is a valid sub-class thunk, then it should be preceeded by
  291. ** three dword values. The first is the subclassing magic number,
  292. ** the second is the WOWCLASS_*, the 3rd is the 32-bit proc address.
  293. */
  294. vpdw = (VPVOID)((DWORD)vpProc16 - sizeof(DWORD)*3);
  295. GETVDMPTR( vpdw, sizeof(DWORD)*3, lpdw );
  296. iClass = (INT)*(lpdw+1);
  297. dwResult = *(lpdw+2); // Get the lpfn32 value
  298. if ( *lpdw != SUBCLASS_MAGIC ) {
  299. dwResult = 0; // Zero it if it wasn't valid
  300. iClass = WOWCLASS_WIN16;
  301. } else {
  302. if ( dwResult == 0 ) {
  303. // They cheated and looked up the export from USER.EXE
  304. dwResult = (DWORD) GetStdClassWndProc( iClass );
  305. }
  306. }
  307. if (piClass) {
  308. *piClass = iClass;
  309. }
  310. FREEVDMPTR( lpdw );
  311. return( dwResult );
  312. }