test: getset.c Source File

Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

# getset.c

Go to the documentation of this file.

    00001 /****************************** Module Header ******************************\
    00002 * Module Name: getset.c
    00003 *
    00004 * Copyright (c) 1985 - 1999, Microsoft Corporation
    00005 *
    00006 * This module contains window manager information routines
    00007 *
    00008 * History:
    00009 * 22-Oct-1990 MikeHar   Ported functions from Win 3.0 sources.
    00010 * 13-Feb-1991 MikeKe    Added Revalidation code (None)
    00011 * 08-Feb-1991 IanJa     Unicode/ANSI aware and neutral
    00012 \***************************************************************************/
    00013
    00014 #include "precomp.h"
    00015 #pragma hdrstop
    00016
    00017 /****************************************************************************\
    00018 * DefSetText
    00019 *
    00020 * Processes WM_SETTEXT messages by text-alloc'ing a string in the alternate
    00021 * ds and setting 'hwnd->hName' to it's handle.
    00022 *
    00023 * History:
    00024 * 23-Oct-1990 MikeHar   Ported from Windows.
    00025 * 09-Nov-1990 DarrinM   Cleanup.
    00026 \****************************************************************************/
    00027
    00028 BOOL DefSetText(
    00029     PWND          pwnd,
    00030     PLARGE_STRING cczpstr)
    00031 {
    00032     /*
    00033      * Note -- string buffer may be on client side.
    00034      */
    00035     PDESKTOP pdesk;
    00036     DWORD cbString;
    00037     BOOL  fTranslateOk;
    00038
    00039     if (pwnd->head.rpdesk == NULL || cczpstr == NULL || cczpstr->Buffer == NULL) {
    00040         pwnd->strName.Length = 0;
    00041         return TRUE;
    00042     }
    00043
    00044     /*
    00045      * Capture the new window name
    00046      */
    00047     if (cczpstr->bAnsi)
    00048         cbString = (cczpstr->Length + 1) * sizeof(WCHAR);
    00049     else
    00050         cbString = cczpstr->Length + sizeof(WCHAR);
    00051
    00052     /*
    00053      * If the current buffer is not large enough,
    00054      * reallocate it.
    00055      */
    00056     pdesk = pwnd->head.rpdesk;
    00057     if (pwnd->strName.MaximumLength < cbString) {
    00058         if (pwnd->strName.Buffer != NULL)
    00059             DesktopFree(pdesk, pwnd->strName.Buffer);
    00060         pwnd->strName.Buffer = (LPWSTR)DesktopAlloc(pdesk, cbString, DTAG_TEXT);
    00061         pwnd->strName.Length = 0;
    00062         if (pwnd->strName.Buffer == NULL) {
    00063             pwnd->strName.MaximumLength = 0;
    00064             return FALSE;
    00065         }
    00066         pwnd->strName.MaximumLength = cbString;
    00067     }
    00068
    00069     fTranslateOk = TRUE;
    00070     if (cczpstr->Length != 0) {
    00071         try {
    00072             if (!cczpstr->bAnsi) {
    00073                 RtlCopyMemory(pwnd->strName.Buffer, cczpstr->Buffer, cbString);
    00074             } else {
    00075                 LPCSTR ccxpszAnsi = (LPCSTR)cczpstr->Buffer;
    00076
    00077                 fTranslateOk = NT_SUCCESS(RtlMultiByteToUnicodeN(pwnd->strName.Buffer,
    00078                         cbString, &cbString,
    00079                         (LPSTR)ccxpszAnsi, cbString / sizeof(WCHAR)));
    00080             }
    00081         } except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
    00082             pwnd->strName.Length = 0;
    00083             return FALSE;
    00084         }
    00085     }
    00086
    00087     if (fTranslateOk) {
    00088         pwnd->strName.Length = cbString - sizeof(WCHAR);
    00089         return TRUE;
    00090     } else {
    00091         pwnd->strName.Length = 0;
    00092         return FALSE;
    00093     }
    00094 }
    00095
    00096 /***************************************************************************\
    00097 * FCallerOk
    00098 *
    00099 * Ensures that no client stomps on server windows.
    00100 *
    00101 * 04-Feb-1992 ScottLu   Created.
    00102 \***************************************************************************/
    00103
    00104 BOOL FCallerOk(
    00105     PWND pwnd)
    00106 {
    00107     PTHREADINFO pti = PtiCurrent();
    00108
    00109     if ((GETPTI(pwnd)->TIF_flags & (TIF_SYSTEMTHREAD | TIF_CSRSSTHREAD)) &&
    00110             !(pti->TIF_flags & (TIF_SYSTEMTHREAD | TIF_CSRSSTHREAD))) {
    00111         return FALSE;
    00112     }
    00113
    00114     if (GETPTI(pwnd)->pEThread->Cid.UniqueProcess == gpidLogon &&
    00115             pti->pEThread->Cid.UniqueProcess != gpidLogon) {
    00116         return FALSE;
    00117     }
    00118
    00119     return TRUE;
    00120 }
    00121
    00122 /***************************************************************************\
    00123 * _SetWindowWord (supports SetWindowWordA/W API)
    00124 *
    00125 * Set a window word.  Positive index values set application window words
    00126 * while negative index values set system window words.  The negative
    00127 * indices are published in WINDOWS.H.
    00128 *
    00129 * History:
    00130 * 26-Nov-1990 DarrinM   Wrote.
    00131 \***************************************************************************/
    00132
    00133 WORD _SetWindowWord(
    00134     PWND pwnd,
    00135     int  index,
    00136     WORD value)
    00137 {
    00138     WORD wOld;
    00139
    00140     /*
    00141      * Don't allow setting of words belonging to a system thread if the caller
    00142      * is not a system thread. Same goes for winlogon.
    00143      */
    00144     if (!FCallerOk(pwnd)) {
    00145         RIPERR0(ERROR_INVALID_INDEX, RIP_VERBOSE, "");
    00146         return 0;
    00147     }
    00148
    00149     /*
    00150      * Applications can not set a WORD into a dialog Proc or any of the
    00151      * non-public reserved bytes in DLGWINDOWEXTRA (usersrv stores pointers
    00152      * theres)
    00153      */
    00154     if (TestWF(pwnd, WFDIALOGWINDOW)) {
    00155         if  (((index >= DWLP_DLGPROC) && (index < DWLP_MSGRESULT)) ||
    00156                 ((index > DWLP_USER+sizeof(LONG_PTR)-sizeof(WORD)) && (index < DLGWINDOWEXTRA))) {
    00157             RIPERR3(ERROR_INVALID_INDEX, RIP_WARNING,
    00158                   "SetWindowWord: Trying to set WORD of a windowproc pwnd=(%#p) index=(%ld) fnid (%lX)",
    00159                 pwnd, index, (DWORD)pwnd->fnid);
    00160             return 0;
    00161         } else {
    00162
    00163             /*
    00164              * If this is really a dialog and not some other server class
    00165              * where usersrv has stored some data (Windows Compuserve -
    00166              * wincim - does this) then store the data now that we have
    00167              * verified the index limits.
    00168              */
    00169             if (GETFNID(pwnd) == FNID_DIALOG)
    00170                 goto DoSetWord;
    00171         }
    00172     }
    00173
    00174     if (index == GWLP_USERDATA) {
    00175         wOld = (WORD)pwnd->dwUserData;
    00176         pwnd->dwUserData = MAKELONG(value, HIWORD(pwnd->dwUserData));
    00177         return wOld;
    00178     }
    00179
    00180     // fix for RedShift, they call SetWindowWord
    00181     // tn play with the low word of the style dword
    00182     if (index == GWL_STYLE) {
    00183         wOld = (WORD)pwnd->style;
    00184         pwnd->style = MAKELONG(value, HIWORD(pwnd->style));
    00185         return wOld;
    00186     }
    00187
    00188     if (GETFNID(pwnd) != 0) {
    00189         if (index >= 0 &&
    00190                 (index < (int)(CBFNID(pwnd->fnid)-sizeof(WND)))) {
    00191             switch (GETFNID(pwnd)) {
    00192             case FNID_MDICLIENT:
    00193                 if (index == 0)
    00194                     break;
    00195                 goto DoDefault;
    00196
    00197             case FNID_BUTTON:
    00198                 /*
    00199                  * CorelDraw, Direct Access 1.0 and WordPerfect 6.0 do a
    00200                  * get/set on the first button window word.  Allow this
    00201                  * for compatibility.
    00202                  */
    00203                 if (index == 0) {
    00204                     /*
    00205                      *  Since we now use a lookaside buffer for the control's
    00206                      *  private data, we need to indirect into this structure.
    00207                      */
    00208                     PBUTN pbutn = ((PBUTNWND)pwnd)->pbutn;
    00209                     if (!pbutn || (LONG_PTR)pbutn == (LONG_PTR)-1) {
    00210                         return 0;
    00211                     } else {
    00212                         try {
    00213                             wOld = (WORD)ProbeAndReadUlong(&pbutn->buttonState);
    00214                             pbutn->buttonState = value;
    00215                         } except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
    00216                             wOld = 0;
    00217                         }
    00218                         return wOld;
    00219                     }
    00220                 }
    00221                 goto DoDefault;
    00222
    00223             default:
    00224 DoDefault:
    00225                 RIPERR3(ERROR_INVALID_INDEX,
    00226                         RIP_WARNING,
    00227                         "SetWindowWord: Trying to set private server data pwnd=(%#p) index=(%ld) fnid (%lX)",
    00228                         pwnd, index, (DWORD)pwnd->fnid);
    00229                 return 0;
    00230                 break;
    00231             }
    00232         }
    00233     }
    00234
    00235 DoSetWord:
    00236     if ((index < 0) || ((UINT)index + sizeof(WORD) > (UINT)pwnd->cbwndExtra)) {
    00237         RIPERR0(ERROR_INVALID_INDEX, RIP_WARNING,"SetWindowWord Fails because of invalid index");
    00238         return 0;
    00239     } else {
    00240         WORD UNALIGNED *pw;
    00241
    00242         pw = (WORD UNALIGNED *)((BYTE *)(pwnd + 1) + index);
    00243         wOld = *pw;
    00244         *pw = value;
    00245         return (WORD)wOld;
    00246     }
    00247 }
    00248
    00249 /***************************************************************************\
    00250 * xxxSetWindowLong (API)
    00251 *
    00252 * Set a window long.  Positive index values set application window longs
    00253 * while negative index values set system window longs.  The negative
    00254 * indices are published in WINDOWS.H.
    00255 *
    00256 * History:
    00257 * 26-Nov-1990 DarrinM   Wrote.
    00258 \***************************************************************************/
    00259
    00260 ULONG_PTR xxxSetWindowLongPtr(
    00261     PWND  pwnd,
    00262     int   index,
    00263     ULONG_PTR dwData,
    00264     BOOL  bAnsi)
    00265 {
    00266     ULONG_PTR dwOld;
    00267     DWORD dwCPDType = 0;
    00268
    00269     /*
    00270      * Hide the window proc from other processes
    00271      */
    00272 #if DBG
    00273     if (PpiCurrent() != GETPTI(pwnd)->ppi) {
    00274         RIPMSG0(RIP_WARNING, "Setting cross process windowlong; win95 would fail");
    00275     }
    00276 #endif
    00277
    00278     /*
    00279      * CheckLock(pwnd);  The only case that leaves the critical section is
    00280      * where xxxSetWindowData is called, which does this.  Saves us some locks.
    00281      *
    00282      *
    00283      * Don't allow setting of words belonging to a system thread if the caller
    00284      * is not a system thread. Same goes for winlogon.
    00285      */
    00286     if (!FCallerOk(pwnd)) {
    00287         RIPERR0(ERROR_INVALID_INDEX, RIP_VERBOSE, "");
    00288         return 0;
    00289     }
    00290
    00291     /*
    00292      * If it's a dialog window, only a few indices are permitted.
    00293      */
    00294     if (GETFNID(pwnd) != 0) {
    00295         if (TestWF(pwnd, WFDIALOGWINDOW)) {
    00296             switch (index) {
    00297             case DWLP_MSGRESULT:
    00298                  dwOld = (ULONG_PTR)((PDIALOG)(pwnd))->resultWP;
    00299                  ((PDIALOG)(pwnd))->resultWP = (LONG_PTR)dwData;
    00300                  return dwOld;
    00301
    00302             case DWLP_USER:
    00303                  dwOld = (ULONG_PTR)((PDIALOG)(pwnd))->unused;
    00304                  ((PDIALOG)(pwnd))->unused = (LONG_PTR)dwData;
    00305                  return dwOld;
    00306
    00307             default:
    00308                 if (index >= 0 && index < DLGWINDOWEXTRA) {
    00309                     RIPERR0(ERROR_PRIVATE_DIALOG_INDEX, RIP_VERBOSE, "");
    00310                     return 0;
    00311                 }
    00312             }
    00313         } else {
    00314             if (index >= 0 &&
    00315                     (index < (int)(CBFNID(pwnd->fnid)-sizeof(WND)))) {
    00316                 switch (GETFNID(pwnd)) {
    00317                 case FNID_BUTTON:
    00318                 case FNID_COMBOBOX:
    00319                 case FNID_COMBOLISTBOX:
    00320                 case FNID_DIALOG:
    00321                 case FNID_LISTBOX:
    00322                 case FNID_STATIC:
    00323                 case FNID_EDIT:
    00324 #ifdef FE_IME
    00325                 case FNID_IME:
    00326 #endif
    00327                     /*
    00328                      * Allow the 0 index for controls to be set if it's
    00329                      * still NULL or the window is being destroyed. This
    00330                      * is where controls store their private data.
    00331                      */
    00332                     if (index == 0) {
    00333                         dwOld = *((PULONG_PTR)(pwnd + 1));
    00334                         if (dwOld == 0 || TestWF(pwnd, WFDESTROYED))
    00335                             goto SetData;
    00336                     }
    00337                     break;
    00338
    00339                 case FNID_MDICLIENT:
    00340                     /*
    00341                      * Allow the 0 index (which is reserved) to be set/get.
    00342                      * Quattro Pro 1.0 uses this index!
    00343                      *
    00344                      * Allow the 4 index to be set if it's still NULL or
    00345                      * the window is being destroyed. This is where we
    00346                      * store our private data.
    00347                      */
    00348 #ifndef _WIN64
    00349                     if (index == 0) {
    00350                         goto SetData;
    00351                     }
    00352 #endif
    00353                     if (index == GWLP_MDIDATA) {
    00354                         dwOld = *((PULONG_PTR)(pwnd + 1));
    00355                         if (dwOld == 0 || TestWF(pwnd, WFDESTROYED))
    00356                             goto SetData;
    00357                     }
    00358                     break;
    00359                 }
    00360
    00361                 RIPERR3(ERROR_INVALID_INDEX,
    00362                         RIP_WARNING,
    00363                         "SetWindowLongPtr: Trying to set private server data pwnd=(%#p) index=(%ld) FNID=(%lX)",
    00364                         pwnd, index, (DWORD)pwnd->fnid);
    00365                 return 0;
    00366             }
    00367         }
    00368     }
    00369
    00370     if (index < 0) {
    00371         return xxxSetWindowData(pwnd, index, dwData, bAnsi);
    00372     } else {
    00373         if ((UINT)index + sizeof(ULONG_PTR) > (UINT)pwnd->cbwndExtra) {
    00374             RIPERR3(ERROR_INVALID_INDEX,
    00375                     RIP_WARNING,
    00376                     "SetWindowLongPtr: Index %d too big for cbWndExtra %d on pwnd %#p",
    00377                     index, pwnd->cbwndExtra, pwnd);
    00378             return 0;
    00379         } else {
    00380             ULONG_PTR UNALIGNED *pudw;
    00381
    00382 SetData:
    00383             pudw = (ULONG_PTR UNALIGNED *)((BYTE *)(pwnd + 1) + index);
    00384             dwOld = *pudw;
    00385             *pudw = dwData;
    00386             return dwOld;
    00387         }
    00388     }
    00389 }
    00390
    00391 #ifdef _WIN64
    00392 DWORD xxxSetWindowLong(
    00393     PWND  pwnd,
    00394     int   index,
    00395     DWORD dwData,
    00396     BOOL  bAnsi)
    00397 {
    00398     DWORD dwOld;
    00399
    00400     /*
    00401      * Hide the window proc from other processes
    00402      */
    00403 #if DBG
    00404     if (PpiCurrent() != GETPTI(pwnd)->ppi) {
    00405         RIPMSG0(RIP_WARNING, "Setting cross process windowlong; win95 would fail");
    00406     }
    00407 #endif
    00408
    00409     /*
    00410      * CheckLock(pwnd);  The only case that leaves the critical section is
    00411      * where xxxSetWindowData is called, which does this.  Saves us some locks.
    00412      *
    00413      *
    00414      * Don't allow setting of words belonging to a system thread if the caller
    00415      * is not a system thread. Same goes for winlogon.
    00416      */
    00417     if (!FCallerOk(pwnd)) {
    00418         RIPERR0(ERROR_INVALID_INDEX, RIP_VERBOSE, "");
    00419         return 0;
    00420     }
    00421
    00422     /*
    00423      * If it's a dialog window, only a few indices are permitted.
    00424      */
    00425     if (GETFNID(pwnd) != 0) {
    00426         if (TestWF(pwnd, WFDIALOGWINDOW)) {
    00427             switch (index) {
    00428             case DWLP_MSGRESULT:
    00429                  dwOld = (DWORD)((PDIALOG)(pwnd))->resultWP;
    00430                  ((PDIALOG)(pwnd))->resultWP = (long)dwData;
    00431                  return dwOld;
    00432
    00433             case DWLP_USER:
    00434                  dwOld = (DWORD)((PDIALOG)(pwnd))->unused;
    00435                  ((PDIALOG)(pwnd))->unused = (long)dwData;
    00436                  return dwOld;
    00437
    00438             default:
    00439                 if (index >= 0 && index < DLGWINDOWEXTRA) {
    00440                     RIPERR0(ERROR_PRIVATE_DIALOG_INDEX, RIP_VERBOSE, "");
    00441                     return 0;
    00442                 }
    00443             }
    00444         } else {
    00445             if (index >= 0 &&
    00446                     (index < (int)(CBFNID(pwnd->fnid)-sizeof(WND)))) {
    00447                 switch (GETFNID(pwnd)) {
    00448                 case FNID_MDICLIENT:
    00449                     /*
    00450                      * Allow the 0 index (which is reserved) to be set/get.
    00451                      * Quattro Pro 1.0 uses this index!
    00452                      */
    00453                     if (index == 0) {
    00454                         goto SetData;
    00455                     }
    00456                     break;
    00457                 }
    00458
    00459                 RIPERR3(ERROR_INVALID_INDEX,
    00460                         RIP_WARNING,
    00461                         "SetWindowLong: Trying to set private server data pwnd=(%#p) index=(%ld) FNID=(%lX)",
    00462                         pwnd, index, (DWORD)pwnd->fnid);
    00463                 return 0;
    00464             }
    00465         }
    00466     }
    00467
    00468     if (index < 0) {
    00469         if ((index != GWL_STYLE) && (index != GWL_EXSTYLE) && (index != GWL_ID) && (index != GWLP_USERDATA)) {
    00470             RIPERR1(ERROR_INVALID_INDEX, RIP_WARNING, "SetWindowLong: invalid index %d", index);
    00471             return 0;
    00472         }
    00473         return (DWORD)xxxSetWindowData(pwnd, index, dwData, bAnsi);
    00474     } else {
    00475         if ((UINT)index + sizeof(DWORD) > (UINT)pwnd->cbwndExtra) {
    00476             RIPERR3(ERROR_INVALID_INDEX,
    00477                     RIP_WARNING,
    00478                     "SetWindowLong: Index %d too big for cbWndExtra %d on pwnd %#p",
    00479                     index, pwnd->cbwndExtra, pwnd);
    00480             return 0;
    00481         } else {
    00482             DWORD UNALIGNED *pudw;
    00483
    00484 SetData:
    00485             pudw = (DWORD UNALIGNED *)((BYTE *)(pwnd + 1) + index);
    00486             dwOld = *pudw;
    00487             *pudw = dwData;
    00488             return dwOld;
    00489         }
    00490     }
    00491 }
    00492 #endif
    00493
    00494 /***************************************************************************\
    00495 * xxxHandleOwnerSwitch
    00496 *
    00497 \***************************************************************************/
    00498
    00499 void xxxHandleOwnerSwitch(PWND pwnd, PWND pwndNewParent, PWND pwndOldParent)
    00500 {
    00501     CheckLock(pwnd);
    00502     CheckLock(pwndNewParent);
    00503     CheckLock(pwndOldParent);
    00504
    00505     if ((pwndOldParent != NULL) &&
    00506             (GETPTI(pwndOldParent) != GETPTI(pwnd))) {
    00507
    00508         /*
    00509          * See if it needs to be unattached.
    00510          */
    00511         if ((pwndNewParent == NULL) ||
    00512             (GETPTI(pwndNewParent) == GETPTI(pwnd)) ||
    00513             (GETPTI(pwndNewParent) != GETPTI(pwndOldParent))) {
    00514
    00515             zzzAttachThreadInput(GETPTI(pwnd), GETPTI(pwndOldParent), FALSE);
    00516         }
    00517     }
    00518
    00519     /*
    00520      * See if it needs to be attached.
    00521      */
    00522     if ((pwndNewParent != NULL) &&
    00523             (GETPTI(pwndNewParent) != GETPTI(pwnd)) &&
    00524             ((pwndOldParent == NULL) ||
    00525                 (GETPTI(pwndNewParent) != GETPTI(pwndOldParent)))) {
    00526
    00527         zzzAttachThreadInput(GETPTI(pwnd), GETPTI(pwndNewParent), TRUE);
    00528     }
    00529
    00530     /*
    00531      * Post hook messages for tray-windows.
    00532      */
    00533     if (IsTrayWindow(pwnd)) {
    00534
    00535         HWND hw = PtoH(pwnd);
    00536
    00537         /*
    00538          * If we're setting the owner and it's changing from owned
    00539          * to unowned or vice-versa, notify the tray.
    00540          */
    00541         if ((pwndOldParent != NULL) && (pwndNewParent == NULL)) {
    00542             xxxCallHook(HSHELL_WINDOWCREATED,
    00543                         (WPARAM)hw,
    00544                         (LONG)0,
    00545                         WH_SHELL);
    00546             PostShellHookMessages(HSHELL_WINDOWCREATED, (LPARAM)hw);
    00547
    00548         } else if ((pwndOldParent == NULL) && (pwndNewParent != NULL)) {
    00549             xxxCallHook(HSHELL_WINDOWDESTROYED,
    00550                         (WPARAM)hw,
    00551                         (LONG)0,
    00552                         WH_SHELL);
    00553             PostShellHookMessages(HSHELL_WINDOWDESTROYED, (LPARAM)hw);
    00554         }
    00555     }
    00556 }
    00557
    00558 /***************************************************************************\
    00559 * xxxSetWindowData
    00560 *
    00561 * SetWindowWord and ServerSetWindowLong are now identical routines because they
    00562 * both can return DWORDs.  This single routine performs the work for them both.
    00563 *
    00564 * History:
    00565 * 26-Nov-1990 DarrinM   Wrote.
    00566 \***************************************************************************/
    00567
    00568 ULONG_PTR xxxSetWindowData(
    00569     PWND  pwnd,
    00570     int   index,
    00571     ULONG_PTR dwData,
    00572     BOOL  bAnsi)
    00573 {
    00574     ULONG_PTR dwT;
    00575     ULONG_PTR dwOld;
    00576     PMENU pmenu;
    00577     PWND  *ppwnd;
    00578     PWND  pwndNewParent;
    00579     PWND  pwndOldParent;
    00580     BOOL  fTopOwner;
    00581     TL    tlpwndOld;
    00582     TL    tlpwndNew;
    00583     DWORD dwCPDType = 0;
    00584
    00585     CheckLock(pwnd);
    00586     UserAssert(IsWinEventNotifyDeferredOK());
    00587
    00588     switch (index) {
    00589     case GWLP_USERDATA:
    00590         dwOld = pwnd->dwUserData;
    00591         pwnd->dwUserData = dwData;
    00592         break;
    00593
    00594     case GWL_EXSTYLE:
    00595     case GWL_STYLE:
    00596         dwOld = xxxSetWindowStyle(pwnd, index, (DWORD)dwData);
    00597         break;
    00598
    00599     case GWLP_ID:
    00600         /*
    00601          * Win95 does a TestWF(pwnd, WFCHILD) here, but we'll do the same
    00602          * check we do everywhere else or it'll cause us trouble.
    00603          */
    00604         if (TestwndChild(pwnd)) {
    00605
    00606             /*
    00607              * pwnd->spmenu is an id in this case.
    00608              */
    00609             dwOld = (ULONG_PTR)pwnd->spmenu;
    00610             pwnd->spmenu = (struct tagMENU *)dwData;
    00611         } else {
    00612             dwOld = 0;
    00613             if (pwnd->spmenu != NULL)
    00614                 dwOld = (ULONG_PTR)PtoH(pwnd->spmenu);
    00615
    00616             if (dwData == 0) {
    00617                 UnlockWndMenu(pwnd, &pwnd->spmenu);
    00618             } else {
    00619                 pmenu = ValidateHmenu((HANDLE)dwData);
    00620                 if (pmenu != NULL) {
    00621                     LockWndMenu(pwnd, &pwnd->spmenu, pmenu);
    00622                 } else {
    00623
    00624                     /*
    00625                      * Menu is invalid, so don't set a new one!
    00626                      */
    00627                     dwOld = 0;
    00628                 }
    00629             }
    00630         }
    00631         break;
    00632
    00633     case GWLP_HINSTANCE:
    00634         dwOld = (ULONG_PTR)pwnd->hModule;
    00635         pwnd->hModule = (HANDLE)dwData;
    00636         break;
    00637
    00638     case GWLP_WNDPROC:  // See similar case DWLP_DLGPROC
    00639
    00640         /*
    00641          * Hide the window proc from other processes
    00642          */
    00643         if (PpiCurrent() != GETPTI(pwnd)->ppi) {
    00644             RIPERR1(ERROR_ACCESS_DENIED, RIP_WARNING,
    00645                 "SetWindowLong: Window owned by another process %#p", pwnd);
    00646             return 0;
    00647         }
    00648
    00649         /*
    00650          * If the window has been zombized by a DestroyWindow but is still
    00651          * around because the window was locked don't let anyone change
    00652          * the window proc from DefWindowProc!
    00653          *
    00654          * !!! LATER long term move this test into the ValidateHWND; kind of
    00655          * !!! LATER close to shipping for that
    00656          */
    00657         if (pwnd->fnid & FNID_DELETED_BIT) {
    00658             UserAssert(pwnd->lpfnWndProc == xxxDefWindowProc);
    00659             RIPERR1(ERROR_ACCESS_DENIED, RIP_WARNING,
    00660                 "SetWindowLong: Window is a zombie %#p", pwnd);
    00661             return 0;
    00662         }
    00663
    00664         /*
    00665          * If the application (client) subclasses a window that has a server -
    00666          * side window proc we must return an address that the client can call:
    00667          * this client-side wndproc expectes Unicode or ANSI depending on bAnsi
    00668          */
    00669
    00670         if (TestWF(pwnd, WFSERVERSIDEPROC)) {
    00671             dwOld = MapServerToClientPfn((ULONG_PTR)pwnd->lpfnWndProc, bAnsi);
    00672
    00673             /*
    00674              * If we don't have a client side address (like for the DDEMLMon
    00675              *  window) then blow off the subclassing.
    00676              */
    00677             if (dwOld == 0) {
    00678                 RIPMSG0(RIP_WARNING, "SetWindowLong: subclass server only window");
    00679                 return(0);
    00680             }
    00681
    00682             ClrWF(pwnd, WFSERVERSIDEPROC);
    00683         } else {
    00684             /*
    00685              * Keep edit control behavior compatible with NT 3.51.
    00686              */
    00687             if (GETFNID(pwnd) == FNID_EDIT) {
    00688                 dwOld = (ULONG_PTR)pwnd->lpfnWndProc;
    00689             } else {
    00690                 dwOld = MapClientNeuterToClientPfn(pwnd->pcls, (ULONG_PTR)pwnd->lpfnWndProc, bAnsi);
    00691             }
    00692
    00693             /*
    00694              * If the client mapping didn't change the window proc then see if
    00695              * we need a callproc handle.
    00696              */
    00697             if (dwOld == (ULONG_PTR)pwnd->lpfnWndProc) {
    00698                 /*
    00699                  * May need to return a CallProc handle if there is an Ansi/Unicode mismatch
    00700                  */
    00701                 if (bAnsi != (TestWF(pwnd, WFANSIPROC) ? TRUE : FALSE)) {
    00702                     dwCPDType |= bAnsi ? CPD_ANSI_TO_UNICODE : CPD_UNICODE_TO_ANSI;
    00703                 }
    00704             }
    00705
    00706             UserAssert(!ISCPDTAG(dwOld));
    00707
    00708             if (dwCPDType) {
    00709                 ULONG_PTR cpd;
    00710
    00711                 cpd = GetCPD(pwnd, dwCPDType | CPD_WND, dwOld);
    00712
    00713                 if (cpd) {
    00714                     dwOld = cpd;
    00715                 } else {
    00716                     RIPMSG0(RIP_WARNING, "SetWindowLong unable to alloc CPD returning handle\n");
    00717                 }
    00718             }
    00719         }
    00720
    00721         /*
    00722          * Convert a possible CallProc Handle into a real address.  They may
    00723          * have kept the CallProc Handle from some previous mixed GetClassinfo
    00724          * or SetWindowLong.
    00725          *
    00726          * WARNING bAnsi is modified here to represent real type of
    00727          * proc rather than if SetWindowLongA or W was called
    00728          *
    00729          */
    00730         if (ISCPDTAG(dwData)) {
    00731             PCALLPROCDATA pCPD;
    00732             if (pCPD = HMValidateHandleNoRip((HANDLE)dwData, TYPE_CALLPROC)) {
    00733                 dwData = pCPD->pfnClientPrevious;
    00734                 bAnsi = pCPD->wType & CPD_UNICODE_TO_ANSI;
    00735             }
    00736         }
    00737
    00738         /*
    00739          * If an app 'unsubclasses' a server-side window proc we need to
    00740          * restore everything so SendMessage and friends know that it's
    00741          * a server-side proc again.  Need to check against client side
    00742          * stub addresses.
    00743          */
    00744         if ((dwT = MapClientToServerPfn(dwData)) != 0) {
    00745             pwnd->lpfnWndProc = (WNDPROC_PWND)dwT;
    00746             SetWF(pwnd, WFSERVERSIDEPROC);
    00747             ClrWF(pwnd, WFANSIPROC);
    00748         } else {
    00749             pwnd->lpfnWndProc = (WNDPROC_PWND)MapClientNeuterToClientPfn(pwnd->pcls, dwData, bAnsi);
    00750             if (bAnsi) {
    00751                 SetWF(pwnd, WFANSIPROC);
    00752             } else {
    00753                 ClrWF(pwnd, WFANSIPROC);
    00754             }
    00755
    00756             pwnd->hMod16 = xxxClientWOWGetProcModule(pwnd->lpfnWndProc);
    00757
    00758         }
    00759
    00760         break;
    00761
    00762     case GWLP_HWNDPARENT:
    00763         /*
    00764          * Special case for pre-1.1 versions of Windows
    00765          * Set/GetWindowWord(GWW_HWNDPARENT) needs to be mapped
    00766          * to the hwndOwner for top level windows.
    00767          */
    00768         fTopOwner = FALSE;
    00769         if (pwnd->spwndParent == PWNDDESKTOP(pwnd)) {
    00770             ppwnd = &pwnd->spwndOwner;
    00771             fTopOwner = TRUE;
    00772         } else {
    00773             ppwnd = &pwnd->spwndParent;
    00774         }
    00775
    00776
    00777         /*
    00778          * If we're a topmost, then we're only changing the owner
    00779          * relationship.  Otherwise, we are doing a relinking of the
    00780          * parent/child relationship.
    00781          */
    00782         pwndOldParent = *ppwnd;
    00783         pwndNewParent = ValidateHwnd((HWND)dwData);
    00784
    00785         if ((pwndNewParent == NULL) && dwData) {
    00786             RIPERR1(ERROR_INVALID_PARAMETER, RIP_VERBOSE, "Set GWL_HWNDPARENT, invalid hwndParent %#p", dwData);
    00787             return 0;
    00788         }
    00789
    00790         dwOld = (ULONG_PTR)HW(*ppwnd);
    00791
    00792         ThreadLock(pwndNewParent, &tlpwndNew);
    00793
    00794         if (fTopOwner) {
    00795
    00796             ThreadLock(pwndOldParent, &tlpwndOld);
    00797
    00798             xxxHandleOwnerSwitch(pwnd, pwndNewParent, pwndOldParent);
    00799
    00800             if (ValidateOwnerDepth(pwnd, pwndNewParent)) {
    00801
    00802                 /*
    00803                  * Set the owner.
    00804                  */
    00805                 if (pwndNewParent) {
    00806                     Lock(ppwnd, pwndNewParent);
    00807                 } else {
    00808                     Unlock(ppwnd);
    00809                 }
    00810             } else {
    00811
    00812                 /*
    00813                  * Undo the switch and set last error.
    00814                  */
    00815                 xxxHandleOwnerSwitch(pwnd, pwndOldParent, pwndNewParent);
    00816                 RIPERR0(ERROR_INVALID_PARAMETER, RIP_ERROR, "Detected loop in owner chain");
    00817                 dwOld = 0;
    00818             }
    00819
    00820             ThreadUnlock(&tlpwndOld);
    00821
    00822         } else {
    00823             if (!xxxSetParent(pwnd, pwndNewParent)) {
    00824                 dwOld = 0;
    00825             }
    00826         }
    00827
    00828         ThreadUnlock(&tlpwndNew);
    00829         break;
    00830
    00831     default:
    00832         RIPERR0(ERROR_INVALID_INDEX, RIP_VERBOSE, "");
    00833         return 0;
    00834     }
    00835
    00836     return dwOld;
    00837 }
    00838
    00839 /***************************************************************************\
    00840 * FindPCPD
    00841 *
    00842 * Searches the list of CallProcData's associated with window to see if
    00843 * one already exists representing this transition.  CPD can be re-used
    00844 * and aren't deleted until a window or thread dies
    00845 *
    00846 *
    00847 * 04-Feb-1993 JohnC     Created.
    00848 \***************************************************************************/
    00849
    00850 PCALLPROCDATA FindPCPD(
    00851     PCALLPROCDATA pCPD,
    00852     ULONG_PTR      dwClientPrevious,
    00853     WORD          wCPDType)
    00854 {
    00855     while (pCPD) {
    00856         if ((pCPD->pfnClientPrevious == dwClientPrevious) &&
    00857                 (pCPD->wType == wCPDType))
    00858             return pCPD;
    00859         pCPD = pCPD->spcpdNext;
    00860     }
    00861
    00862     return NULL;
    00863 }
    00864
    00865 /***************************************************************************\
    00866 * GetCPD
    00867 *
    00868 * Searches the list of CallProcData's associated with a class or window
    00869 * (if the class is not provided).  If one already exists representing this
    00870 * transition it is returned or else a new CPD is created
    00871 *
    00872 * 04-Feb-1993 JohnC     Created.
    00873 \***************************************************************************/
    00874
    00875 ULONG_PTR GetCPD(
    00876     PVOID pWndOrCls,
    00877     DWORD CPDOption,
    00878     ULONG_PTR dwProc32)
    00879 {
    00880     PCALLPROCDATA pCPD;
    00881     PCLS          pcls;
    00882 #if DBG
    00883     BOOL          bAnsiProc;
    00884 #endif
    00885
    00886     PTHREADINFO ptiCurrent;
    00887
    00888     if (CPDOption & (CPD_WND | CPD_DIALOG)) {
    00889         UserAssert(!(CPDOption & (CPD_CLASS | CPD_WNDTOCLS)));
    00890         pcls = ((PWND)pWndOrCls)->pcls;
    00891
    00892 #if DBG
    00893         if (CPDOption & CPD_WND) {
    00894             bAnsiProc = !!(TestWF(pWndOrCls, WFANSIPROC));
    00895         } else {
    00896             /*
    00897              * We'll assume the client-side dialog box code knows
    00898              * what it's doing, since we can't check it from here.
    00899              */
    00900             bAnsiProc = !!(CPDOption & CPD_UNICODE_TO_ANSI);
    00901         }
    00902 #endif
    00903     } else {
    00904         UserAssert(CPDOption & (CPD_CLASS | CPD_WNDTOCLS));
    00905         if (CPDOption & CPD_WNDTOCLS)
    00906             pcls = ((PWND)pWndOrCls)->pcls;
    00907         else
    00908             pcls = pWndOrCls;
    00909 #if DBG
    00910         bAnsiProc = !!(pcls->CSF_flags & CSF_ANSIPROC);
    00911 #endif
    00912     }
    00913
    00914 #if DBG
    00915     /*
    00916      * We should never have a CallProc handle as the calling address
    00917      */
    00918     UserAssert(!ISCPDTAG(dwProc32));
    00919
    00920     if (CPDOption & CPD_UNICODE_TO_ANSI) {
    00921         UserAssert(bAnsiProc);
    00922     } else if (CPDOption & CPD_ANSI_TO_UNICODE) {
    00923         UserAssert(!bAnsiProc);
    00924     }
    00925
    00926 #endif // DBG
    00927
    00928     /*
    00929      * See if we already have a CallProc Handle that represents this
    00930      * transition
    00931      */
    00932     pCPD = FindPCPD(pcls->spcpdFirst, dwProc32, (WORD)CPDOption);
    00933
    00934     if (pCPD) {
    00935         return MAKE_CPDHANDLE(PtoH(pCPD));
    00936     }
    00937
    00938     CheckCritIn();
    00939
    00940     ptiCurrent = PtiCurrent();
    00941
    00942     pCPD = HMAllocObject(ptiCurrent,
    00943                          ptiCurrent->rpdesk,
    00944                          TYPE_CALLPROC,
    00945                          sizeof(CALLPROCDATA));
    00946     if (pCPD == NULL) {
    00947         RIPMSG0(RIP_WARNING, "GetCPD unable to alloc CALLPROCDATA\n");
    00948         return 0;
    00949     }
    00950
    00951     /*
    00952      * Link in the new CallProcData to the class list.
    00953      * Note -- these pointers are locked because WOWCleanup can come in
    00954      * and delete objects, so we need to keep the pointers locked.
    00955      */
    00956     Lock(&pCPD->spcpdNext, pcls->spcpdFirst);
    00957     Lock(&pcls->spcpdFirst, pCPD);
    00958
    00959     /*
    00960      * Initialize the CPD
    00961      */
    00962     pCPD->pfnClientPrevious = dwProc32;
    00963     pCPD->wType = (WORD)CPDOption;
    00964
    00965     return MAKE_CPDHANDLE(PtoH(pCPD));
    00966 }
    00967
    00968 /***************************************************************************\
    00969 * MapClientToServerPfn
    00970 *
    00971 * Checks to see if a dword is a client wndproc stub to a server wndproc.
    00972 * If it is, this returns the associated server side wndproc. If it isn't
    00973 * this returns 0.
    00974 *
    00975 * 13-Jan-1992 ScottLu   Created.
    00976 \***************************************************************************/
    00977
    00978 ULONG_PTR MapClientToServerPfn(
    00979     ULONG_PTR dw)
    00980 {
    00981     ULONG_PTR *pdw;
    00982     int   i;
    00983
    00984     pdw = (ULONG_PTR *)&gpsi->apfnClientW;
    00985     for (i = FNID_WNDPROCSTART; i <= FNID_WNDPROCEND; i++, pdw++) {
    00986         if (*pdw == dw)
    00987             return (ULONG_PTR)STOCID(i);
    00988     }
    00989
    00990     pdw = (ULONG_PTR *)&gpsi->apfnClientA;
    00991     for (i = FNID_WNDPROCSTART; i <= FNID_WNDPROCEND; i++, pdw++) {
    00992         if (*pdw == dw)
    00993             return (ULONG_PTR)STOCID(i);
    00994     }
    00995
    00996     return 0;
    00997 }
    00998
    00999 ULONG DBGGetWindowLong(PWND pwnd, int index)
    01000 {
    01001     UserAssert(index >= 0);
    01002     UserAssert((UINT)index + sizeof(DWORD) <= (UINT)pwnd->cbwndExtra);
    01003     return __GetWindowLong(pwnd, index);
    01004 }
    01005
    01006 ULONG_PTR DBGGetWindowLongPtr(PWND pwnd, int index)
    01007 {
    01008     UserAssert(index >= 0);
    01009     UserAssert((UINT)index + sizeof(ULONG_PTR) <= (UINT)pwnd->cbwndExtra);
    01010     return __GetWindowLongPtr(pwnd, index);
    01011 }