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.

830 lines
30 KiB

  1. /*++
  2. Copyright (c) 2000-2001, Microsoft Corporation All rights reserved.
  3. Module Name:
  4. subclass.c
  5. Abstract:
  6. This file contains functions that support our subclassing efforts. Here is how it works:
  7. Each window we create must be subclassed so we can maintain the illusion of Unicodality
  8. on it. We therefore store a pointer to some memory that contains all of the information
  9. we need to properly call the wndproc, stored in a GODOTWND structure. Since the caller
  10. can actually subclass the window, we need to store a linked list of these structures.
  11. NOTE: From comctl32.dll's SUBCLASS.C:
  12. Win95's property code is BROKEN. If you SetProp using a text string, USER
  13. // adds and removes atoms for the property symmetrically, including when the
  14. // window is destroyed with properties lying around (good). Unfortunately, if
  15. // you SetProp using a global atom, USER doesn't do things quite right in the
  16. // window cleanup case. It uses the atom without adding references in SetProp
  17. // calls and without deleting them in RemoveProp calls (good so far). However,
  18. // when a window with one of these properties lying around is cleaned up, USER
  19. // will delete the atom on you. This tends to break apps that do the
  20. // following:
  21. //
  22. // - MyAtom = GlobalAddAtom("foo"); // at app startup
  23. // - SetProp(SomeWindow, MyAtom, MyData);
  24. // - <window gets destroyed, USER deletes atom>
  25. // - <time passes>
  26. // - SetProp(SomeOtherWindow, MyAtom, MyData); // fails or uses random atom
  27. // - GlobalDeleteAtom(MyAtom); // fails or deletes random atom
  28. In order to avoid this bug in the Win9x property code, we do not store this as an atom,
  29. instead choosing to use an actual string and letting the system do all the work to manage
  30. the propname. We also wrap all of the property functions, both A and W, to fail the
  31. creation, altering, or removal of our one property. This does not solve the problem
  32. completely since they can always work outside Godot and wreak havoc, but we cannot solve
  33. THAT without replacing USER32.DLL on the machine! We still do a call to GlobalAddAtom and
  34. just do a lot of aggressive calls to refcount it this way. Slightly slower perf-wise but
  35. better guarantees!
  36. In order to make sure that the user does not directly have their wndproc called by the
  37. OS (which is not Unicode!), we do not ever directly give them the true wndproc, but
  38. instead we give them a special pointer. Per RaymondC, addresses with 64k of the 2gb
  39. boundary (0x7FFF0000 - 0x7FFFFFFF) are always invalid proc addresses, and we need these IDs
  40. to be invalid so that someone not going through CallWindowProc will fault right away rather
  41. then calling into random memory. The first pointer for each window is always going to be
  42. 0x7FFFFFFF - 1, and each additional subclass a user adds via SetWindowLong will subtract
  43. another number (calculated via CWnd). Since the user never could have more than 64,000
  44. subclasses, this should give us plenty of room. Any time we get a call to our CallWindowProc
  45. wrapper, we route these "GodotID" values appropriately.
  46. Note that we also store DLGPROCs via the same means. No particular GODOTWND will ever have
  47. both a DLGPROC and a WNDPROC in it, but they will always have unique IDs for each one so
  48. we need separate GODOTWNDs here. Which one it is can be determined by the fWndproc member.
  49. When they add a sublass (via SetWindowLong), we add the items to the linked list using a
  50. "PUSH" type operation. The most recent subclass is always on top, and the base subclass
  51. is always on the bottom.
  52. If they unsubclass (call SetWindowLong, passing in one of our own GodotID values) in the
  53. right order as they are supposed to, we simply use a "POP" type operation on our linked list.
  54. If they unsubclass in the wrong order, we have a little extra work to do. An outstanding
  55. caller might still want to call via this (now invalid) godotID! To solve this problem, we
  56. do not delete anything in this case but simply NULL out the userLpfn for this GODOTWND.
  57. Then any time they are looking to call a godotID with no userLpfn, we simply skip down to
  58. the first valid wndproc we can find.
  59. Sometimes, the wndproc we need to call is expecting ANSI. Perhaps they subclassed via
  60. SetWindowLongA, or perhaps it is the original wndproc of a system class (so that the actual
  61. wndproc comes from user32.dll or worse from user.exe!). Therefore we store whether the
  62. prop is expecting Unicode or ANSI values.
  63. Functions found in this file:
  64. InitWindow
  65. CleanupWindow
  66. GetWindowLongInternal
  67. SetWindowLongInternal
  68. FauxWndProcOfHwnd
  69. GetUnicodeWindowProp
  70. DoesWndprocExpectAnsi
  71. WndprocFromFauxWndproc
  72. IsSystemClass
  73. CWnd
  74. Revision History:
  75. 28 Feb 2001 v-michka Created.
  76. --*/
  77. #include "precomp.h"
  78. //
  79. // The wnd structure. We store a linked list of these, per window.
  80. // In our most optimal case, this is a list with just one wnd in it.
  81. // WARNING: This structure should be DWORD-aligned!
  82. // WARNING: Do not ever change this structure in a way that would break old clients!!!
  83. //
  84. struct GODOTWND
  85. {
  86. WNDPROC userLpfn; // the lpfn to be calling
  87. UINT godotID; // the fake pointer we hand to the user
  88. BYTE fUnicode : 1; // Is the user lpfn expecting Unicode? All but system wndprocs should
  89. BYTE fWndproc : 1; // wndproc or dlgproc in the userLpfn member?
  90. BYTE bVersion : 8; // Version of the structure, will be 0 for now.
  91. ULONG Reserved : 22; // RESERVED for future use
  92. struct GODOTWND* next; // Pointer to the next GODOTWND to chain to
  93. };
  94. // We keep UNICODE and ANSI versions of this string for ease of comparison.
  95. // Since we never support the user mucking with (or even seeing!) these
  96. // properties, and we do not want to have to convert the string just to
  97. // support the comparisons that we have to do.
  98. // WARNING: You must keep these two strings in synch!!!
  99. const char m_szMemBlock[] = "GodotMemoryBlock";
  100. const WCHAR m_wzMemBlock[] = L"GodotMemoryBlock";
  101. ATOM m_aMemBlock;
  102. const WCHAR c_wzCaptureClass[] = L"ClsCapWin";
  103. const WCHAR c_wzOleaut32Class[] = L"OLEAUT32";
  104. // our own hack ANSI class
  105. #define ANSIWINDOWCLASS (LPWSTR)0x00000001
  106. // some external forward declares
  107. int __stdcall GodotGetClassNameW(HWND hWnd, LPWSTR lpClassName, int nMaxCount);
  108. // our forward declares
  109. /*BOOL IsAnAnsiClass(LPCWSTR lpszClass);*/
  110. int CWnd(struct GODOTWND* head);
  111. /*-------------------------------
  112. IsInternalWindowProperty
  113. // If this is our special wnd prop for the memory
  114. // handle, return FALSE
  115. -------------------------------*/
  116. BOOL IsInternalWindowProperty(LPCWSTR lpsz, BOOL fUnicode)
  117. {
  118. if(FSTRING_VALID(lpsz))
  119. {
  120. if(fUnicode)
  121. return(CompareHelper((LPCWSTR)m_wzMemBlock, lpsz, FALSE) == 0);
  122. else
  123. return((lstrcmpiA((LPCSTR)m_szMemBlock, (LPCSTR)lpsz) == 0));
  124. }
  125. else
  126. return(MAKEINTATOM(lpsz) == MAKEINTATOM(m_aMemBlock));
  127. }
  128. /*-------------------------------
  129. InitWindow
  130. Create the first GODOTWND for the window. Assumes that the lpfn passed
  131. in is (in fact) the subclass.
  132. We use lpszClass to find out whether this is an ANSI or a Unicode window:
  133. 1) If the caller passes ANSIWINDOWCLASS then we are sure it is ANSI
  134. 2) If the caller is being lazy and passes NULL, then we find out the class name
  135. 3) If they pass the class name, we check it
  136. NOTE: We do not put critical sections here because only the
  137. creating thread of a window can ever really initialize
  138. the window with us. Kind of a built-in guard.
  139. -------------------------------*/
  140. BOOL InitWindow(HWND hwnd, LPCWSTR lpszClass)
  141. {
  142. if(GetPropA(hwnd, m_szMemBlock) != 0)
  143. {
  144. // Why get called twice? The only case where this ought
  145. // to happen is child controls of dialogs that are created
  146. // by the caller prior to WM_INITDIALOG. We can just skip
  147. // out in that case.
  148. return(FALSE);
  149. }
  150. else
  151. {
  152. BOOL fUnicode = TRUE;
  153. struct GODOTWND* newWnd;
  154. if(!FSTRING_VALID(lpszClass))
  155. {
  156. // no class name given; lets get it the hard way
  157. WCHAR * wzClassName[128]; // ATOM max is 255 bytes
  158. int cchClassName;
  159. ZeroMemory((LPWSTR)wzClassName, 128);
  160. cchClassName = GodotGetClassNameW(hwnd, (LPWSTR)wzClassName, 128);
  161. wzClassName[cchClassName - 1] = 0;
  162. if(lpszClass == ANSIWINDOWCLASS)
  163. {
  164. // This is our hack flag that indicates that the caller
  165. // is assuring us that this is an ANSI wndproc.
  166. if(gwcscmp(c_wzOleaut32Class, (LPWSTR)wzClassName) == 0)
  167. {
  168. // The un-subclass-able window
  169. return(FALSE);
  170. }
  171. fUnicode = FALSE;
  172. }
  173. else
  174. {
  175. if(gwcscmp(c_wzCaptureClass, (LPWSTR)wzClassName) == 0)
  176. {
  177. // Its a capture window, so lets remember this for all time
  178. SetCaptureWindowProp(hwnd);
  179. }
  180. fUnicode = TRUE;
  181. }
  182. }
  183. newWnd = GodotHeapAlloc(sizeof(struct GODOTWND));
  184. if(newWnd)
  185. {
  186. newWnd->fWndproc = TRUE;
  187. newWnd->godotID = ZEORETHGODOTWND - 1;
  188. // Do the subclass
  189. newWnd->userLpfn = (WNDPROC)SetWindowLongA(hwnd, GWL_WNDPROC, (LONG)&WindowProc);
  190. // Is this a Unicode proc? Well, it is if we have
  191. // not already decided it is an ANSI proc and if
  192. // the actual proc is in the upper 2gb of virtual
  193. // mem reserved for the system.
  194. // CONSIDER: This assumption might suck if a true
  195. // system component ever used Godot!
  196. newWnd->fUnicode = (BYTE)(fUnicode && ((UINT)newWnd->userLpfn < LOWESTSYSMEMLOC));
  197. newWnd->next = NULL;
  198. // We have to aggressively refcount our prop to keep anyone from
  199. // losing it. Thus we do an initial GlobalAddAtom on it and then
  200. // subsequently call SetPropA on it with the same string.
  201. if(!m_aMemBlock)
  202. m_aMemBlock = GlobalAddAtomA(m_szMemBlock);
  203. // Tag the window with the prop that
  204. // contains our GODOTWND linked list
  205. if(SetPropA(hwnd, m_szMemBlock, (HANDLE)newWnd))
  206. {
  207. return(TRUE);
  208. }
  209. }
  210. // If we make it here, then something crucial failed
  211. if(newWnd)
  212. GodotHeapFree(newWnd);
  213. return(FALSE);
  214. }
  215. }
  216. /*-------------------------------
  217. CleanupWindow
  218. We need to make sure we get rid of all the members of
  219. the linked list that we alloc'ed. The window is being
  220. destroyed.
  221. -------------------------------*/
  222. BOOL CleanupWindow(HWND hwnd)
  223. {
  224. struct GODOTWND* current;
  225. struct GODOTWND* next;
  226. BOOL RetVal;
  227. __try
  228. {
  229. EnterCriticalSection(&g_csWnds);
  230. current = GetPropA(hwnd, m_szMemBlock);
  231. while (current != NULL)
  232. {
  233. next = current->next;
  234. GodotHeapFree(current);
  235. current = next;
  236. }
  237. // If this is a common dlg, then the prop must be removed.
  238. RemoveComdlgPropIfPresent(hwnd);
  239. // We must do this remove; if not, then we will be causing the
  240. // prop to be cleaned up by the system and will ruin the other
  241. // windows out there.
  242. RetVal = (RemovePropA(hwnd, m_szMemBlock) != NULL);
  243. }
  244. __finally
  245. {
  246. LeaveCriticalSection(&g_csWnds);
  247. }
  248. return(RetVal);
  249. }
  250. /*-------------------------------
  251. GetWindowLongInternal
  252. Our own internal version of GetWindowLong, which returns a godotID for both WNDPROC and
  253. DLGPROC subclasses. If the window is not one of ours, then we just yield to the actual
  254. GetWindowLong. If, however, it is one our windows but we do not have a subclass in place
  255. (should only be possible for cases such as nIndex==DWL_DLGPROC on non-dialogs) then we
  256. return 0 and set last error to ERROR_INVALID_INDEX, just like the API would do.
  257. -------------------------------*/
  258. LONG GetWindowLongInternal(HWND hwnd, int nIndex, BOOL fUnicode)
  259. {
  260. if(nIndex==GWL_WNDPROC || nIndex==DWL_DLGPROC)
  261. {
  262. struct GODOTWND* current;
  263. LONG RetVal = 0;
  264. __try
  265. {
  266. EnterCriticalSection(&g_csWnds);
  267. current = GetPropA(hwnd, m_szMemBlock);
  268. if(current == NULL)
  269. {
  270. // No list, so we assume this is not one of our windows
  271. RetVal = GetWindowLongA(hwnd, nIndex);
  272. }
  273. else
  274. {
  275. // The top relevant proc must always be valid, so we
  276. // can just return it. Note that we always return the
  277. // GodotID, for both dlgprocs and wndprocs.
  278. while(current)
  279. {
  280. if(((nIndex==GWL_WNDPROC) && current->fWndproc) ||
  281. ((nIndex==DWL_DLGPROC) && !current->fWndproc))
  282. {
  283. RetVal = (LONG)current->godotID;
  284. break;
  285. }
  286. current = current->next;
  287. }
  288. }
  289. }
  290. __except( EXCEPTION_EXECUTE_HANDLER )
  291. {
  292. RetVal = 0;
  293. }
  294. LeaveCriticalSection(&g_csWnds);
  295. if(RetVal==0)
  296. SetLastError(ERROR_INVALID_INDEX);
  297. return(RetVal);
  298. }
  299. else
  300. {
  301. // No wrapper needed for non-wndproc calls
  302. return(GetWindowLongA(hwnd, nIndex));
  303. }
  304. }
  305. /*-------------------------------
  306. SetWindowLongInternal
  307. Our own internal version of SetWindowLong, which does the right thing with subclassing both
  308. WNDPROCs and DLGPROCs. Note that the only time we ever *change* the actual subclass that
  309. Windows knows of is when someone subclasses a window that we did not create. Then in the case
  310. of a SetWindowLongA call we just leave it to the API, or in the SetWindowLongW case we hook
  311. up the window, starting with an ANSI proc (which is what should be there now). Otherwise, our
  312. own wndproc is already in charge and the only thing that we do is shuffle who we plan to
  313. call later.
  314. We always return real WNDPROCs when removing a subclass, and godotIDs when adding one.
  315. -------------------------------*/
  316. LONG SetWindowLongInternal(HWND hwnd, int nIndex, LONG dwNewLong, BOOL fUnicode)
  317. {
  318. if(nIndex==GWL_WNDPROC || nIndex==DWL_DLGPROC)
  319. {
  320. struct GODOTWND* head;
  321. LONG RetVal;
  322. BOOL fWndproc; // wndproc or dlgproc?
  323. DWORD dwProcessId = 0;
  324. GetWindowThreadProcessId(hwnd, &dwProcessId);
  325. if(GetCurrentProcessId() != dwProcessId)
  326. {
  327. // Not legal to cross the process boundary on a subclass
  328. SetLastError(ERROR_INVALID_WINDOW_HANDLE);
  329. return(0);
  330. }
  331. // No one can muck with wndprocs until we are done here
  332. EnterCriticalSection(&g_csWnds);
  333. RetVal = 0;
  334. fWndproc = (nIndex==GWL_WNDPROC);
  335. head = GetPropA(hwnd, m_szMemBlock);
  336. if(head == NULL)
  337. {
  338. // No list, so assume this is not (yet?) one of our windows.
  339. // If they called SetWindowLongA then we will yield to the API's wisdom.
  340. if(!fUnicode)
  341. {
  342. RetVal = SetWindowLongA(hwnd, nIndex, dwNewLong);
  343. LeaveCriticalSection(&g_csWnds);
  344. return(RetVal);
  345. }
  346. // We will now try hook up this ANSI window
  347. if(!InitWindow(hwnd, ANSIWINDOWCLASS))
  348. {
  349. // Window init failed, so we need to fail the subclass.
  350. SetLastError(ERROR_OUTOFMEMORY);
  351. LeaveCriticalSection(&g_csWnds);
  352. return(RetVal);
  353. }
  354. else
  355. {
  356. // This is a new subclass proc! We will create a Unicode
  357. // one atop the ANSI one that was just created.
  358. struct GODOTWND* current = GodotHeapAlloc(sizeof(struct GODOTWND));
  359. if(current == NULL)
  360. {
  361. // Cannot allocate, so bail.
  362. CleanupWindow(hwnd);
  363. SetLastError(ERROR_OUTOFMEMORY);
  364. LeaveCriticalSection(&g_csWnds);
  365. return(RetVal);
  366. }
  367. else
  368. {
  369. head = GetPropA(hwnd, m_szMemBlock);
  370. // Lets fill up the new structure
  371. current->userLpfn = (WNDPROC)dwNewLong;
  372. current->fWndproc = (BYTE)fWndproc;
  373. current->godotID = ZEORETHGODOTWND - (CWnd(head) + 1);
  374. current->fUnicode = (BYTE)fUnicode;
  375. current->next = head;
  376. SetPropA(hwnd, m_szMemBlock, (HANDLE)current);
  377. RetVal = current->next->godotID;
  378. LeaveCriticalSection(&g_csWnds);
  379. return(RetVal);
  380. }
  381. }
  382. }
  383. else
  384. {
  385. if(INSIDE_GODOT_RANGE(dwNewLong))
  386. {
  387. // This is one of our faux windows, so they are unsubclassing.
  388. struct GODOTWND* current = head;
  389. struct GODOTWND* next = current->next;
  390. if((next != NULL) &&
  391. (next->godotID == dwNewLong) &&
  392. (next->fWndproc == fWndproc))
  393. {
  394. // Must handle the "head" case separately:
  395. // basically it's just a pop operation.
  396. RetVal = (LONG)current->userLpfn;
  397. GodotHeapFree(current);
  398. // CONSIDER: If they unsubclassed out of order, then
  399. // this next godotID might not be valid. We could
  400. // clean up this (next->userLpfn == NULL) case now?
  401. SetPropA(hwnd, m_szMemBlock, (HANDLE)next);
  402. LeaveCriticalSection(&g_csWnds);
  403. return(RetVal);
  404. }
  405. while(current != NULL)
  406. {
  407. next = current->next;
  408. // Make sure there is a "next" wndproc, that it is
  409. // both the proc and proctypethat we want
  410. if((next != NULL) &&
  411. (next->godotID == dwNewLong) &&
  412. (next->fWndproc == fWndproc))
  413. {
  414. // We do not free it up since it is not at the head.
  415. // It will be zombied by having a NULL userLpfn.
  416. RetVal = (LONG)next->userLpfn;
  417. current->userLpfn = NULL;
  418. LeaveCriticalSection(&g_csWnds);
  419. return(RetVal);
  420. }
  421. current = current->next;
  422. }
  423. // We never found it. Let the user know their call failed.
  424. // Note that this will handle cases we could have detected
  425. // such as trying to unsubclass the true head, trying to
  426. // unsubclass a dlgproc with a wndproc nIndex, etc. Since
  427. // they all get the same error, there was just no need.
  428. SetLastError(ERROR_INVALID_PARAMETER);
  429. RetVal = 0;
  430. LeaveCriticalSection(&g_csWnds);
  431. return(RetVal);
  432. }
  433. else
  434. {
  435. // This is a new subclass proc!
  436. struct GODOTWND* current = GodotHeapAlloc(sizeof(struct GODOTWND));
  437. if(current == NULL)
  438. {
  439. // Cannot allocate, so bail.
  440. SetLastError(ERROR_OUTOFMEMORY);
  441. LeaveCriticalSection(&g_csWnds);
  442. return(RetVal);
  443. }
  444. else
  445. {
  446. // The original subclass window stays the same, we just put the
  447. // new info into the linked list. We basically just do a push
  448. // on it so it is at the head. The extra SetProp here will keep
  449. // us from (hopefully) running into Win9x property bugs.
  450. current->userLpfn = (WNDPROC)dwNewLong;
  451. current->fWndproc = (BYTE)fWndproc;
  452. current->godotID = ZEORETHGODOTWND - (CWnd(head) + 1);
  453. current->fUnicode = (BYTE)fUnicode;
  454. current->next = head;
  455. SetPropA(hwnd, m_szMemBlock, (HANDLE)current);
  456. // Ok, make sure we return the right previous proc
  457. // based on what type of proc they asked to replace.
  458. current = current->next;
  459. while(current)
  460. {
  461. if((fWndproc == current->fWndproc) &&
  462. (current->userLpfn))
  463. {
  464. RetVal = (LONG)current->godotID;
  465. break;
  466. }
  467. current = current->next;
  468. }
  469. LeaveCriticalSection(&g_csWnds);
  470. return(RetVal);
  471. }
  472. }
  473. }
  474. }
  475. else
  476. {
  477. // Its not even for a wndproc, so we will just ask the OS
  478. return(SetWindowLongA(hwnd, nIndex, dwNewLong));
  479. }
  480. }
  481. /*-------------------------------
  482. GetUnicodeWindowProp
  483. Returns TRUE if this window has
  484. the UNICODE window prop set.
  485. -------------------------------*/
  486. BOOL GetUnicodeWindowProp(HWND hwnd)
  487. {
  488. struct GODOTWND* current = GetPropA(hwnd, m_szMemBlock);
  489. return(current != NULL);
  490. }
  491. /*-------------------------------
  492. DoesProcExpectAnsi
  493. Returns TRUE if the proc for the window is the one provided
  494. by the system by default, or if we marked as ANSI for any other
  495. reason. Note that this proc can accept a *real* wndproc rather
  496. than a GodotID here; we detect either case.
  497. -------------------------------*/
  498. BOOL DoesProcExpectAnsi(HWND hwnd, WNDPROC godotID, FAUXPROCTYPE fpt)
  499. {
  500. struct GODOTWND* wnd;
  501. BOOL RetVal = TRUE;
  502. __try
  503. {
  504. EnterCriticalSection(&g_csWnds);
  505. wnd = GetPropA(hwnd, m_szMemBlock);
  506. if(wnd==NULL)
  507. {
  508. RetVal = TRUE;
  509. }
  510. else if(wnd && (godotID == 0))
  511. {
  512. while(wnd != NULL)
  513. {
  514. // UNDONE: What do we do in the (fpt==fptUnknown && godotID==0) case?
  515. if(((fpt==fptWndproc && wnd->fWndproc) ||
  516. (fpt==fptDlgproc && !wnd->fWndproc)) &&
  517. (wnd->userLpfn))
  518. {
  519. RetVal = !wnd->fUnicode;
  520. break;
  521. }
  522. wnd = wnd->next;
  523. }
  524. }
  525. else
  526. {
  527. while(wnd != NULL)
  528. {
  529. if(((INSIDE_GODOT_RANGE(godotID)) && (wnd->godotID == (UINT)godotID)) ||
  530. ((OUTSIDE_GODOT_RANGE(godotID)) && wnd->userLpfn == godotID))
  531. {
  532. while(wnd != NULL)
  533. {
  534. if(wnd->userLpfn)
  535. {
  536. RetVal = !wnd->fUnicode;
  537. break;
  538. }
  539. wnd = wnd->next;
  540. }
  541. break;
  542. }
  543. wnd = wnd->next;
  544. }
  545. }
  546. }
  547. __except( EXCEPTION_EXECUTE_HANDLER )
  548. {
  549. RetVal = TRUE;
  550. }
  551. LeaveCriticalSection(&g_csWnds);
  552. return(RetVal);
  553. }
  554. /*-------------------------------
  555. WndprocFromFauxWndproc
  556. Given a Godot ID, return a valid wndproc. Returns
  557. the original faux wndproc if it cannot find a valid
  558. real one (probably due to there not being one!).
  559. -------------------------------*/
  560. WNDPROC WndprocFromFauxWndproc(HWND hwnd, WNDPROC fauxLpfn, FAUXPROCTYPE fpt)
  561. {
  562. struct GODOTWND* wnd;
  563. WNDPROC RetVal = fauxLpfn;
  564. __try
  565. {
  566. EnterCriticalSection(&g_csWnds);
  567. wnd = GetPropA(hwnd, m_szMemBlock);
  568. if(fauxLpfn == 0)
  569. {
  570. // A "0" faux lpfn is a signal to just
  571. // pass back the top valid userLpfn.
  572. while(wnd != NULL)
  573. {
  574. if(((fpt==fptWndproc) && (wnd->fWndproc)) ||
  575. ((fpt==fptDlgproc) && (!wnd->fWndproc)))
  576. {
  577. RetVal = wnd->userLpfn;
  578. break;
  579. }
  580. wnd = wnd->next;
  581. }
  582. }
  583. else if(OUTSIDE_GODOT_RANGE(fauxLpfn))
  584. {
  585. // Not a faux wndproc, so we will just return
  586. // what was passed in, and assume it is valid
  587. }
  588. else
  589. {
  590. // We iterate through our GODOTWND
  591. // linked list, looking for a match.
  592. while (wnd != NULL)
  593. {
  594. if(wnd->godotID == (UINT)fauxLpfn)
  595. {
  596. // Found it!!! Now we have to make sure it
  597. // is still a valid one (i.e. that user has
  598. // not unsubclassed out of order!)
  599. while ((wnd != NULL) &&
  600. (((fpt==fptWndproc) && (wnd->fWndproc)) ||
  601. ((fpt==fptDlgproc) && (!wnd->fWndproc))) ||
  602. ((fpt==fptUnknown) && (wnd->userLpfn == NULL)))
  603. wnd=wnd->next;
  604. break;
  605. }
  606. wnd = wnd->next;
  607. }
  608. // If we do not have a wnd at this point, then there was no
  609. // likely candidate, so return the caller's faux wndproc.
  610. // Otherwiwe, pass the one we found.
  611. if(wnd != NULL)
  612. RetVal = wnd->userLpfn;
  613. }
  614. }
  615. __except( EXCEPTION_EXECUTE_HANDLER )
  616. {
  617. RetVal = fauxLpfn;
  618. }
  619. LeaveCriticalSection(&g_csWnds);
  620. return(RetVal);
  621. }
  622. /*-------------------------------
  623. CWnd
  624. How big is this GODOTWND linked list?
  625. -------------------------------*/
  626. int CWnd(struct GODOTWND* head)
  627. {
  628. int count = 0;
  629. struct GODOTWND* current;
  630. current = head;
  631. for (current = head; current != NULL; current = current->next)
  632. {
  633. count++;
  634. }
  635. return(count);
  636. }
  637. /*
  638. // A little system classes struct
  639. struct ANSICLASS {
  640. WCHAR * wzName;
  641. };
  642. // These are all the documented system classes. Also, for Toolbar windows, we
  643. // need to mark the Unicodality as FALSE, since MFC uses the SetWindowText and
  644. // GetWindowText APIs for its custom draw min-caption-like things for floating
  645. // toolbars. This is only the low level wndproc which will get this setting,
  646. // so it should not adversely affect anyone.
  647. // The other common controls are added just in case anyone ELSE overloads msgs
  648. // such as window titles for their own purposes the way that MFC decided to do.
  649. // BASE SYSTEM CLASSES are marked with an asterick.
  650. struct ANSICLASS m_rgwzAnsiClasses[] = {
  651. {L"#32768"}, // *#32768
  652. {L"#32769"}, // *#32769
  653. {L"#32770"}, // *#32770
  654. {L"#32771"}, // *#32771
  655. {WC_BUTTONW}, // *Button
  656. {WC_COMBOBOXW}, // *ComboBox
  657. {WC_COMBOBOXEXW}, // ComboBoxEx32
  658. {L"ComboLBox"}, // *ComboLBox
  659. {WC_EDITW}, // *Edit
  660. {WC_LISTBOXW}, // *ListBox
  661. {L"MDIClient"}, // *MDIClient
  662. {STATUSCLASSNAMEW}, // msctls_statusbar32
  663. {TRACKBAR_CLASSW}, // msctls_trackbar32
  664. {UPDOWN_CLASSW}, // msctls_updown32
  665. {PROGRESS_CLASSW}, // msctls_progress32
  666. {HOTKEY_CLASSW}, // msctls_hotkey32
  667. {REBARCLASSNAMEW}, // ReBarWindow32
  668. {WC_SCROLLBARW}, // *ScrollBar
  669. {WC_STATICW}, // *Static
  670. {WC_PAGESCROLLERW}, // SysPager
  671. {WC_IPADDRESSW}, // SysIPAddress32
  672. {DATETIMEPICK_CLASSW}, // SysDateTimePick32
  673. {MONTHCAL_CLASSW}, // SysMonthCal32
  674. {ANIMATE_CLASSW}, // SysAnimate32
  675. {WC_HEADERW}, // SysHeader32
  676. {WC_LISTVIEWW}, // SysListView32
  677. {WC_TREEVIEWW}, // SysTreeView32
  678. {WC_TABCONTROLW}, // SysTabControl32
  679. {TOOLBARCLASSNAMEW}, // ToolbarWindow32
  680. {TOOLTIPS_CLASSW}, // tooltips_class32
  681. {NULL}
  682. };
  683. //-------------------------------
  684. // IsAnAnsiClass
  685. //
  686. // Returns TRUE if the class is a "system" class (which has
  687. // a default wndproc). Also returns TRUE for other classes
  688. // which need to be marked as "ANSI".
  689. ---------------------------------
  690. BOOL IsAnAnsiClass(LPCWSTR lpwz)
  691. {
  692. if(FSTRING_VALID(lpwz))
  693. {
  694. // PERF: We optimize by making sure that the first character matches
  695. // one of the known system classes. Be sure to add the case
  696. // here if you add any classes to m_rgwzAnsiClasses!
  697. switch(*lpwz)
  698. case '#':
  699. case 'B':
  700. case 'b':
  701. case 'C':
  702. case 'c':
  703. case 'E':
  704. case 'e':
  705. case 'L':
  706. case 'l':
  707. case 'M':
  708. case 'm':
  709. case 'R':
  710. case 'S':
  711. case 's':
  712. case 'T':
  713. case 't':
  714. {
  715. int iClass = 0;
  716. while(m_rgwzAnsiClasses[iClass].wzName)
  717. {
  718. if(CompareHelper(lpwz, (LPWSTR)(m_rgwzAnsiClasses[iClass].wzName), FALSE) == 0)
  719. {
  720. return(TRUE);
  721. }
  722. iClass++;
  723. }
  724. break;
  725. }
  726. }
  727. return(FALSE);
  728. }
  729. */