test: clinit.c Source File

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

# clinit.c

Go to the documentation of this file.

    00001 /****************************** Module Header ******************************\
    00002 * Module Name: clinit.c
    00003 *
    00004 * Copyright (c) 1985 - 1999, Microsoft Corporation
    00005 *
    00006 * This module contains all the init code for the USER.DLL. When the DLL is
    00007 * dynlinked its initialization procedure (UserDllInitialize) is called by
    00008 * the loader.
    00009 *
    00010 * History:
    00011 * 18-Sep-1990 DarrinM Created.
    00012 \***************************************************************************/
    00013
    00014 #include "precomp.h"
    00015 #pragma hdrstop
    00016 #include <conroute.h>
    00017 #include "csrhlpr.h"
    00018
    00019 #include "badapps.h"
    00020
    00021 /*
    00022  * Global variables local to this module (startup).
    00023  */
    00024 BOOL         gfFirstThread = TRUE;
    00025 PDESKTOPINFO pdiLocal;
    00026 BOOL         gbIhaveBeenInited;
    00027 static DWORD gdwLpkEntryPoints;
    00028
    00029 CONST WCHAR pwszWindowsKey[]      = L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows";
    00030 CONST WCHAR szAppInit[] = L"AppInit_DLLs";
    00031
    00032 CONST WCHAR gwszShimDll[] = L"shim.dll";
    00033 CONST CHAR  gszLoadPathDll[] = "LoadPatchDll";
    00034
    00035 /*
    00036  * External declared routines needed for startup.
    00037  */
    00038 BOOL GdiProcessSetup();
    00039 BOOL GdiDllInitialize(IN PVOID hmod, IN DWORD Reason, IN PCONTEXT pctx OPTIONAL);
    00040
    00041 WCHAR szWindowStationDirectory[MAX_SESSION_PATH];
    00042 #ifdef _JANUS_
    00043 BOOL InitInstrument(LPDWORD lpEMIControl);
    00044 #endif
    00045 /***************************************************************************\
    00046 * UserClientDllInitialize
    00047 *
    00048 * When USER.DLL is loaded by an EXE (either at EXE load or at LoadModule
    00049 * time) this routine is called by the loader. Its purpose is to initialize
    00050 * everything that will be needed for future User API calls by the app.
    00051 *
    00052 * History:
    00053 * 19-Sep-1990 DarrinM Created.
    00054 \***************************************************************************/
    00055
    00056 extern CONST PCSR_CALLBACK_ROUTINE apfnDispatch[];
    00057 extern CONST ULONG                 ulMaxApiIndex;
    00058
    00059 BOOL UserClientDllInitialize(
    00060     IN PVOID    hmod,
    00061     IN DWORD    Reason,
    00062     IN PCONTEXT pctx OPTIONAL)
    00063 {
    00064     SYSTEM_BASIC_INFORMATION SystemInformation;
    00065     BOOL bRet = FALSE;
    00066
    00067     DBG_UNREFERENCED_PARAMETER(pctx);
    00068
    00069 #if DBG
    00070     if (RtlGetNtGlobalFlags() & FLG_SHOW_LDR_SNAPS) {
    00071         RIPMSG1(RIP_WARNING,
    00072                 "UserClientDllInitialize: entered for reason %x",
    00073                 Reason);
    00074     }
    00075 #endif
    00076
    00077     if (Reason == DLL_PROCESS_ATTACH) {
    00078
    00079         NTSTATUS    status;
    00080         USERCONNECT userconnect;
    00081         ULONG       ulConnect = sizeof(USERCONNECT);
    00082         ULONG       SessionId = NtCurrentPeb()->SessionId;
    00083         WCHAR       szSessionDir[MAX_SESSION_PATH];
    00084
    00085         DisableThreadLibraryCalls(hmod);
    00086
    00087         if (gbIhaveBeenInited) {
    00088             return TRUE;
    00089         }
    00090
    00091         gbIhaveBeenInited = TRUE;
    00092
    00093         status  = RtlInitializeCriticalSection(&gcsClipboard);
    00094         status |= RtlInitializeCriticalSection(&gcsLookaside);
    00095         status |= RtlInitializeCriticalSection(&gcsHdc);
    00096         status |= RtlInitializeCriticalSection(&gcsAccelCache);
    00097         status |= RtlInitializeCriticalSection(&gcsDDEML);
    00098
    00099 #ifdef WX86
    00100         status |= RtlInitializeCriticalSection(&gcsWx86Load);
    00101 #endif
    00102
    00103         if (!NT_SUCCESS(status)) {
    00104             RIPMSG1(RIP_WARNING,
    00105                     "UserClientDllInitialize: Failed to create critical sections. Status %x",
    00106                     status);
    00107             return FALSE;
    00108         }
    00109 #if DBG
    00110         gpDDEMLHeap = RtlCreateHeap(HEAP_GROWABLE | HEAP_CLASS_1
    00111                               | HEAP_TAIL_CHECKING_ENABLED | HEAP_FREE_CHECKING_ENABLED
    00112                               , NULL, 8 * 1024, 2 * 1024, NULL, NULL);
    00113
    00114         if (gpDDEMLHeap == NULL) {
    00115             gpDDEMLHeap = RtlProcessHeap();
    00116         }
    00117 #endif
    00118
    00119         status = NtQuerySystemInformation(SystemBasicInformation,
    00120                                           &SystemInformation,
    00121                                           sizeof(SystemInformation),
    00122                                           NULL);
    00123         if (!NT_SUCCESS(status)) {
    00124             RIPMSG1(RIP_WARNING,
    00125                     "UserClientDllInitialize: NtQuerySystemInformation failed with Status %x",
    00126                     status);
    00127             return FALSE;
    00128         }
    00129         gHighestUserAddress = SystemInformation.MaximumUserModeAddress;
    00130
    00131         userconnect.ulVersion = USERCURRENTVERSION;
    00132
    00133         if (ISTS()) {
    00134
    00135             if (SessionId == 0) {
    00136                 wcscpy(szSessionDir, WINSS_OBJECT_DIRECTORY_NAME);
    00137             } else {
    00138                 swprintf(szSessionDir, L"%ws\\%ld%ws",
    00139                          SESSION_ROOT,
    00140                          SessionId,
    00141                          WINSS_OBJECT_DIRECTORY_NAME);
    00142             }
    00143
    00144             status = UserConnectToServer(szSessionDir,
    00145                                          &userconnect,
    00146                                          &ulConnect,
    00147                                          (PBOOLEAN)&gfServerProcess);
    00148
    00149         } else {
    00150
    00151             status = UserConnectToServer(WINSS_OBJECT_DIRECTORY_NAME,
    00152                                          &userconnect,
    00153                                          &ulConnect,
    00154                                          (PBOOLEAN)&gfServerProcess);
    00155         }
    00156
    00157         if (!NT_SUCCESS(status)) {
    00158             RIPMSG1(RIP_WARNING,
    00159                     "UserClientDllInitialize: UserConnectToServer failed with status %x",
    00160                     status);
    00161             return FALSE;
    00162         }
    00163
    00164
    00165         /*
    00166          * If this is the server process, the shared info is not
    00167          * yet valid, so don't copy out the returned info.
    00168          */
    00169         if (!gfServerProcess) {
    00170             HINSTANCE hImm32 = NULL;
    00171
    00172             gSharedInfo = userconnect.siClient;
    00173             gpsi = gSharedInfo.psi;
    00174
    00175             // make sure the stub (dummy) routine works
    00176             UserAssert(sizeof(LRESULT) == sizeof(ULONG_PTR));
    00177             UserAssert(sizeof(PVOID) == sizeof(ULONG_PTR));
    00178             if (IS_IME_ENABLED()) {
    00179                 WCHAR wszImmFile[MAX_PATH];
    00180
    00181                 InitializeImmEntryTable();
    00182                 GetImmFileName(wszImmFile);
    00183                 hImm32 = GetModuleHandleW(wszImmFile);
    00184             }
    00185             if (!fpImmRegisterClient(&userconnect.siClient, hImm32)) {
    00186                 RIPMSG0(RIP_WARNING,
    00187                         "UserClientDllInitialize: ImmRegisterClient failed");
    00188                 return FALSE;
    00189             }
    00190         }
    00191
    00192         pfnFindResourceExA = (PFNFINDA)FindResourceExA;
    00193         pfnFindResourceExW = (PFNFINDW)FindResourceExW;
    00194         pfnLoadResource    = (PFNLOAD)LoadResource;
    00195         pfnSizeofResource  = (PFNSIZEOF)SizeofResource;
    00196
    00197         /*
    00198          * Register with the base the USER hook it should call when it
    00199          * does a WinExec() (this is soft-linked because some people still
    00200          * use charmode nt!
    00201          */
    00202         RegisterWaitForInputIdle(WaitForInputIdle);
    00203
    00204
    00205         /*
    00206          * Remember USER.DLL's hmodule so we can grab resources from it later.
    00207          */
    00208         hmodUser = hmod;
    00209
    00210         pUserHeap = RtlProcessHeap();
    00211
    00212         /*
    00213          * Initialize callback table
    00214          */
    00215         NtCurrentPeb()->KernelCallbackTable = apfnDispatch;
    00216         NtCurrentPeb()->PostProcessInitRoutine = NULL;
    00217
    00218         if (SessionId != 0) {
    00219             swprintf(szWindowStationDirectory,L"%ws\\%ld%ws",SESSION_ROOT,SessionId,WINSTA_DIR);
    00220             RtlInitUnicodeString(&strRootDirectory, szWindowStationDirectory);
    00221
    00222         } else {
    00223             RtlInitUnicodeString(&strRootDirectory, WINSTA_DIR);
    00224         }
    00225
    00226 #ifdef _JANUS_
    00227         gfEMIEnable = InitInstrument(&gdwEMIControl);
    00228         if (gfServerProcess) {
    00229             gfEMIEnable = FALSE;
    00230         }
    00231 #endif
    00232     } else if (Reason == DLL_PROCESS_DETACH) {
    00233
    00234         if (ghImm32 != NULL) {
    00235             // IMM32.DLL is loaded by USER32, so free it.
    00236             FreeLibrary(ghImm32);
    00237         }
    00238
    00239         /*
    00240          * If we loaded OLE, tell it we're done.
    00241          */
    00242         if (ghinstOLE != NULL) {
    00243             /*
    00244              * Later5.0 GerardoB. This causes check OLE32.DLL to fault
    00245              *  because they get their DLL_PROCESS_DETACH first
    00246              * (*(OLEUNINITIALIZEPROC)gpfnOLEOleUninitialize)();
    00247              */
    00248             RIPMSG0(RIP_WARNING, "OLE would fault if I call OleUninitialize now");
    00249             FreeLibrary(ghinstOLE);
    00250         }
    00251
    00252         /*
    00253          * If we loaded WinSta.Dll for Terminal Services, then
    00254          * unload it now.
    00255          */
    00256         if (ghinstWinStaDll != NULL) {
    00257             FreeLibrary(ghinstWinStaDll);
    00258         }
    00259
    00260 #ifdef _JANUS_
    00261         if (gfEMIEnable && (ghAdvApi != NULL)) {
    00262             FreeLibrary(ghAdvApi);
    00263         }
    00264 #endif
    00265
    00266         RtlDeleteCriticalSection(&gcsClipboard);
    00267         RtlDeleteCriticalSection(&gcsLookaside);
    00268         RtlDeleteCriticalSection(&gcsHdc);
    00269         RtlDeleteCriticalSection(&gcsAccelCache);
    00270         RtlDeleteCriticalSection(&gcsDDEML);
    00271 #if DBG
    00272         if (gpDDEMLHeap != RtlProcessHeap()) {
    00273             RtlDestroyHeap(gpDDEMLHeap);
    00274         }
    00275 #endif
    00276
    00277
    00278 #ifdef WX86
    00279         RtlDeleteCriticalSection(&gcsWx86Load);
    00280 #endif
    00281
    00282     }
    00283
    00284     bRet = GdiDllInitialize(hmod, Reason, pctx);
    00285     if (!bRet) {
    00286         RIPMSG0(RIP_WARNING,
    00287                 "UserClientDllInitialize: GdiDllInitialize failed");
    00288     }
    00289
    00290     return(bRet);
    00291 }
    00292
    00293 /***************************************************************************\
    00294 * LoadCursorsAndIcons
    00295 *
    00296 * This gets called from our initialization call from csr so they're around
    00297 * when window classes get registered. Window classes get registered right
    00298 * after the initial csr initialization call.
    00299 *
    00300 * Later on these default images will get overwritten by custom
    00301 * registry entries.  See UpdateCursors/IconsFromRegistry().
    00302 *
    00303 * 27-Sep-1992 ScottLu      Created.
    00304 * 14-Oct-1995 SanfordS     Rewrote.
    00305 \***************************************************************************/
    00306
    00307 BOOL LoadCursorsAndIcons(VOID)
    00308 {
    00309     int    i;
    00310     HANDLE h;
    00311     BOOL   fSuccess = TRUE;
    00312
    00313     for (i = 0; i < COIC_CONFIGURABLE; i++) {
    00314         /*
    00315          * load the small version of WINLOGO which will be set into
    00316          * gpsi->hIconSmWindows on the kernel side.
    00317          */
    00318         if (i == OIC_WINLOGO_DEFAULT - OIC_FIRST_DEFAULT) {
    00319             h = LoadIcoCur(NULL,
    00320                            (LPCWSTR)UIntToPtr( (OIC_FIRST_DEFAULT + i) ),
    00321                            RT_ICON,
    00322                            SYSMET(CXSMICON),
    00323                            SYSMET(CYSMICON),
    00324                            LR_GLOBAL);
    00325
    00326             fSuccess &= !!h;
    00327         }
    00328         h = LoadIcoCur(NULL,
    00329                        (LPCWSTR)UIntToPtr( (OIC_FIRST_DEFAULT + i) ),
    00330                        RT_ICON,
    00331                        0,
    00332                        0,
    00333                        LR_SHARED | LR_GLOBAL);
    00334
    00335         fSuccess &= !!h;
    00336     }
    00337
    00338     for (i = 0; i < COCR_CONFIGURABLE; i++) {
    00339         h = LoadIcoCur(NULL,
    00340                        (LPCWSTR)UIntToPtr( (OCR_FIRST_DEFAULT + i) ),
    00341                        RT_CURSOR,
    00342                        0,
    00343                        0,
    00344                        LR_SHARED | LR_GLOBAL);
    00345
    00346         fSuccess &= !!h;
    00347     }
    00348
    00349     if (!fSuccess) {
    00350         RIPMSG0(RIP_WARNING, "LoadCursorsAndIcons failed to load cursors");
    00351     }
    00352
    00353     /*
    00354      * Now go to the kernel and fixup the IDs from DEFAULT values
    00355      * to standard values.
    00356      */
    00357     NtUserCallNoParam(SFI__LOADCURSORSANDICONS);
    00358
    00359     return fSuccess;
    00360 }
    00361
    00362 /***************************************************************************\
    00363 * RW_RegisterControls
    00364 *
    00365 * Register the control classes. This function must be called for each
    00366 * client process.
    00367 *
    00368 * History:
    00369 * ??-??-?? DarrinM Ported.
    00370 * ??-??-?? MikeKe Moved here from server.
    00371 \***************************************************************************/
    00372
    00373 /*
    00374  * NOTE -- the class names must stay in the RegisterClass exactly as they are, since
    00375  * MS-TEST assumes these names exist as strings.
    00376  */
    00377
    00378 BOOL RW_RegisterControls(VOID)
    00379 {
    00380     int        i;
    00381     WNDCLASSEX wndcls;
    00382     BOOL       fSuccess = TRUE;
    00383
    00384     static CONST struct {
    00385         UINT    style;
    00386         WNDPROC lpfnWndProcW;
    00387         int     cbWndExtra;
    00388         LPCTSTR lpszCursor;
    00389         HBRUSH  hbrBackground;
    00390         LPCTSTR lpszClassName;
    00391         WORD    fnid;
    00392     } rc[] = {
    00393
    00394         {CS_GLOBALCLASS | CS_PARENTDC | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW,
    00395          ButtonWndProcW,
    00396          sizeof(BUTNWND) - sizeof(WND),
    00397          IDC_ARROW,
    00398          NULL,
    00399          L"Button",
    00400          FNID_BUTTON
    00401         },
    00402
    00403         {CS_GLOBALCLASS | CS_DBLCLKS | CS_PARENTDC | CS_VREDRAW | CS_HREDRAW,
    00404          ComboBoxWndProcW,
    00405          sizeof(COMBOWND) - sizeof(WND),
    00406          IDC_ARROW,
    00407          NULL,
    00408          L"ComboBox",
    00409          FNID_COMBOBOX
    00410         },
    00411
    00412         {CS_GLOBALCLASS | CS_DBLCLKS | CS_SAVEBITS,
    00413          ComboListBoxWndProcW,
    00414          sizeof(LBWND) - sizeof(WND),
    00415          IDC_ARROW,
    00416          NULL,
    00417          L"ComboLBox",
    00418          FNID_COMBOLISTBOX
    00419         },
    00420
    00421         {CS_GLOBALCLASS | CS_DBLCLKS | CS_SAVEBITS,
    00422          DefDlgProcW,
    00423          DLGWINDOWEXTRA,
    00424          IDC_ARROW,
    00425          NULL,
    00426          DIALOGCLASS,
    00427          FNID_DIALOG
    00428         },
    00429
    00430         {CS_GLOBALCLASS | CS_PARENTDC | CS_DBLCLKS,
    00431          EditWndProcW,
    00432          max((sizeof(EDITWND) - sizeof(WND)), CBEDITEXTRA),
    00433          IDC_IBEAM,
    00434          NULL,
    00435          L"Edit",
    00436          FNID_EDIT
    00437         },
    00438
    00439         {CS_GLOBALCLASS | CS_PARENTDC | CS_DBLCLKS,
    00440          ListBoxWndProcW,
    00441          sizeof(LBWND) - sizeof(WND),
    00442          IDC_ARROW,
    00443          NULL,
    00444          L"ListBox",
    00445          FNID_LISTBOX
    00446         },
    00447
    00448         {CS_GLOBALCLASS,
    00449          MDIClientWndProcW,
    00450          sizeof(MDIWND) - sizeof(WND),
    00451          IDC_ARROW,
    00452          (HBRUSH)(COLOR_APPWORKSPACE + 1),
    00453          L"MDIClient",
    00454          FNID_MDICLIENT
    00455         },
    00456
    00457         {CS_GLOBALCLASS,
    00458          ImeWndProcW,
    00459          sizeof(IMEWND) - sizeof(WND),
    00460          IDC_ARROW,
    00461          NULL,
    00462          L"IME",
    00463          FNID_IME
    00464         },
    00465
    00466         {CS_GLOBALCLASS | CS_PARENTDC | CS_DBLCLKS,
    00467          StaticWndProcW,
    00468          sizeof(STATWND) - sizeof(WND),
    00469          IDC_ARROW,
    00470          NULL,
    00471          L"Static",
    00472          FNID_STATIC
    00473         }
    00474     };
    00475
    00476
    00477     /*
    00478      * Classes are registered via the table.
    00479      */
    00480     RtlZeroMemory(&wndcls, sizeof(wndcls));
    00481     wndcls.cbSize       = sizeof(wndcls);
    00482     wndcls.hInstance    = hmodUser;
    00483
    00484     for (i = 0; i < (sizeof(rc)/sizeof(rc[0])); i++) {
    00485         wndcls.style        = rc[i].style;
    00486         wndcls.lpfnWndProc  = rc[i].lpfnWndProcW;
    00487         wndcls.cbWndExtra   = rc[i].cbWndExtra;
    00488         wndcls.hCursor      = LoadCursor(NULL, rc[i].lpszCursor);
    00489         wndcls.hbrBackground= rc[i].hbrBackground;
    00490         wndcls.lpszClassName= rc[i].lpszClassName;
    00491
    00492         fSuccess &= !!RegisterClassExWOWW(&wndcls, NULL, rc[i].fnid);
    00493     }
    00494
    00495     if (!fSuccess) {
    00496         RIPMSG0(RIP_WARNING, "RW_RegisterControls failed to register classes");
    00497     }
    00498
    00499     return fSuccess;
    00500 }
    00501
    00502 /***************************************************************************\
    00503 * RW_RegisterDDEML
    00504 *
    00505 * Register all the DDEML classes
    00506 *
    00507 * History:
    00508 * 01-Dec-1991 Sanfords Created.
    00509 \***************************************************************************/
    00510
    00511 BOOL RW_RegisterDDEML(VOID)
    00512 {
    00513     WNDCLASSEXA wndclsa;
    00514     WNDCLASSEXW wndclsw;
    00515     BOOL        fSuccess = TRUE;
    00516
    00517     RtlZeroMemory(&wndclsw, sizeof(wndclsw));
    00518     wndclsw.cbSize        = sizeof(wndclsw);
    00519     wndclsw.lpfnWndProc   = DDEMLMotherWndProc;
    00520     wndclsw.cbWndExtra    = sizeof(PCL_INSTANCE_INFO);
    00521     wndclsw.hInstance     = hmodUser;
    00522     wndclsw.lpszClassName = L"DDEMLMom";
    00523
    00524     fSuccess &= !!RegisterClassExWOWW(&wndclsw, NULL, FNID_DDE_BIT);
    00525
    00526     RtlZeroMemory(&wndclsa, sizeof(wndclsa));
    00527     wndclsa.cbSize        = sizeof(wndclsa);
    00528     wndclsa.lpfnWndProc   = DDEMLClientWndProc;
    00529     wndclsa.cbWndExtra    =
    00530             sizeof(PCL_CONV_INFO) +     // GWL_PCI
    00531             sizeof(CONVCONTEXT)   +     // GWL_CONVCONTEXT
    00532             sizeof(LONG)          +     // GWL_CONVSTATE
    00533             sizeof(HANDLE)        +     // GWL_CHINST
    00534             sizeof(HANDLE);             // GWL_SHINST
    00535     wndclsa.hInstance     = hmodUser;
    00536     wndclsa.lpszClassName = "DDEMLAnsiClient";
    00537
    00538     fSuccess &= !!RegisterClassExWOWA(&wndclsa, NULL, FNID_DDE_BIT);
    00539
    00540     wndclsw.cbSize        = sizeof(wndclsw);
    00541     wndclsw.lpfnWndProc   = DDEMLClientWndProc;
    00542     wndclsw.cbWndExtra    =
    00543             sizeof(PCL_CONV_INFO) +     // GWL_PCI
    00544             sizeof(CONVCONTEXT)   +     // GWL_CONVCONTEXT
    00545             sizeof(LONG)          +     // GWL_CONVSTATE
    00546             sizeof(HANDLE)        +     // GWL_CHINST
    00547             sizeof(HANDLE);             // GWL_SHINST
    00548     wndclsw.hInstance     = hmodUser;
    00549     wndclsw.lpszClassName = L"DDEMLUnicodeClient";
    00550
    00551     fSuccess &= !!RegisterClassExWOWW(&wndclsw, NULL, FNID_DDE_BIT);
    00552
    00553     wndclsa.cbSize        = sizeof(wndclsa);
    00554     wndclsa.lpfnWndProc   = DDEMLServerWndProc;
    00555     wndclsa.cbWndExtra    = sizeof(PSVR_CONV_INFO);     // GWL_PSI
    00556     wndclsa.hInstance     = hmodUser;
    00557     wndclsa.lpszClassName = "DDEMLAnsiServer";
    00558
    00559     fSuccess &= !!RegisterClassExWOWA(&wndclsa, NULL, FNID_DDE_BIT);
    00560
    00561     wndclsw.cbSize        = sizeof(wndclsw);
    00562     wndclsw.lpfnWndProc   = DDEMLServerWndProc;
    00563     wndclsw.cbWndExtra    = sizeof(PSVR_CONV_INFO);     // GWL_PSI
    00564     wndclsw.hInstance     = hmodUser;
    00565     wndclsw.lpszClassName = L"DDEMLUnicodeServer";
    00566
    00567     fSuccess &= !!RegisterClassExWOWW(&wndclsw, NULL, FNID_DDE_BIT);
    00568
    00569     if (!fSuccess) {
    00570         RIPMSG0(RIP_WARNING, "RW_RegisterDDEML failed to register classes");
    00571     }
    00572
    00573     return fSuccess;
    00574 }
    00575
    00576 /***************************************************************************\
    00577 * GetBadAppCmdLine()
    00578 *
    00579 *   This routine checks if the app specified by 'lpApplicationName'
    00580 *   needs patching.
    00581 *
    00582 * Arguments:
    00583 *
    00584 *   lpApplicationName - contains the full path and application name
    00585 *       for the binary that needs to be identified for patching
    00586 *
    00587 * Return Value:
    00588 *
    00589 *   Returns a pointer to the command line for the patch DLL.
    00590 *
    00591 *   NOTE: The caller needs to free the pointer returned by this function
    00592 *
    00593 * History:
    00594 *
    00595 * 27-Jul-1998  clupu   Created.
    00596 \***************************************************************************/
    00597 LPSTR
    00598 GetBadAppCmdLine(
    00599     IN LPCWSTR lpApplicationName)
    00600 {
    00601
    00602 #define DLLPATCH_NAME       L"DllPatch"
    00603
    00604     UNICODE_STRING      strKeyPath;
    00605     UNICODE_STRING      strDllPatchName;
    00606     OBJECT_ATTRIBUTES   objA;
    00607     WCHAR               strBuffer[256];
    00608     WCHAR               strDllPatch[64];
    00609     WCHAR               strName[32];
    00610     HANDLE              hkey;
    00611     NTSTATUS            Status;
    00612     WCHAR*              lpShortName;
    00613     BADAPP_DATA         badAppData;
    00614     BADAPP_PROP         badAppProp;
    00615     ULONG               iValue, cbSize, cbCrtSize;
    00616     LPSTR               pszCmdLine = NULL;
    00617     BOOL                bRet;
    00618
    00619     PKEY_VALUE_FULL_INFORMATION pKeyValueInformation;
    00620
    00621 #if DBG
    00622     /*
    00623      * Assert that there is at least one path separator
    00624      */
    00625
    00626     lpShortName = (LPWSTR)lpApplicationName;
    00627
    00628     while (*lpShortName != 0) {
    00629         if (*lpShortName == OBJ_NAME_PATH_SEPARATOR) {
    00630             break;
    00631         }
    00632         lpShortName++;
    00633     }
    00634
    00635     UserAssert(*lpShortName == OBJ_NAME_PATH_SEPARATOR);
    00636 #endif // DBG
    00637
    00638     /*
    00639      * Get the short name of the file
    00640      */
    00641     lpShortName = (WCHAR*)lpApplicationName + wcslen(lpApplicationName) - 1;
    00642
    00643
    00644     while (*lpShortName != OBJ_NAME_PATH_SEPARATOR) {
    00645         lpShortName--;
    00646     }
    00647
    00648     /*
    00649      * Prepare the registry key
    00650      */
    00651     wcscpy(strBuffer,
    00652            L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager\\AppCompatibility");
    00653
    00654     wcscat(strBuffer, lpShortName);
    00655
    00656     RtlInitUnicodeString(&strKeyPath, strBuffer);
    00657
    00658     InitializeObjectAttributes(&objA,
    00659                                &strKeyPath,
    00660                                OBJ_CASE_INSENSITIVE,
    00661                                NULL,
    00662                                NULL);
    00663
    00664     Status = NtOpenKey(&hkey, GENERIC_READ, &objA);
    00665
    00666     if (!NT_SUCCESS(Status)) {
    00667         return NULL;
    00668     }
    00669
    00670     /*
    00671      * Now verify that this is the actual version of the app
    00672      */
    00673
    00674     pKeyValueInformation = NULL;
    00675     cbCrtSize = 0;
    00676
    00677     badAppProp.Size     = sizeof(BADAPP_PROP);
    00678     badAppData.Size     = sizeof(BADAPP_DATA);
    00679     badAppData.FilePath = (LPCWSTR)lpApplicationName;
    00680
    00681     /*
    00682      * Presume innocent
    00683      */
    00684     bRet = FALSE;
    00685
    00686     for (iValue = 0; ; iValue++) {
    00687
    00688         Status = NtEnumerateValueKey(hkey,
    00689                                      iValue,
    00690                                      KeyValueFullInformation,
    00691                                      pKeyValueInformation,
    00692                                      cbCrtSize,
    00693                                      &cbSize);
    00694
    00695         if (Status == STATUS_NO_MORE_ENTRIES) {
    00696             break;
    00697         }
    00698
    00699         if (Status == STATUS_BUFFER_TOO_SMALL ||
    00700             Status == STATUS_BUFFER_OVERFLOW) {
    00701
    00702             if (pKeyValueInformation != NULL) {
    00703                 RtlFreeHeap(RtlProcessHeap(), 0, pKeyValueInformation);
    00704             }
    00705
    00706             pKeyValueInformation = RtlAllocateHeap(RtlProcessHeap(),
    00707                                                    0,
    00708                                                    cbSize);
    00709
    00710             if (pKeyValueInformation == NULL) {
    00711
    00712                 /*
    00713                  * Print some memory allocation error message
    00714                  */
    00715                 TAGMSG0(DBGTAG_Shim, "Memory allocation error");
    00716                 break;
    00717             }
    00718
    00719             cbCrtSize = cbSize;
    00720
    00721             /*
    00722              * Enumerate the key again. This time it should have
    00723              * a big enough buffer.
    00724              */
    00725             Status = NtEnumerateValueKey(hkey,
    00726                                          iValue,
    00727                                          KeyValueFullInformation,
    00728                                          pKeyValueInformation,
    00729                                          cbCrtSize,
    00730                                          &cbSize);
    00731
    00732             UserAssert(!NT_SUCCESS(Status) || (cbCrtSize == cbSize));
    00733         }
    00734
    00735
    00736         if (NT_SUCCESS(Status) && pKeyValueInformation->Type == REG_BINARY) {
    00737
    00738             RtlCopyMemory(strName,
    00739                           pKeyValueInformation->Name,
    00740                           pKeyValueInformation->NameLength);
    00741
    00742             strName[pKeyValueInformation->NameLength / sizeof(WCHAR)] = 0;
    00743
    00744             badAppData.Blob = (PBYTE)pKeyValueInformation +
    00745                               pKeyValueInformation->DataOffset;
    00746
    00747             badAppData.BlobSize = pKeyValueInformation->DataLength;
    00748
    00749             if (SHIsBadApp(&badAppData, &badAppProp)) {
    00750
    00751                 TAGMSG0(DBGTAG_Shim, "SHIsBadApp returned TRUE");
    00752
    00753                 bRet = TRUE;
    00754                 break;
    00755             } else {
    00756                 TAGMSG0(DBGTAG_Shim, "SHIsBadApp returned FALSE");
    00757             }
    00758         } else {
    00759             if (!NT_SUCCESS(Status)) {
    00760                 TAGMSG1(DBGTAG_Shim, "failed reading key. Status 0x%x",
    00761                         Status);
    00762             }
    00763         }
    00764     }
    00765
    00766     if (pKeyValueInformation != NULL) {
    00767         RtlFreeHeap(RtlProcessHeap(), 0, pKeyValueInformation);
    00768         pKeyValueInformation = NULL;
    00769     }
    00770
    00771
    00772     if (bRet) {
    00773
    00774         /*
    00775          * Read the REG_SZ for 'DllPatch-name'
    00776          */
    00777         wsprintf(strDllPatch, L"%ws-%ws", DLLPATCH_NAME, strName);
    00778
    00779         RtlInitUnicodeString(&strDllPatchName, strDllPatch);
    00780
    00781         Status = NtQueryValueKey(hkey,
    00782                                  &strDllPatchName,
    00783                                  KeyValueFullInformation,
    00784                                  NULL,
    00785                                  0,
    00786                                  &cbSize);
    00787
    00788         if (Status == STATUS_BUFFER_TOO_SMALL ||
    00789             Status == STATUS_BUFFER_OVERFLOW) {
    00790
    00791             LPWSTR pwszCmdLine;
    00792
    00793             pKeyValueInformation = RtlAllocateHeap(RtlProcessHeap(),
    00794                                                    0,
    00795                                                    cbSize);
    00796
    00797             if (pKeyValueInformation == NULL) {
    00798
    00799                 /*
    00800                  * Print some memory allocation error message
    00801                  */
    00802                 TAGMSG0(DBGTAG_Shim, "Memory allocation error");
    00803                 goto Exit;
    00804             }
    00805
    00806             Status = NtQueryValueKey(hkey,
    00807                                      &strDllPatchName,
    00808                                      KeyValueFullInformation,
    00809                                      pKeyValueInformation,
    00810                                      cbSize,
    00811                                      &cbCrtSize);
    00812
    00813             /*
    00814              * Bail out if this is not of the type we expect
    00815              */
    00816             if (!NT_SUCCESS(Status) || pKeyValueInformation->Type != REG_SZ) {
    00817                 TAGMSG1(DBGTAG_Shim, "The key '%s' is not of REG_SZ type",
    00818                         strDllPatch);
    00819                 goto Exit;
    00820             }
    00821
    00822             pwszCmdLine = (PWCHAR)((PBYTE)pKeyValueInformation +
    00823                                    pKeyValueInformation->DataOffset +
    00824                                    pKeyValueInformation->DataLength);
    00825
    00826             /*
    00827              * NULL terminate the string
    00828              */
    00829             *(pwszCmdLine - 1) = 0;
    00830
    00831             pwszCmdLine = (LPWSTR)((PBYTE)pKeyValueInformation +
    00832                                    pKeyValueInformation->DataOffset);
    00833
    00834             TAGMSG2(DBGTAG_Shim, "The app '%ws' has a patch DLL '%ws'",
    00835                     lpApplicationName,
    00836                     pwszCmdLine);
    00837
    00838             cbSize = wcslen(pwszCmdLine);
    00839
    00840             pszCmdLine = RtlAllocateHeap(RtlProcessHeap(),
    00841                                          0,
    00842                                          cbSize + 1);
    00843
    00844             if (pszCmdLine == NULL) {
    00845                 TAGMSG0(DBGTAG_Shim, "Memory allocation error");
    00846                 goto Exit;
    00847             }
    00848
    00849             WideCharToMultiByte(CP_OEMCP,
    00850                                 0,
    00851                                 pwszCmdLine,
    00852                                 cbSize + 1,
    00853                                 pszCmdLine,
    00854                                 cbSize + 1,
    00855                                 (LPSTR)NULL,
    00856                                 (LPBOOL)NULL);
    00857         }
    00858     }
    00859
    00860 Exit:
    00861
    00862     NtClose(hkey);
    00863
    00864     return pszCmdLine;
    00865 }
    00866
    00867 /***************************************************************************\
    00868 * CheckBadApp()
    00869 *
    00870 * History:
    00871 *
    00872 * 27-Jul-1998  clupu   Created.
    00873 \***************************************************************************/
    00874
    00875 typedef BOOL (*PFNLOADPATCHDLL)(LPSTR pwszPatchDll);
    00876
    00877 BOOL CheckBadApp(VOID)
    00878 {
    00879     WCHAR           wszAppName[MAX_PATH];
    00880     PFNLOADPATCHDLL pfnLoadPatchDll;
    00881     LPSTR           pszCmdLine;
    00882     BOOL            bRet;
    00883     DWORD           dwSize;
    00884     HMODULE         hMod;
    00885
    00886     dwSize = GetModuleFileNameW(NULL, wszAppName, MAX_PATH);
    00887
    00888     UserAssert(dwSize > 0);
    00889
    00890     pszCmdLine = GetBadAppCmdLine(wszAppName);
    00891
    00892     if (pszCmdLine == NULL) {
    00893         return TRUE;
    00894     }
    00895
    00896     if ( _stricmp( pszCmdLine, "disable" ) == 0 ) {
    00897        return FALSE;
    00898     }
    00899
    00900     hMod = LoadLibraryW(gwszShimDll);
    00901
    00902     if (hMod == NULL) {
    00903         RIPMSG0(RIP_WARNING, "Couldn't load SHIM.DLL");
    00904         goto Exit;
    00905     }
    00906     pfnLoadPatchDll = (PFNLOADPATCHDLL)GetProcAddress(hMod, gszLoadPathDll);
    00907
    00908     if (pfnLoadPatchDll == NULL) {
    00909         RIPMSG1(RIP_WARNING, "Couldn't find '%s' in SHIM.DLL",
    00910                 gszLoadPathDll);
    00911
    00912         FreeLibrary(hMod);
    00913         goto Exit;
    00914     }
    00915
    00916     bRet = (*pfnLoadPatchDll)(pszCmdLine);
    00917
    00918     UserAssert(bRet);
    00919
    00920 Exit:
    00921
    00922     RtlFreeHeap(RtlProcessHeap(), 0, pszCmdLine);
    00923     return TRUE;
    00924 }
    00925
    00926 /***************************************************************************\
    00927 * LoadAppDlls()
    00928 *
    00929 * History:
    00930 *
    00931 * 10-Apr-1992  sanfords   Birthed.
    00932 \***************************************************************************/
    00933 VOID LoadAppDlls(VOID)
    00934 {
    00935     extern BOOL gfLogonProcess;
    00936     UNICODE_STRING UnicodeString;
    00937     OBJECT_ATTRIBUTES ObjA;
    00938     HKEY hKeyWindows;
    00939     NTSTATUS Status;
    00940     DWORD cbSize;
    00941     struct {
    00942         KEY_VALUE_PARTIAL_INFORMATION KeyInfo;
    00943         WCHAR awch[24];
    00944     } KeyFile;
    00945     PKEY_VALUE_PARTIAL_INFORMATION  lpKeyFile = (PKEY_VALUE_PARTIAL_INFORMATION)&KeyFile;
    00946     DWORD cbSizeCurrent = sizeof(KeyFile);
    00947     BOOL bAlloc = FALSE;
    00948
    00949     if (gfLogonProcess || gfServerProcess) {
    00950
    00951         /*
    00952          * Don't let the logon process load appdlls because if the dll
    00953          * sets any hooks or creates any windows, the logon process
    00954          * will fail SetThreadDesktop().  This hack fixes that. (SAS)
    00955          */
    00956         return;
    00957     }
    00958
    00959     /*
    00960      * If the image is an NT Native image, we are running in the
    00961      * context of the server.
    00962      */
    00963     if (RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress)->
    00964         OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_NATIVE) {
    00965         return;
    00966     }
    00967
    00968     RtlInitUnicodeString(&UnicodeString, pwszWindowsKey);
    00969     InitializeObjectAttributes(&ObjA,
    00970             &UnicodeString,
    00971             OBJ_CASE_INSENSITIVE,
    00972             NULL,
    00973             NULL);
    00974
    00975
    00976     Status = NtOpenKey(&hKeyWindows,
    00977                     KEY_READ,
    00978                     &ObjA);
    00979
    00980
    00981     if (!NT_SUCCESS(Status))
    00982         return;
    00983
    00984     /*
    00985      * Read the "AppInit_Dlls" value.
    00986      */
    00987     RtlInitUnicodeString(&UnicodeString, szAppInit);
    00988
    00989     while (TRUE) {
    00990         Status = NtQueryValueKey(hKeyWindows,
    00991             &UnicodeString,
    00992             KeyValuePartialInformation,
    00993             lpKeyFile,
    00994             cbSizeCurrent,
    00995             &cbSize);
    00996
    00997         if (Status == STATUS_BUFFER_OVERFLOW) {
    00998             if (bAlloc) {
    00999                 UserGlobalFree(lpKeyFile);
    01000             }
    01001             lpKeyFile = GlobalAlloc(LPTR, cbSize);
    01002             if (!lpKeyFile) {
    01003                 RIPERR0(ERROR_OUTOFMEMORY,
    01004                     RIP_WARNING,
    01005                     "LoadAppDlls failed");
    01006                 NtClose(hKeyWindows);
    01007                 return;
    01008             }
    01009             bAlloc = TRUE;
    01010             cbSizeCurrent = cbSize;
    01011             continue;
    01012         }
    01013         break;
    01014     }
    01015     if (NT_SUCCESS(Status)) {
    01016         LPWSTR pszSrc;
    01017         LPWSTR pszDst;
    01018         LPWSTR pszBase;
    01019         WCHAR  ch;
    01020
    01021     /*
    01022      * Process the DLL data.
    01023      */
    01024         pszBase = pszDst = pszSrc = (LPWSTR)lpKeyFile->Data;
    01025         while (*pszSrc != TEXT('\0')) {
    01026
    01027             while (*pszSrc == TEXT(' ') || *pszSrc  == TEXT(','))
    01028                 pszSrc++;
    01029
    01030             if (*pszSrc == TEXT('\0'))
    01031                 break;
    01032
    01033             while (*pszSrc != TEXT(',')  &&
    01034                    *pszSrc != TEXT('\0') &&
    01035                    *pszSrc != TEXT(' ')) {
    01036                 *pszDst++ = *pszSrc++;
    01037             }
    01038
    01039             ch = *pszSrc;               // get it here cuz its being done in-place.
    01040             *pszDst++ = TEXT('\0');     // '\0' is dll name delimiter
    01041
    01042             LoadLibrary(pszBase);
    01043             pszBase = pszDst;
    01044
    01045             pszSrc++;
    01046
    01047             if (ch == TEXT('\0'))
    01048                 break;
    01049         }
    01050
    01051     }
    01052
    01053
    01054     if (bAlloc) {
    01055         UserGlobalFree(lpKeyFile);
    01056     }
    01057     NtClose(hKeyWindows);
    01058
    01059 }
    01060
    01061 VOID
    01062 InitOemXlateTables()
    01063 {
    01064     char ach[NCHARS];
    01065     WCHAR awch[NCHARS];
    01066     WCHAR awchCtrl[NCTRLS];
    01067     INT i;
    01068     INT cch;
    01069     char OemToAnsi[NCHARS];
    01070     char AnsiToOem[NCHARS];
    01071
    01072     for (i = 0; i < NCHARS; i++) {
    01073         ach[i] = (char)i;
    01074     }
    01075
    01076     /*
    01077      * First generate pAnsiToOem table.
    01078      */
    01079
    01080     if (GetOEMCP() == GetACP()) {
    01081         /*
    01082          * For far east code pages using MultiByteToWideChar below
    01083          * won't work.  Conveniently for these code pages the OEM
    01084          * CP equals the ANSI codepage making it trivial to compute
    01085          * pOemToAnsi and pAnsiToOem arrays
    01086          *
    01087          */
    01088
    01089         RtlCopyMemory(OemToAnsi, ach, NCHARS);
    01090         RtlCopyMemory(AnsiToOem, ach, NCHARS);
    01091
    01092     }
    01093     else
    01094     {
    01095         cch = MultiByteToWideChar(
    01096             CP_ACP,                           // ANSI -> Unicode
    01097             MB_PRECOMPOSED,                   // map to precomposed
    01098             ach, NCHARS,                      // source & length
    01099             awch, NCHARS);                    // destination & length
    01100
    01101         UserAssert(cch == NCHARS);
    01102
    01103         WideCharToMultiByte(
    01104             CP_OEMCP,                         // Unicode -> OEM
    01105             0,                                // gives best visual match
    01106             awch, NCHARS,                     // source & length
    01107             AnsiToOem, NCHARS,               // dest & max poss. length
    01108             "_",                              // default char
    01109             NULL);                            // (don't care whether defaulted)
    01110         /*
    01111          * Now generate pOemToAnsi table.
    01112          */
    01113         cch = MultiByteToWideChar(
    01114             CP_OEMCP,                         // OEM -> Unicode
    01115             MB_PRECOMPOSED | MB_USEGLYPHCHARS,// visual map to precomposed
    01116             ach, NCHARS,                      // source & length
    01117             awch, NCHARS);                    // destination
    01118
    01119         UserAssert(cch == NCHARS);
    01120
    01121         /*
    01122          * Now patch special cases for Win3.1 compatibility
    01123          *
    01124          * 0x07 BULLET              (glyph 0x2022) must become 0x0007 BELL
    01125          * 0x0F WHITE STAR WITH SUN (glyph 0x263C) must become 0x00A4 CURRENCY SIGN
    01126          * 0x7F HOUSE               (glyph 0x2302) must become 0x007f DELETE
    01127          */
    01128         awch[0x07] = 0x0007;
    01129         awch[0x0F] = 0x00a4;
    01130         awch[0x7f] = 0x007f;
    01131
    01132         WideCharToMultiByte(
    01133             CP_ACP,                           // Unicode -> ANSI
    01134             0,                                // gives best visual match
    01135             awch, NCHARS,                     // source & length
    01136             OemToAnsi, NCHARS,               // dest & max poss. length
    01137             "_",                              // default char
    01138             NULL);                            // (don't care whether defaulted)
    01139
    01140         /*
    01141          * Now for all OEM chars < 0x20 (control chars), test whether the glyph
    01142          * we have is really in CP_ACP or not.  If not, then restore the
    01143          * original control character. Note: 0x00 remains 0x00.
    01144          */
    01145         MultiByteToWideChar(CP_ACP, 0, OemToAnsi, NCTRLS, awchCtrl, NCTRLS);
    01146
    01147         for (i = 1; i < NCTRLS; i++) {
    01148             if (awchCtrl[i] != awch[i]) {
    01149                 OemToAnsi[i] = (char)i;
    01150             }
    01151         }
    01152     }
    01153     NtUserCallTwoParam((ULONG_PTR)OemToAnsi, (ULONG_PTR)AnsiToOem, SFI_INITANSIOEM);
    01154 }
    01155
    01156 const PFNCLIENT   pfnClientA = {
    01157         (KPROC)ScrollBarWndProcA,
    01158         (KPROC)DefWindowProcA,
    01159         (KPROC)MenuWndProcA,
    01160         (KPROC)DesktopWndProcA,
    01161         (KPROC)DefWindowProcA,
    01162         (KPROC)ButtonWndProcA,
    01163         (KPROC)ComboBoxWndProcA,
    01164         (KPROC)ComboListBoxWndProcA,
    01165         (KPROC)DefDlgProcA,
    01166         (KPROC)EditWndProcA,
    01167         (KPROC)ListBoxWndProcA,
    01168         (KPROC)MDIClientWndProcA,
    01169         (KPROC)StaticWndProcA,
    01170         (KPROC)ImeWndProcA,
    01171         (KPROC)fnHkINLPCWPSTRUCTA,
    01172         (KPROC)fnHkINLPCWPRETSTRUCTA,
    01173         (KPROC)DispatchHookA,
    01174         (KPROC)DispatchClientMessage,
    01175         (KPROC)MB_DlgProcA,
    01176         (KPROC)MDIActivateDlgProcA};
    01177
    01178 const   PFNCLIENT   pfnClientW = {
    01179         (KPROC)ScrollBarWndProcW,
    01180         (KPROC)DefWindowProcW,
    01181         (KPROC)MenuWndProcW,
    01182         (KPROC)DesktopWndProcW,
    01183         (KPROC)DefWindowProcW,
    01184         (KPROC)ButtonWndProcW,
    01185         (KPROC)ComboBoxWndProcW,
    01186         (KPROC)ComboListBoxWndProcW,
    01187         (KPROC)DefDlgProcW,
    01188         (KPROC)EditWndProcW,
    01189         (KPROC)ListBoxWndProcW,
    01190         (KPROC)MDIClientWndProcW,
    01191         (KPROC)StaticWndProcW,
    01192         (KPROC)ImeWndProcW,
    01193         (KPROC)fnHkINLPCWPSTRUCTW,
    01194         (KPROC)fnHkINLPCWPRETSTRUCTW,
    01195         (KPROC)DispatchHookW,
    01196         (KPROC)DispatchClientMessage,
    01197         (KPROC)MB_DlgProcW,
    01198         (KPROC)MDIActivateDlgProcW};
    01199
    01200 const PFNCLIENTWORKER   pfnClientWorker = {
    01201         (KPROC)ButtonWndProcWorker,
    01202         (KPROC)ComboBoxWndProcWorker,
    01203         (KPROC)ListBoxWndProcWorker,
    01204         (KPROC)DefDlgProcWorker,
    01205         (KPROC)EditWndProcWorker,
    01206         (KPROC)ListBoxWndProcWorker,
    01207         (KPROC)MDIClientWndProcWorker,
    01208         (KPROC)StaticWndProcWorker,
    01209         (KPROC)ImeWndProcWorker};
    01210
    01211
    01212 /***************************************************************************\
    01213 * ClientThreadSetup
    01214 *
    01215 *
    01216 *
    01217 \***************************************************************************/
    01218
    01219 BOOL ClientThreadSetup(VOID)
    01220 {
    01221     PCLIENTINFO pci;
    01222     BOOL        fFirstThread;
    01223     DWORD       ConnectState;
    01224
    01225 #ifdef TRACE_THREAD_INIT
    01226     KdPrint(("USER32: ClientThreadSetup (pteb: %#p)\n", NtCurrentTeb()));
    01227 #endif
    01228
    01229     /*
    01230      * BUG 268642: Only the first thread calls GdiProcessSetup but all the other
    01231      * threads must wait until the setup for GDI is finished.
    01232      *
    01233      * We can safely use gcsAccelCache critical section to protect this (even
    01234      * though the name is not intuitive at all)
    01235      */
    01236
    01237     RtlEnterCriticalSection(&gcsAccelCache);
    01238
    01239     fFirstThread = gfFirstThread;
    01240
    01241     /*
    01242      * setup GDI before continuing
    01243      */
    01244     if (fFirstThread) {
    01245         gfFirstThread = FALSE;
    01246         GdiProcessSetup();
    01247     }
    01248
    01249     RtlLeaveCriticalSection(&gcsAccelCache);
    01250
    01251     /*
    01252      * We've already checked to see if we need to connect
    01253      * (i.e. NtCurrentTeb()->Win32ThreadInfo == NULL)  This routine
    01254      * just does the connecting.  If we've already been through here
    01255      * once, don't do it again.
    01256      */
    01257     pci = GetClientInfo();
    01258     if (pci->CI_flags & CI_INITIALIZED) {
    01259         RIPMSG0(RIP_ERROR, "Already initialized!");
    01260         return FALSE;
    01261     }
    01262
    01263     /*
    01264      * Create the queue info and thread info. Only once for this process do
    01265      * we pass client side addresses to the server (for server callbacks).
    01266      */
    01267     if (gfServerProcess && fFirstThread) {
    01268
    01269         USERCONNECT userconnect;
    01270         NTSTATUS    Status;
    01271
    01272         /*
    01273          * We know that the shared info is now available in
    01274          * the kernel.  Map it into the server process.
    01275          */
    01276         userconnect.ulVersion = USERCURRENTVERSION;
    01277         userconnect.dwDispatchCount = gDispatchTableValues;
    01278         Status = NtUserProcessConnect(NtCurrentProcess(),
    01279                                       &userconnect,
    01280                                       sizeof(USERCONNECT));
    01281         if (!NT_SUCCESS(Status))
    01282             return FALSE;
    01283
    01284         gSharedInfo = userconnect.siClient;
    01285         gpsi = gSharedInfo.psi;
    01286         UserAssert(gpsi);
    01287
    01288         UserAssert(pfnClientA.pfnScrollBarWndProc   == (KPROC)ScrollBarWndProcA);
    01289         UserAssert(pfnClientA.pfnTitleWndProc       == (KPROC)DefWindowProcA);
    01290         UserAssert(pfnClientA.pfnMenuWndProc        == (KPROC)MenuWndProcA);
    01291         UserAssert(pfnClientA.pfnDesktopWndProc     == (KPROC)DesktopWndProcA);
    01292         UserAssert(pfnClientA.pfnDefWindowProc      == (KPROC)DefWindowProcA);
    01293         UserAssert(pfnClientA.pfnHkINLPCWPSTRUCT    == (KPROC)fnHkINLPCWPSTRUCTA);
    01294         UserAssert(pfnClientA.pfnHkINLPCWPRETSTRUCT == (KPROC)fnHkINLPCWPRETSTRUCTA);
    01295         UserAssert(pfnClientA.pfnButtonWndProc      == (KPROC)ButtonWndProcA);
    01296         UserAssert(pfnClientA.pfnComboBoxWndProc    == (KPROC)ComboBoxWndProcA);
    01297         UserAssert(pfnClientA.pfnComboListBoxProc   == (KPROC)ComboListBoxWndProcA);
    01298         UserAssert(pfnClientA.pfnDialogWndProc      == (KPROC)DefDlgProcA);
    01299         UserAssert(pfnClientA.pfnEditWndProc        == (KPROC)EditWndProcA);
    01300         UserAssert(pfnClientA.pfnListBoxWndProc     == (KPROC)ListBoxWndProcA);
    01301         UserAssert(pfnClientA.pfnMB_DlgProc         == (KPROC)MB_DlgProcA);
    01302         UserAssert(pfnClientA.pfnMDIActivateDlgProc == (KPROC)MDIActivateDlgProcA);
    01303         UserAssert(pfnClientA.pfnMDIClientWndProc   == (KPROC)MDIClientWndProcA);
    01304         UserAssert(pfnClientA.pfnStaticWndProc      == (KPROC)StaticWndProcA);
    01305         UserAssert(pfnClientA.pfnDispatchHook       == (KPROC)DispatchHookA);
    01306         UserAssert(pfnClientA.pfnDispatchMessage    == (KPROC)DispatchClientMessage);
    01307         UserAssert(pfnClientA.pfnImeWndProc         == (KPROC)ImeWndProcA);
    01308
    01309         UserAssert(pfnClientW.pfnScrollBarWndProc   == (KPROC)ScrollBarWndProcW);
    01310         UserAssert(pfnClientW.pfnTitleWndProc       == (KPROC)DefWindowProcW);
    01311         UserAssert(pfnClientW.pfnMenuWndProc        == (KPROC)MenuWndProcW);
    01312         UserAssert(pfnClientW.pfnDesktopWndProc     == (KPROC)DesktopWndProcW);
    01313         UserAssert(pfnClientW.pfnDefWindowProc      == (KPROC)DefWindowProcW);
    01314         UserAssert(pfnClientW.pfnHkINLPCWPSTRUCT    == (KPROC)fnHkINLPCWPSTRUCTW);
    01315         UserAssert(pfnClientW.pfnHkINLPCWPRETSTRUCT == (KPROC)fnHkINLPCWPRETSTRUCTW);
    01316         UserAssert(pfnClientW.pfnButtonWndProc      == (KPROC)ButtonWndProcW);
    01317         UserAssert(pfnClientW.pfnComboBoxWndProc    == (KPROC)ComboBoxWndProcW);
    01318         UserAssert(pfnClientW.pfnComboListBoxProc   == (KPROC)ComboListBoxWndProcW);
    01319         UserAssert(pfnClientW.pfnDialogWndProc      == (KPROC)DefDlgProcW);
    01320         UserAssert(pfnClientW.pfnEditWndProc        == (KPROC)EditWndProcW);
    01321         UserAssert(pfnClientW.pfnListBoxWndProc     == (KPROC)ListBoxWndProcW);
    01322         UserAssert(pfnClientW.pfnMB_DlgProc         == (KPROC)MB_DlgProcW);
    01323         UserAssert(pfnClientW.pfnMDIActivateDlgProc == (KPROC)MDIActivateDlgProcW);
    01324         UserAssert(pfnClientW.pfnMDIClientWndProc   == (KPROC)MDIClientWndProcW);
    01325         UserAssert(pfnClientW.pfnStaticWndProc      == (KPROC)StaticWndProcW);
    01326         UserAssert(pfnClientW.pfnDispatchHook       == (KPROC)DispatchHookW);
    01327         UserAssert(pfnClientW.pfnDispatchMessage    == (KPROC)DispatchClientMessage);
    01328         UserAssert(pfnClientW.pfnImeWndProc         == (KPROC)ImeWndProcW);
    01329
    01330         UserAssert(pfnClientWorker.pfnButtonWndProc      == (KPROC)ButtonWndProcWorker);
    01331         UserAssert(pfnClientWorker.pfnComboBoxWndProc    == (KPROC)ComboBoxWndProcWorker);
    01332         UserAssert(pfnClientWorker.pfnComboListBoxProc   == (KPROC)ListBoxWndProcWorker);
    01333         UserAssert(pfnClientWorker.pfnDialogWndProc      == (KPROC)DefDlgProcWorker);
    01334         UserAssert(pfnClientWorker.pfnEditWndProc        == (KPROC)EditWndProcWorker);
    01335         UserAssert(pfnClientWorker.pfnListBoxWndProc     == (KPROC)ListBoxWndProcWorker);
    01336         UserAssert(pfnClientWorker.pfnMDIClientWndProc   == (KPROC)MDIClientWndProcWorker);
    01337         UserAssert(pfnClientWorker.pfnStaticWndProc      == (KPROC)StaticWndProcWorker);
    01338         UserAssert(pfnClientWorker.pfnImeWndProc         == (KPROC)ImeWndProcWorker);
    01339
    01340 #if DBG
    01341         {
    01342             PULONG_PTR pdw;
    01343
    01344             /*
    01345              * Make sure that everyone got initialized
    01346              */
    01347             for (pdw = (PULONG_PTR)&pfnClientA;
    01348                  (ULONG_PTR)pdw<(ULONG_PTR)(&pfnClientA) + sizeof(pfnClientA);
    01349                  pdw++) {
    01350                 UserAssert(*pdw);
    01351             }
    01352
    01353             for (pdw = (PULONG_PTR)&pfnClientW;
    01354                  (ULONG_PTR)pdw<(ULONG_PTR)(&pfnClientW) + sizeof(pfnClientW);
    01355                  pdw++) {
    01356                 UserAssert(*pdw);
    01357             }
    01358         }
    01359 #endif
    01360
    01361 #if DBG
    01362     {
    01363         extern CONST INT gcapfnScSendMessage;
    01364         BOOLEAN apfnCheckMessage[64];
    01365         int i;
    01366
    01367         /*
    01368          * Do some verification of the message table. Since we only have
    01369          * 6 bits to store the function index, the function table can have
    01370          * at most 64 entries. Also verify that none of the indexes point
    01371          * past the end of the table and that all the function entries
    01372          * are used.
    01373          */
    01374         UserAssert(gcapfnScSendMessage <= 64);
    01375         RtlZeroMemory(apfnCheckMessage, sizeof(apfnCheckMessage));
    01376         for (i = 0; i < WM_USER; i++) {
    01377             UserAssert(MessageTable[i].iFunction < gcapfnScSendMessage);
    01378             apfnCheckMessage[MessageTable[i].iFunction] = TRUE;
    01379         }
    01380
    01381         for (i = 0; i < gcapfnScSendMessage; i++) {
    01382             UserAssert(apfnCheckMessage[i]);
    01383         }
    01384     }
    01385 #endif
    01386
    01387     }
    01388
    01389     /*
    01390      * Pass the function pointer arrays to the kernel.  This also establishes
    01391      * the kernel state for the thread.  If ClientThreadSetup is called from
    01392      * CsrConnectToUser this call will raise an exception if the thread
    01393      * cannot be converted to a gui thread.  The exception is handled in
    01394      * CsrConnectToUser.
    01395      */
    01396 #if DBG && !defined(BUILD_WOW6432)
    01397     /*
    01398      * On debug systems, go to the kernel for all processes to verify we're
    01399      * loading user32.dll at the right address.
    01400      */
    01401     if (fFirstThread) {
    01402 #elif defined(BUILD_WOW6432)
    01403     /*
    01404      * On WOW64 allways register the client fns
    01405      */
    01406     {
    01407 #else
    01408     if (gfServerProcess && fFirstThread) {
    01409 #endif
    01410         if (!NT_SUCCESS(NtUserInitializeClientPfnArrays(&pfnClientA, &pfnClientW, &pfnClientWorker, hmodUser))) {
    01411
    01412             RIPERR0(ERROR_OUTOFMEMORY,
    01413                     RIP_WARNING,
    01414                     "NtUserInitializeClientPfnArrays failed");
    01415
    01416             return FALSE;
    01417         }
    01418     }
    01419
    01420     /*
    01421      * Mark this thread as being initialized.  If the connection to
    01422      * the server fails, NtCurrentTeb()->Win32ThreadInfo will remain
    01423      * NULL.
    01424      */
    01425     pci->CI_flags |= CI_INITIALIZED;
    01426
    01427     /*
    01428      * Some initialization only has to occur once per process
    01429      */
    01430     if (fFirstThread) {
    01431
    01432         ConnectState = (DWORD)NtUserCallNoParam(SFI_REMOTECONNECTSTATE);
    01433
    01434         /*
    01435          * Winstation Winlogon and CSR must do graphics initialization
    01436          * after the connect.
    01437          */
    01438
    01439         if (ConnectState != CTX_W32_CONNECT_STATE_IDLE) {
    01440
    01441             if ((ghdcBits2 = CreateCompatibleDC(NULL)) == NULL) {
    01442                 RIPERR0(ERROR_OUTOFMEMORY, RIP_WARNING, "ghdcBits2 creation failed");
    01443                 return FALSE;
    01444             }
    01445
    01446             /*
    01447              * Get things we need from Gdi.
    01448              */
    01449             if (ghbrWhite == NULL)
    01450                 ghbrWhite = GetStockObject(WHITE_BRUSH);
    01451
    01452             if (ghbrBlack == NULL)
    01453                 ghbrBlack = GetStockObject(BLACK_BRUSH);
    01454
    01455             InitClientDrawing();
    01456         }
    01457
    01458         gfSystemInitialized = NtUserGetThreadDesktop(GetCurrentThreadId(),
    01459                                                      NULL) != NULL;
    01460
    01461         /*
    01462          * If an lpk is loaded for this process notify the kernel
    01463          */
    01464         if (gdwLpkEntryPoints) {
    01465             NtUserCallOneParam(gdwLpkEntryPoints, SFI_REGISTERLPK);
    01466         }
    01467
    01468         if (gfServerProcess || (GetClientInfo()->pDeskInfo == NULL)) {
    01469
    01470             /*
    01471              * Perform any server initialization.
    01472              */
    01473             UserAssert(gpsi);
    01474
    01475             if (pdiLocal = LocalAlloc(LPTR, sizeof(DESKTOPINFO))) {
    01476
    01477                 GetClientInfo()->pDeskInfo = pdiLocal;
    01478
    01479             } else {
    01480
    01481                 RIPERR0(ERROR_OUTOFMEMORY, RIP_WARNING, "pdiLocal creation failed");
    01482
    01483                 return FALSE;
    01484             }
    01485         }
    01486
    01487         if (gfServerProcess) {
    01488             /*
    01489              * Winstation Winlogon and CSR must do graphics initialization
    01490              * after the connect.
    01491              */
    01492             if (ConnectState != CTX_W32_CONNECT_STATE_IDLE) {
    01493                 if (!LoadCursorsAndIcons()) {
    01494                     RIPERR0(ERROR_OUTOFMEMORY, RIP_WARNING, "LoadCursorsAndIcons failed");
    01495                     return FALSE;
    01496                 }
    01497             }
    01498
    01499             InitOemXlateTables();
    01500         }
    01501
    01502         if ( ! CheckBadApp() ) {
    01503             RIPERR0(ERROR_OUTOFMEMORY, RIP_WARNING, "Don't start app for server appliance");
    01504             return FALSE;
    01505         }
    01506
    01507         LoadAppDlls();
    01508     } else if (gfServerProcess) {
    01509         GetClientInfo()->pDeskInfo = pdiLocal;
    01510     }
    01511
    01512     /*
    01513      * Kernel sets CI_REGISTERCLASSES when appropriate (i.e. always
    01514      * for the first thread and for other threads if the last GUI
    01515      * thread for a process has exited) except for the CSR proces.
    01516      * For the CSR process, you must register the classes on the
    01517      * first thread anyways.
    01518      */
    01519
    01520     if (fFirstThread || (pci->CI_flags & CI_REGISTERCLASSES)) {
    01521
    01522         /*
    01523          * If it's the first thread we already made it to the kernel
    01524          * to get the ConnectState...
    01525          */
    01526         if (!fFirstThread) {
    01527             ConnectState = (DWORD)NtUserCallNoParam(SFI_REMOTECONNECTSTATE);
    01528         }
    01529
    01530         if (ConnectState != CTX_W32_CONNECT_STATE_IDLE) {
    01531
    01532             /*
    01533              * Register the control classes.
    01534              */
    01535             RW_RegisterControls();
    01536             RW_RegisterDDEML();
    01537         }
    01538     }
    01539
    01540     return TRUE;
    01541 }
    01542
    01543 /***************************************************************************\
    01544 * Dispatch routines.
    01545 *
    01546 *
    01547 \***************************************************************************/
    01548
    01549 HLOCAL WINAPI DispatchLocalAlloc(
    01550     UINT   uFlags,
    01551     UINT   uBytes,
    01552     HANDLE hInstance)
    01553 {
    01554     UNREFERENCED_PARAMETER(hInstance);
    01555
    01556     return LocalAlloc(uFlags, uBytes);
    01557 }
    01558
    01559 HLOCAL WINAPI DispatchLocalReAlloc(
    01560     HLOCAL hMem,
    01561     UINT   uBytes,
    01562     UINT   uFlags,
    01563     HANDLE hInstance,
    01564     PVOID* ppv)
    01565 {
    01566     UNREFERENCED_PARAMETER(hInstance);
    01567     UNREFERENCED_PARAMETER(ppv);
    01568
    01569     return LocalReAlloc(hMem, uBytes, uFlags);
    01570 }
    01571
    01572 LPVOID WINAPI DispatchLocalLock(
    01573     HLOCAL hMem,
    01574     HANDLE hInstance)
    01575 {
    01576     UNREFERENCED_PARAMETER(hInstance);
    01577
    01578     return LocalLock(hMem);
    01579 }
    01580
    01581 BOOL WINAPI DispatchLocalUnlock(
    01582     HLOCAL hMem,
    01583     HANDLE hInstance)
    01584 {
    01585     UNREFERENCED_PARAMETER(hInstance);
    01586
    01587     return LocalUnlock(hMem);
    01588 }
    01589
    01590 UINT WINAPI DispatchLocalSize(
    01591     HLOCAL hMem,
    01592     HANDLE hInstance)
    01593 {
    01594     UNREFERENCED_PARAMETER(hInstance);
    01595
    01596     return (UINT)LocalSize(hMem);
    01597 }
    01598
    01599 HLOCAL WINAPI DispatchLocalFree(
    01600     HLOCAL hMem,
    01601     HANDLE hInstance)
    01602 {
    01603     UNREFERENCED_PARAMETER(hInstance);
    01604
    01605     return LocalFree(hMem);
    01606 }
    01607
    01608 /***************************************************************************\
    01609 * Allocation routines for RTL functions.
    01610 *
    01611 *
    01612 \***************************************************************************/
    01613
    01614 PVOID UserRtlAllocMem(
    01615     ULONG uBytes)
    01616 {
    01617     return UserLocalAlloc(HEAP_ZERO_MEMORY, uBytes);
    01618 }
    01619
    01620 VOID UserRtlFreeMem(
    01621     PVOID pMem)
    01622 {
    01623     UserLocalFree(pMem);
    01624 }
    01625
    01626 VOID UserRtlRaiseStatus(
    01627     NTSTATUS Status)
    01628 {
    01629     RtlRaiseStatus(Status);
    01630 }
    01631
    01632 /***************************************************************************\
    01633 * InitClientDrawing
    01634 *
    01635 * History:
    01636 * 20-Aug-1992 mikeke    Created
    01637 \***************************************************************************/
    01638
    01639 BOOL InitClientDrawing(VOID)
    01640 {
    01641     static CONST WORD patGray[8] = {0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa};
    01642     BOOL fSuccess = TRUE;
    01643
    01644     HBITMAP hbmGray = CreateBitmap(8, 8, 1, 1, (LPBYTE)patGray);;
    01645
    01646     fSuccess &= !!hbmGray;
    01647
    01648     /*
    01649      * Create the global-objects for client drawing.
    01650      */
    01651     ghbrWindowText = CreateSolidBrush(GetSysColor(COLOR_WINDOWTEXT));
    01652     fSuccess &= !!ghbrWindowText;
    01653
    01654     ghFontSys = GetStockObject(SYSTEM_FONT);
    01655     fSuccess &= !!ghFontSys;
    01656
    01657     ghdcGray = CreateCompatibleDC(NULL);
    01658     fSuccess &= !!ghdcGray;
    01659
    01660     if (!fSuccess) {
    01661         RIPMSG0(RIP_WARNING, "InitClientDrawing failed to allocate resources");
    01662         return FALSE;
    01663     }
    01664
    01665     /*
    01666      * Setup the gray surface.
    01667      */
    01668     SelectObject(ghdcGray, hbmGray);
    01669     SelectObject(ghdcGray, ghFontSys);
    01670     SelectObject(ghdcGray, gpsi->hbrGray);
    01671
    01672     /*
    01673      * Setup the gray attributes.
    01674      */
    01675     SetBkMode(ghdcGray, OPAQUE);
    01676     SetTextColor(ghdcGray, 0x00000000L);
    01677     SetBkColor(ghdcGray, 0x00FFFFFFL);
    01678
    01679     gcxGray = 8;
    01680     gcyGray = 8;
    01681
    01682     return TRUE;
    01683 }
    01684
    01685 VOID
    01686 InitializeLpkHooks(
    01687     CONST FARPROC *lpfpLpkHooks
    01688     )
    01689 {
    01690     /*
    01691      * Called from GdiInitializeLanguagePack().  Remember what entry points
    01692      * are supported.  Pass the information to the kernel the first time
    01693      * this process connects in ClientThreadSetup().
    01694      */
    01695     if (lpfpLpkHooks[LPK_TABBED_TEXT_OUT]) {
    01696         fpLpkTabbedTextOut = (FPLPKTABBEDTEXTOUT)lpfpLpkHooks[LPK_TABBED_TEXT_OUT];
    01697         gdwLpkEntryPoints |= (1 << LPK_TABBED_TEXT_OUT);
    01698     }
    01699     if (lpfpLpkHooks[LPK_PSM_TEXT_OUT]) {
    01700         fpLpkPSMTextOut = (FPLPKPSMTEXTOUT)lpfpLpkHooks[LPK_PSM_TEXT_OUT];
    01701         gdwLpkEntryPoints |= (1 << LPK_PSM_TEXT_OUT);
    01702     }
    01703     if (lpfpLpkHooks[LPK_DRAW_TEXT_EX]) {
    01704         fpLpkDrawTextEx = (FPLPKDRAWTEXTEX)lpfpLpkHooks[LPK_DRAW_TEXT_EX];
    01705         gdwLpkEntryPoints |= (1 << LPK_DRAW_TEXT_EX);
    01706     }
    01707     if (lpfpLpkHooks[LPK_EDIT_CONTROL]) {
    01708         fpLpkEditControl = (PLPKEDITCALLOUT)lpfpLpkHooks[LPK_EDIT_CONTROL];
    01709         gdwLpkEntryPoints |= (1 << LPK_EDIT_CONTROL);
    01710     }
    01711 }
    01712
    01713 /***************************************************************************\
    01714 *
    01715 * CtxInitUser32
    01716 *
    01717 * Called by CreateWindowStation() and winsrv.dll DoConnect routine.
    01718 *
    01719 * Winstation Winlogon and CSR must do graphics initialization
    01720 * after the connect.  This is because no video driver is loaded
    01721 * until then.
    01722 *
    01723 * This routine must contain everything that was skipped before.
    01724 *
    01725 * History:
    01726 * Dec-11-1997 clupu    Ported from Citrix
    01727 \***************************************************************************/
    01728
    01729 BOOL CtxInitUser32(
    01730     VOID)
    01731 {
    01732     /*
    01733      * Only do once.
    01734      */
    01735     if (ghdcBits2 != NULL || !ISREMOTESESSION())
    01736         return TRUE;
    01737
    01738     ghdcBits2 = CreateCompatibleDC(NULL);
    01739
    01740     if (ghdcBits2 == NULL) {
    01741         RIPMSG0(RIP_WARNING, "Could not allocate ghdcBits2");
    01742         return FALSE;
    01743     }
    01744
    01745     /*
    01746      * Get things we need from Gdi.
    01747      */
    01748     if (ghbrWhite == NULL)
    01749         ghbrWhite = GetStockObject(WHITE_BRUSH);
    01750
    01751     if (ghbrBlack == NULL)
    01752         ghbrBlack = GetStockObject(BLACK_BRUSH);
    01753
    01754     UserAssert(ghbrWhite != NULL && ghbrBlack != NULL);
    01755
    01756     if (!InitClientDrawing()) {
    01757         RIPMSG0(RIP_WARNING, "InitClientDrawing failed");
    01758         return FALSE;
    01759     }
    01760
    01761     if (gfServerProcess) {
    01762         if (!LoadCursorsAndIcons()) {
    01763             RIPMSG0(RIP_WARNING, "LoadCursorsAndIcons failed");
    01764             return FALSE;
    01765         }
    01766     }
    01767
    01768     /*
    01769      * Register the control classes.
    01770      */
    01771     if (!RW_RegisterControls())
    01772         return FALSE;
    01773
    01774     if (!RW_RegisterDDEML())
    01775         return FALSE;
    01776
    01777     return TRUE;
    01778 }
    01779
    01780 DWORD GetRipComponent(VOID) { return RIP_USER; }
    01781
    01782 DWORD GetDbgTagFlags(int tag)
    01783 {
    01784 #if DEBUGTAGS
    01785     return (gpsi != NULL ? gpsi->adwDBGTAGFlags[tag] : 0);
    01786 #else
    01787     return 0;
    01788     UNREFERENCED_PARAMETER(tag);
    01789 #endif // DEBUGTAGS
    01790 }
    01791
    01792 DWORD GetRipPID(VOID) { return (gpsi != NULL ? gpsi->wRIPPID : 0); }
    01793 DWORD GetRipFlags(VOID) { return (gpsi != NULL ? gpsi->wRIPFlags : RIPF_DEFAULT); }
    01794
    01795 VOID SetRipFlags(DWORD dwRipFlags, DWORD dwRipPID)
    01796 {
    01797     NtUserSetRipFlags(dwRipFlags, dwRipPID);
    01798 }
    01799
    01800 VOID SetDbgTag(int tag, DWORD dwBitFlags)
    01801 {
    01802     NtUserSetDbgTag(tag, dwBitFlags);
    01803 }
    01804