/* * UserLoadKbdLayout * * Loads keyboard layout and creates KL object */ static PKL UserLoadKbdLayout(PUNICODE_STRING pwszKLID, HKL hKL) { LCID lCid; CHARSETINFO cs; PKL pKl; /* Create keyboard layout object */ pKl = UserCreateObject(gHandleTable, NULL, NULL, NULL, TYPE_KBDLAYOUT, sizeof(KL)); if (!pKl) { ERR("Failed to create object!\n"); return NULL; } pKl->hkl = hKL; pKl->spkf = UserLoadKbdFile(pwszKLID); /* Dereference keyboard layout */ UserDereferenceObject(pKl); /* If we failed, remove KL object */ if (!pKl->spkf) { ERR("UserLoadKbdFile(%wZ) failed!\n", pwszKLID); UserDeleteObject(pKl->head.h, TYPE_KBDLAYOUT); return NULL; } // Up to Language Identifiers.. RtlUnicodeStringToInteger(pwszKLID, (ULONG)16, (PULONG)&lCid); TRACE("Language Identifiers %wZ LCID 0x%x\n", pwszKLID, lCid); if (co_IntGetCharsetInfo(lCid, &cs)) { pKl->iBaseCharset = cs.ciCharset; pKl->dwFontSigs = cs.fs.fsCsb[0]; pKl->CodePage = (USHORT)cs.ciACP; TRACE("Charset %u Font Sig %lu CodePage %u\n", pKl->iBaseCharset, pKl->dwFontSigs, pKl->CodePage); } else { pKl->iBaseCharset = ANSI_CHARSET; pKl->dwFontSigs = FS_LATIN1; pKl->CodePage = CP_ACP; } // Set initial system character set and font signature. if (gSystemFS == 0) { gSystemCPCharSet = pKl->iBaseCharset; gSystemFS = pKl->dwFontSigs; } return pKl; }
static VOID NTAPI IntAddSynthesizedFormats(PWINSTATION_OBJECT pWinStaObj) { PCLIP pTextEl, pUniTextEl, pOemTextEl, pLocaleEl, pBmEl, pDibEl; pTextEl = IntIsFormatAvailable(pWinStaObj, CF_TEXT); pOemTextEl = IntIsFormatAvailable(pWinStaObj, CF_OEMTEXT); pUniTextEl = IntIsFormatAvailable(pWinStaObj, CF_UNICODETEXT); pLocaleEl = IntIsFormatAvailable(pWinStaObj, CF_LOCALE); pBmEl = IntIsFormatAvailable(pWinStaObj, CF_BITMAP); pDibEl = IntIsFormatAvailable(pWinStaObj, CF_DIB); /* Add CF_LOCALE format if we have CF_TEXT */ if (!pLocaleEl && pTextEl) { PCLIPBOARDDATA pMemObj; HANDLE hMem; pMemObj = (PCLIPBOARDDATA)UserCreateObject(gHandleTable, NULL, NULL, &hMem, TYPE_CLIPDATA, sizeof(CLIPBOARDDATA) + sizeof(LCID)); if (pMemObj) { pMemObj->cbData = sizeof(LCID); *((LCID*)pMemObj->Data) = NtCurrentTeb()->CurrentLocale; IntAddFormatedData(pWinStaObj, CF_LOCALE, hMem, TRUE, TRUE); /* Release the extra reference (UserCreateObject added 2 references) */ UserDereferenceObject(pMemObj); } } /* Add CF_TEXT. Note: it is synthesized in user32.dll */ if (!pTextEl && (pUniTextEl || pOemTextEl)) IntAddFormatedData(pWinStaObj, CF_TEXT, DATA_SYNTH_USER, FALSE, TRUE); /* Add CF_OEMTEXT. Note: it is synthesized in user32.dll */ if (!pOemTextEl && (pUniTextEl || pTextEl)) IntAddFormatedData(pWinStaObj, CF_OEMTEXT, DATA_SYNTH_USER, FALSE, TRUE); /* Add CF_UNICODETEXT. Note: it is synthesized in user32.dll */ if (!pUniTextEl && (pTextEl || pOemTextEl)) IntAddFormatedData(pWinStaObj, CF_UNICODETEXT, DATA_SYNTH_USER, FALSE, TRUE); /* Add CF_BITMAP. Note: it is synthesized on demand */ if (!pBmEl && pDibEl) IntAddFormatedData(pWinStaObj, CF_BITMAP, DATA_SYNTH_KRNL, FALSE, TRUE); /* Note: We need to render the DIB or DIBV5 format as soon as possible because pallette information may change */ if (!pDibEl && pBmEl) IntSynthesizeDib(pWinStaObj, pBmEl->hData); }
/* IntCreateMonitorObject * * Creates a MONITOR * * Return value * If the function succeeds a pointer to a MONITOR is returned. On failure * NULL is returned. */ static PMONITOR IntCreateMonitorObject() { HANDLE Handle; PMONITOR Monitor; Monitor = UserCreateObject(gHandleTable, NULL, &Handle, otMonitor, sizeof (MONITOR)); if (Monitor == NULL) { return NULL; } ExInitializeFastMutex(&Monitor->Lock); return Monitor; }
/* FUNCTIONS *****************************************************************/ static PTIMER FASTCALL CreateTimer(VOID) { HANDLE Handle; PTIMER Ret = NULL; Ret = UserCreateObject(gHandleTable, NULL, &Handle, otTimer, sizeof(TIMER)); if (Ret) { Ret->head.h = Handle; InsertTailList(&TimersListHead, &Ret->ptmrList); } return Ret; }
HANDLE APIENTRY NtUserConvertMemHandle( PVOID pData, DWORD cbData) { HANDLE hMem = NULL; PCLIPBOARDDATA pMemObj; UserEnterExclusive(); /* Create Clipboard data object */ pMemObj = UserCreateObject(gHandleTable, NULL, NULL, &hMem, TYPE_CLIPDATA, sizeof(CLIPBOARDDATA) + cbData); if (!pMemObj) goto cleanup; pMemObj->cbData = cbData; /* Copy data */ _SEH2_TRY { ProbeForRead(pData, cbData, 1); memcpy(pMemObj->Data, pData, cbData); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { pMemObj = NULL; } _SEH2_END; /* Release the extra reference (UserCreateObject added 2 references) */ UserDereferenceObject(pMemObj); /* If we failed to copy data, remove handle */ if (!pMemObj) { UserDeleteObject(hMem, TYPE_CLIPDATA); hMem = NULL; } cleanup: UserLeave(); return hMem; }
HANDLE IntCreateCurIconHandle(BOOLEAN Animated) { PCURICON_OBJECT CurIcon; HANDLE hCurIcon; CurIcon = UserCreateObject( gHandleTable, NULL, NULL, &hCurIcon, TYPE_CURSOR, Animated ? sizeof(ACON) : sizeof(CURICON_OBJECT)); if (!CurIcon) { EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); return FALSE; } UserDereferenceObject(CurIcon); return hCurIcon; }
HACCEL APIENTRY NtUserCreateAcceleratorTable( LPACCEL Entries, ULONG EntriesCount) { PACCELERATOR_TABLE Accel; HACCEL hAccel; ULONG Index; NTSTATUS Status = STATUS_SUCCESS; DECLARE_RETURN(HACCEL); TRACE("Enter NtUserCreateAcceleratorTable(Entries %p, EntriesCount %u)\n", Entries, EntriesCount); UserEnterExclusive(); if (!Entries || EntriesCount <= 0) { SetLastNtError(STATUS_INVALID_PARAMETER); RETURN( (HACCEL) NULL ); } Accel = UserCreateObject(gHandleTable, NULL, NULL, (PHANDLE)&hAccel, TYPE_ACCELTABLE, sizeof(ACCELERATOR_TABLE)); if (Accel == NULL) { SetLastNtError(STATUS_NO_MEMORY); RETURN( (HACCEL) NULL ); } Accel->Count = EntriesCount; Accel->Table = ExAllocatePoolWithTag(PagedPool, EntriesCount * sizeof(ACCEL), USERTAG_ACCEL); if (Accel->Table == NULL) { UserDereferenceObject(Accel); UserDeleteObject(hAccel, TYPE_ACCELTABLE); SetLastNtError(STATUS_NO_MEMORY); RETURN( (HACCEL) NULL); } _SEH2_TRY { ProbeForRead(Entries, EntriesCount * sizeof(ACCEL), 4); for (Index = 0; Index < EntriesCount; Index++) { Accel->Table[Index].fVirt = Entries[Index].fVirt & FVIRT_MASK; if(Accel->Table[Index].fVirt & FVIRTKEY) { Accel->Table[Index].key = Entries[Index].key; } else { RtlMultiByteToUnicodeN(&Accel->Table[Index].key, sizeof(WCHAR), NULL, (PCSTR)&Entries[Index].key, sizeof(CHAR)); } Accel->Table[Index].cmd = Entries[Index].cmd; } } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { Status = _SEH2_GetExceptionCode(); } _SEH2_END; if (!NT_SUCCESS(Status)) { ExFreePoolWithTag(Accel->Table, USERTAG_ACCEL); UserDereferenceObject(Accel); UserDeleteObject(hAccel, TYPE_ACCELTABLE); SetLastNtError(Status); RETURN( (HACCEL) NULL); } /* FIXME: Save HandleTable in a list somewhere so we can clean it up again */ RETURN(hAccel); CLEANUP: TRACE("Leave NtUserCreateAcceleratorTable(Entries %p, EntriesCount %u) = %p\n", Entries, EntriesCount, _ret_); UserLeave(); END_CLEANUP; }
/* * @implemented */ DWORD_PTR APIENTRY NtUserCallOneParam( DWORD_PTR Param, DWORD Routine) { DECLARE_RETURN(DWORD_PTR); TRACE("Enter NtUserCallOneParam\n"); UserEnterExclusive(); switch(Routine) { case ONEPARAM_ROUTINE_POSTQUITMESSAGE: { PTHREADINFO pti; pti = PsGetCurrentThreadWin32Thread(); MsqPostQuitMessage(pti->MessageQueue, Param); RETURN(TRUE); } case ONEPARAM_ROUTINE_BEGINDEFERWNDPOS: { PSMWP psmwp; HDWP hDwp = NULL; INT count = (INT)Param; if (count < 0) { EngSetLastError(ERROR_INVALID_PARAMETER); RETURN(0); } /* Windows allows zero count, in which case it allocates context for 8 moves */ if (count == 0) count = 8; psmwp = (PSMWP) UserCreateObject( gHandleTable, NULL, (PHANDLE)&hDwp, otSMWP, sizeof(SMWP)); if (!psmwp) RETURN(0); psmwp->acvr = ExAllocatePoolWithTag(PagedPool, count * sizeof(CVR), USERTAG_SWP); if (!psmwp->acvr) { UserDeleteObject(hDwp, otSMWP); RETURN(0); } RtlZeroMemory(psmwp->acvr, count * sizeof(CVR)); psmwp->bHandle = TRUE; psmwp->ccvr = 0; // actualCount psmwp->ccvrAlloc = count; // suggestedCount RETURN((DWORD_PTR)hDwp); } case ONEPARAM_ROUTINE_SHOWCURSOR: RETURN( (DWORD_PTR)UserShowCursor((BOOL)Param) ); case ONEPARAM_ROUTINE_GETDESKTOPMAPPING: { PTHREADINFO ti; ti = GetW32ThreadInfo(); if (ti != NULL) { /* Try convert the pointer to a user mode pointer if the desktop is mapped into the process */ RETURN((DWORD_PTR)DesktopHeapAddressToUser((PVOID)Param)); } else { RETURN(0); } } case ONEPARAM_ROUTINE_WINDOWFROMDC: RETURN( (DWORD_PTR)IntWindowFromDC((HDC)Param)); case ONEPARAM_ROUTINE_SWAPMOUSEBUTTON: { DWORD_PTR Result; Result = gspv.bMouseBtnSwap; gspv.bMouseBtnSwap = Param ? TRUE : FALSE; gpsi->aiSysMet[SM_SWAPBUTTON] = gspv.bMouseBtnSwap; RETURN(Result); } case ONEPARAM_ROUTINE_SWITCHCARETSHOWING: RETURN( (DWORD_PTR)IntSwitchCaretShowing((PVOID)Param)); case ONEPARAM_ROUTINE_SETCARETBLINKTIME: RETURN( (DWORD_PTR)IntSetCaretBlinkTime((UINT)Param)); case ONEPARAM_ROUTINE_SETMESSAGEEXTRAINFO: RETURN( (DWORD_PTR)MsqSetMessageExtraInfo((LPARAM)Param)); case ONEPARAM_ROUTINE_CREATEEMPTYCUROBJECT: { PCURICON_OBJECT CurIcon; DWORD_PTR Result ; if (!(CurIcon = IntCreateCurIconHandle())) { EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); RETURN(0); } Result = (DWORD_PTR)CurIcon->Self; UserDereferenceObject(CurIcon); RETURN(Result); } case ONEPARAM_ROUTINE_GETCURSORPOSITION: { BOOL ret = TRUE; _SEH2_TRY { ProbeForWrite((POINT*)Param,sizeof(POINT),1); RtlCopyMemory((POINT*)Param,&gpsi->ptCursor,sizeof(POINT)); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { SetLastNtError(_SEH2_GetExceptionCode()); ret = FALSE; } _SEH2_END; RETURN (ret); } case ONEPARAM_ROUTINE_ENABLEPROCWNDGHSTING: { BOOL Enable; PPROCESSINFO Process = PsGetCurrentProcessWin32Process(); if(Process != NULL) { Enable = (BOOL)(Param != 0); if(Enable) { Process->W32PF_flags &= ~W32PF_NOWINDOWGHOSTING; } else { Process->W32PF_flags |= W32PF_NOWINDOWGHOSTING; } RETURN( TRUE); } RETURN( FALSE); } case ONEPARAM_ROUTINE_GETINPUTEVENT: RETURN( (DWORD_PTR)IntMsqSetWakeMask(Param)); case ONEPARAM_ROUTINE_GETKEYBOARDTYPE: RETURN( UserGetKeyboardType(Param)); case ONEPARAM_ROUTINE_GETKEYBOARDLAYOUT: RETURN( (DWORD_PTR)UserGetKeyboardLayout(Param)); case ONEPARAM_ROUTINE_RELEASEDC: RETURN (UserReleaseDC(NULL, (HDC) Param, FALSE)); case ONEPARAM_ROUTINE_REALIZEPALETTE: RETURN (UserRealizePalette((HDC) Param)); case ONEPARAM_ROUTINE_GETQUEUESTATUS: { RETURN (IntGetQueueStatus((DWORD)Param)); } case ONEPARAM_ROUTINE_ENUMCLIPBOARDFORMATS: /* FIXME: Should use UserEnterShared */ RETURN(IntEnumClipboardFormats(Param)); case ONEPARAM_ROUTINE_CSRSS_GUICHECK: IntUserManualGuiCheck(Param); RETURN(TRUE); case ONEPARAM_ROUTINE_GETCURSORPOS: { BOOL Ret = TRUE; PPOINTL pptl; PTHREADINFO pti = PsGetCurrentThreadWin32Thread(); if (pti->hdesk != InputDesktopHandle) RETURN(FALSE); _SEH2_TRY { pptl = (PPOINTL)Param; *pptl = gpsi->ptCursor; } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { Ret = FALSE; } _SEH2_END; RETURN(Ret); } case ONEPARAM_ROUTINE_SETPROCDEFLAYOUT: { PPROCESSINFO ppi; if (Param & LAYOUT_ORIENTATIONMASK) { ppi = PsGetCurrentProcessWin32Process(); ppi->dwLayout = Param; RETURN(TRUE); } EngSetLastError(ERROR_INVALID_PARAMETER); RETURN(FALSE); } case ONEPARAM_ROUTINE_GETPROCDEFLAYOUT: { BOOL Ret = TRUE; PPROCESSINFO ppi; PDWORD pdwLayout; if ( PsGetCurrentProcess() == CsrProcess) { EngSetLastError(ERROR_INVALID_ACCESS); RETURN(FALSE); } ppi = PsGetCurrentProcessWin32Process(); _SEH2_TRY { pdwLayout = (PDWORD)Param; *pdwLayout = ppi->dwLayout; } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { SetLastNtError(_SEH2_GetExceptionCode()); Ret = FALSE; } _SEH2_END; RETURN(Ret); } case ONEPARAM_ROUTINE_REPLYMESSAGE: RETURN (co_MsqReplyMessage((LRESULT) Param)); case ONEPARAM_ROUTINE_MESSAGEBEEP: RETURN ( UserPostMessage(hwndSAS, WM_LOGONNOTIFY, LN_MESSAGE_BEEP, Param) ); /* TODO: Implement sound sentry */ } ERR("Calling invalid routine number 0x%x in NtUserCallOneParam(), Param=0x%x\n", Routine, Param); EngSetLastError(ERROR_INVALID_PARAMETER); RETURN( 0); CLEANUP: TRACE("Leave NtUserCallOneParam, ret=%i\n",_ret_); UserLeave(); END_CLEANUP; }
static VOID NTAPI IntSynthesizeDib( PWINSTATION_OBJECT pWinStaObj, HBITMAP hbm) { HDC hdc; ULONG cjInfoSize, cjDataSize; PCLIPBOARDDATA pClipboardData; HANDLE hMem; INT iResult; struct { BITMAPINFOHEADER bmih; RGBQUAD rgbColors[256]; } bmiBuffer; PBITMAPINFO pbmi = (PBITMAPINFO)&bmiBuffer; /* Get the display DC */ hdc = UserGetDCEx(NULL, NULL, DCX_USESTYLE); if (!hdc) { return; } /* Get information about the bitmap format */ iResult = GreGetDIBitsInternal(hdc, hbm, 0, 0, NULL, pbmi, DIB_RGB_COLORS, 0, sizeof(bmiBuffer)); if (iResult == 0) { goto cleanup; } /* Get the size for a full BITMAPINFO */ cjInfoSize = DIB_BitmapInfoSize(pbmi, DIB_RGB_COLORS); /* Calculate the size of the clipboard data, which is a packed DIB */ cjDataSize = cjInfoSize + pbmi->bmiHeader.biSizeImage; /* Create the clipboard data */ pClipboardData = (PCLIPBOARDDATA)UserCreateObject(gHandleTable, NULL, NULL, &hMem, TYPE_CLIPDATA, cjDataSize); if (!pClipboardData) { goto cleanup; } /* Set the data size */ pClipboardData->cbData = cjDataSize; /* Copy the BITMAPINFOHEADER */ memcpy(pClipboardData->Data, pbmi, sizeof(BITMAPINFOHEADER)); /* Get the bitmap bits and the color table */ iResult = GreGetDIBitsInternal(hdc, hbm, 0, abs(pbmi->bmiHeader.biHeight), (LPBYTE)pClipboardData->Data + cjInfoSize, (LPBITMAPINFO)pClipboardData->Data, DIB_RGB_COLORS, pbmi->bmiHeader.biSizeImage, cjInfoSize); /* Add the clipboard data */ IntAddFormatedData(pWinStaObj, CF_DIB, hMem, TRUE, TRUE); /* Release the extra reference (UserCreateObject added 2 references) */ UserDereferenceObject(pClipboardData); cleanup: UserReleaseDC(NULL, hdc, FALSE); }
/* IntCreateMonitorObject * * Creates a MONITOR * * Return value * If the function succeeds a pointer to a MONITOR is returned. On failure * NULL is returned. */ static PMONITOR IntCreateMonitorObject() { return UserCreateObject(gHandleTable, NULL, NULL, NULL, TYPE_MONITOR, sizeof(MONITOR)); }
HWINEVENTHOOK APIENTRY NtUserSetWinEventHook( UINT eventMin, UINT eventMax, HMODULE hmodWinEventProc, PUNICODE_STRING puString, WINEVENTPROC lpfnWinEventProc, DWORD idProcess, DWORD idThread, UINT dwflags) { PEVENTHOOK pEH; HWINEVENTHOOK Ret = NULL; NTSTATUS Status; HANDLE Handle; PETHREAD Thread = NULL; TRACE("NtUserSetWinEventHook hmod 0x%x, pfn 0x%x\n",hmodWinEventProc, lpfnWinEventProc); UserEnterExclusive(); if ( !GlobalEvents ) { GlobalEvents = ExAllocatePoolWithTag(PagedPool, sizeof(EVENTTABLE), TAG_HOOK); if (GlobalEvents == NULL) { EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); goto SetEventExit; } GlobalEvents->Counts = 0; InitializeListHead(&GlobalEvents->Events); } if (eventMin > eventMax) { EngSetLastError(ERROR_INVALID_HOOK_FILTER); goto SetEventExit; } if (!lpfnWinEventProc) { EngSetLastError(ERROR_INVALID_FILTER_PROC); goto SetEventExit; } if ((dwflags & WINEVENT_INCONTEXT) && !hmodWinEventProc) { EngSetLastError(ERROR_HOOK_NEEDS_HMOD); goto SetEventExit; } if (idThread) { Status = PsLookupThreadByThreadId((HANDLE)(DWORD_PTR)idThread, &Thread); if (!NT_SUCCESS(Status)) { EngSetLastError(ERROR_INVALID_THREAD_ID); goto SetEventExit; } } // Creator, pti is set here. pEH = UserCreateObject(gHandleTable, NULL, &Handle, otEvent, sizeof(EVENTHOOK)); if (pEH) { InsertTailList(&GlobalEvents->Events, &pEH->Chain); GlobalEvents->Counts++; UserHMGetHandle(pEH) = Handle; pEH->eventMin = eventMin; pEH->eventMax = eventMax; pEH->idProcess = idProcess; // These are cmp'ed pEH->idThread = idThread; // " pEH->Flags = dwflags; /* If WINEVENT_INCONTEXT, set offset from hmod and proc. Save ihmod from the atom index table where the hmod data is saved to be recalled later if fSync set by WINEVENT_INCONTEXT. If WINEVENT_OUTOFCONTEXT just use proc.. Do this instead.... */ if (NULL != hmodWinEventProc) { pEH->offPfn = (ULONG_PTR)((char *)lpfnWinEventProc - (char *)hmodWinEventProc); pEH->ihmod = (INT)hmodWinEventProc; pEH->Proc = lpfnWinEventProc; } else pEH->Proc = lpfnWinEventProc; UserDereferenceObject(pEH); Ret = Handle; IntSetSrvEventMask( eventMin, eventMax); } SetEventExit: if (Thread) ObDereferenceObject(Thread); UserLeave(); return Ret; }
/* * UserLoadKbdFile * * Loads keyboard layout DLL and creates KBDFILE object */ static PKBDFILE UserLoadKbdFile(PUNICODE_STRING pwszKLID) { PKBDFILE pkf, pRet = NULL; NTSTATUS Status; ULONG cbSize; HKEY hKey = NULL; WCHAR wszLayoutPath[MAX_PATH] = L"\\SystemRoot\\System32\\"; WCHAR wszLayoutRegKey[256] = L"\\REGISTRY\\Machine\\SYSTEM\\CurrentControlSet\\" L"Control\\Keyboard Layouts\\"; /* Create keyboard layout file object */ pkf = UserCreateObject(gHandleTable, NULL, NULL, NULL, TYPE_KBDFILE, sizeof(KBDFILE)); if (!pkf) { ERR("Failed to create object!\n"); return NULL; } /* Set keyboard layout name */ swprintf(pkf->awchKF, L"%wZ", pwszKLID); /* Open layout registry key */ RtlStringCbCatW(wszLayoutRegKey, sizeof(wszLayoutRegKey), pkf->awchKF); Status = RegOpenKey(wszLayoutRegKey, &hKey); if (!NT_SUCCESS(Status)) { ERR("Failed to open keyboard layouts registry key %ws (%lx)\n", wszLayoutRegKey, Status); goto cleanup; } /* Read filename of layout DLL */ cbSize = sizeof(wszLayoutPath) - wcslen(wszLayoutPath)*sizeof(WCHAR); Status = RegQueryValue(hKey, L"Layout File", REG_SZ, wszLayoutPath + wcslen(wszLayoutPath), &cbSize); if (!NT_SUCCESS(Status)) { ERR("Can't get layout filename for %wZ (%lx)\n", pwszKLID, Status); goto cleanup; } /* Load keyboard file now */ if (!UserLoadKbdDll(wszLayoutPath, &pkf->hBase, &pkf->pKbdTbl)) { ERR("Failed to load %ws dll!\n", wszLayoutPath); goto cleanup; } /* Update next field */ pkf->pkfNext = gpkfList; gpkfList = pkf; /* Return keyboard file */ pRet = pkf; cleanup: if (hKey) ZwClose(hKey); if (pkf) UserDereferenceObject(pkf); // we dont need ptr anymore if (!pRet) { /* We have failed - destroy created object */ if (pkf) UserDeleteObject(pkf->head.h, TYPE_KBDFILE); } return pRet; }