diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 58898b3..c5ae3b4 100755 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,3 +1,85 @@ +KernelEx v4.5 Beta 1 by Xeno86 +2010-01-18 + +disable named/rcdata resource types mirroring + +changed obfuscator for non-negative PIDs + +fix crash when a process is created with '.exe' renamed to '.dll' + +added GDI anti-leaking code which forces NT destroying rules on font and bitmap objects. + +implemented extended TLS (Thread Local Storage), extends limit of 80 to ~1100 slots + +added Thunking Unicode Layer - set of user32 APIs +which provides consistent Unicode window procedures conversion, +allowing correct message conversion and mixture of window subclassing with NT-like rules. + +revamped non-shared api library loading process + +added jemalloc memory allocator, replacing standard Windows heap for applications + +fix: LoadShfolderProc could crash if shfolder.dll was unloaded by the application + +added USERENV library from Wine project + +changed module configuration settings storage - single module can now have different configurations under different processes (better accuracy, overriding is supported, recursive inheritance is supported, speed gains) + +change: Allow api library to be loaded even if some overridden modules aren't found (skips module tables) + +shell folder fix - display CSIDL_COMMON_* folders in start menu + +added support for environment variables in AppSettings database + +added kexCOM - implementing IShellLinkW and IExtractIconW interfaces for CLSID_ShellLink which are missing from Windows 98 shell + +Compatibility tab changes: +* redesigned, added baloon tips +* added option to disable configuration inheritance to child processes +* added option to override module configuration with process'es configuration (debug only) +* fixed COM implementation + +changes into the installer: +* enforce reboot after install/uninstall before subsequent installation, +* copy kernel32.bak to temporary file during uninstall before reboot +* forbid direct downgrades + +API changes: + +fix GlobalLock and GlobalUnlock to work properly with HeapAlloc pointers +make CreateFile ignore unsupported FILE_SHARE_DELETE flag +make GetDiskFreeSpace, GetDiskFreeSpaceEx not fail on certain file paths +implemented USERENV.GetUserProfileDirectory, GetAllUsersProfileDirectory, GetProfilesDirectory +added various winspool unicode (unicows) apis and stubs +added EnumServicesStatusEx stubs +fix CreateDIBSection to behave consistently with NT +fix GetTempFileName to behave consistently with NT +make ExtCreatePen not fail on PS_USERSTYLE pen style +replaced MSLU GetObjectW (bug: MSLU always returns full object size regardless of buffer size passed) with custom implementation +replaced MSLU RegEnumValueW with custom implementation +added support for REG_EXPAND_SZ and REG_MULTI_SZ in RegQueryValueExW +fixed RegQueryValueExW not handling return values properly +fix: win9x doesn't allow MB_ERR_INVALID_CHARS parameter to be set for UTF-7 or UTF-8 codepages in MultiByteToWideChar and WideCharToMultiByte calls +fix: RegisterWaitForSingleObject should test object state once and return immediatelly when dwMiliseconds is zero +implemented GDI32.GetCharABCWidthsI, ADVAPI32.RtlGenRandom, KERNEL32.GetModuleHandleEx +fixed uxtheme return addresses +implemented theme metric functions +fix WTSGetActiveConsoleSessionId should return 0 = local session instead 0xffffffff = no session +implemented kernel32.DelayLoadFailureHook, QueueUserWorkItem, RegisterWaitForSingleObject, RegisterWaitForSingleObjectEx, UnregisterWait, UnregisterWaitEx, IsWow64Process, ProcessIdToSessionId, WTSGetActiveConsoleSessionId, IsWow64Process +removed shlwapi.StrCmpLogicalW (which is available with IE6-updated shlwapi) +implemented advapi32.DeleteAce +added stubs for advapi32.NotifyBootConfigStatus, QueryWindows31FilesMigration, SynchronizeWindows31FilesAndWindowsNTRegistry +changed advapi32.CreateWellKnownSid +change: logfont* is optional in gdi32.EnumFontFamiliesEx on NT but not on 9x +added stubs for kernel32.HeapSetInformation, GetProcessIoCounters, RtlCaptureStackBackTrace +support events signalling in ReadFile & WriteFile overlapped apis +fixed system bug in user32.GetNextDlgTabItem - system crashes trying to get next control in dialog to tab when there is only one control on dialog +fixed GetDefaultPrinterW +replaced SHGetFolderLocation Wine implementation with custom implementation +fix: custom SHGetFolderLocation shouldn't be enabled for shell32 >= 5.0 + +--------------------------------------- + KernelEx v4.0 Final 2 by Xeno86 2009-08-20 diff --git a/COMPATIBILITY.txt b/COMPATIBILITY.txt deleted file mode 100755 index 2866703..0000000 --- a/COMPATIBILITY.txt +++ /dev/null @@ -1,69 +0,0 @@ -KernelEx v4.0 Final 2 by Xeno86 -2009-08-20 - -Major changes: --------------- -* system won't try to load auxiliary libraries (PSAPI, MSIMG32, PDH, UXTHEME, WTSAPI32) when extensions are disabled - -Fixed regressions: ------------------- -* fixed ZoneAlarm not working properly -* Firefox 3 couldn't be uninstalled if KernelEx was installed with extensions disabled -* Foobar2000 v0.9.6.x installer was crashing - -################################################# - -KernelEx v4.0 Final by Xeno86 -2009-07-23 - -Now working on Windows 98/Me: ------------------------------ -* Flash 10 in Internet Explorer - -Major changes: --------------- -* added option to installer to select between enabling KernelEx extensions for all applications and disabling them -* added installation verifier -* printer driver software no longer running in NT mode -* file select dialogs in Flash applets and certain applications should work correctly now -* improved RP9 compatibility -* loading MSLU altered floating point unit flags and caused certain programs to crash -* MSLU (Unicows.dll) is no longer loaded right on startup and should be seen referenced less often in system -* Dependency Walker is no longer slow when profiling -* startup speed improvements -* stability improvements -* tons of small changes - -################################################# - -KernelEx v4.0 RC 2 by Xeno86 -2009-03-21 - -Now working on Windows 98/Me: ------------------------------ -* The Chronicles of Riddick EFBB Demo -* QEmu 0.9 - -Fixed regressions: ------------------- -* fixed Adobe Acrobat Reader 7.0 not working with RC 1 -* .Net framework was broken in RC 1 now should work correctly -* input issue in Firefox 3 affecting special characters -* eMule couldn't complete downloads in RC 1, now fixed -* transparency issue in Firefox 3 -* incompatibility with Norton Utilities - -################################################# - -KernelEx v4.0 RC 1 by Xeno86 -2009-03-10 - -Now working on Windows 98/Me: ------------------------------ -* Firefox 3.6 alpha -* JDK 6 / JRE 6 works fine with the exception of Java applets which don't work (reason: missing proper named-pipe support in the system) -* PDF-XChange Viewer now works - -Fixed regressions: ------------------- -* Sysinternals TCPView display fix diff --git a/KernelEx.dsw b/KernelEx.dsw index 7262326..7407f28 100755 --- a/KernelEx.dsw +++ b/KernelEx.dsw @@ -23,9 +23,6 @@ Package=<5> Package=<4> {{{ - Begin Project Dependency - Project_Dep_Name prep - End Project Dependency }}} ############################################################################### @@ -38,9 +35,6 @@ Package=<5> Package=<4> {{{ - Begin Project Dependency - Project_Dep_Name prep - End Project Dependency }}} ############################################################################### @@ -57,6 +51,18 @@ Package=<4> ############################################################################### +Project: "kexCOM"=.\kexCOM\kexCOM.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + Project: "kexcontrol"=.\kexcontrol\kexcontrol.dsp - Package Owner=<4> Package=<5> diff --git a/KernelEx.nsi b/KernelEx.nsi index d57528e..51f4665 100755 --- a/KernelEx.nsi +++ b/KernelEx.nsi @@ -1,4 +1,12 @@ - !define VERSION '4.0 Final 2' + !define _VERSION '4.5 Beta 1' + + !ifndef _DEBUG + !define FLAVOUR 'Release' + !define VERSION '${_VERSION}' + !else + !define FLAVOUR 'Debug' + !define VERSION '${_VERSION} Debug' + !endif ;-------------------------------- ;Includes @@ -66,8 +74,6 @@ LangString DESC_INSTALLING ${LANG_ENGLISH} "Installing" LangString DESC_DOWNLOADING1 ${LANG_ENGLISH} "Downloading" LangString DESC_DOWNLOADFAILED ${LANG_ENGLISH} "Download Failed:" - LangString DESC_PRODUCT_TIMEOUT ${LANG_ENGLISH} "The installation of the $(DESC_SHORTPRODUCT) \ - has timed out." LangString ERROR_PRODUCT_INVALID_PATH ${LANG_ENGLISH} "The $(DESC_SHORTPRODUCT) Installation$\n\ was not found in the following location:$\n" LangString ERROR_PRODUCT_FATAL ${LANG_ENGLISH} "A fatal error occurred during the installation$\n\ @@ -159,8 +165,7 @@ Section "MSLU" SECPRODUCT DetailPrint "$(DESC_INSTALLING) $(DESC_SHORTPRODUCT)..." Banner::show /NOUNLOAD "$(DESC_INSTALLING) $(DESC_SHORTPRODUCT)..." CreateDirectory "$INSTDIR\MSLU" - nsExec::Exec '"$TEMP\unicows.exe" /t:$INSTDIR\MSLU' - Pop $0 + ExecWait '"$TEMP\unicows.exe" /t:$INSTDIR\MSLU' $0 Banner::destroy Delete "$TEMP\unicows.exe" @@ -169,18 +174,12 @@ Section "MSLU" SECPRODUCT ; it will return "error" ; If the process timed out it will return "timeout" ; else it will return the return code from the executed process. - StrCmp $0 "" lbl_NoError + StrCmp $0 "" lbl_Error StrCmp $0 "0" lbl_NoError - StrCmp $0 "error" lbl_Error - StrCmp $0 "timeout" lbl_TimeOut ; all others are fatal DetailPrint "$(ERROR_PRODUCT_FATAL)[$0]" Goto lbl_commonError - lbl_TimeOut: - DetailPrint "$(DESC_PRODUCT_TIMEOUT)" - Goto lbl_commonError - lbl_Error: DetailPrint "$(ERROR_PRODUCT_INVALID_PATH)" Goto lbl_commonError @@ -200,14 +199,28 @@ SectionEnd Section "Install" SetDetailsView show + + ReadRegStr $0 HKLM "Software\Microsoft\Windows\CurrentVersion\RunServicesOnce" "KexNeedsReboot" + IfErrors +5 + DetailPrint "Detected unfinished previous installation." + DetailPrint "You have to restart the system in order to complete it before you can proceed." + MessageBox MB_ICONSTOP|MB_OK "You have to restart the system first." + Abort + SetOutPath "$INSTDIR" SetOverwrite on - File setup\Release\setupkex.exe + File setup\${FLAVOUR}\setupkex.exe SetOverwrite lastused +!ifdef _DEBUG nsExec::ExecToLog '"$INSTDIR\setupkex.exe" "$INSTDIR\kernel32.bak"' Pop $0 +!else + ExecWait '"$INSTDIR\setupkex.exe" "$INSTDIR\kernel32.bak"' $0 + StrCmp $0 "" 0 +2 + StrCpy $0 "error" +!endif DetailPrint " setup returned: $0" Delete "$INSTDIR\setupkex.exe" StrCmp $0 "0" +3 @@ -219,33 +232,40 @@ Section "Install" ;UpdateDLL_Func params: ;$R4 - target; $R5 - tempdir; $R6 - register?; $R7 - source GetTempFileName $0 "$INSTDIR" - File /oname=$0 "Core\Release\KernelEx.dll" + File /oname=$0 "Core\${FLAVOUR}\KernelEx.dll" StrCpy $R4 "$INSTDIR\KernelEx.dll" StrCpy $R6 "0" StrCpy $R7 $0 Call UpgradeDLL_Func GetTempFileName $0 "$INSTDIR" - File /oname=$0 "apilibs\kexbases\Release\kexbases.dll" + File /oname=$0 "apilibs\kexbases\${FLAVOUR}\kexbases.dll" StrCpy $R4 "$INSTDIR\kexbases.dll" StrCpy $R6 "0" StrCpy $R7 $0 Call UpgradeDLL_Func GetTempFileName $0 "$INSTDIR" - File /oname=$0 "apilibs\kexbasen\Release\kexbasen.dll" + File /oname=$0 "apilibs\kexbasen\${FLAVOUR}\kexbasen.dll" StrCpy $R4 "$INSTDIR\kexbasen.dll" StrCpy $R6 "0" StrCpy $R7 $0 Call UpgradeDLL_Func GetTempFileName $0 "$INSTDIR" - File /oname=$0 "sheet\Release\sheet.dll" + File /oname=$0 "sheet\${FLAVOUR}\sheet.dll" StrCpy $R4 "$INSTDIR\sheet.dll" StrCpy $R6 "1" StrCpy $R7 $0 Call UpgradeDLL_Func + GetTempFileName $0 "$INSTDIR" + File /oname=$0 "kexCOM\${FLAVOUR}\kexCOM.dll" + StrCpy $R4 "$INSTDIR\kexCOM.dll" + StrCpy $R6 "1" + StrCpy $R7 $0 + Call UpgradeDLL_Func + SetOverwrite on File apilibs\core.ini @@ -287,6 +307,13 @@ Section "Install" WriteRegStr HKLM "Software\KernelEx\KnownDLLs" \ "WTSAPI32" "WTSAPI32.DLL" + GetTempFileName $0 "$INSTDIR" + File /oname=$0 auxiliary\userenv.dll + Delete "$INSTDIR\userenv.dll" + Rename /REBOOTOK $0 "$INSTDIR\userenv.dll" + WriteRegStr HKLM "Software\KernelEx\KnownDLLs" \ + "USERENV" "USERENV.DLL" + SetOverwrite lastused ExecWait '"$WINDIR\regedit.exe" /s "$INSTDIR\settings.reg"' @@ -306,7 +333,7 @@ Section "Install" ;Write verifier SetOverWrite on - File verify\Release\verify.exe + File verify\${FLAVOUR}\verify.exe WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Run" \ "KexVerify" "$INSTDIR\verify.exe" SetOverwrite lastused @@ -314,6 +341,7 @@ Section "Install" ;Create uninstaller WriteUninstaller "$INSTDIR\Uninstall.exe" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\RunServicesOnce" "KexNeedsReboot" "" SetRebootFlag true SectionEnd @@ -324,21 +352,29 @@ SectionEnd Section "Uninstall" SetDetailsView show - - MessageBox MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2 "$(DESC_SETTINGS_PRESERVE)" IDYES +2 IDNO 0 - DeleteRegKey HKLM "Software\KernelEx" - - DeleteRegKey HKLM "System\CurrentControlSet\Control\MPRServices\KernelEx" - DeleteRegKey /ifempty HKLM "System\CurrentControlSet\Control\MPRServices" + + ReadRegStr $0 HKLM "Software\Microsoft\Windows\CurrentVersion\RunServicesOnce" "KexNeedsReboot" + IfErrors +5 + DetailPrint "Detected unfinished previous installation." + DetailPrint "You have to restart the system in order to complete it before you can proceed." + MessageBox MB_ICONSTOP|MB_OK "You have to restart the system first." + Abort ;Files to uninstall - Rename /REBOOTOK "$INSTDIR\kernel32.bak" "$SYSDIR\kernel32.dll" + IfFileExists "$INSTDIR\kernel32.bak" 0 +5 + GetTempFileName $0 "$SYSDIR" + Delete $0 + Rename "$INSTDIR\kernel32.bak" $0 + Rename /REBOOTOK $0 "$SYSDIR\kernel32.dll" + Delete /REBOOTOK "$INSTDIR\KernelEx.dll" Delete /REBOOTOK "$INSTDIR\kexbases.dll" Delete /REBOOTOK "$INSTDIR\kexbasen.dll" Delete "$INSTDIR\core.ini" UnRegDLL "$INSTDIR\sheet.dll" Delete /REBOOTOK "$INSTDIR\sheet.dll" + UnRegDLL "$INSTDIR\kexCOM.dll" + Delete /REBOOTOK "$INSTDIR\kexCOM.dll" Delete "$INSTDIR\license.txt" Delete /REBOOTOK "$INSTDIR\msimg32.dll" @@ -351,6 +387,8 @@ Section "Uninstall" DeleteRegValue HKLM "Software\KernelEx\KnownDLLs" "UXTHEME" Delete /REBOOTOK "$INSTDIR\wtsapi32.dll" DeleteRegValue HKLM "Software\KernelEx\KnownDLLs" "WTSAPI32" + Delete /REBOOTOK "$INSTDIR\userenv.dll" + DeleteRegValue HKLM "Software\KernelEx\KnownDLLs" "USERENV" Delete "$INSTDIR\verify.exe" DeleteRegValue HKLM "Software\Microsoft\Windows\CurrentVersion\Run" "KexVerify" @@ -360,8 +398,15 @@ Section "Uninstall" RMDir /r "$INSTDIR\MSLU" WriteINIStr $WINDIR\wininit.ini Rename DIRNUL $INSTDIR + MessageBox MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2 "$(DESC_SETTINGS_PRESERVE)" IDYES +2 IDNO 0 + DeleteRegKey HKLM "Software\KernelEx" + + DeleteRegKey HKLM "System\CurrentControlSet\Control\MPRServices\KernelEx" + DeleteRegKey /ifempty HKLM "System\CurrentControlSet\Control\MPRServices" + DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\KernelEx" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\RunServicesOnce" "KexNeedsReboot" "" SetRebootFlag true SectionEnd diff --git a/NEWS.txt b/NEWS.txt new file mode 100755 index 0000000..72d58ed --- /dev/null +++ b/NEWS.txt @@ -0,0 +1,123 @@ +KernelEx v4.5 Beta 1 by Xeno86 +2010-01-18 + +What's new: +---------------------------------- +* Noticeably improved speed of applications which make extensive use of memory. +This was made possible by introducing new memory allocator originating from FreeBSD - jemalloc. +It improves heap memory allocation/free speed and reduces virtual memory fragmentation. +* Improved compatibility with Unicode applications by implementing new windowing layer +which provides NT-consistent way to work with Unicode window procedures. +* Extended TLS slot limitation from 80 to 1000+, for some heavy apps. +* Lifted PE loader named resource limitation, allowing named resource-heavy libraries to load. +* Changed kernel obfuscator to produce positive object (process, thread) IDs in order to improve compatibility. +* Introduced kexCOM - new library to take care of missing COM interfaces. Fixes creating shell shortcuts in newer installers. +* GDI object destroying rules adjusted in order to fix certain resource leaks or unstability with Flash and other apps. +* Implemented certain userenv, unicode winspool, thread pool functions. +* Lot of API fixes and stubs. +* Improved Compatibility tab. +* Various architecture improvements. +* Fixed uninstall kernel32.bak not restoring reliably issue. + +Apps now working / fixed: +------------------------- +* .NET Framework 2 (fixed install/uninstall and apps) +* AbiWord 2.8 (usable, minor problems) +* Adobe Flash 10.1 beta +* Adobe Acrobat Reader 9 (very unstable) +* Adobe ImageReady CS2 (no Photoshop yet) +* Arora (WebKit Internet Browser) +* FastStone Image Viewer (fixed plugin crash) +* Foxit Reader 3.1 +* ICQ 6.5 / ICQLite +* InkScape (usable) +* GIMP 2.6 (usable, fixed brush trace) +* Half-Life 2 Episode One/Two +* Miranda IM 0.8.x Unicode +* Mozilla Thunderbird 3 (fixed out of space errors) +* Nero DiscSpeed 4 +* QtCreator 1.2.1 +* SoftMaker Office 2008 (fixed input bugs) +* WinAmp 5.5x (fixed ML crash, charset problems) +* X-Moto + + +Notes: +------ +* This release is beta quality in order to test several major changes in KernelEx. +Please test the apps which were working before. Compare the performance and memory usage of any heavy apps you use. +Pay attention to possible national language input problems. +* If you want to downgrade to Final 2, you have to uninstall this beta first. +* Enjoy this great release. win9x 4ever. + +################################################# + +KernelEx v4.0 Final 2 by Xeno86 +2009-08-20 + +Major changes: +-------------- +* system won't try to load auxiliary libraries (PSAPI, MSIMG32, PDH, UXTHEME, WTSAPI32) when extensions are disabled + +Fixed regressions: +------------------ +* fixed ZoneAlarm not working properly +* Firefox 3 couldn't be uninstalled if KernelEx was installed with extensions disabled +* Foobar2000 v0.9.6.x installer was crashing + +################################################# + +KernelEx v4.0 Final by Xeno86 +2009-07-23 + +Now working on Windows 98/Me: +----------------------------- +* Flash 10 in Internet Explorer + +Major changes: +-------------- +* added option to installer to select between enabling KernelEx extensions for all applications and disabling them +* added installation verifier +* printer driver software no longer running in NT mode +* file select dialogs in Flash applets and certain applications should work correctly now +* improved RP9 compatibility +* loading MSLU altered floating point unit flags and caused certain programs to crash +* MSLU (Unicows.dll) is no longer loaded right on startup and should be seen referenced less often in system +* Dependency Walker is no longer slow when profiling +* startup speed improvements +* stability improvements +* tons of small changes + +################################################# + +KernelEx v4.0 RC 2 by Xeno86 +2009-03-21 + +Now working on Windows 98/Me: +----------------------------- +* The Chronicles of Riddick EFBB Demo +* QEmu 0.9 + +Fixed regressions: +------------------ +* fixed Adobe Acrobat Reader 7.0 not working with RC 1 +* .Net framework was broken in RC 1 now should work correctly +* input issue in Firefox 3 affecting special characters +* eMule couldn't complete downloads in RC 1, now fixed +* transparency issue in Firefox 3 +* incompatibility with Norton Utilities + +################################################# + +KernelEx v4.0 RC 1 by Xeno86 +2009-03-10 + +Now working on Windows 98/Me: +----------------------------- +* Firefox 3.6 alpha +* JDK 6 / JRE 6 works fine with the exception of Java applets which don't work (reason: missing proper named-pipe support in the system) +* PDF-XChange Viewer now works + +Fixed regressions: +------------------ +* Sysinternals TCPView display fix diff --git a/apilibs/CORE.INI b/apilibs/CORE.INI old mode 100644 new mode 100755 diff --git a/apilibs/kexbasen/advapi32/_advapi32_apilist.c b/apilibs/kexbasen/advapi32/_advapi32_apilist.c old mode 100644 new mode 100755 index 2f4207a..6954b5e --- a/apilibs/kexbasen/advapi32/_advapi32_apilist.c +++ b/apilibs/kexbasen/advapi32/_advapi32_apilist.c @@ -40,7 +40,6 @@ static const apilib_named_api advapi32_named_apis[] = DECL_API("RegDeleteValueW", RegDeleteValueW_fwd), DECL_API("RegEnumKeyExW", RegEnumKeyExW_fwd), DECL_API("RegEnumKeyW", RegEnumKeyW_fwd), - DECL_API("RegEnumValueW", RegEnumValueW_fwd), DECL_API("RegLoadKeyW", RegLoadKeyW_fwd), DECL_API("RegOpenKeyExW", RegOpenKeyExW_fwd), DECL_API("RegOpenKeyW", RegOpenKeyW_fwd), diff --git a/apilibs/kexbasen/advapi32/_advapi32_apilist.h b/apilibs/kexbasen/advapi32/_advapi32_apilist.h old mode 100644 new mode 100755 index c72bc4d..10c2b8f --- a/apilibs/kexbasen/advapi32/_advapi32_apilist.h +++ b/apilibs/kexbasen/advapi32/_advapi32_apilist.h @@ -37,7 +37,6 @@ FWDPROC RegDeleteKeyW_fwd; FWDPROC RegDeleteValueW_fwd; FWDPROC RegEnumKeyExW_fwd; FWDPROC RegEnumKeyW_fwd; -FWDPROC RegEnumValueW_fwd; FWDPROC RegLoadKeyW_fwd; FWDPROC RegOpenKeyExW_fwd; FWDPROC RegOpenKeyW_fwd; diff --git a/apilibs/kexbasen/advapi32/uniadvapi32.c b/apilibs/kexbasen/advapi32/uniadvapi32.c old mode 100644 new mode 100755 index 5b0c37d..4cebde9 --- a/apilibs/kexbasen/advapi32/uniadvapi32.c +++ b/apilibs/kexbasen/advapi32/uniadvapi32.c @@ -30,7 +30,6 @@ FORWARD_TO_UNICOWS(RegDeleteKeyW); FORWARD_TO_UNICOWS(RegDeleteValueW); FORWARD_TO_UNICOWS(RegEnumKeyExW); FORWARD_TO_UNICOWS(RegEnumKeyW); -FORWARD_TO_UNICOWS(RegEnumValueW); FORWARD_TO_UNICOWS(RegLoadKeyW); FORWARD_TO_UNICOWS(RegOpenKeyExW); FORWARD_TO_UNICOWS(RegOpenKeyW); diff --git a/apilibs/kexbasen/comdlg32/_comdlg32_apilist.c b/apilibs/kexbasen/comdlg32/_comdlg32_apilist.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbasen/comdlg32/_comdlg32_apilist.h b/apilibs/kexbasen/comdlg32/_comdlg32_apilist.h old mode 100644 new mode 100755 diff --git a/apilibs/kexbasen/comdlg32/openfilename_fix.c b/apilibs/kexbasen/comdlg32/openfilename_fix.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbasen/comdlg32/unicomdlg32.c b/apilibs/kexbasen/comdlg32/unicomdlg32.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbasen/common.c b/apilibs/kexbasen/common.c old mode 100644 new mode 100755 index 24270dd..1b7db4e --- a/apilibs/kexbasen/common.c +++ b/apilibs/kexbasen/common.c @@ -54,6 +54,5 @@ char* file_fixWprefix(char* in) void fatal_error(const char* msg) { MessageBox(NULL, msg, "KernelEx error", MB_OK | MB_ICONERROR); -#pragma message("place DBGBREAK here!!!!") ExitProcess(1); } diff --git a/apilibs/kexbasen/common.h b/apilibs/kexbasen/common.h old mode 100644 new mode 100755 index f06cc90..15fdb90 --- a/apilibs/kexbasen/common.h +++ b/apilibs/kexbasen/common.h @@ -25,6 +25,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + typedef int __stdcall STUB(void); typedef int __stdcall FWDPROC(void); @@ -34,14 +38,17 @@ int WINAPI CommonUnimpStub(void); char* file_fixWprefix(char* in); void fatal_error(const char* msg); +#ifdef __cplusplus +}; +#endif #ifdef __GNUC__ -#define UNIMPL_FUNC(name,params) \ - __asm__( ".text\n" \ - ".globl _" #name "_stub@0\n" \ - "_" #name "_new@0:\n\t" \ - "xor %eax, %eax\n\t" \ - "movb $" #params ", %cl\n\t" \ +#define UNIMPL_FUNC(name,params) \ + __asm__( ".text\n" \ + ".globl _" #name "_stub@0\n" \ + "_" #name "_stub@0:\n\t" \ + "xor %eax, %eax\n\t" \ + "movb $" #params ", %cl\n\t" \ "jmp _CommonUnimpStub@0\n\t" \ ) #else @@ -61,7 +68,7 @@ void fatal_error(const char* msg); const WCHAR* p; \ int c; \ for (p = str##W ; *p ; p++); \ - c = (int) p - (int) str##W; \ + c = p - str##W + 1; \ c *= acp_mcs; \ str##A = (char*) alloca(c); \ WtoA(str, c) @@ -94,7 +101,7 @@ void fatal_error(const char* msg); const WCHAR* p; \ int c; \ for (p = str##W ; *p ; p++); \ - c = (int) p - (int) str##W; \ + c = p - str##W + 1; \ c *= acp_mcs; \ str##A = (char*) alloca(c); \ file_WtoA(str, c); \ diff --git a/apilibs/kexbasen/dirlist b/apilibs/kexbasen/dirlist old mode 100644 new mode 100755 index 151d792..e44e532 --- a/apilibs/kexbasen/dirlist +++ b/apilibs/kexbasen/dirlist @@ -6,4 +6,4 @@ comdlg32 shell32 rpcrt4 winspool -shlwapi +shfolder diff --git a/apilibs/kexbasen/gdi32/UberGDI.c b/apilibs/kexbasen/gdi32/UberGDI.c old mode 100644 new mode 100755 index c6af993..36bb72c --- a/apilibs/kexbasen/gdi32/UberGDI.c +++ b/apilibs/kexbasen/gdi32/UberGDI.c @@ -202,6 +202,46 @@ BOOL WINAPI GetCharWidthI_new( return TRUE; } +//NOTE: usp10 is probing for that function, don't forget to exclude it + +/* MAKE_EXPORT GetCharABCWidthsI_new=GetCharABCWidthsI */ +BOOL WINAPI GetCharABCWidthsI_new( + HDC hdc, // handle to DC + UINT giFirst, // first glyph index in range + UINT cgi, // count of glyph indices in range + LPWORD pgi, // array of glyph indices + LPABC lpabc // array of character widths +) +{ + SCRIPT_CACHE cache = 0; + WORD glyph; + + if ( !hdc || !lpabc || cgi<=0) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + if ( !pgi ) //cgi glyphs starting giFirst + { + for ( glyph = giFirst; glyph < giFirst+cgi; glyph++) + { + ScriptGetGlyphABCWidth(hdc,&cache,glyph,lpabc); + lpabc++; + } + } + else + { + for ( glyph = 0; glyph < cgi; glyph++) + { + ScriptGetGlyphABCWidth(hdc,&cache,*pgi,lpabc); + pgi++; + lpabc++; + } + } + ScriptFreeCache(&cache); + return TRUE; +} + /* MAKE_EXPORT GetGlyphOutlineW_new=GetGlyphOutlineW */ DWORD WINAPI GetGlyphOutlineW_new( HDC hdc, // handle to DC diff --git a/apilibs/kexbasen/gdi32/_gdi32_apilist.c b/apilibs/kexbasen/gdi32/_gdi32_apilist.c old mode 100644 new mode 100755 index 008b775..00c15b2 --- a/apilibs/kexbasen/gdi32/_gdi32_apilist.c +++ b/apilibs/kexbasen/gdi32/_gdi32_apilist.c @@ -43,6 +43,7 @@ static const apilib_named_api gdi32_named_apis[] = DECL_API("CreateScalableFontResourceW", CreateScalableFontResourceW_fwd), DECL_API("EnumFontsW", EnumFontsW_fwd), DECL_API("EnumICMProfilesW", EnumICMProfilesW_fwd), + DECL_API("GetCharABCWidthsI", GetCharABCWidthsI_new), DECL_API("GetCharABCWidthsW", GetCharABCWidthsW_fwd), DECL_API("GetCharWidthI", GetCharWidthI_new), DECL_API("GetCharacterPlacementW", GetCharacterPlacementW_fwd), @@ -55,7 +56,6 @@ static const apilib_named_api gdi32_named_apis[] = DECL_API("GetKerningPairsW", GetKerningPairsW_fwd), DECL_API("GetLogColorSpaceW", GetLogColorSpaceW_fwd), DECL_API("GetMetaFileW", GetMetaFileW_fwd), - DECL_API("GetObjectW", GetObjectW_fwd), DECL_API("GetOutlineTextMetricsW", GetOutlineTextMetricsW_fwd), DECL_API("GetTextExtentExPointI", GetTextExtentExPointI_new), DECL_API("GetTextExtentExPointW", GetTextExtentExPointW_fwd), diff --git a/apilibs/kexbasen/gdi32/_gdi32_apilist.h b/apilibs/kexbasen/gdi32/_gdi32_apilist.h old mode 100644 new mode 100755 index 0a63828..cfbde91 --- a/apilibs/kexbasen/gdi32/_gdi32_apilist.h +++ b/apilibs/kexbasen/gdi32/_gdi32_apilist.h @@ -33,6 +33,7 @@ int WINAPI GetGlyphIndicesA_new(HDC hdc, LPCSTR lpstr, int c, LPWORD pgi, DWORD BOOL WINAPI GetTextExtentExPointI_new(HDC hdc, LPWORD pgiIn, int cgi, int nMaxExtent, LPINT lpnFit, LPINT alpDx, LPSIZE lpSize); BOOL WINAPI GetTextExtentPointI_new(HDC hdc, LPWORD pgiIn, int cgi, LPSIZE lpSize); BOOL WINAPI GetCharWidthI_new(HDC hdc, UINT giFirst, UINT cgi, WORD* pgi, INT* lpBuffer); +BOOL WINAPI GetCharABCWidthsI_new(HDC hdc, UINT giFirst, UINT cgi, LPWORD pgi, LPABC lpabc); DWORD WINAPI GetGlyphOutlineW_new(HDC hdc, UINT uChar, UINT uFormat, LPGLYPHMETRICS lpgm, DWORD cbBuffer, LPVOID lpvBuffer, CONST MAT2 *lpmat2); FWDPROC CopyEnhMetaFileW_fwd; FWDPROC CopyMetaFileW_fwd; @@ -54,7 +55,6 @@ FWDPROC GetICMProfileW_fwd; FWDPROC GetKerningPairsW_fwd; FWDPROC GetLogColorSpaceW_fwd; FWDPROC GetMetaFileW_fwd; -FWDPROC GetObjectW_fwd; FWDPROC GetOutlineTextMetricsW_fwd; FWDPROC GetTextExtentExPointW_fwd; FWDPROC GetTextFaceW_fwd; diff --git a/apilibs/kexbasen/gdi32/unigdi32.c b/apilibs/kexbasen/gdi32/unigdi32.c old mode 100644 new mode 100755 index 7e1fc6b..eadb461 --- a/apilibs/kexbasen/gdi32/unigdi32.c +++ b/apilibs/kexbasen/gdi32/unigdi32.c @@ -41,7 +41,6 @@ FORWARD_TO_UNICOWS(GetICMProfileW); FORWARD_TO_UNICOWS(GetKerningPairsW); FORWARD_TO_UNICOWS(GetLogColorSpaceW); FORWARD_TO_UNICOWS(GetMetaFileW); -FORWARD_TO_UNICOWS(GetObjectW); FORWARD_TO_UNICOWS(GetOutlineTextMetricsW); FORWARD_TO_UNICOWS(GetTextExtentExPointW); FORWARD_TO_UNICOWS(GetTextFaceW); diff --git a/apilibs/kexbasen/kernel32/DelayLoadFailureHook.c b/apilibs/kexbasen/kernel32/DelayLoadFailureHook.c new file mode 100755 index 0000000..9f06a6e --- /dev/null +++ b/apilibs/kexbasen/kernel32/DelayLoadFailureHook.c @@ -0,0 +1,63 @@ +/* + * KernelEx + * + * Copyright (C) 2009, Tihiy + * This file is part of KernelEx source code. + * + * KernelEx is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. + * + * KernelEx is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include + +typedef struct +{ + DWORD unknown[3]; + LPSTR dllName; + DWORD unknown2; + LPSTR procName; +} SHLWAPI_DELAYLOAD, *PSHLWAPI_DELAYLOAD; + +/* + * shlwapi has half of whole Windows API reimplemented + * and DelayLoadFailureHook in some retarded wrapper export + */ + +static HMODULE hShlwapi; +typedef FARPROC (WINAPI* DLFH) (DWORD, PSHLWAPI_DELAYLOAD); + +/* MAKE_EXPORT DelayLoadFailureHook_new=DelayLoadFailureHook */ +FARPROC WINAPI DelayLoadFailureHook_new( + LPSTR pszDllName, + LPSTR pszProcName +) +{ + SHLWAPI_DELAYLOAD param; + + if (!hShlwapi) + { + hShlwapi = GetModuleHandle("shlwapi.dll"); + if (!hShlwapi) + hShlwapi = LoadLibrary("shlwapi.dll"); + } + + DLFH ShlwapiDelayLoad = (DLFH) GetProcAddress(hShlwapi,"DelayLoadFailureHook"); + if (!ShlwapiDelayLoad) + return NULL; + + param.dllName = pszDllName; + param.procName = pszProcName; + + return ShlwapiDelayLoad(4,¶m); +} diff --git a/apilibs/kexbasen/kernel32/ThreadPool.c b/apilibs/kexbasen/kernel32/ThreadPool.c new file mode 100755 index 0000000..f0de55e --- /dev/null +++ b/apilibs/kexbasen/kernel32/ThreadPool.c @@ -0,0 +1,238 @@ +/* + * KernelEx + * Copyright (C) 2009, Tihiy + * Copyright (c) 2006 Robert Shearman (WINE Project) + * + * This file is part of KernelEx source code. + * + * KernelEx is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. + * + * KernelEx is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include "shlord.h" + +/* + * The following functions are implemented: + * QueueUserWorkItem (with SHLWAPI.SHQueueUserWorkItem) + * RegisterWaitForSingleObject + * RegisterWaitForSingleObjectEx + * UnregisterWait + * UnregisterWaitEx + * all functions could be implemented with shlwapi, + * but they don't support async de-registration and most flags + * Also, Wine functions can cause problems in cases like + * when second unregister is called, or handle is reused... + * But Windows XP also fails hard in such cases. + */ + +#define TPS_EXECUTEIO 0x00000001 +#define TPS_LONGEXECTIME 0x00000008 + +typedef BOOL (WINAPI* SHQueueUserWorkItem_API) (LPTHREAD_START_ROUTINE pfnCallback, + LPVOID pContext, + LONG lPriority, + PDWORD dwTag, + PDWORD * pdwId, + LPCSTR pszModule, + DWORD dwFlags); + +static SHQueueUserWorkItem_API SHQueueUserWorkItem; + + +/* MAKE_EXPORT QueueUserWorkItem_new=QueueUserWorkItem */ +BOOL WINAPI QueueUserWorkItem_new( LPTHREAD_START_ROUTINE Function, PVOID Context, ULONG Flags) +{ + if (!SHQueueUserWorkItem) + SHQueueUserWorkItem = (SHQueueUserWorkItem_API)GetShlwapiProc(260); + + DWORD dwFlags = 0; + if (Flags & WT_EXECUTEINIOTHREAD) dwFlags |= TPS_EXECUTEIO; + if (Flags & WT_EXECUTELONGFUNCTION) dwFlags |= TPS_LONGEXECTIME; + + return SHQueueUserWorkItem( Function, Context, 0, NULL, NULL, NULL, dwFlags ); +} + +//registerwait routines +typedef struct +{ + HANDLE Object; + HANDLE CancelEvent; + WAITORTIMERCALLBACK Callback; + PVOID Context; + ULONG Milliseconds; + ULONG Flags; + HANDLE CompletionEvent; + LONG DeleteCount; + BOOLEAN CallbackInProgress; +} wait_work_item_struct, *wait_work_item_ptr; + +static void delete_wait_work_item(wait_work_item_ptr wait_work_item) +{ + CloseHandle( wait_work_item->CancelEvent ); + wait_work_item->CancelEvent = 0; //in case someone tries to work on deleted handle + HeapFree( GetProcessHeap(), 0, wait_work_item ); +} + +static DWORD CALLBACK wait_thread_proc(LPVOID Arg) +{ + wait_work_item_ptr wait_work_item = (wait_work_item_ptr)Arg; + BOOL alertable = (wait_work_item->Flags & WT_EXECUTEINIOTHREAD) ? TRUE : FALSE; + HANDLE handles[2] = { wait_work_item->Object, wait_work_item->CancelEvent }; + HANDLE completion_event; + DWORD status; + + + while (TRUE) + { + status = WaitForMultipleObjectsEx( 2, handles, FALSE, wait_work_item->Milliseconds, alertable ); + if (status == STATUS_WAIT_0 || status == STATUS_TIMEOUT) + { + BOOL TimerOrWaitFired = (status == STATUS_WAIT_0) ? FALSE : TRUE; + + wait_work_item->CallbackInProgress = TRUE; + wait_work_item->Callback( wait_work_item->Context, TimerOrWaitFired ); + wait_work_item->CallbackInProgress = FALSE; + + if (wait_work_item->Flags & WT_EXECUTEONLYONCE) + break; + } + else + break; //CancelEvent signalled + } + + completion_event = wait_work_item->CompletionEvent; + if (completion_event) + SetEvent( completion_event ); + + if ( InterlockedIncrement( &wait_work_item->DeleteCount ) == 2 ) + delete_wait_work_item( wait_work_item ); + + return 0; +} + +/* MAKE_EXPORT RegisterWaitForSingleObject_new=RegisterWaitForSingleObject */ +BOOL WINAPI RegisterWaitForSingleObject_new(PHANDLE phNewWaitObject, HANDLE hObject, WAITORTIMERCALLBACK Callback, + PVOID Context, ULONG dwMilliseconds, ULONG dwFlags) +{ + //validate stuff first. we aren't Wine. + if (!phNewWaitObject || IsBadCodePtr((FARPROC)Callback) || WaitForSingleObject(hObject,0) == WAIT_FAILED) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + wait_work_item_ptr wait_work_item; + wait_work_item = (wait_work_item_ptr)HeapAlloc(GetProcessHeap(), 0, sizeof(*wait_work_item)); + + if (!wait_work_item) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return FALSE; + } + + if ( dwMilliseconds == 0 ) dwFlags |= WT_EXECUTEONLYONCE; + wait_work_item->Object = hObject; + wait_work_item->Callback = Callback; + wait_work_item->Context = Context; + wait_work_item->Milliseconds = dwMilliseconds; + wait_work_item->Flags = dwFlags; + wait_work_item->CallbackInProgress = FALSE; + wait_work_item->DeleteCount = 0; + wait_work_item->CompletionEvent = NULL; + wait_work_item->CancelEvent = CreateEvent( NULL, TRUE, FALSE, NULL ); + if (!wait_work_item->CancelEvent) + { + HeapFree( GetProcessHeap(), 0, wait_work_item ); + return FALSE; + } + + if ( !QueueUserWorkItem_new(wait_thread_proc, wait_work_item, dwFlags) ) + { + delete_wait_work_item( wait_work_item ); + return FALSE; + } + + *phNewWaitObject = (HANDLE)wait_work_item; + return TRUE; +} + +/* MAKE_EXPORT RegisterWaitForSingleObjectEx_new=RegisterWaitForSingleObjectEx */ +HANDLE WINAPI RegisterWaitForSingleObjectEx_new(HANDLE hObject, + WAITORTIMERCALLBACK Callback, PVOID Context, + ULONG dwMilliseconds, ULONG dwFlags) +{ + HANDLE retHandle; + if ( RegisterWaitForSingleObject_new(&retHandle,hObject,Callback,Context,dwMilliseconds,dwFlags) ) + return retHandle; + else + return NULL; +} + +/* MAKE_EXPORT UnregisterWaitEx_new=UnregisterWaitEx */ +BOOL WINAPI UnregisterWaitEx_new(HANDLE WaitHandle, HANDLE CompletionEvent) +{ + if (!WaitHandle) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + BOOL pending = FALSE; + wait_work_item_ptr wait_work_item = (wait_work_item_ptr)WaitHandle; + if ( !SetEvent( wait_work_item->CancelEvent ) ) //signal cancel + return FALSE; + if (wait_work_item->CallbackInProgress) + { + if (CompletionEvent != NULL) + { + if (CompletionEvent == INVALID_HANDLE_VALUE) + { + CompletionEvent = CreateEvent( NULL, TRUE, FALSE, NULL ); + if (!CompletionEvent) + return FALSE; + InterlockedExchangePointer( &wait_work_item->CompletionEvent, CompletionEvent ); + if (wait_work_item->CallbackInProgress) + WaitForSingleObject( CompletionEvent, INFINITE ); + CloseHandle( CompletionEvent ); + } + else + { + InterlockedExchangePointer( &wait_work_item->CompletionEvent, CompletionEvent ); + if (wait_work_item->CallbackInProgress) + pending = TRUE; + } + } + else + pending = TRUE; + } + + if ( InterlockedIncrement(&wait_work_item->DeleteCount) == 2 ) + { + pending = FALSE; //somehow callback is complete already + delete_wait_work_item( wait_work_item ); + } + if ( pending ) + { + SetLastError(ERROR_IO_PENDING); + return FALSE; + } + + return TRUE; + +} + +/* MAKE_EXPORT UnregisterWait_new=UnregisterWait */ +BOOL WINAPI UnregisterWait_new(HANDLE WaitHandle) +{ + return UnregisterWaitEx_new(WaitHandle,NULL); +} diff --git a/apilibs/kexbasen/kernel32/TlsExt.c b/apilibs/kexbasen/kernel32/TlsExt.c new file mode 100755 index 0000000..d355ae8 --- /dev/null +++ b/apilibs/kexbasen/kernel32/TlsExt.c @@ -0,0 +1,427 @@ +/* + * KernelEx + * Copyright (C) 2009, Xeno86 + * + * This file is part of KernelEx source code. + * + * KernelEx is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. + * + * KernelEx is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include "k32ord.h" +#include "kexcoresdk.h" +#include "../../../core/structs.h" + +/* + * Design note: + * + * We use last TLS slot (79) specially, storing there + * a pointer to extended TLS slot table. + */ + +#define __ASM_IS_L33T__ + +#define TLS_SIZE 80 /* size of TDB98->TlsSlots */ +#define TLS_BITMAP_SIZE 3 /* size of PDB98->tlsInUseBits */ +#define EXT_TLS_SIZE 1024 +#define EXT_TLS_BITMAP_SIZE ((EXT_TLS_SIZE - 1) / (8 * sizeof(DWORD)) + 1) +#define TOTAL_TLS_SIZE (TLS_SIZE-1 + EXT_TLS_SIZE) + +/* Process extended TLS bitmap. */ +static DWORD ExtTlsBitmap[EXT_TLS_BITMAP_SIZE]; + +/* Pointer to TlsLock in kernel32. */ +static CRITICAL_SECTION* TlsLock; +static CRITICAL_SECTION* k32lock; +static DWORD lasterror_offs; + +static LPVOID* AllocExtTlsSlots() +{ + LPVOID* p; + p = (LPVOID*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LPVOID) * EXT_TLS_SIZE); + if (!p) + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return p; +} + +static CRITICAL_SECTION* find_TlsLock() +{ + PROC pTlsAlloc = kexGetProcAddress(GetModuleHandle("KERNEL32"), "TlsAlloc"); + return *(CRITICAL_SECTION**)((DWORD) pTlsAlloc + 2); +} + +static inline +PDB98* get_pdb(void) +{ + TIB98* tib; + __asm mov eax, fs:18h; + __asm mov tib, eax; + return tib->pProcess; +} + +/* initialization */ +BOOL init_exttls(void) +{ + BOOL ret = FALSE; + PDB98* pdb = get_pdb(); + DWORD GV = kexGetVersion(); + + //offsets for GetLastError value differ + //between systems :( + //we set them here + if (GV == 0xc0000a04) //98 + { + lasterror_offs = 0x60; + } + else if (GV == 0xc0005a04) //Me + { + lasterror_offs = 0x74; + } + else + { + return FALSE; + } + + //find TlsLock + TlsLock = find_TlsLock(); + k32lock = (CRITICAL_SECTION*) kexGetK32Lock(); + + _EnterSysLevel(TlsLock); + + //check if TLS index 79 free + if (!(pdb->tlsInUseBits[2] & (1 << 15))) + { + //reserve TLS index 79 + pdb->tlsInUseBits[2] |= (1 << 15); + ret = TRUE; + } + + _LeaveSysLevel(TlsLock); + + if (!ret) + kexDebugPrint("init_exttls failed"); + + return ret; +} + +void detach_exttls(void) +{ + TDB98* tdb; + LPVOID* ext; + + __asm mov eax, fs:18h; + __asm sub eax, 8; + __asm mov tdb, eax; + + ext = (LPVOID*) tdb->TlsSlots[TLS_SIZE-1]; + if (ext) + HeapFree(GetProcessHeap(), 0, ext); +} + +/* MAKE_EXPORT TlsAlloc_new=TlsAlloc */ +DWORD WINAPI TlsAlloc_new(void) +{ + PDB98* pdb; + DWORD index = 0; + int i; + + pdb = get_pdb(); + + _EnterSysLevel(TlsLock); + + for (i = 0 ; i < TLS_BITMAP_SIZE ; i++, index += 32) + { + if (pdb->tlsInUseBits[i] == 0xffffffff) + continue; + + for (int j = 0, a = 1 ; j < 32, index < TLS_SIZE-1 ; j++, a <<= 1, index++) + { + if ((pdb->tlsInUseBits[i] & a) == 0) + { + pdb->tlsInUseBits[i] |= a; + _LeaveSysLevel(TlsLock); + return index; + } + } + } + + for (i = 0 ; i < EXT_TLS_BITMAP_SIZE ; i++, index += 32) + { + if (ExtTlsBitmap[i] == 0xffffffff) + continue; + + for (int j = 0, a = 1 ; j < 32, index < TOTAL_TLS_SIZE ; j++, a <<= 1, index++) + { + if ((ExtTlsBitmap[i] & a) == 0) + { + ExtTlsBitmap[i] |= a; + _LeaveSysLevel(TlsLock); + return index; + } + } + } + + _LeaveSysLevel(TlsLock); + + SetLastError(ERROR_NO_MORE_ITEMS); + return TLS_OUT_OF_INDEXES; +} + +/* MAKE_EXPORT TlsFree_new=TlsFree */ +BOOL WINAPI TlsFree_new(DWORD dwTlsIndex) +{ + int ret; + PDB98* pdb = get_pdb(); + + _EnterSysLevel(TlsLock); + + if (dwTlsIndex < TLS_SIZE-1) + { + int rem = dwTlsIndex % (sizeof(DWORD) * 8); + int div = dwTlsIndex / (sizeof(DWORD) * 8); + pdb->tlsInUseBits[div] &= ~(1 << rem); + ret = 1; + } + else if (dwTlsIndex < TOTAL_TLS_SIZE) + { + dwTlsIndex -= TLS_SIZE-1; + int rem = dwTlsIndex % (sizeof(DWORD) * 8); + int div = dwTlsIndex / (sizeof(DWORD) * 8); + ExtTlsBitmap[div] &= ~(1 << rem); + ret = 2; + } + else + { + SetLastError(ERROR_INVALID_PARAMETER); + ret = 0; + } + + if (ret) + { + const NODE* thread; + + _EnterSysLevel(k32lock); + + for (thread = pdb->ThreadList->firstNode ; thread != NULL ; thread = thread->next) + { + TDB98* tdb = (TDB98*) thread->data; + if (ret == 1) + tdb->TlsSlots[dwTlsIndex] = NULL; + else + { + LPVOID* ext = (LPVOID*) tdb->TlsSlots[TLS_SIZE-1]; + if (ext) + ext[dwTlsIndex] = 0; + } + } + + _LeaveSysLevel(k32lock); + } + + _LeaveSysLevel(TlsLock); + + return ret; +} + +#ifdef __ASM_IS_L33T__ + +/* MAKE_EXPORT TlsGetValue_new2=TlsGetValue */ +__declspec(naked) +LPVOID WINAPI TlsGetValue_new2(DWORD dwTlsIndex) +{ +__asm { + mov ecx, [esp+4] ;dwTlsIndex + mov edx, fs:18h // Thread Info Block + cmp ecx, TLS_SIZE-1 + jnb __more + mov eax, [edx+ecx*4+88h] +__exit_no_error: + mov ecx, lasterror_offs + mov dword ptr [edx+ecx], NO_ERROR +__exit: + retn 4 +__more: + cmp ecx, TOTAL_TLS_SIZE + jnb __error + mov eax, [edx+(TLS_SIZE-1)*4+88h] + test eax, eax + jz __exit_no_error + sub ecx, TLS_SIZE-1 + mov eax, [eax+ecx*4] + jmp __exit_no_error +__error: + mov ecx, lasterror_offs + mov dword ptr [edx+ecx], ERROR_INVALID_PARAMETER + xor eax, eax + jmp __exit + } +} + +/* MAKE_EXPORT TlsSetValue_new2=TlsSetValue */ +__declspec(naked) +BOOL WINAPI TlsSetValue_new2(DWORD dwTlsIndex, LPVOID lpTlsValue) +{ +__asm { + mov ecx, [esp+4] ;dwTlsIndex + mov edx, fs:18h // Thread Info Block + cmp ecx, TLS_SIZE-1 + jnb __more + mov eax, [esp+8] ;lpTlsValue + mov [edx+ecx*4+88h], eax +__exit_no_error: + mov eax, 1 +__exit: + retn 8 +__more: + cmp ecx, TOTAL_TLS_SIZE + jnb __error + mov eax, [edx+(TLS_SIZE-1)*4+88h] + test eax, eax + jz __alloc +__no_alloc: + mov edx, [esp+8] ;lpTlsValue + sub ecx, TLS_SIZE-1 + mov [eax+ecx*4], edx + jmp __exit_no_error +__alloc: + call AllocExtTlsSlots + test eax, eax + jz __exit + mov ecx, fs:18h + lea edx, [ecx+(TLS_SIZE-1)*4+88h] + mov [edx], eax + mov ecx, [esp+4] ;dwTlsIndex + jmp __no_alloc +__error: + mov ecx, lasterror_offs + mov dword ptr [edx+ecx], ERROR_INVALID_PARAMETER + xor eax, eax + jmp __exit + } +} + +#else //__ASM_IS_L33T__ + +static inline void SetLastError_fast(TDB98* tdb, DWORD error) +{ + *(DWORD*) ((DWORD) tdb + lasterror_offs + 8) = error; +} + +LPVOID WINAPI TlsGetValue_new2(DWORD dwTlsIndex) +{ + TDB98* tdb; + + __asm mov eax, fs:18h; + __asm sub eax, 8; + __asm mov tdb, eax; + + if (dwTlsIndex < TLS_SIZE-1) + { + SetLastError_fast(tdb, NO_ERROR); + return tdb->TlsSlots[dwTlsIndex]; + } + else if (dwTlsIndex < TOTAL_TLS_SIZE) + { + LPVOID* ext; + ext = (LPVOID*) tdb->TlsSlots[TLS_SIZE-1]; + if (ext) + return ext[dwTlsIndex-TLS_SIZE-1]; + else + return NULL; + } + else + { + SetLastError_fast(tdb, ERROR_INVALID_PARAMETER); + return NULL; + } +} + +BOOL WINAPI TlsSetValue_new2(DWORD dwTlsIndex, LPVOID lpTlsValue) +{ + TDB98* tdb; + + __asm mov eax, fs:18h; + __asm sub eax, 8; + __asm mov tdb, eax; + + if (dwTlsIndex < TLS_SIZE-1) + { + tdb->TlsSlots[dwTlsIndex] = lpTlsValue; + return TRUE; + } + else if (dwTlsIndex < TOTAL_TLS_SIZE) + { + LPVOID* ext = (LPVOID*) tdb->TlsSlots[TLS_SIZE-1]; + if (!ext) + { + ext = AllocExtTlsSlots(); + if (!ext) + return FALSE; + tdb->TlsSlots[TLS_SIZE-1] = ext; + } + ext[dwTlsIndex-TLS_SIZE-1] = lpTlsValue; + return TRUE; + } + else + { + SetLastError_fast(tdb, ERROR_INVALID_PARAMETER); + return FALSE; + } +} + +#endif + +/* ORIGINAL UNALTERED FUNCTION AS REFERENCE +__declspec(naked) +LPVOID WINAPI TlsGetValue_new(DWORD dwTlsIndex) +{ +__asm { + mov ecx, dwTlsIndex + mov edx, fs:18h // Thread Info Block + cmp ecx, 50h + jnb __error + mov eax, [edx+ecx*4+88h] + mov dword ptr [edx+60h], NO_ERROR +__exit: + retn 4 +__error: + mov dword ptr [edx+60h], ERROR_INVALID_PARAMETER //Me:[edx+74h] + xor eax, eax + jmp __exit + } +} +*/ + +/* ORIGINAL UNALTERED FUNCTION AS REFERENCE +__declspec(naked) +BOOL WINAPI TlsSetValue_new(DWORD dwTlsIndex, LPVOID lpTlsValue) +{ +__asm { + mov ecx, dwTlsIndex + mov edx, fs:18h // Thread Info Block + cmp ecx, 50h + jnb __error + mov eax, lpTlsValue + mov [edx+ecx*4+88h], eax + mov eax, 1 +__exit: + retn 8 +__error: + mov dword ptr [edx+60h], ERROR_INVALID_PARAMETER //Me:[edx+74h] + xor eax, eax + jmp __exit + } +} +*/ diff --git a/apilibs/kexbasen/kernel32/_kernel32_apilist.c b/apilibs/kexbasen/kernel32/_kernel32_apilist.c old mode 100644 new mode 100755 index 3c11fc9..15c8143 --- a/apilibs/kexbasen/kernel32/_kernel32_apilist.c +++ b/apilibs/kexbasen/kernel32/_kernel32_apilist.c @@ -23,9 +23,24 @@ #include "kexcoresdk.h" #include "_kernel32_apilist.h" +extern BOOL init_jemalloc(); +extern BOOL init_exttls(); +extern void uninit_jemalloc(); +extern void detach_exttls(); + BOOL init_kernel32() { - return TRUE; + return init_jemalloc() && init_exttls(); +} + +void uninit_kernel32() +{ + uninit_jemalloc(); +} + +void detach_kernel32() +{ + detach_exttls(); } static const apilib_named_api kernel32_named_apis[] = @@ -42,6 +57,7 @@ static const apilib_named_api kernel32_named_apis[] = DECL_API("CreateProcessW", CreateProcessW_fwd), DECL_API("CreateSemaphoreW", CreateSemaphoreW_fwd), DECL_API("CreateWaitableTimerW", CreateWaitableTimerW_fwd), + DECL_API("DelayLoadFailureHook", DelayLoadFailureHook_new), DECL_API("EnumCalendarInfoExW", EnumCalendarInfoExW_fwd), DECL_API("EnumCalendarInfoW", EnumCalendarInfoW_fwd), DECL_API("EnumDateFormatsExW", EnumDateFormatsExW_fwd), @@ -75,6 +91,12 @@ static const apilib_named_api kernel32_named_apis[] = DECL_API("GetProfileStringW", GetProfileStringW_fwd), DECL_API("GetTimeFormatW", GetTimeFormatW_fwd), DECL_API("GetVolumeInformationW", GetVolumeInformationW_fwd), + DECL_API("HeapAlloc", HeapAlloc_new), + DECL_API("HeapCreate", HeapCreate_new), + DECL_API("HeapDestroy", HeapDestroy_new), + DECL_API("HeapFree", HeapFree_new), + DECL_API("HeapReAlloc", HeapReAlloc_new), + DECL_API("HeapSize", HeapSize_new), DECL_API("IsBadStringPtrW", IsBadStringPtrW_fwd), DECL_API("OpenEventW", OpenEventW_fwd), DECL_API("OpenFileMappingW", OpenFileMappingW_fwd), @@ -83,10 +105,13 @@ static const apilib_named_api kernel32_named_apis[] = DECL_API("OpenWaitableTimerW", OpenWaitableTimerW_fwd), DECL_API("PeekConsoleInputW", PeekConsoleInputW_fwd), DECL_API("QueryDosDeviceW", QueryDosDeviceW_fwd), + DECL_API("QueueUserWorkItem", QueueUserWorkItem_new), DECL_API("ReadConsoleInputW", ReadConsoleInputW_fwd), DECL_API("ReadConsoleOutputCharacterW", ReadConsoleOutputCharacterW_fwd), DECL_API("ReadConsoleOutputW", ReadConsoleOutputW_fwd), DECL_API("ReadConsoleW", ReadConsoleW_fwd), + DECL_API("RegisterWaitForSingleObject", RegisterWaitForSingleObject_new), + DECL_API("RegisterWaitForSingleObjectEx", RegisterWaitForSingleObjectEx_new), DECL_API("ScrollConsoleScreenBufferW", ScrollConsoleScreenBufferW_fwd), DECL_API("SetCalendarInfoW", SetCalendarInfoW_fwd), DECL_API("SetComputerNameW", SetComputerNameW_fwd), @@ -94,6 +119,12 @@ static const apilib_named_api kernel32_named_apis[] = DECL_API("SetEnvironmentVariableW", SetEnvironmentVariableW_fwd), DECL_API("SetLocaleInfoW", SetLocaleInfoW_fwd), DECL_API("SetVolumeLabelW", SetVolumeLabelW_fwd), + DECL_API("TlsAlloc", TlsAlloc_new), + DECL_API("TlsFree", TlsFree_new), + DECL_API("TlsGetValue", TlsGetValue_new2), + DECL_API("TlsSetValue", TlsSetValue_new2), + DECL_API("UnregisterWait", UnregisterWait_new), + DECL_API("UnregisterWaitEx", UnregisterWaitEx_new), DECL_API("WaitNamedPipeW", WaitNamedPipeW_fwd), DECL_API("WriteConsoleInputW", WriteConsoleInputW_fwd), DECL_API("WriteConsoleOutputCharacterW", WriteConsoleOutputCharacterW_fwd), diff --git a/apilibs/kexbasen/kernel32/_kernel32_apilist.h b/apilibs/kexbasen/kernel32/_kernel32_apilist.h old mode 100644 new mode 100755 index 15ecdb0..1086eb7 --- a/apilibs/kexbasen/kernel32/_kernel32_apilist.h +++ b/apilibs/kexbasen/kernel32/_kernel32_apilist.h @@ -25,9 +25,29 @@ #include "kexcoresdk.h" BOOL init_kernel32(); +void uninit_kernel32(); +void detach_kernel32(); extern const apilib_api_table apitable_kernel32; /*** AUTOGENERATED APILIST DECLARATIONS BEGIN ***/ +FARPROC WINAPI DelayLoadFailureHook_new(LPSTR pszDllName, LPSTR pszProcName); +BOOL WINAPI QueueUserWorkItem_new(LPTHREAD_START_ROUTINE Function, PVOID Context, ULONG Flags); +BOOL WINAPI RegisterWaitForSingleObject_new(PHANDLE phNewWaitObject, HANDLE hObject, WAITORTIMERCALLBACK Callback, PVOID Context, ULONG dwMilliseconds, ULONG dwFlags); +HANDLE WINAPI RegisterWaitForSingleObjectEx_new(HANDLE hObject, WAITORTIMERCALLBACK Callback, PVOID Context, ULONG dwMilliseconds, ULONG dwFlags); +BOOL WINAPI UnregisterWaitEx_new(HANDLE WaitHandle, HANDLE CompletionEvent); +BOOL WINAPI UnregisterWait_new(HANDLE WaitHandle); +DWORD WINAPI TlsAlloc_new(void); +BOOL WINAPI TlsFree_new(DWORD dwTlsIndex); +LPVOID WINAPI TlsGetValue_new2(DWORD dwTlsIndex); +BOOL WINAPI TlsSetValue_new2(DWORD dwTlsIndex, LPVOID lpTlsValue); +LPVOID WINAPI TlsGetValue_new2(DWORD dwTlsIndex); +BOOL WINAPI TlsSetValue_new2(DWORD dwTlsIndex, LPVOID lpTlsValue); +HANDLE WINAPI HeapCreate_new(DWORD flOptions, DWORD dwInitialSize, DWORD dwMaximumSize); +BOOL WINAPI HeapDestroy_new(HANDLE hHeap); +LPVOID WINAPI HeapAlloc_new(HANDLE hHeap, DWORD dwFlags, DWORD dwBytes); +BOOL WINAPI HeapFree_new(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem); +DWORD WINAPI HeapSize_new(HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem); +LPVOID WINAPI HeapReAlloc_new(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem, DWORD dwBytes); FWDPROC BuildCommDCBAndTimeoutsW_fwd; FWDPROC BuildCommDCBW_fwd; FWDPROC CallNamedPipeW_fwd; diff --git a/apilibs/kexbasen/kernel32/allocator.c b/apilibs/kexbasen/kernel32/allocator.c new file mode 100755 index 0000000..1866535 --- /dev/null +++ b/apilibs/kexbasen/kernel32/allocator.c @@ -0,0 +1,268 @@ +/* + * KernelEx + * Copyright (C) 2009, Xeno86 + * + * This file is part of KernelEx source code. + * + * KernelEx is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. + * + * KernelEx is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/************************************************************************/ +/* N O T E S */ +/************************************************************************/ + +/* Shared heap and default process heap (GetProcessHeap) is handled by + * standard system implementation. This releases us from the hassle of + * making special hacks for handling GlobalAlloc and LocalAlloc. + * This covers 99% of applications. + * + * One custom heap is used per process, regardless of the number of + * HeapCreate calls. Two distinct handle values are used to indicate + * belonging to jemalloc and whether HEAP_GENERATE_EXCEPTIONS flag + * was set. + * All calls which do not have our handles are forwarded to system. + * + * One arena is used and TLS usage is disabled for optimal performance + * on single processor system. HEAP_NO_SERIALIZE flag is ignored + * because there is single heap per process. + */ + +/************************************************************************/ +/* M A C R O S A N D W R A P P E R S */ +/************************************************************************/ + +#define malloc(a) je_malloc(a) +#define valloc(a) je_valloc(a) +#define calloc(a, b) je_calloc(a, b) +#define realloc(a, b) je_realloc(a, b) +#define free(a) je_free(a) + +#define MOZ_MEMORY +#define MOZ_MEMORY_WINDOWS +#define NO_TLS + +#if (_MSC_VER < 1300) +#define __STDC_LIMIT_MACROS +#include "stdint.h" +#endif + +#include "jemalloc/jemalloc.c" + +int* _errno(void) +{ + static int myerrno = 0; + return &myerrno; +} + +#define TAG(A, B, C, D) (ULONG)(((A)<<0) + ((B)<<8) + ((C)<<16) + ((D)<<24)) +#define JM_HEAP_NORM ((HANDLE) TAG('J','E','M','N')) +#define JM_HEAP_EXCP ((HANDLE) TAG('J','E','M','E')) + +#define HEAP_SHARED 0x04000000 + +BOOL init_jemalloc() +{ + if (malloc_init_hard()) + return FALSE; + return TRUE; +} + +void uninit_jemalloc() +{ + malloc_print_stats(); +} + +/************************************************************************/ +/* T H E C O D E */ +/************************************************************************/ + +typedef union +{ + BYTE db; + WORD dw; + DWORD dd; +} UFooter; + +static inline +int footer_size(DWORD alloc_bytes) +{ + if (alloc_bytes <= 256 - 1) + return 1; + else if (alloc_bytes < 64*1024 - 2) + return 2; + else + return 4; +} + +static inline +int footer_size_for_usable_size(size_t usable) +{ + if (usable <= 256) + return 1; + else if (usable <= 64*1024) + return 2; + else + return 4; +} + +static inline +DWORD read_footer(const void* ptr, size_t usable, int fs) +{ + UFooter* footer; + if (!ptr) + return 0; + footer = (UFooter*) ((DWORD) ptr + usable - fs); + if (fs == sizeof(BYTE)) + return footer->db; + else if (fs == sizeof(WORD)) + return footer->dw; + else + return footer->dd; +} + +static inline +void write_footer(void* ptr, size_t usable, int fs, DWORD value) +{ + UFooter* footer = (UFooter*) ((DWORD) ptr + usable - fs); + if (fs == sizeof(BYTE)) + footer->db = (BYTE) value; + else if (fs == sizeof(WORD)) + footer->dw = (WORD) value; + else + footer->dd = (DWORD) value; +} + +/* MAKE_EXPORT HeapCreate_new=HeapCreate */ +HANDLE WINAPI HeapCreate_new(DWORD flOptions, DWORD dwInitialSize, DWORD dwMaximumSize) +{ + if (flOptions & HEAP_SHARED) + return HeapCreate(flOptions, dwInitialSize, dwMaximumSize); + if (flOptions & HEAP_GENERATE_EXCEPTIONS) + return JM_HEAP_EXCP; + else + return JM_HEAP_NORM; +} + +/* MAKE_EXPORT HeapDestroy_new=HeapDestroy */ +BOOL WINAPI HeapDestroy_new(HANDLE hHeap) +{ + if (hHeap == JM_HEAP_NORM || hHeap == JM_HEAP_EXCP) + return TRUE; + else + return HeapDestroy(hHeap); +} + +/* MAKE_EXPORT HeapAlloc_new=HeapAlloc */ +LPVOID WINAPI HeapAlloc_new(HANDLE hHeap, DWORD dwFlags, DWORD dwBytes) +{ + if (hHeap == JM_HEAP_NORM || hHeap == JM_HEAP_EXCP) + { + LPVOID ret; + int fs = footer_size(dwBytes); + + if (dwFlags & HEAP_ZERO_MEMORY) + ret = calloc(1, dwBytes + fs); + else + ret = malloc(dwBytes + fs); + if (!ret && (hHeap == JM_HEAP_EXCP || (dwFlags & HEAP_GENERATE_EXCEPTIONS))) + RaiseException(STATUS_NO_MEMORY, 0, 0, NULL); + + if (ret) + write_footer(ret, malloc_usable_size(ret), fs, dwBytes); + + return ret; + } + else + return HeapAlloc(hHeap, dwFlags, dwBytes); +} + +/* MAKE_EXPORT HeapFree_new=HeapFree */ +BOOL WINAPI HeapFree_new(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem) +{ + if (hHeap == JM_HEAP_NORM || hHeap == JM_HEAP_EXCP) + { + free(lpMem); + return TRUE; + } + else + return HeapFree(hHeap, dwFlags, lpMem); +} + +/* MAKE_EXPORT HeapSize_new=HeapSize */ +DWORD WINAPI HeapSize_new(HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem) +{ + if (hHeap == JM_HEAP_NORM || hHeap == JM_HEAP_EXCP) + { + size_t usable = malloc_usable_size(lpMem); + int fs = footer_size_for_usable_size(usable); + + return read_footer(lpMem, usable, fs); + } + else + return HeapSize(hHeap, dwFlags, lpMem); +} + +/* MAKE_EXPORT HeapReAlloc_new=HeapReAlloc */ +LPVOID WINAPI HeapReAlloc_new(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem, DWORD dwBytes) +{ + if (hHeap == JM_HEAP_NORM || hHeap == JM_HEAP_EXCP) + { + LPVOID ret; + int fs = footer_size(dwBytes); + size_t usable = malloc_usable_size(lpMem); + + if (dwFlags & HEAP_REALLOC_IN_PLACE_ONLY) + { + if (usable > dwBytes + fs) + { + size_t fsu = footer_size_for_usable_size(usable); + if (dwFlags & HEAP_ZERO_MEMORY) + { + DWORD old = read_footer(lpMem, usable, fsu); + if (dwBytes > old) + memset((void*) ((DWORD) lpMem + old), 0, dwBytes - old); + } + + write_footer(lpMem, usable, fsu, dwBytes); + ret = lpMem; + } + else + ret = NULL; + } + else if (dwFlags & HEAP_ZERO_MEMORY) + { + DWORD old = read_footer(lpMem, usable, footer_size_for_usable_size(usable)); + ret = realloc(lpMem, dwBytes + fs); + if (ret) + { + if (dwBytes > old) + memset((void*) ((DWORD) ret + old), 0, dwBytes - old); + write_footer(ret, malloc_usable_size(ret), fs, dwBytes); + } + } + else + { + ret = realloc(lpMem, dwBytes + fs); + if (ret) + write_footer(ret, malloc_usable_size(ret), fs, dwBytes); + } + if (!ret && (hHeap == JM_HEAP_EXCP || (dwFlags & HEAP_GENERATE_EXCEPTIONS))) + RaiseException(STATUS_NO_MEMORY, 0, 0, NULL); + return ret; + } + else + return HeapReAlloc(hHeap, dwFlags, lpMem, dwBytes); +} + diff --git a/apilibs/kexbasen/kernel32/jemalloc/jemalloc.c b/apilibs/kexbasen/kernel32/jemalloc/jemalloc.c new file mode 100755 index 0000000..b1f481a --- /dev/null +++ b/apilibs/kexbasen/kernel32/jemalloc/jemalloc.c @@ -0,0 +1,7270 @@ +/* -*- Mode: C; tab-width: 8; c-basic-offset: 8 -*- */ +/* vim:set softtabstop=8 shiftwidth=8: */ +/*- + * Copyright (C) 2006-2008 Jason Evans . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice(s), this list of conditions and the following disclaimer as + * the first lines of this file unmodified other than the possible + * addition of one or more copyright notices. + * 2. Redistributions in binary form must reproduce the above copyright + * notice(s), this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ******************************************************************************* + * + * This allocator implementation is designed to provide scalable performance + * for multi-threaded programs on multi-processor systems. The following + * features are included for this purpose: + * + * + Multiple arenas are used if there are multiple CPUs, which reduces lock + * contention and cache sloshing. + * + * + Cache line sharing between arenas is avoided for internal data + * structures. + * + * + Memory is managed in chunks and runs (chunks can be split into runs), + * rather than as individual pages. This provides a constant-time + * mechanism for associating allocations with particular arenas. + * + * Allocation requests are rounded up to the nearest size class, and no record + * of the original request size is maintained. Allocations are broken into + * categories according to size class. Assuming runtime defaults, 4 kB pages + * and a 16 byte quantum on a 32-bit system, the size classes in each category + * are as follows: + * + * |=====================================| + * | Category | Subcategory | Size | + * |=====================================| + * | Small | Tiny | 2 | + * | | | 4 | + * | | | 8 | + * | |----------------+---------| + * | | Quantum-spaced | 16 | + * | | | 32 | + * | | | 48 | + * | | | ... | + * | | | 480 | + * | | | 496 | + * | | | 512 | + * | |----------------+---------| + * | | Sub-page | 1 kB | + * | | | 2 kB | + * |=====================================| + * | Large | 4 kB | + * | | 8 kB | + * | | 12 kB | + * | | ... | + * | | 1012 kB | + * | | 1016 kB | + * | | 1020 kB | + * |=====================================| + * | Huge | 1 MB | + * | | 2 MB | + * | | 3 MB | + * | | ... | + * |=====================================| + * + * A different mechanism is used for each category: + * + * Small : Each size class is segregated into its own set of runs. Each run + * maintains a bitmap of which regions are free/allocated. + * + * Large : Each allocation is backed by a dedicated run. Metadata are stored + * in the associated arena chunk header maps. + * + * Huge : Each allocation is backed by a dedicated contiguous set of chunks. + * Metadata are stored in a separate red-black tree. + * + ******************************************************************************* + */ + +/* + * MALLOC_PRODUCTION disables assertions and statistics gathering. It also + * defaults the A and J runtime options to off. These settings are appropriate + * for production systems. + */ +#ifndef MOZ_MEMORY_DEBUG +# define MALLOC_PRODUCTION +#endif + +/* + * Use only one arena by default. Mozilla does not currently make extensive + * use of concurrent allocation, so the increased fragmentation associated with + * multiple arenas is not warranted. + */ +#define MOZ_MEMORY_NARENAS_DEFAULT_ONE + +/* + * MALLOC_STATS enables statistics calculation, and is required for + * jemalloc_stats(). + */ +/* #define MALLOC_STATS */ + +#ifndef MALLOC_PRODUCTION + /* + * MALLOC_DEBUG enables assertions and other sanity checks, and disables + * inline functions. + */ +# define MALLOC_DEBUG + + /* Memory filling (junk/zero). */ +# define MALLOC_FILL + + /* Allocation tracing. */ +# ifndef MOZ_MEMORY_WINDOWS +# define MALLOC_UTRACE +# endif + + /* Support optional abort() on OOM. */ +# define MALLOC_XMALLOC + + /* Support SYSV semantics. */ +# define MALLOC_SYSV +#endif + +/* + * MALLOC_VALIDATE causes malloc_usable_size() to perform some pointer + * validation. There are many possible errors that validation does not even + * attempt to detect. + */ +#define MALLOC_VALIDATE + +/* Embed no-op macros that support memory allocation tracking via valgrind. */ +#ifdef MOZ_VALGRIND +# define MALLOC_VALGRIND +#endif +#ifdef MALLOC_VALGRIND +# include +#else +# define VALGRIND_MALLOCLIKE_BLOCK(addr, sizeB, rzB, is_zeroed) +# define VALGRIND_FREELIKE_BLOCK(addr, rzB) +#endif + +/* + * MALLOC_BALANCE enables monitoring of arena lock contention and dynamically + * re-balances arena load if exponentially averaged contention exceeds a + * certain threshold. + */ +/* #define MALLOC_BALANCE */ + +#if (!defined(MOZ_MEMORY_WINDOWS) && !defined(MOZ_MEMORY_DARWIN)) + /* + * MALLOC_PAGEFILE causes all mmap()ed memory to be backed by temporary + * files, so that if a chunk is mapped, it is guaranteed to be swappable. + * This avoids asynchronous OOM failures that are due to VM over-commit. + * + * XXX OS X over-commits, so we should probably use mmap() instead of + * vm_allocate(), so that MALLOC_PAGEFILE works. + */ +#define MALLOC_PAGEFILE +#endif + +#ifdef MALLOC_PAGEFILE +/* Write size when initializing a page file. */ +# define MALLOC_PAGEFILE_WRITE_SIZE 512 +#endif + +#ifdef MOZ_MEMORY_LINUX +#define _GNU_SOURCE /* For mremap(2). */ +#define issetugid() 0 +#if 0 /* Enable in order to test decommit code on Linux. */ +# define MALLOC_DECOMMIT +#endif +#endif + +#ifndef MOZ_MEMORY_WINCE +#include + +#include +#include +#endif +#include +#include +#include +#include + +#ifdef MOZ_MEMORY_WINDOWS +#ifndef MOZ_MEMORY_WINCE +#include +#else +#include +#define SIZE_MAX UINT_MAX +#endif +#include + +#pragma warning( disable: 4267 4996 4146 ) + +#define false FALSE +#define true TRUE +#define inline __inline +#define SIZE_T_MAX SIZE_MAX +#define STDERR_FILENO 2 +#define PATH_MAX MAX_PATH +#define vsnprintf _vsnprintf + +#ifndef NO_TLS +static unsigned long tlsIndex = 0xffffffff; +#endif + +#define __thread +#ifdef MOZ_MEMORY_WINDOWS +#define _pthread_self() GetCurrentThreadId() +#else +#define _pthread_self() __threadid() +#endif +#define issetugid() 0 + +#ifndef MOZ_MEMORY_WINCE +/* use MSVC intrinsics */ +#pragma intrinsic(_BitScanForward) +static __forceinline int +ffs(int x) +{ + unsigned long i; + +#if 0 + if (_BitScanForward(&i, x) != 0) + i++; + else + i = 0; +#else + _asm + { + bsf eax, [x] + jnz found + xor eax, eax + jmp done + found: + inc eax + done: + mov [i], eax + } +#endif + return i; +} + +/* Implement getenv without using malloc */ +static char mozillaMallocOptionsBuf[64]; + +#define getenv xgetenv +static char * +getenv(const char *name) +{ + + if (GetEnvironmentVariableA(name, (LPSTR)&mozillaMallocOptionsBuf, + sizeof(mozillaMallocOptionsBuf)) > 0) + return (mozillaMallocOptionsBuf); + + return (NULL); +} +#else + +static void abort() { + DebugBreak(); + exit(-3); +} + +static int errno = 0; +#define ENOMEM 12 +#define EINVAL 22 + +static char * +getenv(const char *name) +{ + return (NULL); +} + +static int +ffs(int x) +{ + int ret; + + if (x == 0) + return 0; + ret = 2; + if ((x & 0x0000ffff) == 0) { ret += 16; x >>= 16;} + if ((x & 0x000000ff) == 0) { ret += 8; x >>= 8;} + if ((x & 0x0000000f) == 0) { ret += 4; x >>= 4;} + if ((x & 0x00000003) == 0) { ret += 2; x >>= 2;} + ret -= (x & 1); + + return (ret); +} +#endif + +typedef unsigned char uint8_t; +typedef unsigned uint32_t; +#ifdef _MSC_VER +typedef unsigned __int64 uint64_t; +typedef unsigned __int64 uintmax_t; +#else +typedef unsigned long long uint64_t; +typedef unsigned long long uintmax_t; +#endif +typedef long ssize_t; + +#define MALLOC_DECOMMIT +#endif + +#ifndef MOZ_MEMORY_WINDOWS +#ifndef MOZ_MEMORY_SOLARIS +#include +#endif +#ifndef __DECONST +# define __DECONST(type, var) ((type)(uintptr_t)(const void *)(var)) +#endif +#ifndef MOZ_MEMORY +__FBSDID("$FreeBSD: head/lib/libc/stdlib/malloc.c 180599 2008-07-18 19:35:44Z jasone $"); +#include "libc_private.h" +#ifdef MALLOC_DEBUG +# define _LOCK_DEBUG +#endif +#include "spinlock.h" +#include "namespace.h" +#endif +#include +#ifndef MADV_FREE +# define MADV_FREE MADV_DONTNEED +#endif +#ifndef MAP_NOSYNC +# define MAP_NOSYNC 0 +#endif +#include +#ifndef MOZ_MEMORY +#include +#endif +#include +#include +#ifndef MOZ_MEMORY_SOLARIS +#include +#endif +#include +#ifndef MOZ_MEMORY +#include /* Must come after several other sys/ includes. */ + +#include +#include +#include +#endif + +#include +#include +#ifndef SIZE_T_MAX +# define SIZE_T_MAX SIZE_MAX +#endif +#include +#ifdef MOZ_MEMORY_DARWIN +#define _pthread_self pthread_self +#define _pthread_mutex_init pthread_mutex_init +#define _pthread_mutex_trylock pthread_mutex_trylock +#define _pthread_mutex_lock pthread_mutex_lock +#define _pthread_mutex_unlock pthread_mutex_unlock +#endif +#include +#include +#include +#include +#include +#include +#include +#ifndef MOZ_MEMORY_DARWIN +#include +#endif +#include + +#ifdef MOZ_MEMORY_DARWIN +#include +#include +#include +#include +#include +#endif + +#ifndef MOZ_MEMORY +#include "un-namespace.h" +#endif + +#endif + +#include "jemalloc.h" + +#ifdef MOZ_MEMORY_DARWIN +static const bool __isthreaded = true; +#endif + +#if defined(MOZ_MEMORY_SOLARIS) && defined(MAP_ALIGN) && !defined(JEMALLOC_NEVER_USES_MAP_ALIGN) +#define JEMALLOC_USES_MAP_ALIGN /* Required on Solaris 10. Might improve performance elsewhere. */ +#endif + +#if defined(MOZ_MEMORY_WINCE) +#define JEMALLOC_USES_MAP_ALIGN /* Required for Windows CE */ +#endif + +#define __DECONST(type, var) ((type)(uintptr_t)(const void *)(var)) + +#include "qr.h" +#include "ql.h" +#ifdef MOZ_MEMORY_WINDOWS + /* MSVC++ does not support C99 variable-length arrays. */ +# define RB_NO_C99_VARARRAYS +#endif +#include "rb.h" + +#ifdef MALLOC_DEBUG + /* Disable inlining to make debugging easier. */ +#ifdef inline +#undef inline +#endif + +# define inline +#endif + +/* Size of stack-allocated buffer passed to strerror_r(). */ +#define STRERROR_BUF 64 + +/* Minimum alignment of allocations is 2^QUANTUM_2POW_MIN bytes. */ +# define QUANTUM_2POW_MIN 4 +#ifdef MOZ_MEMORY_SIZEOF_PTR_2POW +# define SIZEOF_PTR_2POW MOZ_MEMORY_SIZEOF_PTR_2POW +#else +# define SIZEOF_PTR_2POW 2 +#endif +#define PIC +#ifndef MOZ_MEMORY_DARWIN +static const bool __isthreaded = true; +#else +# define NO_TLS +#endif +#if 0 +#ifdef __i386__ +# define QUANTUM_2POW_MIN 4 +# define SIZEOF_PTR_2POW 2 +# define CPU_SPINWAIT __asm__ volatile("pause") +#endif +#ifdef __ia64__ +# define QUANTUM_2POW_MIN 4 +# define SIZEOF_PTR_2POW 3 +#endif +#ifdef __alpha__ +# define QUANTUM_2POW_MIN 4 +# define SIZEOF_PTR_2POW 3 +# define NO_TLS +#endif +#ifdef __sparc64__ +# define QUANTUM_2POW_MIN 4 +# define SIZEOF_PTR_2POW 3 +# define NO_TLS +#endif +#ifdef __amd64__ +# define QUANTUM_2POW_MIN 4 +# define SIZEOF_PTR_2POW 3 +# define CPU_SPINWAIT __asm__ volatile("pause") +#endif +#ifdef __arm__ +# define QUANTUM_2POW_MIN 3 +# define SIZEOF_PTR_2POW 2 +# define NO_TLS +#endif +#ifdef __mips__ +# define QUANTUM_2POW_MIN 3 +# define SIZEOF_PTR_2POW 2 +# define NO_TLS +#endif +#ifdef __powerpc__ +# define QUANTUM_2POW_MIN 4 +# define SIZEOF_PTR_2POW 2 +#endif +#endif + +#define SIZEOF_PTR (1U << SIZEOF_PTR_2POW) + +/* sizeof(int) == (1U << SIZEOF_INT_2POW). */ +#ifndef SIZEOF_INT_2POW +# define SIZEOF_INT_2POW 2 +#endif + +/* We can't use TLS in non-PIC programs, since TLS relies on loader magic. */ +#if (!defined(PIC) && !defined(NO_TLS)) +# define NO_TLS +#endif + +#ifdef NO_TLS + /* MALLOC_BALANCE requires TLS. */ +# ifdef MALLOC_BALANCE +# undef MALLOC_BALANCE +# endif +#endif + +/* + * Size and alignment of memory chunks that are allocated by the OS's virtual + * memory system. + */ +#ifdef MOZ_MEMORY_WINCE +#define CHUNK_2POW_DEFAULT 21 +#else +#define CHUNK_2POW_DEFAULT 20 +#endif +/* Maximum number of dirty pages per arena. */ +#define DIRTY_MAX_DEFAULT (1U << 10) + +/* Default reserve chunks. */ +#define RESERVE_MIN_2POW_DEFAULT 1 +/* + * Default range (in chunks) between reserve_min and reserve_max, in addition + * to the mandatory one chunk per arena. + */ +#ifdef MALLOC_PAGEFILE +# define RESERVE_RANGE_2POW_DEFAULT 5 +#else +# define RESERVE_RANGE_2POW_DEFAULT 0 +#endif + +/* + * Maximum size of L1 cache line. This is used to avoid cache line aliasing, + * so over-estimates are okay (up to a point), but under-estimates will + * negatively affect performance. + */ +#define CACHELINE_2POW 6 +#define CACHELINE ((size_t)(1U << CACHELINE_2POW)) + +/* Smallest size class to support. */ +#define TINY_MIN_2POW 1 + +/* + * Maximum size class that is a multiple of the quantum, but not (necessarily) + * a power of 2. Above this size, allocations are rounded up to the nearest + * power of 2. + */ +#define SMALL_MAX_2POW_DEFAULT 9 +#define SMALL_MAX_DEFAULT (1U << SMALL_MAX_2POW_DEFAULT) + +/* + * RUN_MAX_OVRHD indicates maximum desired run header overhead. Runs are sized + * as small as possible such that this setting is still honored, without + * violating other constraints. The goal is to make runs as small as possible + * without exceeding a per run external fragmentation threshold. + * + * We use binary fixed point math for overhead computations, where the binary + * point is implicitly RUN_BFP bits to the left. + * + * Note that it is possible to set RUN_MAX_OVRHD low enough that it cannot be + * honored for some/all object sizes, since there is one bit of header overhead + * per object (plus a constant). This constraint is relaxed (ignored) for runs + * that are so small that the per-region overhead is greater than: + * + * (RUN_MAX_OVRHD / (reg_size << (3+RUN_BFP)) + */ +#define RUN_BFP 12 +/* \/ Implicit binary fixed point. */ +#define RUN_MAX_OVRHD 0x0000003dU +#define RUN_MAX_OVRHD_RELAX 0x00001800U + +/* Put a cap on small object run size. This overrides RUN_MAX_OVRHD. */ +#define RUN_MAX_SMALL_2POW 15 +#define RUN_MAX_SMALL (1U << RUN_MAX_SMALL_2POW) + +/* + * Hyper-threaded CPUs may need a special instruction inside spin loops in + * order to yield to another virtual CPU. If no such instruction is defined + * above, make CPU_SPINWAIT a no-op. + */ +#ifndef CPU_SPINWAIT +# define CPU_SPINWAIT +#endif + +/* + * Adaptive spinning must eventually switch to blocking, in order to avoid the + * potential for priority inversion deadlock. Backing off past a certain point + * can actually waste time. + */ +#define SPIN_LIMIT_2POW 11 + +/* + * Conversion from spinning to blocking is expensive; we use (1U << + * BLOCK_COST_2POW) to estimate how many more times costly blocking is than + * worst-case spinning. + */ +#define BLOCK_COST_2POW 4 + +#ifdef MALLOC_BALANCE + /* + * We use an exponential moving average to track recent lock contention, + * where the size of the history window is N, and alpha=2/(N+1). + * + * Due to integer math rounding, very small values here can cause + * substantial degradation in accuracy, thus making the moving average decay + * faster than it would with precise calculation. + */ +# define BALANCE_ALPHA_INV_2POW 9 + + /* + * Threshold value for the exponential moving contention average at which to + * re-assign a thread. + */ +# define BALANCE_THRESHOLD_DEFAULT (1U << (SPIN_LIMIT_2POW-4)) +#endif + +/******************************************************************************/ + +/* + * Mutexes based on spinlocks. We can't use normal pthread spinlocks in all + * places, because they require malloc()ed memory, which causes bootstrapping + * issues in some cases. + */ +#if defined(MOZ_MEMORY_WINDOWS) +#define malloc_mutex_t CRITICAL_SECTION +#define malloc_spinlock_t CRITICAL_SECTION +#elif defined(MOZ_MEMORY_DARWIN) +typedef struct { + OSSpinLock lock; +} malloc_mutex_t; +typedef struct { + OSSpinLock lock; +} malloc_spinlock_t; +#elif defined(MOZ_MEMORY) +typedef pthread_mutex_t malloc_mutex_t; +typedef pthread_mutex_t malloc_spinlock_t; +#else +/* XXX these should #ifdef these for freebsd (and linux?) only */ +typedef struct { + spinlock_t lock; +} malloc_mutex_t; +typedef malloc_spinlock_t malloc_mutex_t; +#endif + +/* Set to true once the allocator has been initialized. */ +static bool malloc_initialized = false; + +#if defined(MOZ_MEMORY_WINDOWS) +/* No init lock for Windows. */ +#elif defined(MOZ_MEMORY_DARWIN) +static malloc_mutex_t init_lock = {OS_SPINLOCK_INIT}; +#elif defined(MOZ_MEMORY_LINUX) +static malloc_mutex_t init_lock = PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP; +#elif defined(MOZ_MEMORY) +static malloc_mutex_t init_lock = PTHREAD_MUTEX_INITIALIZER; +#else +static malloc_mutex_t init_lock = {_SPINLOCK_INITIALIZER}; +#endif + +/******************************************************************************/ +/* + * Statistics data structures. + */ + +#ifdef MALLOC_STATS + +typedef struct malloc_bin_stats_s malloc_bin_stats_t; +struct malloc_bin_stats_s { + /* + * Number of allocation requests that corresponded to the size of this + * bin. + */ + uint64_t nrequests; + + /* Total number of runs created for this bin's size class. */ + uint64_t nruns; + + /* + * Total number of runs reused by extracting them from the runs tree for + * this bin's size class. + */ + uint64_t reruns; + + /* High-water mark for this bin. */ + unsigned long highruns; + + /* Current number of runs in this bin. */ + unsigned long curruns; +}; + +typedef struct arena_stats_s arena_stats_t; +struct arena_stats_s { + /* Number of bytes currently mapped. */ + size_t mapped; + + /* + * Total number of purge sweeps, total number of madvise calls made, + * and total pages purged in order to keep dirty unused memory under + * control. + */ + uint64_t npurge; + uint64_t nmadvise; + uint64_t purged; +#ifdef MALLOC_DECOMMIT + /* + * Total number of decommit/commit operations, and total number of + * pages decommitted. + */ + uint64_t ndecommit; + uint64_t ncommit; + uint64_t decommitted; +#endif + + /* Per-size-category statistics. */ + size_t allocated_small; + uint64_t nmalloc_small; + uint64_t ndalloc_small; + + size_t allocated_large; + uint64_t nmalloc_large; + uint64_t ndalloc_large; + +#ifdef MALLOC_BALANCE + /* Number of times this arena reassigned a thread due to contention. */ + uint64_t nbalance; +#endif +}; + +typedef struct chunk_stats_s chunk_stats_t; +struct chunk_stats_s { + /* Number of chunks that were allocated. */ + uint64_t nchunks; + + /* High-water mark for number of chunks allocated. */ + unsigned long highchunks; + + /* + * Current number of chunks allocated. This value isn't maintained for + * any other purpose, so keep track of it in order to be able to set + * highchunks. + */ + unsigned long curchunks; +}; + +#endif /* #ifdef MALLOC_STATS */ + +/******************************************************************************/ +/* + * Extent data structures. + */ + +/* Tree of extents. */ +typedef struct extent_node_s extent_node_t; +struct extent_node_s { + /* Linkage for the size/address-ordered tree. */ + rb_node(extent_node_t) link_szad; + + /* Linkage for the address-ordered tree. */ + rb_node(extent_node_t) link_ad; + + /* Pointer to the extent that this tree node is responsible for. */ + void *addr; + + /* Total region size. */ + size_t size; +}; +typedef rb_tree(extent_node_t) extent_tree_t; + +/******************************************************************************/ +/* + * Radix tree data structures. + */ + +#ifdef MALLOC_VALIDATE + /* + * Size of each radix tree node (must be a power of 2). This impacts tree + * depth. + */ +# if (SIZEOF_PTR == 4) +# define MALLOC_RTREE_NODESIZE (1U << 14) +# else +# define MALLOC_RTREE_NODESIZE CACHELINE +# endif + +typedef struct malloc_rtree_s malloc_rtree_t; +struct malloc_rtree_s { + malloc_spinlock_t lock; + void **root; + unsigned height; + unsigned level2bits[1]; /* Dynamically sized. */ +}; +#endif + +/******************************************************************************/ +/* + * Reserve data structures. + */ + +/* Callback registration. */ +typedef struct reserve_reg_s reserve_reg_t; +struct reserve_reg_s { + /* Linkage for list of all registered callbacks. */ + ql_elm(reserve_reg_t) link; + + /* Callback function pointer. */ + reserve_cb_t *cb; + + /* Opaque application data pointer. */ + void *ctx; + + /* + * Sequence number of condition notification most recently sent to this + * callback. + */ + uint64_t seq; +}; + +/******************************************************************************/ +/* + * Arena data structures. + */ + +typedef struct arena_s arena_t; +typedef struct arena_bin_s arena_bin_t; + +/* Each element of the chunk map corresponds to one page within the chunk. */ +typedef struct arena_chunk_map_s arena_chunk_map_t; +struct arena_chunk_map_s { + /* + * Linkage for run trees. There are two disjoint uses: + * + * 1) arena_t's runs_avail tree. + * 2) arena_run_t conceptually uses this linkage for in-use non-full + * runs, rather than directly embedding linkage. + */ + rb_node(arena_chunk_map_t) link; + + /* + * Run address (or size) and various flags are stored together. The bit + * layout looks like (assuming 32-bit system): + * + * ???????? ???????? ????---- --ckdzla + * + * ? : Unallocated: Run address for first/last pages, unset for internal + * pages. + * Small: Run address. + * Large: Run size for first page, unset for trailing pages. + * - : Unused. + * c : decommitted? + * k : key? + * d : dirty? + * z : zeroed? + * l : large? + * a : allocated? + * + * Following are example bit patterns for the three types of runs. + * + * r : run address + * s : run size + * x : don't care + * - : 0 + * [cdzla] : bit set + * + * Unallocated: + * ssssssss ssssssss ssss---- --c----- + * xxxxxxxx xxxxxxxx xxxx---- ----d--- + * ssssssss ssssssss ssss---- -----z-- + * + * Small: + * rrrrrrrr rrrrrrrr rrrr---- -------a + * rrrrrrrr rrrrrrrr rrrr---- -------a + * rrrrrrrr rrrrrrrr rrrr---- -------a + * + * Large: + * ssssssss ssssssss ssss---- ------la + * -------- -------- -------- ------la + * -------- -------- -------- ------la + */ + size_t bits; +#ifdef MALLOC_DECOMMIT +#define CHUNK_MAP_DECOMMITTED ((size_t)0x20U) +#endif +#define CHUNK_MAP_KEY ((size_t)0x10U) +#define CHUNK_MAP_DIRTY ((size_t)0x08U) +#define CHUNK_MAP_ZEROED ((size_t)0x04U) +#define CHUNK_MAP_LARGE ((size_t)0x02U) +#define CHUNK_MAP_ALLOCATED ((size_t)0x01U) +}; +typedef rb_tree(arena_chunk_map_t) arena_avail_tree_t; +typedef rb_tree(arena_chunk_map_t) arena_run_tree_t; + +/* Arena chunk header. */ +typedef struct arena_chunk_s arena_chunk_t; +struct arena_chunk_s { + /* Arena that owns the chunk. */ + arena_t *arena; + + /* Linkage for the arena's chunks_dirty tree. */ + rb_node(arena_chunk_t) link_dirty; + + /* Number of dirty pages. */ + size_t ndirty; + + /* Map of pages within chunk that keeps track of free/large/small. */ + arena_chunk_map_t map[1]; /* Dynamically sized. */ +}; +typedef rb_tree(arena_chunk_t) arena_chunk_tree_t; + +typedef struct arena_run_s arena_run_t; +struct arena_run_s { +#ifdef MALLOC_DEBUG + uint32_t magic; +# define ARENA_RUN_MAGIC 0x384adf93 +#endif + + /* Bin this run is associated with. */ + arena_bin_t *bin; + + /* Index of first element that might have a free region. */ + unsigned regs_minelm; + + /* Number of free regions in run. */ + unsigned nfree; + + /* Bitmask of in-use regions (0: in use, 1: free). */ + unsigned regs_mask[1]; /* Dynamically sized. */ +}; + +struct arena_bin_s { + /* + * Current run being used to service allocations of this bin's size + * class. + */ + arena_run_t *runcur; + + /* + * Tree of non-full runs. This tree is used when looking for an + * existing run when runcur is no longer usable. We choose the + * non-full run that is lowest in memory; this policy tends to keep + * objects packed well, and it can also help reduce the number of + * almost-empty chunks. + */ + arena_run_tree_t runs; + + /* Size of regions in a run for this bin's size class. */ + size_t reg_size; + + /* Total size of a run for this bin's size class. */ + size_t run_size; + + /* Total number of regions in a run for this bin's size class. */ + uint32_t nregs; + + /* Number of elements in a run's regs_mask for this bin's size class. */ + uint32_t regs_mask_nelms; + + /* Offset of first region in a run for this bin's size class. */ + uint32_t reg0_offset; + +#ifdef MALLOC_STATS + /* Bin statistics. */ + malloc_bin_stats_t stats; +#endif +}; + +struct arena_s { +#ifdef MALLOC_DEBUG + uint32_t magic; +# define ARENA_MAGIC 0x947d3d24 +#endif + + /* All operations on this arena require that lock be locked. */ +#ifdef MOZ_MEMORY + malloc_spinlock_t lock; +#else + pthread_mutex_t lock; +#endif + +#ifdef MALLOC_STATS + arena_stats_t stats; +#endif + + /* + * Chunk allocation sequence number, used to detect races with other + * threads during chunk allocation, and then discard unnecessary chunks. + */ + uint64_t chunk_seq; + + /* Tree of dirty-page-containing chunks this arena manages. */ + arena_chunk_tree_t chunks_dirty; + + /* + * In order to avoid rapid chunk allocation/deallocation when an arena + * oscillates right on the cusp of needing a new chunk, cache the most + * recently freed chunk. The spare is left in the arena's chunk trees + * until it is deleted. + * + * There is one spare chunk per arena, rather than one spare total, in + * order to avoid interactions between multiple threads that could make + * a single spare inadequate. + */ + arena_chunk_t *spare; + + /* + * Current count of pages within unused runs that are potentially + * dirty, and for which madvise(... MADV_FREE) has not been called. By + * tracking this, we can institute a limit on how much dirty unused + * memory is mapped for each arena. + */ + size_t ndirty; + + /* + * Size/address-ordered tree of this arena's available runs. This tree + * is used for first-best-fit run allocation. + */ + arena_avail_tree_t runs_avail; + +#ifdef MALLOC_BALANCE + /* + * The arena load balancing machinery needs to keep track of how much + * lock contention there is. This value is exponentially averaged. + */ + uint32_t contention; +#endif + + /* + * bins is used to store rings of free regions of the following sizes, + * assuming a 16-byte quantum, 4kB pagesize, and default MALLOC_OPTIONS. + * + * bins[i] | size | + * --------+------+ + * 0 | 2 | + * 1 | 4 | + * 2 | 8 | + * --------+------+ + * 3 | 16 | + * 4 | 32 | + * 5 | 48 | + * 6 | 64 | + * : : + * : : + * 33 | 496 | + * 34 | 512 | + * --------+------+ + * 35 | 1024 | + * 36 | 2048 | + * --------+------+ + */ + arena_bin_t bins[1]; /* Dynamically sized. */ +}; + +/******************************************************************************/ +/* + * Data. + */ + +/* Number of CPUs. */ +static unsigned ncpus; + +/* VM page size. */ +static size_t pagesize; +static size_t pagesize_mask; +static size_t pagesize_2pow; + +/* Various bin-related settings. */ +static size_t bin_maxclass; /* Max size class for bins. */ +static unsigned ntbins; /* Number of (2^n)-spaced tiny bins. */ +static unsigned nqbins; /* Number of quantum-spaced bins. */ +static unsigned nsbins; /* Number of (2^n)-spaced sub-page bins. */ +static size_t small_min; +static size_t small_max; + +/* Various quantum-related settings. */ +static size_t quantum; +static size_t quantum_mask; /* (quantum - 1). */ + +/* Various chunk-related settings. */ +static size_t chunksize; +static size_t chunksize_mask; /* (chunksize - 1). */ +static size_t chunk_npages; +static size_t arena_chunk_header_npages; +static size_t arena_maxclass; /* Max size class for arenas. */ + +/********/ +/* + * Chunks. + */ + +#ifdef MALLOC_VALIDATE +static malloc_rtree_t *chunk_rtree; +#endif + +/* Protects chunk-related data structures. */ +static malloc_mutex_t huge_mtx; + +/* Tree of chunks that are stand-alone huge allocations. */ +static extent_tree_t huge_; + +#ifdef MALLOC_STATS +/* Huge allocation statistics. */ +static uint64_t huge_nmalloc; +static uint64_t huge_ndalloc; +static size_t huge_allocated; +#endif + +/****************/ +/* + * Memory reserve. + */ + +#ifdef MALLOC_PAGEFILE +static char pagefile_templ[PATH_MAX]; +#endif + +/* Protects reserve-related data structures. */ +static malloc_mutex_t reserve_mtx; + +/* + * Bounds on acceptable reserve size, and current reserve size. Reserve + * depletion may cause (reserve_cur < reserve_min). + */ +static size_t reserve_min; +static size_t reserve_cur; +static size_t reserve_max; + +/* List of registered callbacks. */ +static ql_head(reserve_reg_t) reserve_regs; + +/* + * Condition notification sequence number, used to determine whether all + * registered callbacks have been notified of the most current condition. + */ +static uint64_t reserve_seq; + +/* + * Trees of chunks currently in the memory reserve. Depending on function, + * different tree orderings are needed, which is why there are two trees with + * the same contents. + */ +static extent_tree_t reserve_chunks_szad; +static extent_tree_t reserve_chunks_ad; + +/****************************/ +/* + * base (internal allocation). + */ + +/* + * Current pages that are being used for internal memory allocations. These + * pages are carved up in cacheline-size quanta, so that there is no chance of + * false cache line sharing. + */ +static void *base_pages; +static void *base_next_addr; +#ifdef MALLOC_DECOMMIT +static void *base_next_decommitted; +#endif +static void *base_past_addr; /* Addr immediately past base_pages. */ +static extent_node_t *base_nodes; +static reserve_reg_t *base_reserve_regs; +static malloc_mutex_t base_mtx; +#ifdef MALLOC_STATS +static size_t base_mapped; +#endif + +/********/ +/* + * Arenas. + */ + +/* + * Arenas that are used to service external requests. Not all elements of the + * arenas array are necessarily used; arenas are created lazily as needed. + */ +static arena_t **arenas; +static unsigned narenas; +static unsigned narenas_2pow; +#ifndef NO_TLS +# ifdef MALLOC_BALANCE +static unsigned narenas_2pow; +# else +static unsigned next_arena; +# endif +#endif +#ifdef MOZ_MEMORY +static malloc_spinlock_t arenas_lock; /* Protects arenas initialization. */ +#else +static pthread_mutex_t arenas_lock; /* Protects arenas initialization. */ +#endif + +#ifndef NO_TLS +/* + * Map of pthread_self() --> arenas[???], used for selecting an arena to use + * for allocations. + */ +#ifndef MOZ_MEMORY_WINDOWS +static __thread arena_t *arenas_map; +#endif +#endif + +#ifdef MALLOC_STATS +/* Chunk statistics. */ +static chunk_stats_t stats_chunks; +#endif + +/*******************************/ +/* + * Runtime configuration options. + */ +const char *_malloc_options; + +#ifndef MALLOC_PRODUCTION +static bool opt_abort = true; +#ifdef MALLOC_FILL +static bool opt_junk = true; +#endif +#else +static bool opt_abort = false; +#ifdef MALLOC_FILL +static bool opt_junk = false; +#endif +#endif +static size_t opt_dirty_max = DIRTY_MAX_DEFAULT; +#ifdef MALLOC_BALANCE +static uint64_t opt_balance_threshold = BALANCE_THRESHOLD_DEFAULT; +#endif +static bool opt_print_stats = false; +static size_t opt_quantum_2pow = QUANTUM_2POW_MIN; +static size_t opt_small_max_2pow = SMALL_MAX_2POW_DEFAULT; +static size_t opt_chunk_2pow = CHUNK_2POW_DEFAULT; +static int opt_reserve_min_lshift = 0; +static int opt_reserve_range_lshift = 0; +#ifdef MALLOC_PAGEFILE +static bool opt_pagefile = false; +#endif +#ifdef MALLOC_UTRACE +static bool opt_utrace = false; +#endif +#ifdef MALLOC_SYSV +static bool opt_sysv = false; +#endif +#ifdef MALLOC_XMALLOC +static bool opt_xmalloc = false; +#endif +#ifdef MALLOC_FILL +static bool opt_zero = false; +#endif +static int opt_narenas_lshift = 0; + +#ifdef MALLOC_UTRACE +typedef struct { + void *p; + size_t s; + void *r; +} malloc_utrace_t; + +#define UTRACE(a, b, c) \ + if (opt_utrace) { \ + malloc_utrace_t ut; \ + ut.p = (a); \ + ut.s = (b); \ + ut.r = (c); \ + utrace(&ut, sizeof(ut)); \ + } +#else +#define UTRACE(a, b, c) +#endif + +/******************************************************************************/ +/* + * Begin function prototypes for non-inline static functions. + */ + +static char *umax2s(uintmax_t x, char *s); +static bool malloc_mutex_init(malloc_mutex_t *mutex); +static bool malloc_spin_init(malloc_spinlock_t *lock); +static void wrtmessage(const char *p1, const char *p2, const char *p3, + const char *p4); +#ifdef MALLOC_STATS +#ifdef MOZ_MEMORY_DARWIN +/* Avoid namespace collision with OS X's malloc APIs. */ +#define malloc_printf moz_malloc_printf +#endif +static void malloc_printf(const char *format, ...); +#endif +static bool base_pages_alloc_mmap(size_t minsize); +static bool base_pages_alloc(size_t minsize); +static void *base_alloc(size_t size); +static void *base_calloc(size_t number, size_t size); +static extent_node_t *base_node_alloc(void); +static void base_node_dealloc(extent_node_t *node); +static reserve_reg_t *base_reserve_reg_alloc(void); +static void base_reserve_reg_dealloc(reserve_reg_t *reg); +#ifdef MALLOC_STATS +static void stats_print(arena_t *arena); +#endif +static void *pages_map(void *addr, size_t size, int pfd); +static void pages_unmap(void *addr, size_t size); +static void *chunk_alloc_mmap(size_t size, bool pagefile); +#ifdef MALLOC_PAGEFILE +static int pagefile_init(size_t size); +static void pagefile_close(int pfd); +#endif +static void *chunk_recycle_reserve(size_t size, bool zero); +static void *chunk_alloc(size_t size, bool zero, bool pagefile); +static extent_node_t *chunk_dealloc_reserve(void *chunk, size_t size); +static void chunk_dealloc_mmap(void *chunk, size_t size); +static void chunk_dealloc(void *chunk, size_t size); +#ifndef NO_TLS +static arena_t *choose_arena_hard(void); +#endif +static void arena_run_split(arena_t *arena, arena_run_t *run, size_t size, + bool large, bool zero); +static void arena_chunk_init(arena_t *arena, arena_chunk_t *chunk); +static void arena_chunk_dealloc(arena_t *arena, arena_chunk_t *chunk); +static arena_run_t *arena_run_alloc(arena_t *arena, arena_bin_t *bin, + size_t size, bool large, bool zero); +static void arena_purge(arena_t *arena); +static void arena_run_dalloc(arena_t *arena, arena_run_t *run, bool dirty); +static void arena_run_trim_head(arena_t *arena, arena_chunk_t *chunk, + arena_run_t *run, size_t oldsize, size_t newsize); +static void arena_run_trim_tail(arena_t *arena, arena_chunk_t *chunk, + arena_run_t *run, size_t oldsize, size_t newsize, bool dirty); +static arena_run_t *arena_bin_nonfull_run_get(arena_t *arena, arena_bin_t *bin); +static void *arena_bin_malloc_hard(arena_t *arena, arena_bin_t *bin); +static size_t arena_bin_run_size_calc(arena_bin_t *bin, size_t min_run_size); +#ifdef MALLOC_BALANCE +static void arena_lock_balance_hard(arena_t *arena); +#endif +static void *arena_malloc_large(arena_t *arena, size_t size, bool zero); +static void *arena_palloc(arena_t *arena, size_t alignment, size_t size, + size_t alloc_size); +static size_t arena_salloc(const void *ptr); +static void arena_dalloc_large(arena_t *arena, arena_chunk_t *chunk, + void *ptr); +static void arena_ralloc_large_shrink(arena_t *arena, arena_chunk_t *chunk, + void *ptr, size_t size, size_t oldsize); +static bool arena_ralloc_large_grow(arena_t *arena, arena_chunk_t *chunk, + void *ptr, size_t size, size_t oldsize); +static bool arena_ralloc_large(void *ptr, size_t size, size_t oldsize); +static void *arena_ralloc(void *ptr, size_t size, size_t oldsize); +static bool arena_new(arena_t *arena); +static arena_t *arenas_extend(unsigned ind); +static void *huge_malloc(size_t size, bool zero); +static void *huge_palloc(size_t alignment, size_t size); +static void *huge_ralloc(void *ptr, size_t size, size_t oldsize); +static void huge_dalloc(void *ptr); +static void malloc_print_stats(void); +#ifndef MOZ_MEMORY_WINDOWS +static +#endif +bool malloc_init_hard(void); +static void reserve_shrink(void); +static uint64_t reserve_notify(reserve_cnd_t cnd, size_t size, uint64_t seq); +static uint64_t reserve_crit(size_t size, const char *fname, uint64_t seq); +static void reserve_fail(size_t size, const char *fname); + +void _malloc_prefork(void); +void _malloc_postfork(void); + +/* + * End function prototypes. + */ +/******************************************************************************/ + +/* + * umax2s() provides minimal integer printing functionality, which is + * especially useful for situations where allocation in vsnprintf() calls would + * potentially cause deadlock. + */ +#define UMAX2S_BUFSIZE 21 +static char * +umax2s(uintmax_t x, char *s) +{ + unsigned i; + + i = UMAX2S_BUFSIZE - 1; + s[i] = '\0'; + do { + i--; + s[i] = "0123456789"[x % 10]; + x /= 10; + } while (x > 0); + + return (&s[i]); +} + +static void +wrtmessage(const char *p1, const char *p2, const char *p3, const char *p4) +{ +#ifdef MOZ_MEMORY_WINCE + wchar_t buf[1024]; +#define WRT_PRINT(s) \ + MultiByteToWideChar(CP_ACP, 0, s, -1, buf, 1024); \ + OutputDebugStringW(buf) + + WRT_PRINT(p1); + WRT_PRINT(p2); + WRT_PRINT(p3); + WRT_PRINT(p4); +#else +#if defined(MOZ_MEMORY) && !defined(MOZ_MEMORY_WINDOWS) +#define _write write +#endif + _write(STDERR_FILENO, p1, (unsigned int) strlen(p1)); + _write(STDERR_FILENO, p2, (unsigned int) strlen(p2)); + _write(STDERR_FILENO, p3, (unsigned int) strlen(p3)); + _write(STDERR_FILENO, p4, (unsigned int) strlen(p4)); +#endif + +} + +#define _malloc_message malloc_message + +void (*_malloc_message)(const char *p1, const char *p2, const char *p3, + const char *p4) = wrtmessage; + +#ifdef MALLOC_DEBUG +# define assert(e) do { \ + if (!(e)) { \ + char line_buf[UMAX2S_BUFSIZE]; \ + _malloc_message(__FILE__, ":", umax2s(__LINE__, \ + line_buf), ": Failed assertion: "); \ + _malloc_message("\"", #e, "\"\n", ""); \ + abort(); \ + } \ +} while (0) +#else +#define assert(e) +#endif + +/******************************************************************************/ +/* + * Begin mutex. We can't use normal pthread mutexes in all places, because + * they require malloc()ed memory, which causes bootstrapping issues in some + * cases. + */ + +static bool +malloc_mutex_init(malloc_mutex_t *mutex) +{ +#if defined(MOZ_MEMORY_WINCE) + InitializeCriticalSection(mutex); +#elif defined(MOZ_MEMORY_WINDOWS) + if (__isthreaded) + InitializeCriticalSection(mutex); +#elif defined(MOZ_MEMORY_DARWIN) + mutex->lock = OS_SPINLOCK_INIT; +#elif defined(MOZ_MEMORY_LINUX) + pthread_mutexattr_t attr; + if (pthread_mutexattr_init(&attr) != 0) + return (true); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP); + if (pthread_mutex_init(mutex, &attr) != 0) { + pthread_mutexattr_destroy(&attr); + return (true); + } + pthread_mutexattr_destroy(&attr); +#elif defined(MOZ_MEMORY) + if (pthread_mutex_init(mutex, NULL) != 0) + return (true); +#else + static const spinlock_t lock = _SPINLOCK_INITIALIZER; + + mutex->lock = lock; +#endif + return (false); +} + +static inline void +malloc_mutex_lock(malloc_mutex_t *mutex) +{ + +#if defined(MOZ_MEMORY_WINDOWS) + EnterCriticalSection(mutex); +#elif defined(MOZ_MEMORY_DARWIN) + OSSpinLockLock(&mutex->lock); +#elif defined(MOZ_MEMORY) + pthread_mutex_lock(mutex); +#else + if (__isthreaded) + _SPINLOCK(&mutex->lock); +#endif +} + +static inline void +malloc_mutex_unlock(malloc_mutex_t *mutex) +{ + +#if defined(MOZ_MEMORY_WINDOWS) + LeaveCriticalSection(mutex); +#elif defined(MOZ_MEMORY_DARWIN) + OSSpinLockUnlock(&mutex->lock); +#elif defined(MOZ_MEMORY) + pthread_mutex_unlock(mutex); +#else + if (__isthreaded) + _SPINUNLOCK(&mutex->lock); +#endif +} + +static bool +malloc_spin_init(malloc_spinlock_t *lock) +{ +#if defined(MOZ_MEMORY_WINCE) + InitializeCriticalSection(lock); +#elif defined(MOZ_MEMORY_WINDOWS) + if (__isthreaded) + InitializeCriticalSection(lock); +#elif defined(MOZ_MEMORY_DARWIN) + lock->lock = OS_SPINLOCK_INIT; +#elif defined(MOZ_MEMORY_LINUX) + pthread_mutexattr_t attr; + if (pthread_mutexattr_init(&attr) != 0) + return (true); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP); + if (pthread_mutex_init(lock, &attr) != 0) { + pthread_mutexattr_destroy(&attr); + return (true); + } + pthread_mutexattr_destroy(&attr); +#elif defined(MOZ_MEMORY) + if (pthread_mutex_init(lock, NULL) != 0) + return (true); +#else + lock->lock = _SPINLOCK_INITIALIZER; +#endif + return (false); +} + +static inline void +malloc_spin_lock(malloc_spinlock_t *lock) +{ + +#if defined(MOZ_MEMORY_WINDOWS) + EnterCriticalSection(lock); +#elif defined(MOZ_MEMORY_DARWIN) + OSSpinLockLock(&lock->lock); +#elif defined(MOZ_MEMORY) + pthread_mutex_lock(lock); +#else + if (__isthreaded) + _SPINLOCK(&lock->lock); +#endif +} + +static inline void +malloc_spin_unlock(malloc_spinlock_t *lock) +{ +#if defined(MOZ_MEMORY_WINDOWS) + LeaveCriticalSection(lock); +#elif defined(MOZ_MEMORY_DARWIN) + OSSpinLockUnlock(&lock->lock); +#elif defined(MOZ_MEMORY) + pthread_mutex_unlock(lock); +#else + if (__isthreaded) + _SPINUNLOCK(&lock->lock); +#endif +} + +/* + * End mutex. + */ +/******************************************************************************/ +/* + * Begin spin lock. Spin locks here are actually adaptive mutexes that block + * after a period of spinning, because unbounded spinning would allow for + * priority inversion. + */ + +#if defined(MOZ_MEMORY) && !defined(MOZ_MEMORY_DARWIN) +# define malloc_spin_init malloc_mutex_init +# define malloc_spin_lock malloc_mutex_lock +# define malloc_spin_unlock malloc_mutex_unlock +#endif + +#ifndef MOZ_MEMORY +/* + * We use an unpublished interface to initialize pthread mutexes with an + * allocation callback, in order to avoid infinite recursion. + */ +int _pthread_mutex_init_calloc_cb(pthread_mutex_t *mutex, + void *(calloc_cb)(size_t, size_t)); + +__weak_reference(_pthread_mutex_init_calloc_cb_stub, + _pthread_mutex_init_calloc_cb); + +int +_pthread_mutex_init_calloc_cb_stub(pthread_mutex_t *mutex, + void *(calloc_cb)(size_t, size_t)) +{ + + return (0); +} + +static bool +malloc_spin_init(pthread_mutex_t *lock) +{ + + if (_pthread_mutex_init_calloc_cb(lock, base_calloc) != 0) + return (true); + + return (false); +} + +static inline unsigned +malloc_spin_lock(pthread_mutex_t *lock) +{ + unsigned ret = 0; + + if (__isthreaded) { + if (_pthread_mutex_trylock(lock) != 0) { + unsigned i; + volatile unsigned j; + + /* Exponentially back off. */ + for (i = 1; i <= SPIN_LIMIT_2POW; i++) { + for (j = 0; j < (1U << i); j++) + ret++; + + CPU_SPINWAIT; + if (_pthread_mutex_trylock(lock) == 0) + return (ret); + } + + /* + * Spinning failed. Block until the lock becomes + * available, in order to avoid indefinite priority + * inversion. + */ + _pthread_mutex_lock(lock); + assert((ret << BLOCK_COST_2POW) != 0); + return (ret << BLOCK_COST_2POW); + } + } + + return (ret); +} + +static inline void +malloc_spin_unlock(pthread_mutex_t *lock) +{ + + if (__isthreaded) + _pthread_mutex_unlock(lock); +} +#endif + +/* + * End spin lock. + */ +/******************************************************************************/ +/* + * Begin Utility functions/macros. + */ + +/* Return the chunk address for allocation address a. */ +#define CHUNK_ADDR2BASE(a) \ + ((void *)((uintptr_t)(a) & ~chunksize_mask)) + +/* Return the chunk offset of address a. */ +#define CHUNK_ADDR2OFFSET(a) \ + ((size_t)((uintptr_t)(a) & chunksize_mask)) + +/* Return the smallest chunk multiple that is >= s. */ +#define CHUNK_CEILING(s) \ + (((s) + chunksize_mask) & ~chunksize_mask) + +/* Return the smallest cacheline multiple that is >= s. */ +#define CACHELINE_CEILING(s) \ + (((s) + (CACHELINE - 1)) & ~(CACHELINE - 1)) + +/* Return the smallest quantum multiple that is >= a. */ +#define QUANTUM_CEILING(a) \ + (((a) + quantum_mask) & ~quantum_mask) + +/* Return the smallest pagesize multiple that is >= s. */ +#define PAGE_CEILING(s) \ + (((s) + pagesize_mask) & ~pagesize_mask) + +/* Compute the smallest power of 2 that is >= x. */ +static inline size_t +pow2_ceil(size_t x) +{ + + x--; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; +#if (SIZEOF_PTR == 8) + x |= x >> 32; +#endif + x++; + return (x); +} + +#ifdef MALLOC_BALANCE +/* + * Use a simple linear congruential pseudo-random number generator: + * + * prn(y) = (a*x + c) % m + * + * where the following constants ensure maximal period: + * + * a == Odd number (relatively prime to 2^n), and (a-1) is a multiple of 4. + * c == Odd number (relatively prime to 2^n). + * m == 2^32 + * + * See Knuth's TAOCP 3rd Ed., Vol. 2, pg. 17 for details on these constraints. + * + * This choice of m has the disadvantage that the quality of the bits is + * proportional to bit position. For example. the lowest bit has a cycle of 2, + * the next has a cycle of 4, etc. For this reason, we prefer to use the upper + * bits. + */ +# define PRN_DEFINE(suffix, var, a, c) \ +static inline void \ +sprn_##suffix(uint32_t seed) \ +{ \ + var = seed; \ +} \ + \ +static inline uint32_t \ +prn_##suffix(uint32_t lg_range) \ +{ \ + uint32_t ret, x; \ + \ + assert(lg_range > 0); \ + assert(lg_range <= 32); \ + \ + x = (var * (a)) + (c); \ + var = x; \ + ret = x >> (32 - lg_range); \ + \ + return (ret); \ +} +# define SPRN(suffix, seed) sprn_##suffix(seed) +# define PRN(suffix, lg_range) prn_##suffix(lg_range) +#endif + +#ifdef MALLOC_BALANCE +/* Define the PRNG used for arena assignment. */ +static __thread uint32_t balance_x; +PRN_DEFINE(balance, balance_x, 1297, 1301) +#endif + +#ifdef MALLOC_UTRACE +static int +utrace(const void *addr, size_t len) +{ + malloc_utrace_t *ut = (malloc_utrace_t *)addr; + + assert(len == sizeof(malloc_utrace_t)); + + if (ut->p == NULL && ut->s == 0 && ut->r == NULL) + malloc_printf("%d x USER malloc_init()\n", getpid()); + else if (ut->p == NULL && ut->r != NULL) { + malloc_printf("%d x USER %p = malloc(%zu)\n", getpid(), ut->r, + ut->s); + } else if (ut->p != NULL && ut->r != NULL) { + malloc_printf("%d x USER %p = realloc(%p, %zu)\n", getpid(), + ut->r, ut->p, ut->s); + } else + malloc_printf("%d x USER free(%p)\n", getpid(), ut->p); + + return (0); +} +#endif + +static inline const char * +_getprogname(void) +{ + + return (""); +} + +#ifdef MALLOC_STATS +/* + * Print to stderr in such a way as to (hopefully) avoid memory allocation. + */ +static void +malloc_printf(const char *format, ...) +{ +#ifndef WINCE + char buf[4096]; + va_list ap; + + va_start(ap, format); + vsnprintf(buf, sizeof(buf), format, ap); + va_end(ap); + _malloc_message(buf, "", "", ""); +#endif +} +#endif + +/******************************************************************************/ + +#ifdef MALLOC_DECOMMIT +static inline void +pages_decommit(void *addr, size_t size) +{ + +#ifdef MOZ_MEMORY_WINDOWS + VirtualFree(addr, size, MEM_DECOMMIT); +#else + if (mmap(addr, size, PROT_NONE, MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, + 0) == MAP_FAILED) + abort(); +#endif +} + +static inline void +pages_commit(void *addr, size_t size) +{ + +# ifdef MOZ_MEMORY_WINDOWS + VirtualAlloc(addr, size, MEM_COMMIT, PAGE_READWRITE); +# else + if (mmap(addr, size, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | + MAP_ANON, -1, 0) == MAP_FAILED) + abort(); +# endif +} +#endif + +static bool +base_pages_alloc_mmap(size_t minsize) +{ + bool ret; + size_t csize; +#ifdef MALLOC_DECOMMIT + size_t pminsize; +#endif + int pfd; + + assert(minsize != 0); + csize = CHUNK_CEILING(minsize); +#ifdef MALLOC_PAGEFILE + if (opt_pagefile) { + pfd = pagefile_init(csize); + if (pfd == -1) + return (true); + } else +#endif + pfd = -1; + base_pages = pages_map(NULL, csize, pfd); + if (base_pages == NULL) { + ret = true; + goto RETURN; + } + base_next_addr = base_pages; + base_past_addr = (void *)((uintptr_t)base_pages + csize); +#ifdef MALLOC_DECOMMIT + /* + * Leave enough pages for minsize committed, since otherwise they would + * have to be immediately recommitted. + */ + pminsize = PAGE_CEILING(minsize); + base_next_decommitted = (void *)((uintptr_t)base_pages + pminsize); + if (pminsize < csize) + pages_decommit(base_next_decommitted, csize - pminsize); +#endif +#ifdef MALLOC_STATS + base_mapped += csize; +#endif + + ret = false; +RETURN: +#ifdef MALLOC_PAGEFILE + if (pfd != -1) + pagefile_close(pfd); +#endif + return (false); +} + +static bool +base_pages_alloc(size_t minsize) +{ + + if (base_pages_alloc_mmap(minsize) == false) + return (false); + + return (true); +} + +static void * +base_alloc(size_t size) +{ + void *ret; + size_t csize; + + /* Round size up to nearest multiple of the cacheline size. */ + csize = CACHELINE_CEILING(size); + + malloc_mutex_lock(&base_mtx); + /* Make sure there's enough space for the allocation. */ + if ((uintptr_t)base_next_addr + csize > (uintptr_t)base_past_addr) { + if (base_pages_alloc(csize)) { + malloc_mutex_unlock(&base_mtx); + return (NULL); + } + } + /* Allocate. */ + ret = base_next_addr; + base_next_addr = (void *)((uintptr_t)base_next_addr + csize); +#ifdef MALLOC_DECOMMIT + /* Make sure enough pages are committed for the new allocation. */ + if ((uintptr_t)base_next_addr > (uintptr_t)base_next_decommitted) { + void *pbase_next_addr = + (void *)(PAGE_CEILING((uintptr_t)base_next_addr)); + + pages_commit(base_next_decommitted, (uintptr_t)pbase_next_addr - + (uintptr_t)base_next_decommitted); + base_next_decommitted = pbase_next_addr; + } +#endif + malloc_mutex_unlock(&base_mtx); + VALGRIND_MALLOCLIKE_BLOCK(ret, size, 0, false); + + return (ret); +} + +static void * +base_calloc(size_t number, size_t size) +{ + void *ret; + + ret = base_alloc(number * size); +#ifdef MALLOC_VALGRIND + if (ret != NULL) { + VALGRIND_FREELIKE_BLOCK(ret, 0); + VALGRIND_MALLOCLIKE_BLOCK(ret, size, 0, true); + } +#endif + memset(ret, 0, number * size); + + return (ret); +} + +static extent_node_t * +base_node_alloc(void) +{ + extent_node_t *ret; + + malloc_mutex_lock(&base_mtx); + if (base_nodes != NULL) { + ret = base_nodes; + base_nodes = *(extent_node_t **)ret; + VALGRIND_FREELIKE_BLOCK(ret, 0); + VALGRIND_MALLOCLIKE_BLOCK(ret, sizeof(extent_node_t), 0, false); + malloc_mutex_unlock(&base_mtx); + } else { + malloc_mutex_unlock(&base_mtx); + ret = (extent_node_t *)base_alloc(sizeof(extent_node_t)); + } + + return (ret); +} + +static void +base_node_dealloc(extent_node_t *node) +{ + + malloc_mutex_lock(&base_mtx); + VALGRIND_FREELIKE_BLOCK(node, 0); + VALGRIND_MALLOCLIKE_BLOCK(node, sizeof(extent_node_t *), 0, false); + *(extent_node_t **)node = base_nodes; + base_nodes = node; + malloc_mutex_unlock(&base_mtx); +} + +static reserve_reg_t * +base_reserve_reg_alloc(void) +{ + reserve_reg_t *ret; + + malloc_mutex_lock(&base_mtx); + if (base_reserve_regs != NULL) { + ret = base_reserve_regs; + base_reserve_regs = *(reserve_reg_t **)ret; + VALGRIND_FREELIKE_BLOCK(ret, 0); + VALGRIND_MALLOCLIKE_BLOCK(ret, sizeof(reserve_reg_t), 0, false); + malloc_mutex_unlock(&base_mtx); + } else { + malloc_mutex_unlock(&base_mtx); + ret = (reserve_reg_t *)base_alloc(sizeof(reserve_reg_t)); + } + + return (ret); +} + +static void +base_reserve_reg_dealloc(reserve_reg_t *reg) +{ + + malloc_mutex_lock(&base_mtx); + VALGRIND_FREELIKE_BLOCK(reg, 0); + VALGRIND_MALLOCLIKE_BLOCK(reg, sizeof(reserve_reg_t *), 0, false); + *(reserve_reg_t **)reg = base_reserve_regs; + base_reserve_regs = reg; + malloc_mutex_unlock(&base_mtx); +} + +/******************************************************************************/ + +#ifdef MALLOC_STATS +static void +stats_print(arena_t *arena) +{ + unsigned i, gap_start; + +#ifdef xxMOZ_MEMORY_WINDOWS + malloc_printf("dirty: %Iu page%s dirty, %I64u sweep%s," + " %I64u madvise%s, %I64u page%s purged\n", + arena->ndirty, arena->ndirty == 1 ? "" : "s", + arena->stats.npurge, arena->stats.npurge == 1 ? "" : "s", + arena->stats.nmadvise, arena->stats.nmadvise == 1 ? "" : "s", + arena->stats.purged, arena->stats.purged == 1 ? "" : "s"); +# ifdef MALLOC_DECOMMIT + malloc_printf("decommit: %I64u decommit%s, %I64u commit%s," + " %I64u page%s decommitted\n", + arena->stats.ndecommit, (arena->stats.ndecommit == 1) ? "" : "s", + arena->stats.ncommit, (arena->stats.ncommit == 1) ? "" : "s", + arena->stats.decommitted, + (arena->stats.decommitted == 1) ? "" : "s"); +# endif + + malloc_printf(" allocated nmalloc ndalloc\n"); + malloc_printf("small: %12Iu %12I64u %12I64u\n", + arena->stats.allocated_small, arena->stats.nmalloc_small, + arena->stats.ndalloc_small); + malloc_printf("large: %12Iu %12I64u %12I64u\n", + arena->stats.allocated_large, arena->stats.nmalloc_large, + arena->stats.ndalloc_large); + malloc_printf("total: %12Iu %12I64u %12I64u\n", + arena->stats.allocated_small + arena->stats.allocated_large, + arena->stats.nmalloc_small + arena->stats.nmalloc_large, + arena->stats.ndalloc_small + arena->stats.ndalloc_large); + malloc_printf("mapped: %12Iu\n", arena->stats.mapped); +#else + malloc_printf("dirty: %zu page%s dirty, %llu sweep%s," + " %llu madvise%s, %llu page%s purged\n", + arena->ndirty, arena->ndirty == 1 ? "" : "s", + arena->stats.npurge, arena->stats.npurge == 1 ? "" : "s", + arena->stats.nmadvise, arena->stats.nmadvise == 1 ? "" : "s", + arena->stats.purged, arena->stats.purged == 1 ? "" : "s"); +# ifdef MALLOC_DECOMMIT + malloc_printf("decommit: %llu decommit%s, %llu commit%s," + " %llu page%s decommitted\n", + arena->stats.ndecommit, (arena->stats.ndecommit == 1) ? "" : "s", + arena->stats.ncommit, (arena->stats.ncommit == 1) ? "" : "s", + arena->stats.decommitted, + (arena->stats.decommitted == 1) ? "" : "s"); +# endif + + malloc_printf(" allocated nmalloc ndalloc\n"); + malloc_printf("small: %12zu %12llu %12llu\n", + arena->stats.allocated_small, arena->stats.nmalloc_small, + arena->stats.ndalloc_small); + malloc_printf("large: %12zu %12llu %12llu\n", + arena->stats.allocated_large, arena->stats.nmalloc_large, + arena->stats.ndalloc_large); + malloc_printf("total: %12zu %12llu %12llu\n", + arena->stats.allocated_small + arena->stats.allocated_large, + arena->stats.nmalloc_small + arena->stats.nmalloc_large, + arena->stats.ndalloc_small + arena->stats.ndalloc_large); + malloc_printf("mapped: %12zu\n", arena->stats.mapped); +#endif + malloc_printf("bins: bin size regs pgs requests newruns" + " reruns maxruns curruns\n"); + for (i = 0, gap_start = UINT_MAX; i < ntbins + nqbins + nsbins; i++) { + if (arena->bins[i].stats.nrequests == 0) { + if (gap_start == UINT_MAX) + gap_start = i; + } else { + if (gap_start != UINT_MAX) { + if (i > gap_start + 1) { + /* Gap of more than one size class. */ + malloc_printf("[%u..%u]\n", + gap_start, i - 1); + } else { + /* Gap of one size class. */ + malloc_printf("[%u]\n", gap_start); + } + gap_start = UINT_MAX; + } + malloc_printf( +#if defined(xxMOZ_MEMORY_WINDOWS) + "%13u %1s %4u %4u %3u %9I64u %9I64u" + " %9I64u %7u %7u\n", +#else + "%13u %1s %4u %4u %3u %9llu %9llu" + " %9llu %7lu %7lu\n", +#endif + i, + i < ntbins ? "T" : i < ntbins + nqbins ? "Q" : "S", + arena->bins[i].reg_size, + arena->bins[i].nregs, + arena->bins[i].run_size >> pagesize_2pow, + arena->bins[i].stats.nrequests, + arena->bins[i].stats.nruns, + arena->bins[i].stats.reruns, + arena->bins[i].stats.highruns, + arena->bins[i].stats.curruns); + } + } + if (gap_start != UINT_MAX) { + if (i > gap_start + 1) { + /* Gap of more than one size class. */ + malloc_printf("[%u..%u]\n", gap_start, i - 1); + } else { + /* Gap of one size class. */ + malloc_printf("[%u]\n", gap_start); + } + } +} +#endif + +/* + * End Utility functions/macros. + */ +/******************************************************************************/ +/* + * Begin extent tree code. + */ + +static inline int +extent_szad_comp(extent_node_t *a, extent_node_t *b) +{ + int ret; + size_t a_size = a->size; + size_t b_size = b->size; + + ret = (a_size > b_size) - (a_size < b_size); + if (ret == 0) { + uintptr_t a_addr = (uintptr_t)a->addr; + uintptr_t b_addr = (uintptr_t)b->addr; + + ret = (a_addr > b_addr) - (a_addr < b_addr); + } + + return (ret); +} + +/* Wrap red-black tree macros in functions. */ +rb_wrap(static, extent_tree_szad_, extent_tree_t, extent_node_t, + link_szad, extent_szad_comp) + +static inline int +extent_ad_comp(extent_node_t *a, extent_node_t *b) +{ + uintptr_t a_addr = (uintptr_t)a->addr; + uintptr_t b_addr = (uintptr_t)b->addr; + + return ((a_addr > b_addr) - (a_addr < b_addr)); +} + +/* Wrap red-black tree macros in functions. */ +rb_wrap(static, extent_tree_ad_, extent_tree_t, extent_node_t, link_ad, + extent_ad_comp) + +/* + * End extent tree code. + */ +/******************************************************************************/ +/* + * Begin chunk management functions. + */ + +#ifdef MOZ_MEMORY_WINDOWS +#ifdef MOZ_MEMORY_WINCE +#define ALIGN_ADDR2OFFSET(al, ad) \ + ((uintptr_t)ad & (al - 1)) +static void * +pages_map_align(size_t size, int pfd, size_t alignment) +{ + + void *ret; + int offset; + if (size % alignment) + size += (alignment - (size % alignment)); + assert(size >= alignment); + ret = pages_map(NULL, size, pfd); + offset = ALIGN_ADDR2OFFSET(alignment, ret); + if (offset) { + /* try to over allocate by the ammount we're offset */ + void *tmp; + pages_unmap(ret, size); + tmp = VirtualAlloc(NULL, size + alignment - offset, + MEM_RESERVE, PAGE_NOACCESS); + if (offset == ALIGN_ADDR2OFFSET(alignment, tmp)) + ret = VirtualAlloc((void*)((intptr_t)tmp + alignment + - offset), size, MEM_COMMIT, + PAGE_READWRITE); + else + VirtualFree(tmp, 0, MEM_RELEASE); + offset = ALIGN_ADDR2OFFSET(alignment, ret); + + + if (offset) { + /* over allocate to ensure we have an aligned region */ + ret = VirtualAlloc(NULL, size + alignment, MEM_RESERVE, + PAGE_NOACCESS); + offset = ALIGN_ADDR2OFFSET(alignment, ret); + ret = VirtualAlloc((void*)((intptr_t)ret + + alignment - offset), + size, MEM_COMMIT, PAGE_READWRITE); + } + } + return (ret); +} +#endif + +static void * +pages_map(void *addr, size_t size, int pfd) +{ + void *ret = NULL; +#if defined(MOZ_MEMORY_WINCE) + void *va_ret; + assert(addr == NULL); + va_ret = VirtualAlloc(addr, size, MEM_RESERVE, PAGE_NOACCESS); + if (va_ret) + ret = VirtualAlloc(va_ret, size, MEM_COMMIT, PAGE_READWRITE); + assert(va_ret == ret); +#elif defined(MOZ_MEMORY_WINDOWS) + ret = VirtualAlloc(addr, size, MEM_COMMIT | MEM_RESERVE, + PAGE_READWRITE); +#endif + return (ret); +} + +static void +pages_unmap(void *addr, size_t size) +{ + if (VirtualFree(addr, 0, MEM_RELEASE) == 0) { +#ifdef MOZ_MEMORY_WINCE + if (GetLastError() == ERROR_INVALID_PARAMETER) { + MEMORY_BASIC_INFORMATION info; + VirtualQuery(addr, &info, sizeof(info)); + if (VirtualFree(info.AllocationBase, 0, MEM_RELEASE)) + return; + } +#endif + _malloc_message(_getprogname(), + ": (malloc) Error in VirtualFree()\n", "", ""); + if (opt_abort) + abort(); + } +} +#elif (defined(MOZ_MEMORY_DARWIN)) +static void * +pages_map(void *addr, size_t size, int pfd) +{ + void *ret; + kern_return_t err; + int flags; + + if (addr != NULL) { + ret = addr; + flags = 0; + } else + flags = VM_FLAGS_ANYWHERE; + + err = vm_allocate((vm_map_t)mach_task_self(), (vm_address_t *)&ret, + (vm_size_t)size, flags); + if (err != KERN_SUCCESS) + ret = NULL; + + assert(ret == NULL || (addr == NULL && ret != addr) + || (addr != NULL && ret == addr)); + return (ret); +} + +static void +pages_unmap(void *addr, size_t size) +{ + kern_return_t err; + + err = vm_deallocate((vm_map_t)mach_task_self(), (vm_address_t)addr, + (vm_size_t)size); + if (err != KERN_SUCCESS) { + malloc_message(_getprogname(), + ": (malloc) Error in vm_deallocate(): ", + mach_error_string(err), "\n"); + if (opt_abort) + abort(); + } +} + +#define VM_COPY_MIN (pagesize << 5) +static inline void +pages_copy(void *dest, const void *src, size_t n) +{ + + assert((void *)((uintptr_t)dest & ~pagesize_mask) == dest); + assert(n >= VM_COPY_MIN); + assert((void *)((uintptr_t)src & ~pagesize_mask) == src); + + vm_copy(mach_task_self(), (vm_address_t)src, (vm_size_t)n, + (vm_address_t)dest); +} +#else /* MOZ_MEMORY_DARWIN */ +#ifdef JEMALLOC_USES_MAP_ALIGN +static void * +pages_map_align(size_t size, int pfd, size_t alignment) +{ + void *ret; + + /* + * We don't use MAP_FIXED here, because it can cause the *replacement* + * of existing mappings, and we only want to create new mappings. + */ +#ifdef MALLOC_PAGEFILE + if (pfd != -1) { + ret = mmap((void *)alignment, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | + MAP_NOSYNC | MAP_ALIGN, pfd, 0); + } else +#endif + { + ret = mmap((void *)alignment, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | + MAP_NOSYNC | MAP_ALIGN | MAP_ANON, -1, 0); + } + assert(ret != NULL); + + if (ret == MAP_FAILED) + ret = NULL; + return (ret); +} +#endif + +static void * +pages_map(void *addr, size_t size, int pfd) +{ + void *ret; + + /* + * We don't use MAP_FIXED here, because it can cause the *replacement* + * of existing mappings, and we only want to create new mappings. + */ +#ifdef MALLOC_PAGEFILE + if (pfd != -1) { + ret = mmap(addr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | + MAP_NOSYNC, pfd, 0); + } else +#endif + { + ret = mmap(addr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | + MAP_ANON, -1, 0); + } + assert(ret != NULL); + + if (ret == MAP_FAILED) + ret = NULL; + else if (addr != NULL && ret != addr) { + /* + * We succeeded in mapping memory, but not in the right place. + */ + if (munmap(ret, size) == -1) { + char buf[STRERROR_BUF]; + + strerror_r(errno, buf, sizeof(buf)); + _malloc_message(_getprogname(), + ": (malloc) Error in munmap(): ", buf, "\n"); + if (opt_abort) + abort(); + } + ret = NULL; + } + + assert(ret == NULL || (addr == NULL && ret != addr) + || (addr != NULL && ret == addr)); + return (ret); +} + +static void +pages_unmap(void *addr, size_t size) +{ + + if (munmap(addr, size) == -1) { + char buf[STRERROR_BUF]; + + strerror_r(errno, buf, sizeof(buf)); + _malloc_message(_getprogname(), + ": (malloc) Error in munmap(): ", buf, "\n"); + if (opt_abort) + abort(); + } +} +#endif + +#ifdef MALLOC_VALIDATE +static inline malloc_rtree_t * +malloc_rtree_new(unsigned bits) +{ + malloc_rtree_t *ret; + unsigned bits_per_level, height, i; + + bits_per_level = ffs(pow2_ceil((MALLOC_RTREE_NODESIZE / + sizeof(void *)))) - 1; + height = bits / bits_per_level; + if (height * bits_per_level != bits) + height++; + assert(height * bits_per_level >= bits); + + ret = (malloc_rtree_t*)base_calloc(1, sizeof(malloc_rtree_t) + (sizeof(unsigned) * + (height - 1))); + if (ret == NULL) + return (NULL); + + malloc_spin_init(&ret->lock); + ret->height = height; + if (bits_per_level * height > bits) + ret->level2bits[0] = bits % bits_per_level; + else + ret->level2bits[0] = bits_per_level; + for (i = 1; i < height; i++) + ret->level2bits[i] = bits_per_level; + + ret->root = (void**)base_calloc(1, sizeof(void *) << ret->level2bits[0]); + if (ret->root == NULL) { + /* + * We leak the rtree here, since there's no generic base + * deallocation. + */ + return (NULL); + } + + return (ret); +} + +/* The least significant bits of the key are ignored. */ +static inline void * +malloc_rtree_get(malloc_rtree_t *rtree, uintptr_t key) +{ + void *ret; + uintptr_t subkey; + unsigned i, lshift, height, bits; + void **node, **child; + + malloc_spin_lock(&rtree->lock); + for (i = lshift = 0, height = rtree->height, node = rtree->root; + i < height - 1; + i++, lshift += bits, node = child) { + bits = rtree->level2bits[i]; + subkey = (key << lshift) >> ((SIZEOF_PTR << 3) - bits); + child = (void**)node[subkey]; + if (child == NULL) { + malloc_spin_unlock(&rtree->lock); + return (NULL); + } + } + + /* node is a leaf, so it contains values rather than node pointers. */ + bits = rtree->level2bits[i]; + subkey = (key << lshift) >> ((SIZEOF_PTR << 3) - bits); + ret = node[subkey]; + malloc_spin_unlock(&rtree->lock); + + return (ret); +} + +static inline bool +malloc_rtree_set(malloc_rtree_t *rtree, uintptr_t key, void *val) +{ + uintptr_t subkey; + unsigned i, lshift, height, bits; + void **node, **child; + + malloc_spin_lock(&rtree->lock); + for (i = lshift = 0, height = rtree->height, node = rtree->root; + i < height - 1; + i++, lshift += bits, node = child) { + bits = rtree->level2bits[i]; + subkey = (key << lshift) >> ((SIZEOF_PTR << 3) - bits); + child = (void**)node[subkey]; + if (child == NULL) { + child = (void**)base_calloc(1, sizeof(void *) << + rtree->level2bits[i+1]); + if (child == NULL) { + malloc_spin_unlock(&rtree->lock); + return (true); + } + node[subkey] = child; + } + } + + /* node is a leaf, so it contains values rather than node pointers. */ + bits = rtree->level2bits[i]; + subkey = (key << lshift) >> ((SIZEOF_PTR << 3) - bits); + node[subkey] = val; + malloc_spin_unlock(&rtree->lock); + + return (false); +} +#endif + +static void * +chunk_alloc_mmap(size_t size, bool pagefile) +{ + void *ret; +#ifndef JEMALLOC_USES_MAP_ALIGN + size_t offset; +#endif + int pfd; + +#ifdef MALLOC_PAGEFILE + if (opt_pagefile && pagefile) { + pfd = pagefile_init(size); + if (pfd == -1) + return (NULL); + } else +#endif + pfd = -1; + + /* + * Windows requires that there be a 1:1 mapping between VM + * allocation/deallocation operations. Therefore, take care here to + * acquire the final result via one mapping operation. This means + * unmapping any preliminary result that is not correctly aligned. + * + * The MALLOC_PAGEFILE code also benefits from this mapping algorithm, + * since it reduces the number of page files. + */ + +#ifdef JEMALLOC_USES_MAP_ALIGN + ret = pages_map_align(size, pfd, chunksize); +#else + ret = pages_map(NULL, size, pfd); + if (ret == NULL) + goto RETURN; + + offset = CHUNK_ADDR2OFFSET(ret); + if (offset != 0) { + /* Deallocate, then try to allocate at (ret + size - offset). */ + pages_unmap(ret, size); + ret = pages_map((void *)((uintptr_t)ret + size - offset), size, + pfd); + while (ret == NULL) { + /* + * Over-allocate in order to map a memory region that + * is definitely large enough. + */ + ret = pages_map(NULL, size + chunksize, -1); + if (ret == NULL) + goto RETURN; + /* + * Deallocate, then allocate the correct size, within + * the over-sized mapping. + */ + offset = CHUNK_ADDR2OFFSET(ret); + pages_unmap(ret, size + chunksize); + if (offset == 0) + ret = pages_map(ret, size, pfd); + else { + ret = pages_map((void *)((uintptr_t)ret + + chunksize - offset), size, pfd); + } + /* + * Failure here indicates a race with another thread, so + * try again. + */ + } + } +RETURN: +#endif +#ifdef MALLOC_PAGEFILE + if (pfd != -1) + pagefile_close(pfd); +#endif +#ifdef MALLOC_STATS + if (ret != NULL) + stats_chunks.nchunks += (size / chunksize); +#endif + return (ret); +} + +#ifdef MALLOC_PAGEFILE +static int +pagefile_init(size_t size) +{ + int ret; + size_t i; + char pagefile_path[PATH_MAX]; + char zbuf[MALLOC_PAGEFILE_WRITE_SIZE]; + + /* + * Create a temporary file, then immediately unlink it so that it will + * not persist. + */ + strcpy(pagefile_path, pagefile_templ); + ret = mkstemp(pagefile_path); + if (ret == -1) + return (ret); + if (unlink(pagefile_path)) { + char buf[STRERROR_BUF]; + + strerror_r(errno, buf, sizeof(buf)); + _malloc_message(_getprogname(), ": (malloc) Error in unlink(\"", + pagefile_path, "\"):"); + _malloc_message(buf, "\n", "", ""); + if (opt_abort) + abort(); + } + + /* + * Write sequential zeroes to the file in order to assure that disk + * space is committed, with minimal fragmentation. It would be + * sufficient to write one zero per disk block, but that potentially + * results in more system calls, for no real gain. + */ + memset(zbuf, 0, sizeof(zbuf)); + for (i = 0; i < size; i += sizeof(zbuf)) { + if (write(ret, zbuf, sizeof(zbuf)) != sizeof(zbuf)) { + if (errno != ENOSPC) { + char buf[STRERROR_BUF]; + + strerror_r(errno, buf, sizeof(buf)); + _malloc_message(_getprogname(), + ": (malloc) Error in write(): ", buf, "\n"); + if (opt_abort) + abort(); + } + pagefile_close(ret); + return (-1); + } + } + + return (ret); +} + +static void +pagefile_close(int pfd) +{ + + if (close(pfd)) { + char buf[STRERROR_BUF]; + + strerror_r(errno, buf, sizeof(buf)); + _malloc_message(_getprogname(), + ": (malloc) Error in close(): ", buf, "\n"); + if (opt_abort) + abort(); + } +} +#endif + +static void * +chunk_recycle_reserve(size_t size, bool zero) +{ + extent_node_t *node, key; + +#ifdef MALLOC_DECOMMIT + if (size != chunksize) + return (NULL); +#endif + + key.addr = NULL; + key.size = size; + malloc_mutex_lock(&reserve_mtx); + node = extent_tree_szad_nsearch(&reserve_chunks_szad, &key); + if (node != NULL) { + void *ret = node->addr; + + /* Remove node from the tree. */ + extent_tree_szad_remove(&reserve_chunks_szad, node); +#ifndef MALLOC_DECOMMIT + if (node->size == size) { +#else + assert(node->size == size); +#endif + extent_tree_ad_remove(&reserve_chunks_ad, node); + base_node_dealloc(node); +#ifndef MALLOC_DECOMMIT + } else { + /* + * Insert the remainder of node's address range as a + * smaller chunk. Its position within reserve_chunks_ad + * does not change. + */ + assert(node->size > size); + node->addr = (void *)((uintptr_t)node->addr + size); + node->size -= size; + extent_tree_szad_insert(&reserve_chunks_szad, node); + } +#endif + reserve_cur -= size; + /* + * Try to replenish the reserve if this allocation depleted it. + */ +#ifndef MALLOC_DECOMMIT + if (reserve_cur < reserve_min) { + size_t diff = reserve_min - reserve_cur; +#else + while (reserve_cur < reserve_min) { +# define diff chunksize +#endif + void *chunk; + + malloc_mutex_unlock(&reserve_mtx); + chunk = chunk_alloc_mmap(diff, true); + malloc_mutex_lock(&reserve_mtx); + if (chunk == NULL) { + uint64_t seq = 0; + + do { + seq = reserve_notify(RESERVE_CND_LOW, + size, seq); + if (seq == 0) + goto MALLOC_OUT; + } while (reserve_cur < reserve_min); + } else { + extent_node_t *node; + + node = chunk_dealloc_reserve(chunk, diff); + if (node == NULL) { + uint64_t seq = 0; + + pages_unmap(chunk, diff); + do { + seq = reserve_notify( + RESERVE_CND_LOW, size, seq); + if (seq == 0) + goto MALLOC_OUT; + } while (reserve_cur < reserve_min); + } + } + } +MALLOC_OUT: + malloc_mutex_unlock(&reserve_mtx); + +#ifdef MALLOC_DECOMMIT + pages_commit(ret, size); +# undef diff +#else + if (zero) + memset(ret, 0, size); +#endif + return (ret); + } + malloc_mutex_unlock(&reserve_mtx); + + return (NULL); +} + +static void * +chunk_alloc(size_t size, bool zero, bool pagefile) +{ + void *ret; + + assert(size != 0); + assert((size & chunksize_mask) == 0); + + ret = chunk_recycle_reserve(size, zero); + if (ret != NULL) + goto RETURN; + + ret = chunk_alloc_mmap(size, pagefile); + if (ret != NULL) { + goto RETURN; + } + + /* All strategies for allocation failed. */ + ret = NULL; +RETURN: +#ifdef MALLOC_STATS + if (ret != NULL) + stats_chunks.curchunks += (size / chunksize); + if (stats_chunks.curchunks > stats_chunks.highchunks) + stats_chunks.highchunks = stats_chunks.curchunks; +#endif + +#ifdef MALLOC_VALIDATE + if (ret != NULL) { + if (malloc_rtree_set(chunk_rtree, (uintptr_t)ret, ret)) { + chunk_dealloc(ret, size); + return (NULL); + } + } +#endif + + assert(CHUNK_ADDR2BASE(ret) == ret); + return (ret); +} + +static extent_node_t * +chunk_dealloc_reserve(void *chunk, size_t size) +{ + extent_node_t *node; + +#ifdef MALLOC_DECOMMIT + if (size != chunksize) + return (NULL); +#else + extent_node_t *prev, key; + + key.addr = (void *)((uintptr_t)chunk + size); + node = extent_tree_ad_nsearch(&reserve_chunks_ad, &key); + /* Try to coalesce forward. */ + if (node != NULL && node->addr == key.addr) { + /* + * Coalesce chunk with the following address range. This does + * not change the position within reserve_chunks_ad, so only + * remove/insert from/into reserve_chunks_szad. + */ + extent_tree_szad_remove(&reserve_chunks_szad, node); + node->addr = chunk; + node->size += size; + extent_tree_szad_insert(&reserve_chunks_szad, node); + } else { +#endif + /* Coalescing forward failed, so insert a new node. */ + node = base_node_alloc(); + if (node == NULL) + return (NULL); + node->addr = chunk; + node->size = size; + extent_tree_ad_insert(&reserve_chunks_ad, node); + extent_tree_szad_insert(&reserve_chunks_szad, node); +#ifndef MALLOC_DECOMMIT + } + + /* Try to coalesce backward. */ + prev = extent_tree_ad_prev(&reserve_chunks_ad, node); + if (prev != NULL && (void *)((uintptr_t)prev->addr + prev->size) == + chunk) { + /* + * Coalesce chunk with the previous address range. This does + * not change the position within reserve_chunks_ad, so only + * remove/insert node from/into reserve_chunks_szad. + */ + extent_tree_szad_remove(&reserve_chunks_szad, prev); + extent_tree_ad_remove(&reserve_chunks_ad, prev); + + extent_tree_szad_remove(&reserve_chunks_szad, node); + node->addr = prev->addr; + node->size += prev->size; + extent_tree_szad_insert(&reserve_chunks_szad, node); + + base_node_dealloc(prev); + } +#endif + +#ifdef MALLOC_DECOMMIT + pages_decommit(chunk, size); +#else + madvise(chunk, size, MADV_FREE); +#endif + + reserve_cur += size; + if (reserve_cur > reserve_max) + reserve_shrink(); + + return (node); +} + +static void +chunk_dealloc_mmap(void *chunk, size_t size) +{ + + pages_unmap(chunk, size); +} + +static void +chunk_dealloc(void *chunk, size_t size) +{ + extent_node_t *node; + + assert(chunk != NULL); + assert(CHUNK_ADDR2BASE(chunk) == chunk); + assert(size != 0); + assert((size & chunksize_mask) == 0); + +#ifdef MALLOC_STATS + stats_chunks.curchunks -= (size / chunksize); +#endif +#ifdef MALLOC_VALIDATE + malloc_rtree_set(chunk_rtree, (uintptr_t)chunk, NULL); +#endif + + /* Try to merge chunk into the reserve. */ + malloc_mutex_lock(&reserve_mtx); + node = chunk_dealloc_reserve(chunk, size); + malloc_mutex_unlock(&reserve_mtx); + if (node == NULL) + chunk_dealloc_mmap(chunk, size); +} + +/* + * End chunk management functions. + */ +/******************************************************************************/ +/* + * Begin arena. + */ + +/* + * Choose an arena based on a per-thread value (fast-path code, calls slow-path + * code if necessary). + */ +static inline arena_t * +choose_arena(void) +{ + arena_t *ret; + + /* + * We can only use TLS if this is a PIC library, since for the static + * library version, libc's malloc is used by TLS allocation, which + * introduces a bootstrapping issue. + */ +#ifndef NO_TLS + if (__isthreaded == false) { + /* Avoid the overhead of TLS for single-threaded operation. */ + return (arenas[0]); + } + +# ifdef MOZ_MEMORY_WINDOWS + ret = (arena_t*)TlsGetValue(tlsIndex); +# else + ret = arenas_map; +# endif + + if (ret == NULL) { + ret = choose_arena_hard(); + assert(ret != NULL); + } +#else + if (__isthreaded && narenas > 1) { + unsigned long ind; + + /* + * Hash _pthread_self() to one of the arenas. There is a prime + * number of arenas, so this has a reasonable chance of + * working. Even so, the hashing can be easily thwarted by + * inconvenient _pthread_self() values. Without specific + * knowledge of how _pthread_self() calculates values, we can't + * easily do much better than this. + */ + ind = (unsigned long) _pthread_self() % narenas; + + /* + * Optimistially assume that arenas[ind] has been initialized. + * At worst, we find out that some other thread has already + * done so, after acquiring the lock in preparation. Note that + * this lazy locking also has the effect of lazily forcing + * cache coherency; without the lock acquisition, there's no + * guarantee that modification of arenas[ind] by another thread + * would be seen on this CPU for an arbitrary amount of time. + * + * In general, this approach to modifying a synchronized value + * isn't a good idea, but in this case we only ever modify the + * value once, so things work out well. + */ + ret = arenas[ind]; + if (ret == NULL) { + /* + * Avoid races with another thread that may have already + * initialized arenas[ind]. + */ + malloc_spin_lock(&arenas_lock); + if (arenas[ind] == NULL) + ret = arenas_extend((unsigned)ind); + else + ret = arenas[ind]; + malloc_spin_unlock(&arenas_lock); + } + } else + ret = arenas[0]; +#endif + + assert(ret != NULL); + return (ret); +} + +#ifndef NO_TLS +/* + * Choose an arena based on a per-thread value (slow-path code only, called + * only by choose_arena()). + */ +static arena_t * +choose_arena_hard(void) +{ + arena_t *ret; + + assert(__isthreaded); + +#ifdef MALLOC_BALANCE + /* Seed the PRNG used for arena load balancing. */ + SPRN(balance, (uint32_t)(uintptr_t)(_pthread_self())); +#endif + + if (narenas > 1) { +#ifdef MALLOC_BALANCE + unsigned ind; + + ind = PRN(balance, narenas_2pow); + if ((ret = arenas[ind]) == NULL) { + malloc_spin_lock(&arenas_lock); + if ((ret = arenas[ind]) == NULL) + ret = arenas_extend(ind); + malloc_spin_unlock(&arenas_lock); + } +#else + malloc_spin_lock(&arenas_lock); + if ((ret = arenas[next_arena]) == NULL) + ret = arenas_extend(next_arena); + next_arena = (next_arena + 1) % narenas; + malloc_spin_unlock(&arenas_lock); +#endif + } else + ret = arenas[0]; + +#ifdef MOZ_MEMORY_WINDOWS + TlsSetValue(tlsIndex, ret); +#else + arenas_map = ret; +#endif + + return (ret); +} +#endif + +static inline int +arena_chunk_comp(arena_chunk_t *a, arena_chunk_t *b) +{ + uintptr_t a_chunk = (uintptr_t)a; + uintptr_t b_chunk = (uintptr_t)b; + + assert(a != NULL); + assert(b != NULL); + + return ((a_chunk > b_chunk) - (a_chunk < b_chunk)); +} + +/* Wrap red-black tree macros in functions. */ +rb_wrap(static, arena_chunk_tree_dirty_, arena_chunk_tree_t, + arena_chunk_t, link_dirty, arena_chunk_comp) + +static inline int +arena_run_comp(arena_chunk_map_t *a, arena_chunk_map_t *b) +{ + uintptr_t a_mapelm = (uintptr_t)a; + uintptr_t b_mapelm = (uintptr_t)b; + + assert(a != NULL); + assert(b != NULL); + + return ((a_mapelm > b_mapelm) - (a_mapelm < b_mapelm)); +} + +/* Wrap red-black tree macros in functions. */ +rb_wrap(static, arena_run_tree_, arena_run_tree_t, arena_chunk_map_t, link, + arena_run_comp) + +static inline int +arena_avail_comp(arena_chunk_map_t *a, arena_chunk_map_t *b) +{ + int ret; + size_t a_size = a->bits & ~pagesize_mask; + size_t b_size = b->bits & ~pagesize_mask; + + ret = (a_size > b_size) - (a_size < b_size); + if (ret == 0) { + uintptr_t a_mapelm, b_mapelm; + + if ((a->bits & CHUNK_MAP_KEY) == 0) + a_mapelm = (uintptr_t)a; + else { + /* + * Treat keys as though they are lower than anything + * else. + */ + a_mapelm = 0; + } + b_mapelm = (uintptr_t)b; + + ret = (a_mapelm > b_mapelm) - (a_mapelm < b_mapelm); + } + + return (ret); +} + +/* Wrap red-black tree macros in functions. */ +rb_wrap(static, arena_avail_tree_, arena_avail_tree_t, arena_chunk_map_t, link, + arena_avail_comp) + +static inline void * +arena_run_reg_alloc(arena_run_t *run, arena_bin_t *bin) +{ + void *ret; + unsigned i, mask, bit, regind; + + assert(run->magic == ARENA_RUN_MAGIC); + assert(run->regs_minelm < bin->regs_mask_nelms); + + /* + * Move the first check outside the loop, so that run->regs_minelm can + * be updated unconditionally, without the possibility of updating it + * multiple times. + */ + i = run->regs_minelm; + mask = run->regs_mask[i]; + if (mask != 0) { + /* Usable allocation found. */ + bit = ffs((int)mask) - 1; + + regind = ((i << (SIZEOF_INT_2POW + 3)) + bit); + assert(regind < bin->nregs); + ret = (void *)(((uintptr_t)run) + bin->reg0_offset + + (bin->reg_size * regind)); + + /* Clear bit. */ + mask ^= (1U << bit); + run->regs_mask[i] = mask; + + return (ret); + } + + for (i++; i < bin->regs_mask_nelms; i++) { + mask = run->regs_mask[i]; + if (mask != 0) { + /* Usable allocation found. */ + bit = ffs((int)mask) - 1; + + regind = ((i << (SIZEOF_INT_2POW + 3)) + bit); + assert(regind < bin->nregs); + ret = (void *)(((uintptr_t)run) + bin->reg0_offset + + (bin->reg_size * regind)); + + /* Clear bit. */ + mask ^= (1U << bit); + run->regs_mask[i] = mask; + + /* + * Make a note that nothing before this element + * contains a free region. + */ + run->regs_minelm = i; /* Low payoff: + (mask == 0); */ + + return (ret); + } + } + /* Not reached. */ + assert(0); + return (NULL); +} + +static inline void +arena_run_reg_dalloc(arena_run_t *run, arena_bin_t *bin, void *ptr, size_t size) +{ + /* + * To divide by a number D that is not a power of two we multiply + * by (2^21 / D) and then right shift by 21 positions. + * + * X / D + * + * becomes + * + * (X * size_invs[(D >> QUANTUM_2POW_MIN) - 3]) >> SIZE_INV_SHIFT + */ +#define SIZE_INV_SHIFT 21 +#define SIZE_INV(s) (((1U << SIZE_INV_SHIFT) / (s << QUANTUM_2POW_MIN)) + 1) + static const unsigned size_invs[] = { + SIZE_INV(3), + SIZE_INV(4), SIZE_INV(5), SIZE_INV(6), SIZE_INV(7), + SIZE_INV(8), SIZE_INV(9), SIZE_INV(10), SIZE_INV(11), + SIZE_INV(12),SIZE_INV(13), SIZE_INV(14), SIZE_INV(15), + SIZE_INV(16),SIZE_INV(17), SIZE_INV(18), SIZE_INV(19), + SIZE_INV(20),SIZE_INV(21), SIZE_INV(22), SIZE_INV(23), + SIZE_INV(24),SIZE_INV(25), SIZE_INV(26), SIZE_INV(27), + SIZE_INV(28),SIZE_INV(29), SIZE_INV(30), SIZE_INV(31) +#if (QUANTUM_2POW_MIN < 4) + , + SIZE_INV(32), SIZE_INV(33), SIZE_INV(34), SIZE_INV(35), + SIZE_INV(36), SIZE_INV(37), SIZE_INV(38), SIZE_INV(39), + SIZE_INV(40), SIZE_INV(41), SIZE_INV(42), SIZE_INV(43), + SIZE_INV(44), SIZE_INV(45), SIZE_INV(46), SIZE_INV(47), + SIZE_INV(48), SIZE_INV(49), SIZE_INV(50), SIZE_INV(51), + SIZE_INV(52), SIZE_INV(53), SIZE_INV(54), SIZE_INV(55), + SIZE_INV(56), SIZE_INV(57), SIZE_INV(58), SIZE_INV(59), + SIZE_INV(60), SIZE_INV(61), SIZE_INV(62), SIZE_INV(63) +#endif + }; + unsigned diff, regind, elm, bit; + + assert(run->magic == ARENA_RUN_MAGIC); + assert(((sizeof(size_invs)) / sizeof(unsigned)) + 3 + >= (SMALL_MAX_DEFAULT >> QUANTUM_2POW_MIN)); + + /* + * Avoid doing division with a variable divisor if possible. Using + * actual division here can reduce allocator throughput by over 20%! + */ + diff = (unsigned)((uintptr_t)ptr - (uintptr_t)run - bin->reg0_offset); + if ((size & (size - 1)) == 0) { + /* + * log2_table allows fast division of a power of two in the + * [1..128] range. + * + * (x / divisor) becomes (x >> log2_table[divisor - 1]). + */ + static const unsigned char log2_table[] = { + 0, 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7 + }; + + if (size <= 128) + regind = (diff >> log2_table[size - 1]); + else if (size <= 32768) + regind = diff >> (8 + log2_table[(size >> 8) - 1]); + else { + /* + * The run size is too large for us to use the lookup + * table. Use real division. + */ + regind = diff / size; + } + } else if (size <= ((sizeof(size_invs) / sizeof(unsigned)) + << QUANTUM_2POW_MIN) + 2) { + regind = size_invs[(size >> QUANTUM_2POW_MIN) - 3] * diff; + regind >>= SIZE_INV_SHIFT; + } else { + /* + * size_invs isn't large enough to handle this size class, so + * calculate regind using actual division. This only happens + * if the user increases small_max via the 'S' runtime + * configuration option. + */ + regind = diff / size; + }; + assert(diff == regind * size); + assert(regind < bin->nregs); + + elm = regind >> (SIZEOF_INT_2POW + 3); + if (elm < run->regs_minelm) + run->regs_minelm = elm; + bit = regind - (elm << (SIZEOF_INT_2POW + 3)); + assert((run->regs_mask[elm] & (1U << bit)) == 0); + run->regs_mask[elm] |= (1U << bit); +#undef SIZE_INV +#undef SIZE_INV_SHIFT +} + +static void +arena_run_split(arena_t *arena, arena_run_t *run, size_t size, bool large, + bool zero) +{ + arena_chunk_t *chunk; + size_t old_ndirty, run_ind, total_pages, need_pages, rem_pages, i; + + chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(run); + old_ndirty = chunk->ndirty; + run_ind = (unsigned)(((uintptr_t)run - (uintptr_t)chunk) + >> pagesize_2pow); + total_pages = (chunk->map[run_ind].bits & ~pagesize_mask) >> + pagesize_2pow; + need_pages = (size >> pagesize_2pow); + assert(need_pages > 0); + assert(need_pages <= total_pages); + rem_pages = total_pages - need_pages; + + arena_avail_tree_remove(&arena->runs_avail, &chunk->map[run_ind]); + + /* Keep track of trailing unused pages for later use. */ + if (rem_pages > 0) { + chunk->map[run_ind+need_pages].bits = (rem_pages << + pagesize_2pow) | (chunk->map[run_ind+need_pages].bits & + pagesize_mask); + chunk->map[run_ind+total_pages-1].bits = (rem_pages << + pagesize_2pow) | (chunk->map[run_ind+total_pages-1].bits & + pagesize_mask); + arena_avail_tree_insert(&arena->runs_avail, + &chunk->map[run_ind+need_pages]); + } + + for (i = 0; i < need_pages; i++) { +#ifdef MALLOC_DECOMMIT + /* + * Commit decommitted pages if necessary. If a decommitted + * page is encountered, commit all needed adjacent decommitted + * pages in one operation, in order to reduce system call + * overhead. + */ + if (chunk->map[run_ind + i].bits & CHUNK_MAP_DECOMMITTED) { + size_t j; + + /* + * Advance i+j to just past the index of the last page + * to commit. Clear CHUNK_MAP_DECOMMITTED along the + * way. + */ + for (j = 0; i + j < need_pages && (chunk->map[run_ind + + i + j].bits & CHUNK_MAP_DECOMMITTED); j++) { + chunk->map[run_ind + i + j].bits ^= + CHUNK_MAP_DECOMMITTED; + } + + pages_commit((void *)((uintptr_t)chunk + ((run_ind + i) + << pagesize_2pow)), (j << pagesize_2pow)); +# ifdef MALLOC_STATS + arena->stats.ncommit++; +# endif + } else /* No need to zero since commit zeros. */ +#endif + + /* Zero if necessary. */ + if (zero) { + if ((chunk->map[run_ind + i].bits & CHUNK_MAP_ZEROED) + == 0) { + VALGRIND_MALLOCLIKE_BLOCK((void *)((uintptr_t) + chunk + ((run_ind + i) << pagesize_2pow)), + pagesize, 0, false); + memset((void *)((uintptr_t)chunk + ((run_ind + + i) << pagesize_2pow)), 0, pagesize); + VALGRIND_FREELIKE_BLOCK((void *)((uintptr_t) + chunk + ((run_ind + i) << pagesize_2pow)), + 0); + /* CHUNK_MAP_ZEROED is cleared below. */ + } + } + + /* Update dirty page accounting. */ + if (chunk->map[run_ind + i].bits & CHUNK_MAP_DIRTY) { + chunk->ndirty--; + arena->ndirty--; + /* CHUNK_MAP_DIRTY is cleared below. */ + } + + /* Initialize the chunk map. */ + if (large) { + chunk->map[run_ind + i].bits = CHUNK_MAP_LARGE + | CHUNK_MAP_ALLOCATED; + } else { + chunk->map[run_ind + i].bits = (size_t)run + | CHUNK_MAP_ALLOCATED; + } + } + + /* + * Set the run size only in the first element for large runs. This is + * primarily a debugging aid, since the lack of size info for trailing + * pages only matters if the application tries to operate on an + * interior pointer. + */ + if (large) + chunk->map[run_ind].bits |= size; + + if (chunk->ndirty == 0 && old_ndirty > 0) + arena_chunk_tree_dirty_remove(&arena->chunks_dirty, chunk); +} + +static void +arena_chunk_init(arena_t *arena, arena_chunk_t *chunk) +{ + arena_run_t *run; + size_t i; + + VALGRIND_MALLOCLIKE_BLOCK(chunk, (arena_chunk_header_npages << + pagesize_2pow), 0, false); +#ifdef MALLOC_STATS + arena->stats.mapped += chunksize; +#endif + + chunk->arena = arena; + + /* + * Claim that no pages are in use, since the header is merely overhead. + */ + chunk->ndirty = 0; + + /* Initialize the map to contain one maximal free untouched run. */ + run = (arena_run_t *)((uintptr_t)chunk + (arena_chunk_header_npages << + pagesize_2pow)); + for (i = 0; i < arena_chunk_header_npages; i++) + chunk->map[i].bits = 0; + chunk->map[i].bits = arena_maxclass +#ifdef MALLOC_DECOMMIT + | CHUNK_MAP_DECOMMITTED +#endif + | CHUNK_MAP_ZEROED; + for (i++; i < chunk_npages-1; i++) { + chunk->map[i].bits = +#ifdef MALLOC_DECOMMIT + CHUNK_MAP_DECOMMITTED | +#endif + CHUNK_MAP_ZEROED; + } + chunk->map[chunk_npages-1].bits = arena_maxclass +#ifdef MALLOC_DECOMMIT + | CHUNK_MAP_DECOMMITTED +#endif + | CHUNK_MAP_ZEROED; + +#ifdef MALLOC_DECOMMIT + /* + * Start out decommitted, in order to force a closer correspondence + * between dirty pages and committed untouched pages. + */ + pages_decommit(run, arena_maxclass); +# ifdef MALLOC_STATS + arena->stats.ndecommit++; + arena->stats.decommitted += (chunk_npages - arena_chunk_header_npages); +# endif +#endif + + /* Insert the run into the runs_avail tree. */ + arena_avail_tree_insert(&arena->runs_avail, + &chunk->map[arena_chunk_header_npages]); +} + +static void +arena_chunk_dealloc(arena_t *arena, arena_chunk_t *chunk) +{ + + if (arena->spare != NULL) { + if (arena->spare->ndirty > 0) { + arena_chunk_tree_dirty_remove( + &chunk->arena->chunks_dirty, arena->spare); + arena->ndirty -= arena->spare->ndirty; + } + VALGRIND_FREELIKE_BLOCK(arena->spare, 0); + chunk_dealloc((void *)arena->spare, chunksize); +#ifdef MALLOC_STATS + arena->stats.mapped -= chunksize; +#endif + } + + /* + * Remove run from runs_avail, regardless of whether this chunk + * will be cached, so that the arena does not use it. Dirty page + * flushing only uses the chunks_dirty tree, so leaving this chunk in + * the chunks_* trees is sufficient for that purpose. + */ + arena_avail_tree_remove(&arena->runs_avail, + &chunk->map[arena_chunk_header_npages]); + + arena->spare = chunk; +} + +static arena_run_t * +arena_run_alloc(arena_t *arena, arena_bin_t *bin, size_t size, bool large, + bool zero) +{ + arena_chunk_t *chunk; + arena_run_t *run; + arena_chunk_map_t *mapelm, key; + + assert(size <= arena_maxclass); + assert((size & pagesize_mask) == 0); + + chunk = NULL; + while (true) { + /* Search the arena's chunks for the lowest best fit. */ + key.bits = size | CHUNK_MAP_KEY; + mapelm = arena_avail_tree_nsearch(&arena->runs_avail, &key); + if (mapelm != NULL) { + arena_chunk_t *run_chunk = (arena_chunk_t*)CHUNK_ADDR2BASE(mapelm); + size_t pageind = ((uintptr_t)mapelm - + (uintptr_t)run_chunk->map) / + sizeof(arena_chunk_map_t); + + if (chunk != NULL) + chunk_dealloc(chunk, chunksize); + run = (arena_run_t *)((uintptr_t)run_chunk + (pageind + << pagesize_2pow)); + arena_run_split(arena, run, size, large, zero); + return (run); + } + + if (arena->spare != NULL) { + /* Use the spare. */ + chunk = arena->spare; + arena->spare = NULL; + run = (arena_run_t *)((uintptr_t)chunk + + (arena_chunk_header_npages << pagesize_2pow)); + /* Insert the run into the runs_avail tree. */ + arena_avail_tree_insert(&arena->runs_avail, + &chunk->map[arena_chunk_header_npages]); + arena_run_split(arena, run, size, large, zero); + return (run); + } + + /* + * No usable runs. Create a new chunk from which to allocate + * the run. + */ + if (chunk == NULL) { + uint64_t chunk_seq; + + /* + * Record the chunk allocation sequence number in order + * to detect races. + */ + arena->chunk_seq++; + chunk_seq = arena->chunk_seq; + + /* + * Drop the arena lock while allocating a chunk, since + * reserve notifications may cause recursive + * allocation. Dropping the lock here opens an + * allocataion race, but we recover. + */ + malloc_mutex_unlock(&arena->lock); + chunk = (arena_chunk_t *)chunk_alloc(chunksize, true, + true); + malloc_mutex_lock(&arena->lock); + + /* + * Check whether a race allowed a usable run to appear. + */ + if (bin != NULL && (run = bin->runcur) != NULL && + run->nfree > 0) { + if (chunk != NULL) + chunk_dealloc(chunk, chunksize); + return (run); + } + + /* + * If this thread raced with another such that multiple + * chunks were allocated, make sure that there is still + * inadequate space before using this chunk. + */ + if (chunk_seq != arena->chunk_seq) + continue; + + /* + * Check for an error *after* checking for a race, + * since a race could also cause a transient OOM + * condition. + */ + if (chunk == NULL) + return (NULL); + } + + arena_chunk_init(arena, chunk); + run = (arena_run_t *)((uintptr_t)chunk + + (arena_chunk_header_npages << pagesize_2pow)); + /* Update page map. */ + arena_run_split(arena, run, size, large, zero); + return (run); + } +} + +static void +arena_purge(arena_t *arena) +{ + arena_chunk_t *chunk; + size_t i, npages; +#ifdef MALLOC_DEBUG + size_t ndirty = 0; + rb_foreach_begin(arena_chunk_t, link_dirty, &arena->chunks_dirty, + chunk) { + ndirty += chunk->ndirty; + } rb_foreach_end(arena_chunk_t, link_dirty, &arena->chunks_dirty, chunk) + assert(ndirty == arena->ndirty); +#endif + assert(arena->ndirty > opt_dirty_max); + +#ifdef MALLOC_STATS + arena->stats.npurge++; +#endif + + /* + * Iterate downward through chunks until enough dirty memory has been + * purged. Terminate as soon as possible in order to minimize the + * number of system calls, even if a chunk has only been partially + * purged. + */ + while (arena->ndirty > (opt_dirty_max >> 1)) { + chunk = arena_chunk_tree_dirty_last(&arena->chunks_dirty); + assert(chunk != NULL); + + for (i = chunk_npages - 1; chunk->ndirty > 0; i--) { + assert(i >= arena_chunk_header_npages); + + if (chunk->map[i].bits & CHUNK_MAP_DIRTY) { +#ifdef MALLOC_DECOMMIT + assert((chunk->map[i].bits & + CHUNK_MAP_DECOMMITTED) == 0); +#endif + chunk->map[i].bits ^= +#ifdef MALLOC_DECOMMIT + CHUNK_MAP_DECOMMITTED | +#endif + CHUNK_MAP_DIRTY; + /* Find adjacent dirty run(s). */ + for (npages = 1; i > arena_chunk_header_npages + && (chunk->map[i - 1].bits & + CHUNK_MAP_DIRTY); npages++) { + i--; +#ifdef MALLOC_DECOMMIT + assert((chunk->map[i].bits & + CHUNK_MAP_DECOMMITTED) == 0); +#endif + chunk->map[i].bits ^= +#ifdef MALLOC_DECOMMIT + CHUNK_MAP_DECOMMITTED | +#endif + CHUNK_MAP_DIRTY; + } + chunk->ndirty -= npages; + arena->ndirty -= npages; + +#ifdef MALLOC_DECOMMIT + pages_decommit((void *)((uintptr_t) + chunk + (i << pagesize_2pow)), + (npages << pagesize_2pow)); +# ifdef MALLOC_STATS + arena->stats.ndecommit++; + arena->stats.decommitted += npages; +# endif +#else + madvise((void *)((uintptr_t)chunk + (i << + pagesize_2pow)), (npages << pagesize_2pow), + MADV_FREE); +#endif +#ifdef MALLOC_STATS + arena->stats.nmadvise++; + arena->stats.purged += npages; +#endif + if (arena->ndirty <= (opt_dirty_max >> 1)) + break; + } + } + + if (chunk->ndirty == 0) { + arena_chunk_tree_dirty_remove(&arena->chunks_dirty, + chunk); + } + } +} + +static void +arena_run_dalloc(arena_t *arena, arena_run_t *run, bool dirty) +{ + arena_chunk_t *chunk; + size_t size, run_ind, run_pages; + + chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(run); + run_ind = (size_t)(((uintptr_t)run - (uintptr_t)chunk) + >> pagesize_2pow); + assert(run_ind >= arena_chunk_header_npages); + assert(run_ind < chunk_npages); + if ((chunk->map[run_ind].bits & CHUNK_MAP_LARGE) != 0) + size = chunk->map[run_ind].bits & ~pagesize_mask; + else + size = run->bin->run_size; + run_pages = (size >> pagesize_2pow); + + /* Mark pages as unallocated in the chunk map. */ + if (dirty) { + size_t i; + + for (i = 0; i < run_pages; i++) { + assert((chunk->map[run_ind + i].bits & CHUNK_MAP_DIRTY) + == 0); + chunk->map[run_ind + i].bits = CHUNK_MAP_DIRTY; + } + + if (chunk->ndirty == 0) { + arena_chunk_tree_dirty_insert(&arena->chunks_dirty, + chunk); + } + chunk->ndirty += run_pages; + arena->ndirty += run_pages; + } else { + size_t i; + + for (i = 0; i < run_pages; i++) { + chunk->map[run_ind + i].bits &= ~(CHUNK_MAP_LARGE | + CHUNK_MAP_ALLOCATED); + } + } + chunk->map[run_ind].bits = size | (chunk->map[run_ind].bits & + pagesize_mask); + chunk->map[run_ind+run_pages-1].bits = size | + (chunk->map[run_ind+run_pages-1].bits & pagesize_mask); + + /* Try to coalesce forward. */ + if (run_ind + run_pages < chunk_npages && + (chunk->map[run_ind+run_pages].bits & CHUNK_MAP_ALLOCATED) == 0) { + size_t nrun_size = chunk->map[run_ind+run_pages].bits & + ~pagesize_mask; + + /* + * Remove successor from runs_avail; the coalesced run is + * inserted later. + */ + arena_avail_tree_remove(&arena->runs_avail, + &chunk->map[run_ind+run_pages]); + + size += nrun_size; + run_pages = size >> pagesize_2pow; + + assert((chunk->map[run_ind+run_pages-1].bits & ~pagesize_mask) + == nrun_size); + chunk->map[run_ind].bits = size | (chunk->map[run_ind].bits & + pagesize_mask); + chunk->map[run_ind+run_pages-1].bits = size | + (chunk->map[run_ind+run_pages-1].bits & pagesize_mask); + } + + /* Try to coalesce backward. */ + if (run_ind > arena_chunk_header_npages && (chunk->map[run_ind-1].bits & + CHUNK_MAP_ALLOCATED) == 0) { + size_t prun_size = chunk->map[run_ind-1].bits & ~pagesize_mask; + + run_ind -= prun_size >> pagesize_2pow; + + /* + * Remove predecessor from runs_avail; the coalesced run is + * inserted later. + */ + arena_avail_tree_remove(&arena->runs_avail, + &chunk->map[run_ind]); + + size += prun_size; + run_pages = size >> pagesize_2pow; + + assert((chunk->map[run_ind].bits & ~pagesize_mask) == + prun_size); + chunk->map[run_ind].bits = size | (chunk->map[run_ind].bits & + pagesize_mask); + chunk->map[run_ind+run_pages-1].bits = size | + (chunk->map[run_ind+run_pages-1].bits & pagesize_mask); + } + + /* Insert into runs_avail, now that coalescing is complete. */ + arena_avail_tree_insert(&arena->runs_avail, &chunk->map[run_ind]); + + /* Deallocate chunk if it is now completely unused. */ + if ((chunk->map[arena_chunk_header_npages].bits & (~pagesize_mask | + CHUNK_MAP_ALLOCATED)) == arena_maxclass) + arena_chunk_dealloc(arena, chunk); + + /* Enforce opt_dirty_max. */ + if (arena->ndirty > opt_dirty_max) + arena_purge(arena); +} + +static void +arena_run_trim_head(arena_t *arena, arena_chunk_t *chunk, arena_run_t *run, + size_t oldsize, size_t newsize) +{ + size_t pageind = ((uintptr_t)run - (uintptr_t)chunk) >> pagesize_2pow; + size_t head_npages = (oldsize - newsize) >> pagesize_2pow; + + assert(oldsize > newsize); + + /* + * Update the chunk map so that arena_run_dalloc() can treat the + * leading run as separately allocated. + */ + chunk->map[pageind].bits = (oldsize - newsize) | CHUNK_MAP_LARGE | + CHUNK_MAP_ALLOCATED; + chunk->map[pageind+head_npages].bits = newsize | CHUNK_MAP_LARGE | + CHUNK_MAP_ALLOCATED; + + arena_run_dalloc(arena, run, false); +} + +static void +arena_run_trim_tail(arena_t *arena, arena_chunk_t *chunk, arena_run_t *run, + size_t oldsize, size_t newsize, bool dirty) +{ + size_t pageind = ((uintptr_t)run - (uintptr_t)chunk) >> pagesize_2pow; + size_t npages = newsize >> pagesize_2pow; + + assert(oldsize > newsize); + + /* + * Update the chunk map so that arena_run_dalloc() can treat the + * trailing run as separately allocated. + */ + chunk->map[pageind].bits = newsize | CHUNK_MAP_LARGE | + CHUNK_MAP_ALLOCATED; + chunk->map[pageind+npages].bits = (oldsize - newsize) | CHUNK_MAP_LARGE + | CHUNK_MAP_ALLOCATED; + + arena_run_dalloc(arena, (arena_run_t *)((uintptr_t)run + newsize), + dirty); +} + +static arena_run_t * +arena_bin_nonfull_run_get(arena_t *arena, arena_bin_t *bin) +{ + arena_chunk_map_t *mapelm; + arena_run_t *run; + unsigned i, remainder; + + /* Look for a usable run. */ + mapelm = arena_run_tree_first(&bin->runs); + if (mapelm != NULL) { + /* run is guaranteed to have available space. */ + arena_run_tree_remove(&bin->runs, mapelm); + run = (arena_run_t *)(mapelm->bits & ~pagesize_mask); +#ifdef MALLOC_STATS + bin->stats.reruns++; +#endif + return (run); + } + /* No existing runs have any space available. */ + + /* Allocate a new run. */ + run = arena_run_alloc(arena, bin, bin->run_size, false, false); + if (run == NULL) + return (NULL); + /* + * Don't initialize if a race in arena_run_alloc() allowed an existing + * run to become usable. + */ + if (run == bin->runcur) + return (run); + + VALGRIND_MALLOCLIKE_BLOCK(run, sizeof(arena_run_t) + (sizeof(unsigned) * + (bin->regs_mask_nelms - 1)), 0, false); + + /* Initialize run internals. */ + run->bin = bin; + + for (i = 0; i < bin->regs_mask_nelms - 1; i++) + run->regs_mask[i] = UINT_MAX; + remainder = bin->nregs & ((1U << (SIZEOF_INT_2POW + 3)) - 1); + if (remainder == 0) + run->regs_mask[i] = UINT_MAX; + else { + /* The last element has spare bits that need to be unset. */ + run->regs_mask[i] = (UINT_MAX >> ((1U << (SIZEOF_INT_2POW + 3)) + - remainder)); + } + + run->regs_minelm = 0; + + run->nfree = bin->nregs; +#ifdef MALLOC_DEBUG + run->magic = ARENA_RUN_MAGIC; +#endif + +#ifdef MALLOC_STATS + bin->stats.nruns++; + bin->stats.curruns++; + if (bin->stats.curruns > bin->stats.highruns) + bin->stats.highruns = bin->stats.curruns; +#endif + return (run); +} + +/* bin->runcur must have space available before this function is called. */ +static inline void * +arena_bin_malloc_easy(arena_t *arena, arena_bin_t *bin, arena_run_t *run) +{ + void *ret; + + assert(run->magic == ARENA_RUN_MAGIC); + assert(run->nfree > 0); + + ret = arena_run_reg_alloc(run, bin); + assert(ret != NULL); + run->nfree--; + + return (ret); +} + +/* Re-fill bin->runcur, then call arena_bin_malloc_easy(). */ +static void * +arena_bin_malloc_hard(arena_t *arena, arena_bin_t *bin) +{ + + bin->runcur = arena_bin_nonfull_run_get(arena, bin); + if (bin->runcur == NULL) + return (NULL); + assert(bin->runcur->magic == ARENA_RUN_MAGIC); + assert(bin->runcur->nfree > 0); + + return (arena_bin_malloc_easy(arena, bin, bin->runcur)); +} + +/* + * Calculate bin->run_size such that it meets the following constraints: + * + * *) bin->run_size >= min_run_size + * *) bin->run_size <= arena_maxclass + * *) bin->run_size <= RUN_MAX_SMALL + * *) run header overhead <= RUN_MAX_OVRHD (or header overhead relaxed). + * + * bin->nregs, bin->regs_mask_nelms, and bin->reg0_offset are + * also calculated here, since these settings are all interdependent. + */ +static size_t +arena_bin_run_size_calc(arena_bin_t *bin, size_t min_run_size) +{ + size_t try_run_size, good_run_size; + unsigned good_nregs, good_mask_nelms, good_reg0_offset; + unsigned try_nregs, try_mask_nelms, try_reg0_offset; + + assert(min_run_size >= pagesize); + assert(min_run_size <= arena_maxclass); + assert(min_run_size <= RUN_MAX_SMALL); + + /* + * Calculate known-valid settings before entering the run_size + * expansion loop, so that the first part of the loop always copies + * valid settings. + * + * The do..while loop iteratively reduces the number of regions until + * the run header and the regions no longer overlap. A closed formula + * would be quite messy, since there is an interdependency between the + * header's mask length and the number of regions. + */ + try_run_size = min_run_size; + try_nregs = ((try_run_size - sizeof(arena_run_t)) / bin->reg_size) + + 1; /* Counter-act try_nregs-- in loop. */ + do { + try_nregs--; + try_mask_nelms = (try_nregs >> (SIZEOF_INT_2POW + 3)) + + ((try_nregs & ((1U << (SIZEOF_INT_2POW + 3)) - 1)) ? 1 : 0); + try_reg0_offset = try_run_size - (try_nregs * bin->reg_size); + } while (sizeof(arena_run_t) + (sizeof(unsigned) * (try_mask_nelms - 1)) + > try_reg0_offset); + + /* run_size expansion loop. */ + do { + /* + * Copy valid settings before trying more aggressive settings. + */ + good_run_size = try_run_size; + good_nregs = try_nregs; + good_mask_nelms = try_mask_nelms; + good_reg0_offset = try_reg0_offset; + + /* Try more aggressive settings. */ + try_run_size += pagesize; + try_nregs = ((try_run_size - sizeof(arena_run_t)) / + bin->reg_size) + 1; /* Counter-act try_nregs-- in loop. */ + do { + try_nregs--; + try_mask_nelms = (try_nregs >> (SIZEOF_INT_2POW + 3)) + + ((try_nregs & ((1U << (SIZEOF_INT_2POW + 3)) - 1)) ? + 1 : 0); + try_reg0_offset = try_run_size - (try_nregs * + bin->reg_size); + } while (sizeof(arena_run_t) + (sizeof(unsigned) * + (try_mask_nelms - 1)) > try_reg0_offset); + } while (try_run_size <= arena_maxclass && try_run_size <= RUN_MAX_SMALL + && RUN_MAX_OVRHD * (bin->reg_size << 3) > RUN_MAX_OVRHD_RELAX + && (try_reg0_offset << RUN_BFP) > RUN_MAX_OVRHD * try_run_size); + + assert(sizeof(arena_run_t) + (sizeof(unsigned) * (good_mask_nelms - 1)) + <= good_reg0_offset); + assert((good_mask_nelms << (SIZEOF_INT_2POW + 3)) >= good_nregs); + + /* Copy final settings. */ + bin->run_size = good_run_size; + bin->nregs = good_nregs; + bin->regs_mask_nelms = good_mask_nelms; + bin->reg0_offset = good_reg0_offset; + + return (good_run_size); +} + +#ifdef MALLOC_BALANCE +static inline void +arena_lock_balance(arena_t *arena) +{ + unsigned contention; + + contention = malloc_spin_lock(&arena->lock); + if (narenas > 1) { + /* + * Calculate the exponentially averaged contention for this + * arena. Due to integer math always rounding down, this value + * decays somewhat faster then normal. + */ + arena->contention = (((uint64_t)arena->contention + * (uint64_t)((1U << BALANCE_ALPHA_INV_2POW)-1)) + + (uint64_t)contention) >> BALANCE_ALPHA_INV_2POW; + if (arena->contention >= opt_balance_threshold) + arena_lock_balance_hard(arena); + } +} + +static void +arena_lock_balance_hard(arena_t *arena) +{ + uint32_t ind; + + arena->contention = 0; +#ifdef MALLOC_STATS + arena->stats.nbalance++; +#endif + ind = PRN(balance, narenas_2pow); + if (arenas[ind] != NULL) { +#ifdef MOZ_MEMORY_WINDOWS + TlsSetValue(tlsIndex, arenas[ind]); +#else + arenas_map = arenas[ind]; +#endif + } else { + malloc_spin_lock(&arenas_lock); + if (arenas[ind] != NULL) { +#ifdef MOZ_MEMORY_WINDOWS + TlsSetValue(tlsIndex, arenas[ind]); +#else + arenas_map = arenas[ind]; +#endif + } else { +#ifdef MOZ_MEMORY_WINDOWS + TlsSetValue(tlsIndex, arenas_extend(ind)); +#else + arenas_map = arenas_extend(ind); +#endif + } + malloc_spin_unlock(&arenas_lock); + } +} +#endif + +static inline void * +arena_malloc_small(arena_t *arena, size_t size, bool zero) +{ + void *ret; + arena_bin_t *bin; + arena_run_t *run; + + if (size < small_min) { + /* Tiny. */ + size = pow2_ceil(size); + bin = &arena->bins[ffs((int)(size >> (TINY_MIN_2POW + + 1)))]; +#if (!defined(NDEBUG) || defined(MALLOC_STATS)) + /* + * Bin calculation is always correct, but we may need + * to fix size for the purposes of assertions and/or + * stats accuracy. + */ + if (size < (1U << TINY_MIN_2POW)) + size = (1U << TINY_MIN_2POW); +#endif + } else if (size <= small_max) { + /* Quantum-spaced. */ + size = QUANTUM_CEILING(size); + bin = &arena->bins[ntbins + (size >> opt_quantum_2pow) + - 1]; + } else { + /* Sub-page. */ + size = pow2_ceil(size); + bin = &arena->bins[ntbins + nqbins + + (ffs((int)(size >> opt_small_max_2pow)) - 2)]; + } + assert(size == bin->reg_size); + +#ifdef MALLOC_BALANCE + arena_lock_balance(arena); +#else + malloc_spin_lock(&arena->lock); +#endif + if ((run = bin->runcur) != NULL && run->nfree > 0) + ret = arena_bin_malloc_easy(arena, bin, run); + else + ret = arena_bin_malloc_hard(arena, bin); + + if (ret == NULL) { + malloc_spin_unlock(&arena->lock); + return (NULL); + } + +#ifdef MALLOC_STATS + bin->stats.nrequests++; + arena->stats.nmalloc_small++; + arena->stats.allocated_small += size; +#endif + malloc_spin_unlock(&arena->lock); + + VALGRIND_MALLOCLIKE_BLOCK(ret, size, 0, zero); + if (zero == false) { +#ifdef MALLOC_FILL + if (opt_junk) + memset(ret, 0xa5, size); + else if (opt_zero) + memset(ret, 0, size); +#endif + } else + memset(ret, 0, size); + + return (ret); +} + +static void * +arena_malloc_large(arena_t *arena, size_t size, bool zero) +{ + void *ret; + + /* Large allocation. */ + size = PAGE_CEILING(size); +#ifdef MALLOC_BALANCE + arena_lock_balance(arena); +#else + malloc_spin_lock(&arena->lock); +#endif + ret = (void *)arena_run_alloc(arena, NULL, size, true, zero); + if (ret == NULL) { + malloc_spin_unlock(&arena->lock); + return (NULL); + } +#ifdef MALLOC_STATS + arena->stats.nmalloc_large++; + arena->stats.allocated_large += size; +#endif + malloc_spin_unlock(&arena->lock); + + VALGRIND_MALLOCLIKE_BLOCK(ret, size, 0, zero); + if (zero == false) { +#ifdef MALLOC_FILL + if (opt_junk) + memset(ret, 0xa5, size); + else if (opt_zero) + memset(ret, 0, size); +#endif + } + + return (ret); +} + +static inline void * +arena_malloc(arena_t *arena, size_t size, bool zero) +{ + + assert(arena != NULL); + assert(arena->magic == ARENA_MAGIC); + assert(size != 0); + assert(QUANTUM_CEILING(size) <= arena_maxclass); + + if (size <= bin_maxclass) { + return (arena_malloc_small(arena, size, zero)); + } else + return (arena_malloc_large(arena, size, zero)); +} + +static inline void * +imalloc(size_t size) +{ + + assert(size != 0); + + if (size <= arena_maxclass) + return (arena_malloc(choose_arena(), size, false)); + else + return (huge_malloc(size, false)); +} + +static inline void * +icalloc(size_t size) +{ + + if (size <= arena_maxclass) + return (arena_malloc(choose_arena(), size, true)); + else + return (huge_malloc(size, true)); +} + +/* Only handles large allocations that require more than page alignment. */ +static void * +arena_palloc(arena_t *arena, size_t alignment, size_t size, size_t alloc_size) +{ + void *ret; + size_t offset; + arena_chunk_t *chunk; + + assert((size & pagesize_mask) == 0); + assert((alignment & pagesize_mask) == 0); + +#ifdef MALLOC_BALANCE + arena_lock_balance(arena); +#else + malloc_spin_lock(&arena->lock); +#endif + ret = (void *)arena_run_alloc(arena, NULL, alloc_size, true, false); + if (ret == NULL) { + malloc_spin_unlock(&arena->lock); + return (NULL); + } + + chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ret); + + offset = (uintptr_t)ret & (alignment - 1); + assert((offset & pagesize_mask) == 0); + assert(offset < alloc_size); + if (offset == 0) + arena_run_trim_tail(arena, chunk, (arena_run_t*)ret, alloc_size, size, false); + else { + size_t leadsize, trailsize; + + leadsize = alignment - offset; + if (leadsize > 0) { + arena_run_trim_head(arena, chunk, (arena_run_t*)ret, alloc_size, + alloc_size - leadsize); + ret = (void *)((uintptr_t)ret + leadsize); + } + + trailsize = alloc_size - leadsize - size; + if (trailsize != 0) { + /* Trim trailing space. */ + assert(trailsize < alloc_size); + arena_run_trim_tail(arena, chunk, (arena_run_t*)ret, size + trailsize, + size, false); + } + } + +#ifdef MALLOC_STATS + arena->stats.nmalloc_large++; + arena->stats.allocated_large += size; +#endif + malloc_spin_unlock(&arena->lock); + + VALGRIND_MALLOCLIKE_BLOCK(ret, size, 0, false); +#ifdef MALLOC_FILL + if (opt_junk) + memset(ret, 0xa5, size); + else if (opt_zero) + memset(ret, 0, size); +#endif + return (ret); +} + +static inline void * +ipalloc(size_t alignment, size_t size) +{ + void *ret; + size_t ceil_size; + + /* + * Round size up to the nearest multiple of alignment. + * + * This done, we can take advantage of the fact that for each small + * size class, every object is aligned at the smallest power of two + * that is non-zero in the base two representation of the size. For + * example: + * + * Size | Base 2 | Minimum alignment + * -----+----------+------------------ + * 96 | 1100000 | 32 + * 144 | 10100000 | 32 + * 192 | 11000000 | 64 + * + * Depending on runtime settings, it is possible that arena_malloc() + * will further round up to a power of two, but that never causes + * correctness issues. + */ + ceil_size = (size + (alignment - 1)) & (-alignment); + /* + * (ceil_size < size) protects against the combination of maximal + * alignment and size greater than maximal alignment. + */ + if (ceil_size < size) { + /* size_t overflow. */ + return (NULL); + } + + if (ceil_size <= pagesize || (alignment <= pagesize + && ceil_size <= arena_maxclass)) + ret = arena_malloc(choose_arena(), ceil_size, false); + else { + size_t run_size; + + /* + * We can't achieve sub-page alignment, so round up alignment + * permanently; it makes later calculations simpler. + */ + alignment = PAGE_CEILING(alignment); + ceil_size = PAGE_CEILING(size); + /* + * (ceil_size < size) protects against very large sizes within + * pagesize of SIZE_T_MAX. + * + * (ceil_size + alignment < ceil_size) protects against the + * combination of maximal alignment and ceil_size large enough + * to cause overflow. This is similar to the first overflow + * check above, but it needs to be repeated due to the new + * ceil_size value, which may now be *equal* to maximal + * alignment, whereas before we only detected overflow if the + * original size was *greater* than maximal alignment. + */ + if (ceil_size < size || ceil_size + alignment < ceil_size) { + /* size_t overflow. */ + return (NULL); + } + + /* + * Calculate the size of the over-size run that arena_palloc() + * would need to allocate in order to guarantee the alignment. + */ + if (ceil_size >= alignment) + run_size = ceil_size + alignment - pagesize; + else { + /* + * It is possible that (alignment << 1) will cause + * overflow, but it doesn't matter because we also + * subtract pagesize, which in the case of overflow + * leaves us with a very large run_size. That causes + * the first conditional below to fail, which means + * that the bogus run_size value never gets used for + * anything important. + */ + run_size = (alignment << 1) - pagesize; + } + + if (run_size <= arena_maxclass) { + ret = arena_palloc(choose_arena(), alignment, ceil_size, + run_size); + } else if (alignment <= chunksize) + ret = huge_malloc(ceil_size, false); + else + ret = huge_palloc(alignment, ceil_size); + } + + assert(((uintptr_t)ret & (alignment - 1)) == 0); + return (ret); +} + +/* Return the size of the allocation pointed to by ptr. */ +static size_t +arena_salloc(const void *ptr) +{ + size_t ret; + arena_chunk_t *chunk; + size_t pageind, mapbits; + + assert(ptr != NULL); + assert(CHUNK_ADDR2BASE(ptr) != ptr); + + chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr); + pageind = (((uintptr_t)ptr - (uintptr_t)chunk) >> pagesize_2pow); + mapbits = chunk->map[pageind].bits; + assert((mapbits & CHUNK_MAP_ALLOCATED) != 0); + if ((mapbits & CHUNK_MAP_LARGE) == 0) { + arena_run_t *run = (arena_run_t *)(mapbits & ~pagesize_mask); + assert(run->magic == ARENA_RUN_MAGIC); + ret = run->bin->reg_size; + } else { + ret = mapbits & ~pagesize_mask; + assert(ret != 0); + } + + return (ret); +} + +#if (defined(MALLOC_VALIDATE) || defined(MOZ_MEMORY_DARWIN)) +/* + * Validate ptr before assuming that it points to an allocation. Currently, + * the following validation is performed: + * + * + Check that ptr is not NULL. + * + * + Check that ptr lies within a mapped chunk. + */ +static inline size_t +isalloc_validate(const void *ptr) +{ + arena_chunk_t *chunk; + + chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr); + if (chunk == NULL) + return (0); + + if (malloc_rtree_get(chunk_rtree, (uintptr_t)chunk) == NULL) + return (0); + + if (chunk != ptr) { + assert(chunk->arena->magic == ARENA_MAGIC); + return (arena_salloc(ptr)); + } else { + size_t ret; + extent_node_t *node; + extent_node_t key; + + /* Chunk. */ + key.addr = (void *)chunk; + malloc_mutex_lock(&huge_mtx); + node = extent_tree_ad_search(&huge_, &key); + if (node != NULL) + ret = node->size; + else + ret = 0; + malloc_mutex_unlock(&huge_mtx); + return (ret); + } +} +#endif + +static inline size_t +isalloc(const void *ptr) +{ + size_t ret; + arena_chunk_t *chunk; + + assert(ptr != NULL); + + chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr); + if (chunk != ptr) { + /* Region. */ + assert(chunk->arena->magic == ARENA_MAGIC); + + ret = arena_salloc(ptr); + } else { + extent_node_t *node, key; + + /* Chunk (huge allocation). */ + + malloc_mutex_lock(&huge_mtx); + + /* Extract from tree of huge allocations. */ + key.addr = __DECONST(void *, ptr); + node = extent_tree_ad_search(&huge_, &key); + assert(node != NULL); + + ret = node->size; + + malloc_mutex_unlock(&huge_mtx); + } + + return (ret); +} + +static inline void +arena_dalloc_small(arena_t *arena, arena_chunk_t *chunk, void *ptr, + arena_chunk_map_t *mapelm) +{ + arena_run_t *run; + arena_bin_t *bin; + size_t size; + + run = (arena_run_t *)(mapelm->bits & ~pagesize_mask); + assert(run->magic == ARENA_RUN_MAGIC); + bin = run->bin; + size = bin->reg_size; + +#ifdef MALLOC_FILL + if (opt_junk) + memset(ptr, 0x5a, size); +#endif + + arena_run_reg_dalloc(run, bin, ptr, size); + run->nfree++; + + if (run->nfree == bin->nregs) { + /* Deallocate run. */ + if (run == bin->runcur) + bin->runcur = NULL; + else if (bin->nregs != 1) { + size_t run_pageind = (((uintptr_t)run - + (uintptr_t)chunk)) >> pagesize_2pow; + arena_chunk_map_t *run_mapelm = + &chunk->map[run_pageind]; + /* + * This block's conditional is necessary because if the + * run only contains one region, then it never gets + * inserted into the non-full runs tree. + */ + assert(arena_run_tree_search(&bin->runs, run_mapelm) == + run_mapelm); + arena_run_tree_remove(&bin->runs, run_mapelm); + } +#ifdef MALLOC_DEBUG + run->magic = 0; +#endif + VALGRIND_FREELIKE_BLOCK(run, 0); + arena_run_dalloc(arena, run, true); +#ifdef MALLOC_STATS + bin->stats.curruns--; +#endif + } else if (run->nfree == 1 && run != bin->runcur) { + /* + * Make sure that bin->runcur always refers to the lowest + * non-full run, if one exists. + */ + if (bin->runcur == NULL) + bin->runcur = run; + else if ((uintptr_t)run < (uintptr_t)bin->runcur) { + /* Switch runcur. */ + if (bin->runcur->nfree > 0) { + arena_chunk_t *runcur_chunk = + (arena_chunk_t*)CHUNK_ADDR2BASE(bin->runcur); + size_t runcur_pageind = + (((uintptr_t)bin->runcur - + (uintptr_t)runcur_chunk)) >> pagesize_2pow; + arena_chunk_map_t *runcur_mapelm = + &runcur_chunk->map[runcur_pageind]; + + /* Insert runcur. */ + assert(arena_run_tree_search(&bin->runs, + runcur_mapelm) == NULL); + arena_run_tree_insert(&bin->runs, + runcur_mapelm); + } + bin->runcur = run; + } else { + size_t run_pageind = (((uintptr_t)run - + (uintptr_t)chunk)) >> pagesize_2pow; + arena_chunk_map_t *run_mapelm = + &chunk->map[run_pageind]; + + assert(arena_run_tree_search(&bin->runs, run_mapelm) == + NULL); + arena_run_tree_insert(&bin->runs, run_mapelm); + } + } +#ifdef MALLOC_STATS + arena->stats.allocated_small -= size; + arena->stats.ndalloc_small++; +#endif +} + +static void +arena_dalloc_large(arena_t *arena, arena_chunk_t *chunk, void *ptr) +{ + /* Large allocation. */ + malloc_spin_lock(&arena->lock); + +#ifdef MALLOC_FILL +#ifndef MALLOC_STATS + if (opt_junk) +#endif +#endif + { + size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> + pagesize_2pow; + size_t size = chunk->map[pageind].bits & ~pagesize_mask; + +#ifdef MALLOC_FILL +#ifdef MALLOC_STATS + if (opt_junk) +#endif + memset(ptr, 0x5a, size); +#endif +#ifdef MALLOC_STATS + arena->stats.allocated_large -= size; +#endif + } +#ifdef MALLOC_STATS + arena->stats.ndalloc_large++; +#endif + + arena_run_dalloc(arena, (arena_run_t *)ptr, true); + malloc_spin_unlock(&arena->lock); +} + +static inline void +arena_dalloc(arena_t *arena, arena_chunk_t *chunk, void *ptr) +{ + size_t pageind; + arena_chunk_map_t *mapelm; + + assert(arena != NULL); + assert(arena->magic == ARENA_MAGIC); + assert(chunk->arena == arena); + assert(ptr != NULL); + assert(CHUNK_ADDR2BASE(ptr) != ptr); + + pageind = (((uintptr_t)ptr - (uintptr_t)chunk) >> pagesize_2pow); + mapelm = &chunk->map[pageind]; + assert((mapelm->bits & CHUNK_MAP_ALLOCATED) != 0); + if ((mapelm->bits & CHUNK_MAP_LARGE) == 0) { + /* Small allocation. */ + malloc_spin_lock(&arena->lock); + arena_dalloc_small(arena, chunk, ptr, mapelm); + malloc_spin_unlock(&arena->lock); + } else + arena_dalloc_large(arena, chunk, ptr); + VALGRIND_FREELIKE_BLOCK(ptr, 0); +} + +static inline void +idalloc(void *ptr) +{ + arena_chunk_t *chunk; + + assert(ptr != NULL); + + chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr); + if (chunk != ptr) + arena_dalloc(chunk->arena, chunk, ptr); + else + huge_dalloc(ptr); +} + +static void +arena_ralloc_large_shrink(arena_t *arena, arena_chunk_t *chunk, void *ptr, + size_t size, size_t oldsize) +{ + + assert(size < oldsize); + + /* + * Shrink the run, and make trailing pages available for other + * allocations. + */ +#ifdef MALLOC_BALANCE + arena_lock_balance(arena); +#else + malloc_spin_lock(&arena->lock); +#endif + arena_run_trim_tail(arena, chunk, (arena_run_t *)ptr, oldsize, size, + true); +#ifdef MALLOC_STATS + arena->stats.allocated_large -= oldsize - size; +#endif + malloc_spin_unlock(&arena->lock); +} + +static bool +arena_ralloc_large_grow(arena_t *arena, arena_chunk_t *chunk, void *ptr, + size_t size, size_t oldsize) +{ + size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> pagesize_2pow; + size_t npages = oldsize >> pagesize_2pow; + + assert(oldsize == (chunk->map[pageind].bits & ~pagesize_mask)); + + /* Try to extend the run. */ + assert(size > oldsize); +#ifdef MALLOC_BALANCE + arena_lock_balance(arena); +#else + malloc_spin_lock(&arena->lock); +#endif + if (pageind + npages < chunk_npages && (chunk->map[pageind+npages].bits + & CHUNK_MAP_ALLOCATED) == 0 && (chunk->map[pageind+npages].bits & + ~pagesize_mask) >= size - oldsize) { + /* + * The next run is available and sufficiently large. Split the + * following run, then merge the first part with the existing + * allocation. + */ + arena_run_split(arena, (arena_run_t *)((uintptr_t)chunk + + ((pageind+npages) << pagesize_2pow)), size - oldsize, true, + false); + + chunk->map[pageind].bits = size | CHUNK_MAP_LARGE | + CHUNK_MAP_ALLOCATED; + chunk->map[pageind+npages].bits = CHUNK_MAP_LARGE | + CHUNK_MAP_ALLOCATED; + +#ifdef MALLOC_STATS + arena->stats.allocated_large += size - oldsize; +#endif + malloc_spin_unlock(&arena->lock); + return (false); + } + malloc_spin_unlock(&arena->lock); + + return (true); +} + +/* + * Try to resize a large allocation, in order to avoid copying. This will + * always fail if growing an object, and the following run is already in use. + */ +static bool +arena_ralloc_large(void *ptr, size_t size, size_t oldsize) +{ + size_t psize; + + psize = PAGE_CEILING(size); + if (psize == oldsize) { + /* Same size class. */ +#ifdef MALLOC_FILL + if (opt_junk && size < oldsize) { + memset((void *)((uintptr_t)ptr + size), 0x5a, oldsize - + size); + } +#endif + return (false); + } else { + arena_chunk_t *chunk; + arena_t *arena; + + chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr); + arena = chunk->arena; + assert(arena->magic == ARENA_MAGIC); + + if (psize < oldsize) { +#ifdef MALLOC_FILL + /* Fill before shrinking in order avoid a race. */ + if (opt_junk) { + memset((void *)((uintptr_t)ptr + size), 0x5a, + oldsize - size); + } +#endif + arena_ralloc_large_shrink(arena, chunk, ptr, psize, + oldsize); + return (false); + } else { + bool ret = arena_ralloc_large_grow(arena, chunk, ptr, + psize, oldsize); +#ifdef MALLOC_FILL + if (ret == false && opt_zero) { + memset((void *)((uintptr_t)ptr + oldsize), 0, + size - oldsize); + } +#endif + return (ret); + } + } +} + +static void * +arena_ralloc(void *ptr, size_t size, size_t oldsize) +{ + void *ret; + size_t copysize; + + /* Try to avoid moving the allocation. */ + if (size < small_min) { + if (oldsize < small_min && + ffs((int)(pow2_ceil(size) >> (TINY_MIN_2POW + 1))) + == ffs((int)(pow2_ceil(oldsize) >> (TINY_MIN_2POW + 1)))) + goto IN_PLACE; /* Same size class. */ + } else if (size <= small_max) { + if (oldsize >= small_min && oldsize <= small_max && + (QUANTUM_CEILING(size) >> opt_quantum_2pow) + == (QUANTUM_CEILING(oldsize) >> opt_quantum_2pow)) + goto IN_PLACE; /* Same size class. */ + } else if (size <= bin_maxclass) { + if (oldsize > small_max && oldsize <= bin_maxclass && + pow2_ceil(size) == pow2_ceil(oldsize)) + goto IN_PLACE; /* Same size class. */ + } else if (oldsize > bin_maxclass && oldsize <= arena_maxclass) { + assert(size > bin_maxclass); + if (arena_ralloc_large(ptr, size, oldsize) == false) + return (ptr); + } + + /* + * If we get here, then size and oldsize are different enough that we + * need to move the object. In that case, fall back to allocating new + * space and copying. + */ + ret = arena_malloc(choose_arena(), size, false); + if (ret == NULL) + return (NULL); + + /* Junk/zero-filling were already done by arena_malloc(). */ + copysize = (size < oldsize) ? size : oldsize; +#ifdef VM_COPY_MIN + if (copysize >= VM_COPY_MIN) + pages_copy(ret, ptr, copysize); + else +#endif + memcpy(ret, ptr, copysize); + idalloc(ptr); + return (ret); +IN_PLACE: +#ifdef MALLOC_FILL + if (opt_junk && size < oldsize) + memset((void *)((uintptr_t)ptr + size), 0x5a, oldsize - size); + else if (opt_zero && size > oldsize) + memset((void *)((uintptr_t)ptr + oldsize), 0, size - oldsize); +#endif + return (ptr); +} + +static inline void * +iralloc(void *ptr, size_t size) +{ + size_t oldsize; + + assert(ptr != NULL); + assert(size != 0); + + oldsize = isalloc(ptr); + +#ifndef MALLOC_VALGRIND + if (size <= arena_maxclass) + return (arena_ralloc(ptr, size, oldsize)); + else + return (huge_ralloc(ptr, size, oldsize)); +#else + /* + * Valgrind does not provide a public interface for modifying an + * existing allocation, so use malloc/memcpy/free instead. + */ + { + void *ret = imalloc(size); + if (ret != NULL) { + if (oldsize < size) + memcpy(ret, ptr, oldsize); + else + memcpy(ret, ptr, size); + idalloc(ptr); + } + return (ret); + } +#endif +} + +static bool +arena_new(arena_t *arena) +{ + unsigned i; + arena_bin_t *bin; + size_t pow2_size, prev_run_size; + + if (malloc_spin_init(&arena->lock)) + return (true); + +#ifdef MALLOC_STATS + memset(&arena->stats, 0, sizeof(arena_stats_t)); +#endif + + arena->chunk_seq = 0; + + /* Initialize chunks. */ + arena_chunk_tree_dirty_new(&arena->chunks_dirty); + arena->spare = NULL; + + arena->ndirty = 0; + + arena_avail_tree_new(&arena->runs_avail); + +#ifdef MALLOC_BALANCE + arena->contention = 0; +#endif + + /* Initialize bins. */ + prev_run_size = pagesize; + + /* (2^n)-spaced tiny bins. */ + for (i = 0; i < ntbins; i++) { + bin = &arena->bins[i]; + bin->runcur = NULL; + arena_run_tree_new(&bin->runs); + + bin->reg_size = (1U << (TINY_MIN_2POW + i)); + + prev_run_size = arena_bin_run_size_calc(bin, prev_run_size); + +#ifdef MALLOC_STATS + memset(&bin->stats, 0, sizeof(malloc_bin_stats_t)); +#endif + } + + /* Quantum-spaced bins. */ + for (; i < ntbins + nqbins; i++) { + bin = &arena->bins[i]; + bin->runcur = NULL; + arena_run_tree_new(&bin->runs); + + bin->reg_size = quantum * (i - ntbins + 1); + + pow2_size = pow2_ceil(quantum * (i - ntbins + 1)); + prev_run_size = arena_bin_run_size_calc(bin, prev_run_size); + +#ifdef MALLOC_STATS + memset(&bin->stats, 0, sizeof(malloc_bin_stats_t)); +#endif + } + + /* (2^n)-spaced sub-page bins. */ + for (; i < ntbins + nqbins + nsbins; i++) { + bin = &arena->bins[i]; + bin->runcur = NULL; + arena_run_tree_new(&bin->runs); + + bin->reg_size = (small_max << (i - (ntbins + nqbins) + 1)); + + prev_run_size = arena_bin_run_size_calc(bin, prev_run_size); + +#ifdef MALLOC_STATS + memset(&bin->stats, 0, sizeof(malloc_bin_stats_t)); +#endif + } + +#ifdef MALLOC_DEBUG + arena->magic = ARENA_MAGIC; +#endif + + return (false); +} + +/* Create a new arena and insert it into the arenas array at index ind. */ +static arena_t * +arenas_extend(unsigned ind) +{ + arena_t *ret; + + /* Allocate enough space for trailing bins. */ + ret = (arena_t *)base_alloc(sizeof(arena_t) + + (sizeof(arena_bin_t) * (ntbins + nqbins + nsbins - 1))); + if (ret != NULL && arena_new(ret) == false) { + arenas[ind] = ret; + return (ret); + } + /* Only reached if there is an OOM error. */ + + /* + * OOM here is quite inconvenient to propagate, since dealing with it + * would require a check for failure in the fast path. Instead, punt + * by using arenas[0]. In practice, this is an extremely unlikely + * failure. + */ + _malloc_message(_getprogname(), + ": (malloc) Error initializing arena\n", "", ""); + if (opt_abort) + abort(); + + return (arenas[0]); +} + +/* + * End arena. + */ +/******************************************************************************/ +/* + * Begin general internal functions. + */ + +static void * +huge_malloc(size_t size, bool zero) +{ + void *ret; + size_t csize; +#ifdef MALLOC_DECOMMIT + size_t psize; +#endif + extent_node_t *node; + + /* Allocate one or more contiguous chunks for this request. */ + + csize = CHUNK_CEILING(size); + if (csize == 0) { + /* size is large enough to cause size_t wrap-around. */ + return (NULL); + } + + /* Allocate an extent node with which to track the chunk. */ + node = base_node_alloc(); + if (node == NULL) + return (NULL); + + ret = chunk_alloc(csize, zero, true); + if (ret == NULL) { + base_node_dealloc(node); + return (NULL); + } + + /* Insert node into huge. */ + node->addr = ret; +#ifdef MALLOC_DECOMMIT + psize = PAGE_CEILING(size); + node->size = psize; +#else + node->size = csize; +#endif + + malloc_mutex_lock(&huge_mtx); + extent_tree_ad_insert(&huge_, node); +#ifdef MALLOC_STATS + huge_nmalloc++; +# ifdef MALLOC_DECOMMIT + huge_allocated += psize; +# else + huge_allocated += csize; +# endif +#endif + malloc_mutex_unlock(&huge_mtx); + +#ifdef MALLOC_DECOMMIT + if (csize - psize > 0) + pages_decommit((void *)((uintptr_t)ret + psize), csize - psize); +#endif + +#ifdef MALLOC_DECOMMIT + VALGRIND_MALLOCLIKE_BLOCK(ret, psize, 0, zero); +#else + VALGRIND_MALLOCLIKE_BLOCK(ret, csize, 0, zero); +#endif + +#ifdef MALLOC_FILL + if (zero == false) { + if (opt_junk) +# ifdef MALLOC_DECOMMIT + memset(ret, 0xa5, psize); +# else + memset(ret, 0xa5, csize); +# endif + else if (opt_zero) +# ifdef MALLOC_DECOMMIT + memset(ret, 0, psize); +# else + memset(ret, 0, csize); +# endif + } +#endif + + return (ret); +} + +/* Only handles large allocations that require more than chunk alignment. */ +static void * +huge_palloc(size_t alignment, size_t size) +{ + void *ret; + size_t alloc_size, chunk_size, offset; +#ifdef MALLOC_DECOMMIT + size_t psize; +#endif + extent_node_t *node; + int pfd; + + /* + * This allocation requires alignment that is even larger than chunk + * alignment. This means that huge_malloc() isn't good enough. + * + * Allocate almost twice as many chunks as are demanded by the size or + * alignment, in order to assure the alignment can be achieved, then + * unmap leading and trailing chunks. + */ + assert(alignment >= chunksize); + + chunk_size = CHUNK_CEILING(size); + + if (size >= alignment) + alloc_size = chunk_size + alignment - chunksize; + else + alloc_size = (alignment << 1) - chunksize; + + /* Allocate an extent node with which to track the chunk. */ + node = base_node_alloc(); + if (node == NULL) + return (NULL); + + /* + * Windows requires that there be a 1:1 mapping between VM + * allocation/deallocation operations. Therefore, take care here to + * acquire the final result via one mapping operation. + * + * The MALLOC_PAGEFILE code also benefits from this mapping algorithm, + * since it reduces the number of page files. + */ +#ifdef MALLOC_PAGEFILE + if (opt_pagefile) { + pfd = pagefile_init(size); + if (pfd == -1) + return (NULL); + } else +#endif + pfd = -1; +#ifdef JEMALLOC_USES_MAP_ALIGN + ret = pages_map_align(chunk_size, pfd, alignment); +#else + do { + void *over; + + over = chunk_alloc(alloc_size, false, false); + if (over == NULL) { + base_node_dealloc(node); + ret = NULL; + goto RETURN; + } + + offset = (uintptr_t)over & (alignment - 1); + assert((offset & chunksize_mask) == 0); + assert(offset < alloc_size); + ret = (void *)((uintptr_t)over + offset); + chunk_dealloc(over, alloc_size); + ret = pages_map(ret, chunk_size, pfd); + /* + * Failure here indicates a race with another thread, so try + * again. + */ + } while (ret == NULL); +#endif + /* Insert node into huge. */ + node->addr = ret; +#ifdef MALLOC_DECOMMIT + psize = PAGE_CEILING(size); + node->size = psize; +#else + node->size = chunk_size; +#endif + + malloc_mutex_lock(&huge_mtx); + extent_tree_ad_insert(&huge_, node); +#ifdef MALLOC_STATS + huge_nmalloc++; +# ifdef MALLOC_DECOMMIT + huge_allocated += psize; +# else + huge_allocated += chunk_size; +# endif +#endif + malloc_mutex_unlock(&huge_mtx); + +#ifdef MALLOC_DECOMMIT + if (chunk_size - psize > 0) { + pages_decommit((void *)((uintptr_t)ret + psize), + chunk_size - psize); + } +#endif + +#ifdef MALLOC_DECOMMIT + VALGRIND_MALLOCLIKE_BLOCK(ret, psize, 0, false); +#else + VALGRIND_MALLOCLIKE_BLOCK(ret, chunk_size, 0, false); +#endif + +#ifdef MALLOC_FILL + if (opt_junk) +# ifdef MALLOC_DECOMMIT + memset(ret, 0xa5, psize); +# else + memset(ret, 0xa5, chunk_size); +# endif + else if (opt_zero) +# ifdef MALLOC_DECOMMIT + memset(ret, 0, psize); +# else + memset(ret, 0, chunk_size); +# endif +#endif + +RETURN: +#ifdef MALLOC_PAGEFILE + if (pfd != -1) + pagefile_close(pfd); +#endif + return (ret); +} + +static void * +huge_ralloc(void *ptr, size_t size, size_t oldsize) +{ + void *ret; + size_t copysize; + + /* Avoid moving the allocation if the size class would not change. */ + + if (oldsize > arena_maxclass && + CHUNK_CEILING(size) == CHUNK_CEILING(oldsize)) { +#ifdef MALLOC_DECOMMIT + size_t psize = PAGE_CEILING(size); +#endif +#ifdef MALLOC_FILL + if (opt_junk && size < oldsize) { + memset((void *)((uintptr_t)ptr + size), 0x5a, oldsize + - size); + } +#endif +#ifdef MALLOC_DECOMMIT + if (psize < oldsize) { + extent_node_t *node, key; + + pages_decommit((void *)((uintptr_t)ptr + psize), + oldsize - psize); + + /* Update recorded size. */ + malloc_mutex_lock(&huge_mtx); + key.addr = __DECONST(void *, ptr); + node = extent_tree_ad_search(&huge_, &key); + assert(node != NULL); + assert(node->size == oldsize); +# ifdef MALLOC_STATS + huge_allocated -= oldsize - psize; +# endif + node->size = psize; + malloc_mutex_unlock(&huge_mtx); + } else if (psize > oldsize) { + extent_node_t *node, key; + + pages_commit((void *)((uintptr_t)ptr + oldsize), + psize - oldsize); + + /* Update recorded size. */ + malloc_mutex_lock(&huge_mtx); + key.addr = __DECONST(void *, ptr); + node = extent_tree_ad_search(&huge_, &key); + assert(node != NULL); + assert(node->size == oldsize); +# ifdef MALLOC_STATS + huge_allocated += psize - oldsize; +# endif + node->size = psize; + malloc_mutex_unlock(&huge_mtx); + } +#endif +#ifdef MALLOC_FILL + if (opt_zero && size > oldsize) { + memset((void *)((uintptr_t)ptr + oldsize), 0, size + - oldsize); + } +#endif + return (ptr); + } + + /* + * If we get here, then size and oldsize are different enough that we + * need to use a different size class. In that case, fall back to + * allocating new space and copying. + */ + ret = huge_malloc(size, false); + if (ret == NULL) + return (NULL); + + copysize = (size < oldsize) ? size : oldsize; +#ifdef VM_COPY_MIN + if (copysize >= VM_COPY_MIN) + pages_copy(ret, ptr, copysize); + else +#endif + memcpy(ret, ptr, copysize); + idalloc(ptr); + return (ret); +} + +static void +huge_dalloc(void *ptr) +{ + extent_node_t *node, key; + + malloc_mutex_lock(&huge_mtx); + + /* Extract from tree of huge allocations. */ + key.addr = ptr; + node = extent_tree_ad_search(&huge_, &key); + assert(node != NULL); + assert(node->addr == ptr); + extent_tree_ad_remove(&huge_, node); + +#ifdef MALLOC_STATS + huge_ndalloc++; + huge_allocated -= node->size; +#endif + + malloc_mutex_unlock(&huge_mtx); + + /* Unmap chunk. */ +#ifdef MALLOC_FILL + if (opt_junk) + memset(node->addr, 0x5a, node->size); +#endif +#ifdef MALLOC_DECOMMIT + chunk_dealloc(node->addr, CHUNK_CEILING(node->size)); +#else + chunk_dealloc(node->addr, node->size); +#endif + VALGRIND_FREELIKE_BLOCK(node->addr, 0); + + base_node_dealloc(node); +} + +#ifdef MOZ_MEMORY_BSD +static inline unsigned +malloc_ncpus(void) +{ + unsigned ret; + int mib[2]; + size_t len; + + mib[0] = CTL_HW; + mib[1] = HW_NCPU; + len = sizeof(ret); + if (sysctl(mib, 2, &ret, &len, (void *) 0, 0) == -1) { + /* Error. */ + return (1); + } + + return (ret); +} +#elif (defined(MOZ_MEMORY_LINUX)) +#include + +static inline unsigned +malloc_ncpus(void) +{ + unsigned ret; + int fd, nread, column; + char buf[1024]; + static const char matchstr[] = "processor\t:"; + int i; + + /* + * sysconf(3) would be the preferred method for determining the number + * of CPUs, but it uses malloc internally, which causes untennable + * recursion during malloc initialization. + */ + fd = open("/proc/cpuinfo", O_RDONLY); + if (fd == -1) + return (1); /* Error. */ + /* + * Count the number of occurrences of matchstr at the beginnings of + * lines. This treats hyperthreaded CPUs as multiple processors. + */ + column = 0; + ret = 0; + while (true) { + nread = read(fd, &buf, sizeof(buf)); + if (nread <= 0) + break; /* EOF or error. */ + for (i = 0;i < nread;i++) { + char c = buf[i]; + if (c == '\n') + column = 0; + else if (column != -1) { + if (c == matchstr[column]) { + column++; + if (column == sizeof(matchstr) - 1) { + column = -1; + ret++; + } + } else + column = -1; + } + } + } + + if (ret == 0) + ret = 1; /* Something went wrong in the parser. */ + close(fd); + + return (ret); +} +#elif (defined(MOZ_MEMORY_DARWIN)) +#include +#include + +static inline unsigned +malloc_ncpus(void) +{ + kern_return_t error; + natural_t n; + processor_info_array_t pinfo; + mach_msg_type_number_t pinfocnt; + + error = host_processor_info(mach_host_self(), PROCESSOR_BASIC_INFO, + &n, &pinfo, &pinfocnt); + if (error != KERN_SUCCESS) + return (1); /* Error. */ + else + return (n); +} +#elif (defined(MOZ_MEMORY_SOLARIS)) + +static inline unsigned +malloc_ncpus(void) +{ + return sysconf(_SC_NPROCESSORS_ONLN); +} +#else +static inline unsigned +malloc_ncpus(void) +{ + + /* + * We lack a way to determine the number of CPUs on this platform, so + * assume 1 CPU. + */ + return (1); +} +#endif + +static void +malloc_print_stats(void) +{ +#ifdef MALLOC_STATS + if (opt_print_stats) { + char s[UMAX2S_BUFSIZE]; + _malloc_message("___ Begin malloc statistics ___\n", "", "", + ""); + _malloc_message("Assertions ", +#ifdef NDEBUG + "disabled", +#else + "enabled", +#endif + "\n", ""); + _malloc_message("Boolean MALLOC_OPTIONS: ", + opt_abort ? "A" : "a", "", ""); +#ifdef MALLOC_FILL + _malloc_message(opt_junk ? "J" : "j", "", "", ""); +#endif +#ifdef MALLOC_PAGEFILE + _malloc_message(opt_pagefile ? "o" : "O", "", "", ""); +#endif + _malloc_message("P", "", "", ""); +#ifdef MALLOC_UTRACE + _malloc_message(opt_utrace ? "U" : "u", "", "", ""); +#endif +#ifdef MALLOC_SYSV + _malloc_message(opt_sysv ? "V" : "v", "", "", ""); +#endif +#ifdef MALLOC_XMALLOC + _malloc_message(opt_xmalloc ? "X" : "x", "", "", ""); +#endif +#ifdef MALLOC_FILL + _malloc_message(opt_zero ? "Z" : "z", "", "", ""); +#endif + _malloc_message("\n", "", "", ""); + + _malloc_message("CPUs: ", umax2s(ncpus, s), "\n", ""); + _malloc_message("Max arenas: ", umax2s(narenas, s), "\n", ""); +#ifdef MALLOC_BALANCE + _malloc_message("Arena balance threshold: ", + umax2s(opt_balance_threshold, s), "\n", ""); +#endif + _malloc_message("Pointer size: ", umax2s(sizeof(void *), s), + "\n", ""); + _malloc_message("Quantum size: ", umax2s(quantum, s), "\n", ""); + _malloc_message("Max small size: ", umax2s(small_max, s), "\n", + ""); + _malloc_message("Max dirty pages per arena: ", + umax2s(opt_dirty_max, s), "\n", ""); + + _malloc_message("Chunk size: ", umax2s(chunksize, s), "", ""); + _malloc_message(" (2^", umax2s(opt_chunk_2pow, s), ")\n", ""); + +#ifdef MALLOC_STATS + { + size_t allocated, mapped; +#ifdef MALLOC_BALANCE + uint64_t nbalance = 0; +#endif + unsigned i; + arena_t *arena; + + /* Calculate and print allocated/mapped stats. */ + + /* arenas. */ + for (i = 0, allocated = 0; i < narenas; i++) { + if (arenas[i] != NULL) { + malloc_spin_lock(&arenas[i]->lock); + allocated += + arenas[i]->stats.allocated_small; + allocated += + arenas[i]->stats.allocated_large; +#ifdef MALLOC_BALANCE + nbalance += arenas[i]->stats.nbalance; +#endif + malloc_spin_unlock(&arenas[i]->lock); + } + } + + /* huge/base. */ + malloc_mutex_lock(&huge_mtx); + allocated += huge_allocated; + mapped = stats_chunks.curchunks * chunksize; + malloc_mutex_unlock(&huge_mtx); + + malloc_mutex_lock(&base_mtx); + mapped += base_mapped; + malloc_mutex_unlock(&base_mtx); + +#ifdef xxMOZ_MEMORY_WINDOWS + malloc_printf("Allocated: %lu, mapped: %lu\n", + allocated, mapped); +#else + malloc_printf("Allocated: %zu, mapped: %zu\n", + allocated, mapped); +#endif + + malloc_mutex_lock(&reserve_mtx); + malloc_printf("Reserve: min " + "cur max\n"); +#ifdef xxMOZ_MEMORY_WINDOWS + malloc_printf(" %12lu %12lu %12lu\n", + CHUNK_CEILING(reserve_min) >> opt_chunk_2pow, + reserve_cur >> opt_chunk_2pow, + reserve_max >> opt_chunk_2pow); +#else + malloc_printf(" %12zu %12zu %12zu\n", + CHUNK_CEILING(reserve_min) >> opt_chunk_2pow, + reserve_cur >> opt_chunk_2pow, + reserve_max >> opt_chunk_2pow); +#endif + malloc_mutex_unlock(&reserve_mtx); + +#ifdef MALLOC_BALANCE + malloc_printf("Arena balance reassignments: %llu\n", + nbalance); +#endif + + /* Print chunk stats. */ + { + chunk_stats_t chunks_stats; + + malloc_mutex_lock(&huge_mtx); + chunks_stats = stats_chunks; + malloc_mutex_unlock(&huge_mtx); + + malloc_printf("chunks: nchunks " + "highchunks curchunks\n"); + malloc_printf(" %13llu%13lu%13lu\n", + chunks_stats.nchunks, + chunks_stats.highchunks, + chunks_stats.curchunks); + } + + /* Print chunk stats. */ + malloc_printf( + "huge: nmalloc ndalloc allocated\n"); +#ifdef xxMOZ_MEMORY_WINDOWS + malloc_printf(" %12llu %12llu %12lu\n", + huge_nmalloc, huge_ndalloc, huge_allocated); +#else + malloc_printf(" %12llu %12llu %12zu\n", + huge_nmalloc, huge_ndalloc, huge_allocated); +#endif + /* Print stats for each arena. */ + for (i = 0; i < narenas; i++) { + arena = arenas[i]; + if (arena != NULL) { + malloc_printf( + "\narenas[%u]:\n", i); + malloc_spin_lock(&arena->lock); + stats_print(arena); + malloc_spin_unlock(&arena->lock); + } + } + } +#endif /* #ifdef MALLOC_STATS */ + _malloc_message("--- End malloc statistics ---\n", "", "", ""); + } +#endif +} + +/* + * FreeBSD's pthreads implementation calls malloc(3), so the malloc + * implementation has to take pains to avoid infinite recursion during + * initialization. + */ +#if (defined(MOZ_MEMORY_WINDOWS) || defined(MOZ_MEMORY_DARWIN)) && !defined(MOZ_MEMORY_WINCE) +#define malloc_init() false +#else +static inline bool +malloc_init(void) +{ + + if (malloc_initialized == false) + return (malloc_init_hard()); + + return (false); +} +#endif + +#if !defined(MOZ_MEMORY_WINDOWS) || defined(MOZ_MEMORY_WINCE) +static +#endif +bool +malloc_init_hard(void) +{ + unsigned i; + char buf[PATH_MAX + 1]; + const char *opts; + long result; +#ifndef MOZ_MEMORY_WINDOWS + int linklen; +#endif + +#ifndef MOZ_MEMORY_WINDOWS + malloc_mutex_lock(&init_lock); +#endif + + if (malloc_initialized) { + /* + * Another thread initialized the allocator before this one + * acquired init_lock. + */ +#ifndef MOZ_MEMORY_WINDOWS + malloc_mutex_unlock(&init_lock); +#endif + return (false); + } + +#if defined(MOZ_MEMORY_WINDOWS) && !defined(NO_TLS) + /* get a thread local storage index */ + tlsIndex = TlsAlloc(); +#endif + + /* Get page size and number of CPUs */ +#ifdef MOZ_MEMORY_WINDOWS + { + SYSTEM_INFO info; + + GetSystemInfo(&info); + result = info.dwPageSize; + + pagesize = (unsigned) result; + + ncpus = info.dwNumberOfProcessors; + } +#else + ncpus = malloc_ncpus(); + + result = sysconf(_SC_PAGESIZE); + assert(result != -1); + + pagesize = (unsigned) result; +#endif + + /* + * We assume that pagesize is a power of 2 when calculating + * pagesize_mask and pagesize_2pow. + */ + assert(((result - 1) & result) == 0); + pagesize_mask = result - 1; + pagesize_2pow = ffs((int)result) - 1; + +#ifdef MALLOC_PAGEFILE + /* + * Determine where to create page files. It is insufficient to + * unconditionally use P_tmpdir (typically "/tmp"), since for some + * operating systems /tmp is a separate filesystem that is rather small. + * Therefore prefer, in order, the following locations: + * + * 1) MALLOC_TMPDIR + * 2) TMPDIR + * 3) P_tmpdir + */ + { + char *s; + size_t slen; + static const char suffix[] = "/jemalloc.XXXXXX"; + + if ((s = getenv("MALLOC_TMPDIR")) == NULL && (s = + getenv("TMPDIR")) == NULL) + s = P_tmpdir; + slen = strlen(s); + if (slen + sizeof(suffix) > sizeof(pagefile_templ)) { + _malloc_message(_getprogname(), + ": (malloc) Page file path too long\n", + "", ""); + abort(); + } + memcpy(pagefile_templ, s, slen); + memcpy(&pagefile_templ[slen], suffix, sizeof(suffix)); + } +#endif + + for (i = 0; i < 3; i++) { + unsigned j; + + /* Get runtime configuration. */ + switch (i) { + case 0: +#ifndef MOZ_MEMORY_WINDOWS + if ((linklen = readlink("/etc/malloc.conf", buf, + sizeof(buf) - 1)) != -1) { + /* + * Use the contents of the "/etc/malloc.conf" + * symbolic link's name. + */ + buf[linklen] = '\0'; + opts = buf; + } else +#endif + { + /* No configuration specified. */ + buf[0] = '\0'; + opts = buf; + } + break; + case 1: + if (issetugid() == 0 && (opts = + getenv("MALLOC_OPTIONS")) != NULL) { + /* + * Do nothing; opts is already initialized to + * the value of the MALLOC_OPTIONS environment + * variable. + */ + } else { + /* No configuration specified. */ + buf[0] = '\0'; + opts = buf; + } + break; + case 2: + if (_malloc_options != NULL) { + /* + * Use options that were compiled into the + * program. + */ + opts = _malloc_options; + } else { + /* No configuration specified. */ + buf[0] = '\0'; + opts = buf; + } + break; + default: + /* NOTREACHED */ + buf[0] = '\0'; + opts = buf; + assert(false); + } + + for (j = 0; opts[j] != '\0'; j++) { + unsigned k, nreps; + bool nseen; + + /* Parse repetition count, if any. */ + for (nreps = 0, nseen = false;; j++, nseen = true) { + switch (opts[j]) { + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + case '8': case '9': + nreps *= 10; + nreps += opts[j] - '0'; + break; + default: + goto MALLOC_OUT; + } + } +MALLOC_OUT: + if (nseen == false) + nreps = 1; + + for (k = 0; k < nreps; k++) { + switch (opts[j]) { + case 'a': + opt_abort = false; + break; + case 'A': + opt_abort = true; + break; + case 'b': +#ifdef MALLOC_BALANCE + opt_balance_threshold >>= 1; +#endif + break; + case 'B': +#ifdef MALLOC_BALANCE + if (opt_balance_threshold == 0) + opt_balance_threshold = 1; + else if ((opt_balance_threshold << 1) + > opt_balance_threshold) + opt_balance_threshold <<= 1; +#endif + break; + case 'f': + opt_dirty_max >>= 1; + break; + case 'F': + if (opt_dirty_max == 0) + opt_dirty_max = 1; + else if ((opt_dirty_max << 1) != 0) + opt_dirty_max <<= 1; + break; + case 'g': + opt_reserve_range_lshift--; + break; + case 'G': + opt_reserve_range_lshift++; + break; +#ifdef MALLOC_FILL + case 'j': + opt_junk = false; + break; + case 'J': + opt_junk = true; + break; +#endif + case 'k': + /* + * Chunks always require at least one + * header page, so chunks can never be + * smaller than two pages. + */ + if (opt_chunk_2pow > pagesize_2pow + 1) + opt_chunk_2pow--; + break; + case 'K': + if (opt_chunk_2pow + 1 < + (sizeof(size_t) << 3)) + opt_chunk_2pow++; + break; + case 'n': + opt_narenas_lshift--; + break; + case 'N': + opt_narenas_lshift++; + break; +#ifdef MALLOC_PAGEFILE + case 'o': + /* Do not over-commit. */ + opt_pagefile = true; + break; + case 'O': + /* Allow over-commit. */ + opt_pagefile = false; + break; +#endif + case 'p': + opt_print_stats = false; + break; + case 'P': + opt_print_stats = true; + break; + case 'q': + if (opt_quantum_2pow > QUANTUM_2POW_MIN) + opt_quantum_2pow--; + break; + case 'Q': + if (opt_quantum_2pow < pagesize_2pow - + 1) + opt_quantum_2pow++; + break; + case 'r': + opt_reserve_min_lshift--; + break; + case 'R': + opt_reserve_min_lshift++; + break; + case 's': + if (opt_small_max_2pow > + QUANTUM_2POW_MIN) + opt_small_max_2pow--; + break; + case 'S': + if (opt_small_max_2pow < pagesize_2pow + - 1) + opt_small_max_2pow++; + break; +#ifdef MALLOC_UTRACE + case 'u': + opt_utrace = false; + break; + case 'U': + opt_utrace = true; + break; +#endif +#ifdef MALLOC_SYSV + case 'v': + opt_sysv = false; + break; + case 'V': + opt_sysv = true; + break; +#endif +#ifdef MALLOC_XMALLOC + case 'x': + opt_xmalloc = false; + break; + case 'X': + opt_xmalloc = true; + break; +#endif +#ifdef MALLOC_FILL + case 'z': + opt_zero = false; + break; + case 'Z': + opt_zero = true; + break; +#endif + default: { + char cbuf[2]; + + cbuf[0] = opts[j]; + cbuf[1] = '\0'; + _malloc_message(_getprogname(), + ": (malloc) Unsupported character " + "in malloc options: '", cbuf, + "'\n"); + } + } + } + } + } + + /* Take care to call atexit() only once. */ + if (opt_print_stats) { +#ifndef MOZ_MEMORY_WINDOWS + /* Print statistics at exit. */ + atexit(malloc_print_stats); +#endif + } + +#if (!defined(MOZ_MEMORY_WINDOWS) && !defined(MOZ_MEMORY_DARWIN)) + /* Prevent potential deadlock on malloc locks after fork. */ + pthread_atfork(_malloc_prefork, _malloc_postfork, _malloc_postfork); +#endif + + /* Set variables according to the value of opt_small_max_2pow. */ + if (opt_small_max_2pow < opt_quantum_2pow) + opt_small_max_2pow = opt_quantum_2pow; + small_max = (1U << opt_small_max_2pow); + + /* Set bin-related variables. */ + bin_maxclass = (pagesize >> 1); + assert(opt_quantum_2pow >= TINY_MIN_2POW); + ntbins = opt_quantum_2pow - TINY_MIN_2POW; + assert(ntbins <= opt_quantum_2pow); + nqbins = (small_max >> opt_quantum_2pow); + nsbins = pagesize_2pow - opt_small_max_2pow - 1; + + /* Set variables according to the value of opt_quantum_2pow. */ + quantum = (1U << opt_quantum_2pow); + quantum_mask = quantum - 1; + if (ntbins > 0) + small_min = (quantum >> 1) + 1; + else + small_min = 1; + assert(small_min <= quantum); + + /* Set variables according to the value of opt_chunk_2pow. */ + chunksize = (1LU << opt_chunk_2pow); + chunksize_mask = chunksize - 1; + chunk_npages = (chunksize >> pagesize_2pow); + { + size_t header_size; + + /* + * Compute the header size such that it is large + * enough to contain the page map and enough nodes for the + * worst case: one node per non-header page plus one extra for + * situations where we briefly have one more node allocated + * than we will need. + */ + header_size = sizeof(arena_chunk_t) + + (sizeof(arena_chunk_map_t) * (chunk_npages - 1)); + arena_chunk_header_npages = (header_size >> pagesize_2pow) + + ((header_size & pagesize_mask) != 0); + } + arena_maxclass = chunksize - (arena_chunk_header_npages << + pagesize_2pow); + +#ifdef JEMALLOC_USES_MAP_ALIGN + /* + * When using MAP_ALIGN, the alignment parameter must be a power of two + * multiple of the system pagesize, or mmap will fail. + */ + assert((chunksize % pagesize) == 0); + assert((1 << (ffs(chunksize / pagesize) - 1)) == (chunksize/pagesize)); +#endif + + UTRACE(0, 0, 0); + +#ifdef MALLOC_STATS + memset(&stats_chunks, 0, sizeof(chunk_stats_t)); +#endif + + /* Various sanity checks that regard configuration. */ + assert(quantum >= sizeof(void *)); + assert(quantum <= pagesize); + assert(chunksize >= pagesize); + assert(quantum * 4 <= chunksize); + + /* Initialize chunks data. */ + malloc_mutex_init(&huge_mtx); + extent_tree_ad_new(&huge_); +#ifdef MALLOC_STATS + huge_nmalloc = 0; + huge_ndalloc = 0; + huge_allocated = 0; +#endif + + /* Initialize base allocation data structures. */ +#ifdef MALLOC_STATS + base_mapped = 0; +#endif + base_nodes = NULL; + base_reserve_regs = NULL; + malloc_mutex_init(&base_mtx); + +#ifdef MOZ_MEMORY_NARENAS_DEFAULT_ONE + narenas = 1; +#else + if (ncpus > 1) { + /* + * For SMP systems, create four times as many arenas as there + * are CPUs by default. + */ + opt_narenas_lshift += 2; + } + + /* Determine how many arenas to use. */ + narenas = ncpus; +#endif + if (opt_narenas_lshift > 0) { + if ((narenas << opt_narenas_lshift) > narenas) + narenas <<= opt_narenas_lshift; + /* + * Make sure not to exceed the limits of what base_alloc() can + * handle. + */ + if (narenas * sizeof(arena_t *) > chunksize) + narenas = chunksize / sizeof(arena_t *); + } else if (opt_narenas_lshift < 0) { + if ((narenas >> -opt_narenas_lshift) < narenas) + narenas >>= -opt_narenas_lshift; + /* Make sure there is at least one arena. */ + if (narenas == 0) + narenas = 1; + } +#ifdef MALLOC_BALANCE + assert(narenas != 0); + for (narenas_2pow = 0; + (narenas >> (narenas_2pow + 1)) != 0; + narenas_2pow++); +#endif + +#ifdef NO_TLS + if (narenas > 1) { + static const unsigned primes[] = {1, 3, 5, 7, 11, 13, 17, 19, + 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, + 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, + 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, + 223, 227, 229, 233, 239, 241, 251, 257, 263}; + unsigned nprimes, parenas; + + /* + * Pick a prime number of hash arenas that is more than narenas + * so that direct hashing of pthread_self() pointers tends to + * spread allocations evenly among the arenas. + */ + assert((narenas & 1) == 0); /* narenas must be even. */ + nprimes = (sizeof(primes) >> SIZEOF_INT_2POW); + parenas = primes[nprimes - 1]; /* In case not enough primes. */ + for (i = 1; i < nprimes; i++) { + if (primes[i] > narenas) { + parenas = primes[i]; + break; + } + } + narenas = parenas; + } +#endif + +#ifndef NO_TLS +# ifndef MALLOC_BALANCE + next_arena = 0; +# endif +#endif + + /* Allocate and initialize arenas. */ + arenas = (arena_t **)base_alloc(sizeof(arena_t *) * narenas); + if (arenas == NULL) { +#ifndef MOZ_MEMORY_WINDOWS + malloc_mutex_unlock(&init_lock); +#endif + return (true); + } + /* + * Zero the array. In practice, this should always be pre-zeroed, + * since it was just mmap()ed, but let's be sure. + */ + memset(arenas, 0, sizeof(arena_t *) * narenas); + + /* + * Initialize one arena here. The rest are lazily created in + * choose_arena_hard(). + */ + arenas_extend(0); + if (arenas[0] == NULL) { +#ifndef MOZ_MEMORY_WINDOWS + malloc_mutex_unlock(&init_lock); +#endif + return (true); + } +#ifndef NO_TLS + /* + * Assign the initial arena to the initial thread, in order to avoid + * spurious creation of an extra arena if the application switches to + * threaded mode. + */ +#ifdef MOZ_MEMORY_WINDOWS + TlsSetValue(tlsIndex, arenas[0]); +#else + arenas_map = arenas[0]; +#endif +#endif + + /* + * Seed here for the initial thread, since choose_arena_hard() is only + * called for other threads. The seed value doesn't really matter. + */ +#ifdef MALLOC_BALANCE + SPRN(balance, 42); +#endif + + malloc_spin_init(&arenas_lock); + +#ifdef MALLOC_VALIDATE + chunk_rtree = malloc_rtree_new((SIZEOF_PTR << 3) - opt_chunk_2pow); + if (chunk_rtree == NULL) + return (true); +#endif + + /* + * Configure and initialize the memory reserve. This needs to happen + * late during initialization, since chunks are allocated. + */ + malloc_mutex_init(&reserve_mtx); + reserve_min = 0; + reserve_cur = 0; + reserve_max = 0; + if (RESERVE_RANGE_2POW_DEFAULT + opt_reserve_range_lshift >= 0) { + reserve_max += chunksize << (RESERVE_RANGE_2POW_DEFAULT + + opt_reserve_range_lshift); + } + ql_new(&reserve_regs); + reserve_seq = 0; + extent_tree_szad_new(&reserve_chunks_szad); + extent_tree_ad_new(&reserve_chunks_ad); + if (RESERVE_MIN_2POW_DEFAULT + opt_reserve_min_lshift >= 0) { + reserve_min_set(chunksize << (RESERVE_MIN_2POW_DEFAULT + + opt_reserve_min_lshift)); + } + + malloc_initialized = true; +#ifndef MOZ_MEMORY_WINDOWS + malloc_mutex_unlock(&init_lock); +#endif + return (false); +} + +/* XXX Why not just expose malloc_print_stats()? */ +#ifdef MOZ_MEMORY_WINDOWS +void +malloc_shutdown() +{ + + malloc_print_stats(); +} +#endif + +/* + * End general internal functions. + */ +/******************************************************************************/ +/* + * Begin malloc(3)-compatible functions. + */ + +/* + * Inline the standard malloc functions if they are being subsumed by Darwin's + * zone infrastructure. + */ +#ifdef MOZ_MEMORY_DARWIN +# define ZONE_INLINE inline +#else +# define ZONE_INLINE +#endif + +/* Mangle standard interfaces on Darwin and Windows CE, + in order to avoid linking problems. */ +#if defined(MOZ_MEMORY_DARWIN) || defined(MOZ_MEMORY_WINCE) +#define malloc(a) moz_malloc(a) +#define valloc(a) moz_valloc(a) +#define calloc(a, b) moz_calloc(a, b) +#define realloc(a, b) moz_realloc(a, b) +#define free(a) moz_free(a) +#endif + +ZONE_INLINE +void * +malloc(size_t size) +{ + void *ret; + + if (malloc_init()) { + ret = NULL; + goto RETURN; + } + + if (size == 0) { +#ifdef MALLOC_SYSV + if (opt_sysv == false) +#endif + size = 1; +#ifdef MALLOC_SYSV + else { + ret = NULL; + goto RETURN; + } +#endif + } + + ret = imalloc(size); + +RETURN: + if (ret == NULL) { +#ifdef MALLOC_XMALLOC + if (opt_xmalloc) { + _malloc_message(_getprogname(), + ": (malloc) Error in malloc(): out of memory\n", "", + ""); + abort(); + } +#endif + errno = ENOMEM; + } + + UTRACE(0, size, ret); + return (ret); +} + +#ifdef MOZ_MEMORY_SOLARIS +# ifdef __SUNPRO_C +void * +memalign(size_t alignment, size_t size); +#pragma no_inline(memalign) +# elif (defined(__GNU_C__)) +__attribute__((noinline)) +# endif +#else +inline +#endif +void * +memalign(size_t alignment, size_t size) +{ + void *ret; + + assert(((alignment - 1) & alignment) == 0 && alignment >= + sizeof(void *)); + + if (malloc_init()) { + ret = NULL; + goto RETURN; + } + + ret = ipalloc(alignment, size); + +RETURN: +#ifdef MALLOC_XMALLOC + if (opt_xmalloc && ret == NULL) { + _malloc_message(_getprogname(), + ": (malloc) Error in memalign(): out of memory\n", "", ""); + abort(); + } +#endif + UTRACE(0, size, ret); + return (ret); +} + +ZONE_INLINE +int +posix_memalign(void **memptr, size_t alignment, size_t size) +{ + void *result; + + /* Make sure that alignment is a large enough power of 2. */ + if (((alignment - 1) & alignment) != 0 || alignment < sizeof(void *)) { +#ifdef MALLOC_XMALLOC + if (opt_xmalloc) { + _malloc_message(_getprogname(), + ": (malloc) Error in posix_memalign(): " + "invalid alignment\n", "", ""); + abort(); + } +#endif + return (EINVAL); + } + +#ifdef MOZ_MEMORY_DARWIN + result = moz_memalign(alignment, size); +#else + result = memalign(alignment, size); +#endif + if (result == NULL) + return (ENOMEM); + + *memptr = result; + return (0); +} + +ZONE_INLINE +void * +valloc(size_t size) +{ +#ifdef MOZ_MEMORY_DARWIN + return (moz_memalign(pagesize, size)); +#else + return (memalign(pagesize, size)); +#endif +} + +ZONE_INLINE +void * +calloc(size_t num, size_t size) +{ + void *ret; + size_t num_size; + + if (malloc_init()) { + num_size = 0; + ret = NULL; + goto RETURN; + } + + num_size = num * size; + if (num_size == 0) { +#ifdef MALLOC_SYSV + if ((opt_sysv == false) && ((num == 0) || (size == 0))) +#endif + num_size = 1; +#ifdef MALLOC_SYSV + else { + ret = NULL; + goto RETURN; + } +#endif + /* + * Try to avoid division here. We know that it isn't possible to + * overflow during multiplication if neither operand uses any of the + * most significant half of the bits in a size_t. + */ + } else if (((num | size) & (SIZE_T_MAX << (sizeof(size_t) << 2))) + && (num_size / size != num)) { + /* size_t overflow. */ + ret = NULL; + goto RETURN; + } + + ret = icalloc(num_size); + +RETURN: + if (ret == NULL) { +#ifdef MALLOC_XMALLOC + if (opt_xmalloc) { + _malloc_message(_getprogname(), + ": (malloc) Error in calloc(): out of memory\n", "", + ""); + abort(); + } +#endif + errno = ENOMEM; + } + + UTRACE(0, num_size, ret); + return (ret); +} + +ZONE_INLINE +void * +realloc(void *ptr, size_t size) +{ + void *ret; + + if (size == 0) { +#ifdef MALLOC_SYSV + if (opt_sysv == false) +#endif + size = 1; +#ifdef MALLOC_SYSV + else { + if (ptr != NULL) + idalloc(ptr); + ret = NULL; + goto RETURN; + } +#endif + } + + if (ptr != NULL) { + assert(malloc_initialized); + + ret = iralloc(ptr, size); + + if (ret == NULL) { +#ifdef MALLOC_XMALLOC + if (opt_xmalloc) { + _malloc_message(_getprogname(), + ": (malloc) Error in realloc(): out of " + "memory\n", "", ""); + abort(); + } +#endif + errno = ENOMEM; + } + } else { + if (malloc_init()) + ret = NULL; + else + ret = imalloc(size); + + if (ret == NULL) { +#ifdef MALLOC_XMALLOC + if (opt_xmalloc) { + _malloc_message(_getprogname(), + ": (malloc) Error in realloc(): out of " + "memory\n", "", ""); + abort(); + } +#endif + errno = ENOMEM; + } + } + +#ifdef MALLOC_SYSV +RETURN: +#endif + UTRACE(ptr, size, ret); + return (ret); +} + +ZONE_INLINE +void +free(void *ptr) +{ + + UTRACE(ptr, 0, 0); + if (ptr != NULL) { + assert(malloc_initialized); + + idalloc(ptr); + } +} + +/* + * End malloc(3)-compatible functions. + */ +/******************************************************************************/ +/* + * Begin non-standard functions. + */ + +size_t +malloc_usable_size(const void *ptr) +{ + +#ifdef MALLOC_VALIDATE + return (isalloc_validate(ptr)); +#else + assert(ptr != NULL); + + return (isalloc(ptr)); +#endif +} + +#ifdef MALLOC_STATS +void +jemalloc_stats(jemalloc_stats_t *stats) +{ + size_t i; + + assert(stats != NULL); + + /* + * Gather runtime settings. + */ + stats->opt_abort = opt_abort; + stats->opt_junk = +#ifdef MALLOC_FILL + opt_junk ? true : +#endif + false; + stats->opt_utrace = +#ifdef MALLOC_UTRACE + opt_utrace ? true : +#endif + false; + stats->opt_sysv = +#ifdef MALLOC_SYSV + opt_sysv ? true : +#endif + false; + stats->opt_xmalloc = +#ifdef MALLOC_XMALLOC + opt_xmalloc ? true : +#endif + false; + stats->opt_zero = +#ifdef MALLOC_FILL + opt_zero ? true : +#endif + false; + stats->narenas = narenas; + stats->balance_threshold = +#ifdef MALLOC_BALANCE + opt_balance_threshold +#else + SIZE_T_MAX +#endif + ; + stats->quantum = quantum; + stats->small_max = small_max; + stats->large_max = arena_maxclass; + stats->chunksize = chunksize; + stats->dirty_max = opt_dirty_max; + + malloc_mutex_lock(&reserve_mtx); + stats->reserve_min = reserve_min; + stats->reserve_max = reserve_max; + stats->reserve_cur = reserve_cur; + malloc_mutex_unlock(&reserve_mtx); + + /* + * Gather current memory usage statistics. + */ + stats->mapped = 0; + stats->committed = 0; + stats->allocated = 0; + stats->dirty = 0; + + /* Get huge mapped/allocated. */ + malloc_mutex_lock(&huge_mtx); + stats->mapped += stats_chunks.curchunks * chunksize; +#ifdef MALLOC_DECOMMIT + stats->committed += huge_allocated; +#endif + stats->allocated += huge_allocated; + malloc_mutex_unlock(&huge_mtx); + + /* Get base mapped. */ + malloc_mutex_lock(&base_mtx); + stats->mapped += base_mapped; +#ifdef MALLOC_DECOMMIT + stats->committed += base_mapped; +#endif + malloc_mutex_unlock(&base_mtx); + + /* Iterate over arenas and their chunks. */ + for (i = 0; i < narenas; i++) { + arena_t *arena = arenas[i]; + if (arena != NULL) { + arena_chunk_t *chunk; + + malloc_spin_lock(&arena->lock); + stats->allocated += arena->stats.allocated_small; + stats->allocated += arena->stats.allocated_large; +#ifdef MALLOC_DECOMMIT + rb_foreach_begin(arena_chunk_t, link_dirty, + &arena->chunks_dirty, chunk) { + size_t j; + + for (j = 0; j < chunk_npages; j++) { + if ((chunk->map[j].bits & + CHUNK_MAP_DECOMMITTED) == 0) + stats->committed += pagesize; + } + } rb_foreach_end(arena_chunk_t, link_dirty, + &arena->chunks_dirty, chunk) +#endif + stats->dirty += (arena->ndirty << pagesize_2pow); + malloc_spin_unlock(&arena->lock); + } + } + +#ifndef MALLOC_DECOMMIT + stats->committed = stats->mapped; +#endif +} +#endif + +#ifdef MALLOC_XMALLOC +void * +xmalloc(size_t size) +{ + void *ret; + + if (malloc_init()) + reserve_fail(size, "xmalloc"); + + if (size == 0) { +#ifdef MALLOC_SYSV + if (opt_sysv == false) +#endif + size = 1; +#ifdef MALLOC_SYSV + else { + _malloc_message(_getprogname(), + ": (malloc) Error in xmalloc(): ", + "invalid size 0", "\n"); + abort(); + } +#endif + } + + ret = imalloc(size); + if (ret == NULL) { + uint64_t seq = 0; + + do { + seq = reserve_crit(size, "xmalloc", seq); + ret = imalloc(size); + } while (ret == NULL); + } + + UTRACE(0, size, ret); + return (ret); +} + +void * +xcalloc(size_t num, size_t size) +{ + void *ret; + size_t num_size; + + num_size = num * size; + if (malloc_init()) + reserve_fail(num_size, "xcalloc"); + + if (num_size == 0) { +#ifdef MALLOC_SYSV + if ((opt_sysv == false) && ((num == 0) || (size == 0))) +#endif + num_size = 1; +#ifdef MALLOC_SYSV + else { + _malloc_message(_getprogname(), + ": (malloc) Error in xcalloc(): ", + "invalid size 0", "\n"); + abort(); + } +#endif + /* + * Try to avoid division here. We know that it isn't possible to + * overflow during multiplication if neither operand uses any of the + * most significant half of the bits in a size_t. + */ + } else if (((num | size) & (SIZE_T_MAX << (sizeof(size_t) << 2))) + && (num_size / size != num)) { + /* size_t overflow. */ + _malloc_message(_getprogname(), + ": (malloc) Error in xcalloc(): ", + "size overflow", "\n"); + abort(); + } + + ret = icalloc(num_size); + if (ret == NULL) { + uint64_t seq = 0; + + do { + seq = reserve_crit(num_size, "xcalloc", seq); + ret = icalloc(num_size); + } while (ret == NULL); + } + + UTRACE(0, num_size, ret); + return (ret); +} + +void * +xrealloc(void *ptr, size_t size) +{ + void *ret; + + if (size == 0) { +#ifdef MALLOC_SYSV + if (opt_sysv == false) +#endif + size = 1; +#ifdef MALLOC_SYSV + else { + if (ptr != NULL) + idalloc(ptr); + _malloc_message(_getprogname(), + ": (malloc) Error in xrealloc(): ", + "invalid size 0", "\n"); + abort(); + } +#endif + } + + if (ptr != NULL) { + assert(malloc_initialized); + + ret = iralloc(ptr, size); + if (ret == NULL) { + uint64_t seq = 0; + + do { + seq = reserve_crit(size, "xrealloc", seq); + ret = iralloc(ptr, size); + } while (ret == NULL); + } + } else { + if (malloc_init()) + reserve_fail(size, "xrealloc"); + + ret = imalloc(size); + if (ret == NULL) { + uint64_t seq = 0; + + do { + seq = reserve_crit(size, "xrealloc", seq); + ret = imalloc(size); + } while (ret == NULL); + } + } + + UTRACE(ptr, size, ret); + return (ret); +} + +void * +xmemalign(size_t alignment, size_t size) +{ + void *ret; + + assert(((alignment - 1) & alignment) == 0 && alignment >= + sizeof(void *)); + + if (malloc_init()) + reserve_fail(size, "xmemalign"); + + ret = ipalloc(alignment, size); + if (ret == NULL) { + uint64_t seq = 0; + + do { + seq = reserve_crit(size, "xmemalign", seq); + ret = ipalloc(alignment, size); + } while (ret == NULL); + } + + UTRACE(0, size, ret); + return (ret); +} +#endif + +static void +reserve_shrink(void) +{ + extent_node_t *node; + + assert(reserve_cur > reserve_max); +#ifdef MALLOC_DEBUG + { + extent_node_t *node; + size_t reserve_size; + + reserve_size = 0; + rb_foreach_begin(extent_node_t, link_szad, &reserve_chunks_szad, + node) { + reserve_size += node->size; + } rb_foreach_end(extent_node_t, link_szad, &reserve_chunks_szad, + node) + assert(reserve_size == reserve_cur); + + reserve_size = 0; + rb_foreach_begin(extent_node_t, link_ad, &reserve_chunks_ad, + node) { + reserve_size += node->size; + } rb_foreach_end(extent_node_t, link_ad, &reserve_chunks_ad, + node) + assert(reserve_size == reserve_cur); + } +#endif + + /* Discard chunks until the the reserve is below the size limit. */ + rb_foreach_reverse_begin(extent_node_t, link_ad, &reserve_chunks_ad, + node) { +#ifndef MALLOC_DECOMMIT + if (node->size <= reserve_cur - reserve_max) { +#endif + extent_node_t *tnode = extent_tree_ad_prev( + &reserve_chunks_ad, node); + +#ifdef MALLOC_DECOMMIT + assert(node->size <= reserve_cur - reserve_max); +#endif + + /* Discard the entire [multi-]chunk. */ + extent_tree_szad_remove(&reserve_chunks_szad, node); + extent_tree_ad_remove(&reserve_chunks_ad, node); + reserve_cur -= node->size; + pages_unmap(node->addr, node->size); +#ifdef MALLOC_STATS + stats_chunks.curchunks -= (node->size / chunksize); +#endif + base_node_dealloc(node); + if (reserve_cur == reserve_max) + break; + + rb_foreach_reverse_prev(extent_node_t, link_ad, + extent_ad_comp, &reserve_chunks_ad, tnode); +#ifndef MALLOC_DECOMMIT + } else { + /* Discard the end of the multi-chunk. */ + extent_tree_szad_remove(&reserve_chunks_szad, node); + node->size -= reserve_cur - reserve_max; + extent_tree_szad_insert(&reserve_chunks_szad, node); + pages_unmap((void *)((uintptr_t)node->addr + + node->size), reserve_cur - reserve_max); +#ifdef MALLOC_STATS + stats_chunks.curchunks -= ((reserve_cur - reserve_max) / + chunksize); +#endif + reserve_cur = reserve_max; + break; + } +#endif + assert(reserve_cur > reserve_max); + } rb_foreach_reverse_end(extent_node_t, link_ad, &reserve_chunks_ad, + node) +} + +/* Send a condition notification. */ +static uint64_t +reserve_notify(reserve_cnd_t cnd, size_t size, uint64_t seq) +{ + reserve_reg_t *reg; + + /* seq is used to keep track of distinct condition-causing events. */ + if (seq == 0) { + /* Allocate new sequence number. */ + reserve_seq++; + seq = reserve_seq; + } + + /* + * Advance to the next callback registration and send a notification, + * unless one has already been sent for this condition-causing event. + */ + reg = ql_first(&reserve_regs); + if (reg == NULL) + return (0); + ql_first(&reserve_regs) = ql_next(&reserve_regs, reg, link); + if (reg->seq == seq) + return (0); + reg->seq = seq; + malloc_mutex_unlock(&reserve_mtx); + reg->cb(reg->ctx, cnd, size); + malloc_mutex_lock(&reserve_mtx); + + return (seq); +} + +/* Allocation failure due to OOM. Try to free some memory via callbacks. */ +static uint64_t +reserve_crit(size_t size, const char *fname, uint64_t seq) +{ + + /* + * Send one condition notification. Iteration is handled by the + * caller of this function. + */ + malloc_mutex_lock(&reserve_mtx); + seq = reserve_notify(RESERVE_CND_CRIT, size, seq); + malloc_mutex_unlock(&reserve_mtx); + + /* If no notification could be sent, then no further recourse exists. */ + if (seq == 0) + reserve_fail(size, fname); + + return (seq); +} + +/* Permanent allocation failure due to OOM. */ +static void +reserve_fail(size_t size, const char *fname) +{ + uint64_t seq = 0; + + /* Send fail notifications. */ + malloc_mutex_lock(&reserve_mtx); + do { + seq = reserve_notify(RESERVE_CND_FAIL, size, seq); + } while (seq != 0); + malloc_mutex_unlock(&reserve_mtx); + + /* Terminate the application. */ + _malloc_message(_getprogname(), + ": (malloc) Error in ", fname, "(): out of memory\n"); + abort(); +} + +bool +reserve_cb_register(reserve_cb_t *cb, void *ctx) +{ + reserve_reg_t *reg = base_reserve_reg_alloc(); + if (reg == NULL) + return (true); + + ql_elm_new(reg, link); + reg->cb = cb; + reg->ctx = ctx; + reg->seq = 0; + + malloc_mutex_lock(&reserve_mtx); + ql_head_insert(&reserve_regs, reg, link); + malloc_mutex_unlock(&reserve_mtx); + + return (false); +} + +bool +reserve_cb_unregister(reserve_cb_t *cb, void *ctx) +{ + reserve_reg_t *reg = NULL; + + malloc_mutex_lock(&reserve_mtx); + ql_foreach(reg, &reserve_regs, link) { + if (reg->cb == cb && reg->ctx == ctx) { + ql_remove(&reserve_regs, reg, link); + break; + } + } + malloc_mutex_unlock(&reserve_mtx); + + if (reg != NULL) + base_reserve_reg_dealloc(reg); + return (false); + return (true); +} + +size_t +reserve_cur_get(void) +{ + size_t ret; + + malloc_mutex_lock(&reserve_mtx); + ret = reserve_cur; + malloc_mutex_unlock(&reserve_mtx); + + return (ret); +} + +size_t +reserve_min_get(void) +{ + size_t ret; + + malloc_mutex_lock(&reserve_mtx); + ret = reserve_min; + malloc_mutex_unlock(&reserve_mtx); + + return (ret); +} + +bool +reserve_min_set(size_t min) +{ + + min = CHUNK_CEILING(min); + + malloc_mutex_lock(&reserve_mtx); + /* Keep |reserve_max - reserve_min| the same. */ + if (min < reserve_min) { + reserve_max -= reserve_min - min; + reserve_min = min; + } else { + /* Protect against wrap-around. */ + if (reserve_max + min - reserve_min < reserve_max) { + reserve_min = SIZE_T_MAX - (reserve_max - reserve_min) + - chunksize + 1; + reserve_max = SIZE_T_MAX - chunksize + 1; + } else { + reserve_max += min - reserve_min; + reserve_min = min; + } + } + + /* Resize the reserve if necessary. */ + if (reserve_cur < reserve_min) { + size_t size = reserve_min - reserve_cur; + + /* Force the reserve to grow by allocating/deallocating. */ + malloc_mutex_unlock(&reserve_mtx); +#ifdef MALLOC_DECOMMIT + { + void **chunks; + size_t i, n; + + n = size >> opt_chunk_2pow; + chunks = (void**)imalloc(n * sizeof(void *)); + if (chunks == NULL) + return (true); + for (i = 0; i < n; i++) { + chunks[i] = huge_malloc(chunksize, false); + if (chunks[i] == NULL) { + size_t j; + + for (j = 0; j < i; j++) { + huge_dalloc(chunks[j]); + } + idalloc(chunks); + return (true); + } + } + for (i = 0; i < n; i++) + huge_dalloc(chunks[i]); + idalloc(chunks); + } +#else + { + void *x = huge_malloc(size, false); + if (x == NULL) { + return (true); + } + huge_dalloc(x); + } +#endif + } else if (reserve_cur > reserve_max) { + reserve_shrink(); + malloc_mutex_unlock(&reserve_mtx); + } else + malloc_mutex_unlock(&reserve_mtx); + + return (false); +} + +#ifdef MOZ_MEMORY_WINDOWS +void* +_recalloc(void *ptr, size_t count, size_t size) +{ + size_t oldsize = (ptr != NULL) ? isalloc(ptr) : 0; + size_t newsize = count * size; + + /* + * In order for all trailing bytes to be zeroed, the caller needs to + * use calloc(), followed by recalloc(). However, the current calloc() + * implementation only zeros the bytes requested, so if recalloc() is + * to work 100% correctly, calloc() will need to change to zero + * trailing bytes. + */ + + ptr = realloc(ptr, newsize); + if (ptr != NULL && oldsize < newsize) { + memset((void *)((uintptr_t)ptr + oldsize), 0, newsize - + oldsize); + } + + return ptr; +} + +/* + * This impl of _expand doesn't ever actually expand or shrink blocks: it + * simply replies that you may continue using a shrunk block. + */ +void* +_expand(void *ptr, size_t newsize) +{ + if (isalloc(ptr) >= newsize) + return ptr; + + return NULL; +} + +size_t +_msize(const void *ptr) +{ + + return malloc_usable_size(ptr); +} +#endif + +/* + * End non-standard functions. + */ +/******************************************************************************/ +/* + * Begin library-private functions, used by threading libraries for protection + * of malloc during fork(). These functions are only called if the program is + * running in threaded mode, so there is no need to check whether the program + * is threaded here. + */ + +void +_malloc_prefork(void) +{ + unsigned i; + + /* Acquire all mutexes in a safe order. */ + + malloc_spin_lock(&arenas_lock); + for (i = 0; i < narenas; i++) { + if (arenas[i] != NULL) + malloc_spin_lock(&arenas[i]->lock); + } + malloc_spin_unlock(&arenas_lock); + + malloc_mutex_lock(&base_mtx); + + malloc_mutex_lock(&huge_mtx); +} + +void +_malloc_postfork(void) +{ + unsigned i; + + /* Release all mutexes, now that fork() has completed. */ + + malloc_mutex_unlock(&huge_mtx); + + malloc_mutex_unlock(&base_mtx); + + malloc_spin_lock(&arenas_lock); + for (i = 0; i < narenas; i++) { + if (arenas[i] != NULL) + malloc_spin_unlock(&arenas[i]->lock); + } + malloc_spin_unlock(&arenas_lock); +} + +/* + * End library-private functions. + */ +/******************************************************************************/ + +#ifdef MOZ_MEMORY_DARWIN +static malloc_zone_t zone; +static struct malloc_introspection_t zone_introspect; + +static size_t +zone_size(malloc_zone_t *zone, void *ptr) +{ + + /* + * There appear to be places within Darwin (such as setenv(3)) that + * cause calls to this function with pointers that *no* zone owns. If + * we knew that all pointers were owned by *some* zone, we could split + * our zone into two parts, and use one as the default allocator and + * the other as the default deallocator/reallocator. Since that will + * not work in practice, we must check all pointers to assure that they + * reside within a mapped chunk before determining size. + */ + return (isalloc_validate(ptr)); +} + +static void * +zone_malloc(malloc_zone_t *zone, size_t size) +{ + + return (malloc(size)); +} + +static void * +zone_calloc(malloc_zone_t *zone, size_t num, size_t size) +{ + + return (calloc(num, size)); +} + +static void * +zone_valloc(malloc_zone_t *zone, size_t size) +{ + void *ret = NULL; /* Assignment avoids useless compiler warning. */ + + posix_memalign(&ret, pagesize, size); + + return (ret); +} + +static void +zone_free(malloc_zone_t *zone, void *ptr) +{ + + free(ptr); +} + +static void * +zone_realloc(malloc_zone_t *zone, void *ptr, size_t size) +{ + + return (realloc(ptr, size)); +} + +static void * +zone_destroy(malloc_zone_t *zone) +{ + + /* This function should never be called. */ + assert(false); + return (NULL); +} + +static size_t +zone_good_size(malloc_zone_t *zone, size_t size) +{ + size_t ret; + void *p; + + /* + * Actually create an object of the appropriate size, then find out + * how large it could have been without moving up to the next size + * class. + */ + p = malloc(size); + if (p != NULL) { + ret = isalloc(p); + free(p); + } else + ret = size; + + return (ret); +} + +static void +zone_force_lock(malloc_zone_t *zone) +{ + + _malloc_prefork(); +} + +static void +zone_force_unlock(malloc_zone_t *zone) +{ + + _malloc_postfork(); +} + +static malloc_zone_t * +create_zone(void) +{ + + assert(malloc_initialized); + + zone.size = (void *)zone_size; + zone.malloc = (void *)zone_malloc; + zone.calloc = (void *)zone_calloc; + zone.valloc = (void *)zone_valloc; + zone.free = (void *)zone_free; + zone.realloc = (void *)zone_realloc; + zone.destroy = (void *)zone_destroy; + zone.zone_name = "jemalloc_zone"; + zone.batch_malloc = NULL; + zone.batch_free = NULL; + zone.introspect = &zone_introspect; + + zone_introspect.enumerator = NULL; + zone_introspect.good_size = (void *)zone_good_size; + zone_introspect.check = NULL; + zone_introspect.print = NULL; + zone_introspect.log = NULL; + zone_introspect.force_lock = (void *)zone_force_lock; + zone_introspect.force_unlock = (void *)zone_force_unlock; + zone_introspect.statistics = NULL; + + return (&zone); +} + +__attribute__((constructor)) +void +jemalloc_darwin_init(void) +{ + extern unsigned malloc_num_zones; + extern malloc_zone_t **malloc_zones; + + if (malloc_init_hard()) + abort(); + + /* + * The following code is *not* thread-safe, so it's critical that + * initialization be manually triggered. + */ + + /* Register the custom zones. */ + malloc_zone_register(create_zone()); + assert(malloc_zones[malloc_num_zones - 1] == &zone); + + /* + * Shift malloc_zones around so that zone is first, which makes it the + * default zone. + */ + assert(malloc_num_zones > 1); + memmove(&malloc_zones[1], &malloc_zones[0], + sizeof(malloc_zone_t *) * (malloc_num_zones - 1)); + malloc_zones[0] = &zone; +} +#endif diff --git a/apilibs/kexbasen/kernel32/jemalloc/jemalloc.h b/apilibs/kexbasen/kernel32/jemalloc/jemalloc.h new file mode 100755 index 0000000..29987ef --- /dev/null +++ b/apilibs/kexbasen/kernel32/jemalloc/jemalloc.h @@ -0,0 +1,177 @@ +#ifndef MOZ_MEMORY_WINDOWS +# include +#else +# include +# ifndef bool +# define bool BOOL +# endif +#endif + +extern const char *_malloc_options; + +/* + * jemalloc_stats() is not a stable interface. When using jemalloc_stats_t, be + * sure that the compiled results of jemalloc.c are in sync with this header + * file. + */ +typedef struct { + /* + * Run-time configuration settings. + */ + bool opt_abort; /* abort(3) on error? */ + bool opt_junk; /* Fill allocated/free memory with 0xa5/0x5a? */ + bool opt_utrace; /* Trace all allocation events? */ + bool opt_sysv; /* SysV semantics? */ + bool opt_xmalloc; /* abort(3) on OOM? */ + bool opt_zero; /* Fill allocated memory with 0x0? */ + size_t narenas; /* Number of arenas. */ + size_t balance_threshold; /* Arena contention rebalance threshold. */ + size_t quantum; /* Allocation quantum. */ + size_t small_max; /* Max quantum-spaced allocation size. */ + size_t large_max; /* Max sub-chunksize allocation size. */ + size_t chunksize; /* Size of each virtual memory mapping. */ + size_t dirty_max; /* Max dirty pages per arena. */ + size_t reserve_min; /* reserve_low callback threshold. */ + size_t reserve_max; /* Maximum reserve size before unmapping. */ + + /* + * Current memory usage statistics. + */ + size_t mapped; /* Bytes mapped (not necessarily committed). */ + size_t committed; /* Bytes committed (readable/writable). */ + size_t allocated; /* Bytes allocted (in use by application). */ + size_t dirty; /* Bytes dirty (committed unused pages). */ + size_t reserve_cur; /* Current memory reserve. */ +} jemalloc_stats_t; + +#ifndef MOZ_MEMORY_DARWIN +void *malloc(size_t size); +void *valloc(size_t size); +void *calloc(size_t num, size_t size); +void *realloc(void *ptr, size_t size); +void free(void *ptr); +#endif + +int posix_memalign(void **memptr, size_t alignment, size_t size); +void *memalign(size_t alignment, size_t size); +size_t malloc_usable_size(const void *ptr); +void jemalloc_stats(jemalloc_stats_t *stats); + +/* The x*() functions never return NULL. */ +void *xmalloc(size_t size); +void *xcalloc(size_t num, size_t size); +void *xrealloc(void *ptr, size_t size); +void *xmemalign(size_t alignment, size_t size); + +/* + * The allocator maintains a memory reserve that is used to satisfy allocation + * requests when no additional memory can be acquired from the operating + * system. Under normal operating conditions, the reserve size is at least + * reserve_min bytes. If the reserve is depleted or insufficient to satisfy an + * allocation request, then condition notifications are sent to one or more of + * the registered callback functions: + * + * RESERVE_CND_LOW: The reserve had to be used to satisfy an allocation + * request, which dropped the reserve size below the + * minimum. The callee should try to free memory in order + * to restore the reserve. + * + * RESERVE_CND_CRIT: The reserve was not large enough to satisfy a pending + * allocation request. Some callee must free adequate + * memory in order to prevent application failure (unless + * the condition spontaneously desists due to concurrent + * deallocation). + * + * RESERVE_CND_FAIL: An allocation request could not be satisfied, despite all + * attempts. The allocator is about to terminate the + * application. + * + * The order in which the callback functions are called is only loosely + * specified: in the absence of interposing callback + * registrations/unregistrations, enabled callbacks will be called in an + * arbitrary round-robin order. + * + * Condition notifications are sent to callbacks only while conditions exist. + * For example, just before the allocator sends a RESERVE_CND_LOW condition + * notification to a callback, the reserve is in fact depleted. However, due + * to allocator concurrency, the reserve may have been restored by the time the + * callback function executes. Furthermore, if the reserve is restored at some + * point during the delivery of condition notifications to callbacks, no + * further deliveries will occur, since the condition no longer exists. + * + * Callback functions can freely call back into the allocator (i.e. the + * allocator releases all internal resources before calling each callback + * function), though allocation is discouraged, since recursive callbacks are + * likely to result, which places extra burden on the application to avoid + * deadlock. + * + * Callback functions must be thread-safe, since it is possible that multiple + * threads will call into the same callback function concurrently. + */ + +/* Memory reserve condition types. */ +typedef enum { + RESERVE_CND_LOW, + RESERVE_CND_CRIT, + RESERVE_CND_FAIL +} reserve_cnd_t; + +/* + * Reserve condition notification callback function type definition. + * + * Inputs: + * ctx: Opaque application data, as passed to reserve_cb_register(). + * cnd: Condition type being delivered. + * size: Allocation request size for the allocation that caused the condition. + */ +typedef void reserve_cb_t(void *ctx, reserve_cnd_t cnd, size_t size); + +/* + * Register a callback function. + * + * Inputs: + * cb: Callback function pointer. + * ctx: Opaque application data, passed to cb(). + * + * Output: + * ret: If true, failure due to OOM; success otherwise. + */ +bool reserve_cb_register(reserve_cb_t *cb, void *ctx); + +/* + * Unregister a callback function. + * + * Inputs: + * cb: Callback function pointer. + * ctx: Opaque application data, same as that passed to reserve_cb_register(). + * + * Output: + * ret: False upon success, true if the {cb,ctx} registration could not be + * found. + */ +bool reserve_cb_unregister(reserve_cb_t *cb, void *ctx); + +/* + * Get the current reserve size. + * + * ret: Current reserve size. + */ +size_t reserve_cur_get(void); + +/* + * Get the minimum acceptable reserve size. If the reserve drops below this + * value, the RESERVE_CND_LOW condition notification is sent to the callbacks. + * + * ret: Minimum acceptable reserve size. + */ +size_t reserve_min_get(void); + +/* + * Set the minimum acceptable reserve size. + * + * min: Reserve threshold. This value may be internally rounded up. + * ret: False if the reserve was successfully resized; true otherwise. Note + * that failure to resize the reserve also results in a RESERVE_CND_LOW + * condition. + */ +bool reserve_min_set(size_t min); diff --git a/apilibs/kexbasen/kernel32/jemalloc/ql.h b/apilibs/kexbasen/kernel32/jemalloc/ql.h new file mode 100755 index 0000000..9b245b1 --- /dev/null +++ b/apilibs/kexbasen/kernel32/jemalloc/ql.h @@ -0,0 +1,114 @@ +/****************************************************************************** + * + * Copyright (C) 2002 Jason Evans . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice(s), this list of conditions and the following disclaimer + * unmodified other than the allowable addition of one or more + * copyright notices. + * 2. Redistributions in binary form must reproduce the above copyright + * notice(s), this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ******************************************************************************/ + +/* + * List definitions. + */ +#define ql_head(a_type) \ +struct { \ + a_type *qlh_first; \ +} + +#define ql_head_initializer(a_head) {NULL} + +#define ql_elm(a_type) qr(a_type) + +/* List functions. */ +#define ql_new(a_head) do { \ + (a_head)->qlh_first = NULL; \ +} while (0) + +#define ql_elm_new(a_elm, a_field) qr_new((a_elm), a_field) + +#define ql_first(a_head) ((a_head)->qlh_first) + +#define ql_last(a_head, a_field) \ + ((ql_first(a_head) != NULL) \ + ? qr_prev(ql_first(a_head), a_field) : NULL) + +#define ql_next(a_head, a_elm, a_field) \ + ((ql_last(a_head, a_field) != (a_elm)) \ + ? qr_next((a_elm), a_field) : NULL) + +#define ql_prev(a_head, a_elm, a_field) \ + ((ql_first(a_head) != (a_elm)) ? qr_prev((a_elm), a_field) \ + : NULL) + +#define ql_before_insert(a_head, a_qlelm, a_elm, a_field) do { \ + qr_before_insert((a_qlelm), (a_elm), a_field); \ + if (ql_first(a_head) == (a_qlelm)) { \ + ql_first(a_head) = (a_elm); \ + } \ +} while (0) + +#define ql_after_insert(a_qlelm, a_elm, a_field) \ + qr_after_insert((a_qlelm), (a_elm), a_field) + +#define ql_head_insert(a_head, a_elm, a_field) do { \ + if (ql_first(a_head) != NULL) { \ + qr_before_insert(ql_first(a_head), (a_elm), a_field); \ + } \ + ql_first(a_head) = (a_elm); \ +} while (0) + +#define ql_tail_insert(a_head, a_elm, a_field) do { \ + if (ql_first(a_head) != NULL) { \ + qr_before_insert(ql_first(a_head), (a_elm), a_field); \ + } \ + ql_first(a_head) = qr_next((a_elm), a_field); \ +} while (0) + +#define ql_remove(a_head, a_elm, a_field) do { \ + if (ql_first(a_head) == (a_elm)) { \ + ql_first(a_head) = qr_next(ql_first(a_head), a_field); \ + } \ + if (ql_first(a_head) != (a_elm)) { \ + qr_remove((a_elm), a_field); \ + } else { \ + ql_first(a_head) = NULL; \ + } \ +} while (0) + +#define ql_head_remove(a_head, a_type, a_field) do { \ + a_type *t = ql_first(a_head); \ + ql_remove((a_head), t, a_field); \ +} while (0) + +#define ql_tail_remove(a_head, a_type, a_field) do { \ + a_type *t = ql_last(a_head, a_field); \ + ql_remove((a_head), t, a_field); \ +} while (0) + +#define ql_foreach(a_var, a_head, a_field) \ + qr_foreach((a_var), ql_first(a_head), a_field) + +#define ql_reverse_foreach(a_var, a_head, a_field) \ + qr_reverse_foreach((a_var), ql_first(a_head), a_field) diff --git a/apilibs/kexbasen/kernel32/jemalloc/qr.h b/apilibs/kexbasen/kernel32/jemalloc/qr.h new file mode 100755 index 0000000..d52f905 --- /dev/null +++ b/apilibs/kexbasen/kernel32/jemalloc/qr.h @@ -0,0 +1,98 @@ +/****************************************************************************** + * + * Copyright (C) 2002 Jason Evans . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice(s), this list of conditions and the following disclaimer + * unmodified other than the allowable addition of one or more + * copyright notices. + * 2. Redistributions in binary form must reproduce the above copyright + * notice(s), this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ******************************************************************************/ + +/* Ring definitions. */ +#define qr(a_type) \ +struct { \ + a_type *qre_next; \ + a_type *qre_prev; \ +} + +/* Ring functions. */ +#define qr_new(a_qr, a_field) do { \ + (a_qr)->a_field.qre_next = (a_qr); \ + (a_qr)->a_field.qre_prev = (a_qr); \ +} while (0) + +#define qr_next(a_qr, a_field) ((a_qr)->a_field.qre_next) + +#define qr_prev(a_qr, a_field) ((a_qr)->a_field.qre_prev) + +#define qr_before_insert(a_qrelm, a_qr, a_field) do { \ + (a_qr)->a_field.qre_prev = (a_qrelm)->a_field.qre_prev; \ + (a_qr)->a_field.qre_next = (a_qrelm); \ + (a_qr)->a_field.qre_prev->a_field.qre_next = (a_qr); \ + (a_qrelm)->a_field.qre_prev = (a_qr); \ +} while (0) + +#define qr_after_insert(a_qrelm, a_qr, a_field) \ + do \ + { \ + (a_qr)->a_field.qre_next = (a_qrelm)->a_field.qre_next; \ + (a_qr)->a_field.qre_prev = (a_qrelm); \ + (a_qr)->a_field.qre_next->a_field.qre_prev = (a_qr); \ + (a_qrelm)->a_field.qre_next = (a_qr); \ + } while (0) + +#define qr_meld(a_qr_a, a_qr_b, a_field) do { \ + void *t; \ + (a_qr_a)->a_field.qre_prev->a_field.qre_next = (a_qr_b); \ + (a_qr_b)->a_field.qre_prev->a_field.qre_next = (a_qr_a); \ + t = (a_qr_a)->a_field.qre_prev; \ + (a_qr_a)->a_field.qre_prev = (a_qr_b)->a_field.qre_prev; \ + (a_qr_b)->a_field.qre_prev = t; \ +} while (0) + +/* qr_meld() and qr_split() are functionally equivalent, so there's no need to + * have two copies of the code. */ +#define qr_split(a_qr_a, a_qr_b, a_field) \ + qr_meld((a_qr_a), (a_qr_b), a_field) + +#define qr_remove(a_qr, a_field) do { \ + (a_qr)->a_field.qre_prev->a_field.qre_next \ + = (a_qr)->a_field.qre_next; \ + (a_qr)->a_field.qre_next->a_field.qre_prev \ + = (a_qr)->a_field.qre_prev; \ + (a_qr)->a_field.qre_next = (a_qr); \ + (a_qr)->a_field.qre_prev = (a_qr); \ +} while (0) + +#define qr_foreach(var, a_qr, a_field) \ + for ((var) = (a_qr); \ + (var) != NULL; \ + (var) = (((var)->a_field.qre_next != (a_qr)) \ + ? (var)->a_field.qre_next : NULL)) + +#define qr_reverse_foreach(var, a_qr, a_field) \ + for ((var) = ((a_qr) != NULL) ? qr_prev(a_qr, a_field) : NULL; \ + (var) != NULL; \ + (var) = (((var) != (a_qr)) \ + ? (var)->a_field.qre_prev : NULL)) diff --git a/apilibs/kexbasen/kernel32/jemalloc/rb.h b/apilibs/kexbasen/kernel32/jemalloc/rb.h new file mode 100755 index 0000000..d5fecdc --- /dev/null +++ b/apilibs/kexbasen/kernel32/jemalloc/rb.h @@ -0,0 +1,982 @@ +/****************************************************************************** + * + * Copyright (C) 2008 Jason Evans . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice(s), this list of conditions and the following disclaimer + * unmodified other than the allowable addition of one or more + * copyright notices. + * 2. Redistributions in binary form must reproduce the above copyright + * notice(s), this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + * + * cpp macro implementation of left-leaning red-black trees. + * + * Usage: + * + * (Optional.) + * #define SIZEOF_PTR ... + * #define SIZEOF_PTR_2POW ... + * #define RB_NO_C99_VARARRAYS + * + * (Optional, see assert(3).) + * #define NDEBUG + * + * (Required.) + * #include + * #include + * ... + * + * All operations are done non-recursively. Parent pointers are not used, and + * color bits are stored in the least significant bit of right-child pointers, + * thus making node linkage as compact as is possible for red-black trees. + * + * Some macros use a comparison function pointer, which is expected to have the + * following prototype: + * + * int (a_cmp *)(a_type *a_node, a_type *a_other); + * ^^^^^^ + * or a_key + * + * Interpretation of comparision function return values: + * + * -1 : a_node < a_other + * 0 : a_node == a_other + * 1 : a_node > a_other + * + * In all cases, the a_node or a_key macro argument is the first argument to the + * comparison function, which makes it possible to write comparison functions + * that treat the first argument specially. + * + ******************************************************************************/ + +#ifndef RB_H_ +#define RB_H_ + +#if 0 +#include +__FBSDID("$FreeBSD: head/lib/libc/stdlib/rb.h 178995 2008-05-14 18:33:13Z jasone $"); +#endif + +/* Node structure. */ +#define rb_node(a_type) \ +struct { \ + a_type *rbn_left; \ + a_type *rbn_right_red; \ +} + +/* Root structure. */ +#define rb_tree(a_type) \ +struct { \ + a_type *rbt_root; \ + a_type rbt_nil; \ +} + +/* Left accessors. */ +#define rbp_left_get(a_type, a_field, a_node) \ + ((a_node)->a_field.rbn_left) +#define rbp_left_set(a_type, a_field, a_node, a_left) do { \ + (a_node)->a_field.rbn_left = a_left; \ +} while (0) + +/* Right accessors. */ +#define rbp_right_get(a_type, a_field, a_node) \ + ((a_type *) (((intptr_t) (a_node)->a_field.rbn_right_red) \ + & ((ssize_t)-2))) +#define rbp_right_set(a_type, a_field, a_node, a_right) do { \ + (a_node)->a_field.rbn_right_red = (a_type *) (((uintptr_t) a_right) \ + | (((uintptr_t) (a_node)->a_field.rbn_right_red) & ((size_t)1))); \ +} while (0) + +/* Color accessors. */ +#define rbp_red_get(a_type, a_field, a_node) \ + ((bool) (((uintptr_t) (a_node)->a_field.rbn_right_red) \ + & ((size_t)1))) +#define rbp_color_set(a_type, a_field, a_node, a_red) do { \ + (a_node)->a_field.rbn_right_red = (a_type *) ((((intptr_t) \ + (a_node)->a_field.rbn_right_red) & ((ssize_t)-2)) \ + | ((ssize_t)a_red)); \ +} while (0) +#define rbp_red_set(a_type, a_field, a_node) do { \ + (a_node)->a_field.rbn_right_red = (a_type *) (((uintptr_t) \ + (a_node)->a_field.rbn_right_red) | ((size_t)1)); \ +} while (0) +#define rbp_black_set(a_type, a_field, a_node) do { \ + (a_node)->a_field.rbn_right_red = (a_type *) (((intptr_t) \ + (a_node)->a_field.rbn_right_red) & ((ssize_t)-2)); \ +} while (0) + +/* Node initializer. */ +#define rbp_node_new(a_type, a_field, a_tree, a_node) do { \ + rbp_left_set(a_type, a_field, (a_node), &(a_tree)->rbt_nil); \ + rbp_right_set(a_type, a_field, (a_node), &(a_tree)->rbt_nil); \ + rbp_red_set(a_type, a_field, (a_node)); \ +} while (0) + +/* Tree initializer. */ +#define rb_new(a_type, a_field, a_tree) do { \ + (a_tree)->rbt_root = &(a_tree)->rbt_nil; \ + rbp_node_new(a_type, a_field, a_tree, &(a_tree)->rbt_nil); \ + rbp_black_set(a_type, a_field, &(a_tree)->rbt_nil); \ +} while (0) + +/* Tree operations. */ +#define rbp_black_height(a_type, a_field, a_tree, r_height) do { \ + a_type *rbp_bh_t; \ + for (rbp_bh_t = (a_tree)->rbt_root, (r_height) = 0; \ + rbp_bh_t != &(a_tree)->rbt_nil; \ + rbp_bh_t = rbp_left_get(a_type, a_field, rbp_bh_t)) { \ + if (rbp_red_get(a_type, a_field, rbp_bh_t) == false) { \ + (r_height)++; \ + } \ + } \ +} while (0) + +#define rbp_first(a_type, a_field, a_tree, a_root, r_node) do { \ + for ((r_node) = (a_root); \ + rbp_left_get(a_type, a_field, (r_node)) != &(a_tree)->rbt_nil; \ + (r_node) = rbp_left_get(a_type, a_field, (r_node))) { \ + } \ +} while (0) + +#define rbp_last(a_type, a_field, a_tree, a_root, r_node) do { \ + for ((r_node) = (a_root); \ + rbp_right_get(a_type, a_field, (r_node)) != &(a_tree)->rbt_nil; \ + (r_node) = rbp_right_get(a_type, a_field, (r_node))) { \ + } \ +} while (0) + +#define rbp_next(a_type, a_field, a_cmp, a_tree, a_node, r_node) do { \ + if (rbp_right_get(a_type, a_field, (a_node)) \ + != &(a_tree)->rbt_nil) { \ + rbp_first(a_type, a_field, a_tree, rbp_right_get(a_type, \ + a_field, (a_node)), (r_node)); \ + } else { \ + a_type *rbp_n_t = (a_tree)->rbt_root; \ + assert(rbp_n_t != &(a_tree)->rbt_nil); \ + (r_node) = &(a_tree)->rbt_nil; \ + while (true) { \ + int rbp_n_cmp = (a_cmp)((a_node), rbp_n_t); \ + if (rbp_n_cmp < 0) { \ + (r_node) = rbp_n_t; \ + rbp_n_t = rbp_left_get(a_type, a_field, rbp_n_t); \ + } else if (rbp_n_cmp > 0) { \ + rbp_n_t = rbp_right_get(a_type, a_field, rbp_n_t); \ + } else { \ + break; \ + } \ + assert(rbp_n_t != &(a_tree)->rbt_nil); \ + } \ + } \ +} while (0) + +#define rbp_prev(a_type, a_field, a_cmp, a_tree, a_node, r_node) do { \ + if (rbp_left_get(a_type, a_field, (a_node)) != &(a_tree)->rbt_nil) {\ + rbp_last(a_type, a_field, a_tree, rbp_left_get(a_type, \ + a_field, (a_node)), (r_node)); \ + } else { \ + a_type *rbp_p_t = (a_tree)->rbt_root; \ + assert(rbp_p_t != &(a_tree)->rbt_nil); \ + (r_node) = &(a_tree)->rbt_nil; \ + while (true) { \ + int rbp_p_cmp = (a_cmp)((a_node), rbp_p_t); \ + if (rbp_p_cmp < 0) { \ + rbp_p_t = rbp_left_get(a_type, a_field, rbp_p_t); \ + } else if (rbp_p_cmp > 0) { \ + (r_node) = rbp_p_t; \ + rbp_p_t = rbp_right_get(a_type, a_field, rbp_p_t); \ + } else { \ + break; \ + } \ + assert(rbp_p_t != &(a_tree)->rbt_nil); \ + } \ + } \ +} while (0) + +#define rb_first(a_type, a_field, a_tree, r_node) do { \ + rbp_first(a_type, a_field, a_tree, (a_tree)->rbt_root, (r_node)); \ + if ((r_node) == &(a_tree)->rbt_nil) { \ + (r_node) = NULL; \ + } \ +} while (0) + +#define rb_last(a_type, a_field, a_tree, r_node) do { \ + rbp_last(a_type, a_field, a_tree, (a_tree)->rbt_root, r_node); \ + if ((r_node) == &(a_tree)->rbt_nil) { \ + (r_node) = NULL; \ + } \ +} while (0) + +#define rb_next(a_type, a_field, a_cmp, a_tree, a_node, r_node) do { \ + rbp_next(a_type, a_field, a_cmp, a_tree, (a_node), (r_node)); \ + if ((r_node) == &(a_tree)->rbt_nil) { \ + (r_node) = NULL; \ + } \ +} while (0) + +#define rb_prev(a_type, a_field, a_cmp, a_tree, a_node, r_node) do { \ + rbp_prev(a_type, a_field, a_cmp, a_tree, (a_node), (r_node)); \ + if ((r_node) == &(a_tree)->rbt_nil) { \ + (r_node) = NULL; \ + } \ +} while (0) + +#define rb_search(a_type, a_field, a_cmp, a_tree, a_key, r_node) do { \ + int rbp_se_cmp; \ + (r_node) = (a_tree)->rbt_root; \ + while ((r_node) != &(a_tree)->rbt_nil \ + && (rbp_se_cmp = (a_cmp)((a_key), (r_node))) != 0) { \ + if (rbp_se_cmp < 0) { \ + (r_node) = rbp_left_get(a_type, a_field, (r_node)); \ + } else { \ + (r_node) = rbp_right_get(a_type, a_field, (r_node)); \ + } \ + } \ + if ((r_node) == &(a_tree)->rbt_nil) { \ + (r_node) = NULL; \ + } \ +} while (0) + +/* + * Find a match if it exists. Otherwise, find the next greater node, if one + * exists. + */ +#define rb_nsearch(a_type, a_field, a_cmp, a_tree, a_key, r_node) do { \ + a_type *rbp_ns_t = (a_tree)->rbt_root; \ + (r_node) = NULL; \ + while (rbp_ns_t != &(a_tree)->rbt_nil) { \ + int rbp_ns_cmp = (a_cmp)((a_key), rbp_ns_t); \ + if (rbp_ns_cmp < 0) { \ + (r_node) = rbp_ns_t; \ + rbp_ns_t = rbp_left_get(a_type, a_field, rbp_ns_t); \ + } else if (rbp_ns_cmp > 0) { \ + rbp_ns_t = rbp_right_get(a_type, a_field, rbp_ns_t); \ + } else { \ + (r_node) = rbp_ns_t; \ + break; \ + } \ + } \ +} while (0) + +/* + * Find a match if it exists. Otherwise, find the previous lesser node, if one + * exists. + */ +#define rb_psearch(a_type, a_field, a_cmp, a_tree, a_key, r_node) do { \ + a_type *rbp_ps_t = (a_tree)->rbt_root; \ + (r_node) = NULL; \ + while (rbp_ps_t != &(a_tree)->rbt_nil) { \ + int rbp_ps_cmp = (a_cmp)((a_key), rbp_ps_t); \ + if (rbp_ps_cmp < 0) { \ + rbp_ps_t = rbp_left_get(a_type, a_field, rbp_ps_t); \ + } else if (rbp_ps_cmp > 0) { \ + (r_node) = rbp_ps_t; \ + rbp_ps_t = rbp_right_get(a_type, a_field, rbp_ps_t); \ + } else { \ + (r_node) = rbp_ps_t; \ + break; \ + } \ + } \ +} while (0) + +#define rbp_rotate_left(a_type, a_field, a_node, r_node) do { \ + (r_node) = rbp_right_get(a_type, a_field, (a_node)); \ + rbp_right_set(a_type, a_field, (a_node), \ + rbp_left_get(a_type, a_field, (r_node))); \ + rbp_left_set(a_type, a_field, (r_node), (a_node)); \ +} while (0) + +#define rbp_rotate_right(a_type, a_field, a_node, r_node) do { \ + (r_node) = rbp_left_get(a_type, a_field, (a_node)); \ + rbp_left_set(a_type, a_field, (a_node), \ + rbp_right_get(a_type, a_field, (r_node))); \ + rbp_right_set(a_type, a_field, (r_node), (a_node)); \ +} while (0) + +#define rbp_lean_left(a_type, a_field, a_node, r_node) do { \ + bool rbp_ll_red; \ + rbp_rotate_left(a_type, a_field, (a_node), (r_node)); \ + rbp_ll_red = rbp_red_get(a_type, a_field, (a_node)); \ + rbp_color_set(a_type, a_field, (r_node), rbp_ll_red); \ + rbp_red_set(a_type, a_field, (a_node)); \ +} while (0) + +#define rbp_lean_right(a_type, a_field, a_node, r_node) do { \ + bool rbp_lr_red; \ + rbp_rotate_right(a_type, a_field, (a_node), (r_node)); \ + rbp_lr_red = rbp_red_get(a_type, a_field, (a_node)); \ + rbp_color_set(a_type, a_field, (r_node), rbp_lr_red); \ + rbp_red_set(a_type, a_field, (a_node)); \ +} while (0) + +#define rbp_move_red_left(a_type, a_field, a_node, r_node) do { \ + a_type *rbp_mrl_t, *rbp_mrl_u; \ + rbp_mrl_t = rbp_left_get(a_type, a_field, (a_node)); \ + rbp_red_set(a_type, a_field, rbp_mrl_t); \ + rbp_mrl_t = rbp_right_get(a_type, a_field, (a_node)); \ + rbp_mrl_u = rbp_left_get(a_type, a_field, rbp_mrl_t); \ + if (rbp_red_get(a_type, a_field, rbp_mrl_u)) { \ + rbp_rotate_right(a_type, a_field, rbp_mrl_t, rbp_mrl_u); \ + rbp_right_set(a_type, a_field, (a_node), rbp_mrl_u); \ + rbp_rotate_left(a_type, a_field, (a_node), (r_node)); \ + rbp_mrl_t = rbp_right_get(a_type, a_field, (a_node)); \ + if (rbp_red_get(a_type, a_field, rbp_mrl_t)) { \ + rbp_black_set(a_type, a_field, rbp_mrl_t); \ + rbp_red_set(a_type, a_field, (a_node)); \ + rbp_rotate_left(a_type, a_field, (a_node), rbp_mrl_t); \ + rbp_left_set(a_type, a_field, (r_node), rbp_mrl_t); \ + } else { \ + rbp_black_set(a_type, a_field, (a_node)); \ + } \ + } else { \ + rbp_red_set(a_type, a_field, (a_node)); \ + rbp_rotate_left(a_type, a_field, (a_node), (r_node)); \ + } \ +} while (0) + +#define rbp_move_red_right(a_type, a_field, a_node, r_node) do { \ + a_type *rbp_mrr_t; \ + rbp_mrr_t = rbp_left_get(a_type, a_field, (a_node)); \ + if (rbp_red_get(a_type, a_field, rbp_mrr_t)) { \ + a_type *rbp_mrr_u, *rbp_mrr_v; \ + rbp_mrr_u = rbp_right_get(a_type, a_field, rbp_mrr_t); \ + rbp_mrr_v = rbp_left_get(a_type, a_field, rbp_mrr_u); \ + if (rbp_red_get(a_type, a_field, rbp_mrr_v)) { \ + rbp_color_set(a_type, a_field, rbp_mrr_u, \ + rbp_red_get(a_type, a_field, (a_node))); \ + rbp_black_set(a_type, a_field, rbp_mrr_v); \ + rbp_rotate_left(a_type, a_field, rbp_mrr_t, rbp_mrr_u); \ + rbp_left_set(a_type, a_field, (a_node), rbp_mrr_u); \ + rbp_rotate_right(a_type, a_field, (a_node), (r_node)); \ + rbp_rotate_left(a_type, a_field, (a_node), rbp_mrr_t); \ + rbp_right_set(a_type, a_field, (r_node), rbp_mrr_t); \ + } else { \ + rbp_color_set(a_type, a_field, rbp_mrr_t, \ + rbp_red_get(a_type, a_field, (a_node))); \ + rbp_red_set(a_type, a_field, rbp_mrr_u); \ + rbp_rotate_right(a_type, a_field, (a_node), (r_node)); \ + rbp_rotate_left(a_type, a_field, (a_node), rbp_mrr_t); \ + rbp_right_set(a_type, a_field, (r_node), rbp_mrr_t); \ + } \ + rbp_red_set(a_type, a_field, (a_node)); \ + } else { \ + rbp_red_set(a_type, a_field, rbp_mrr_t); \ + rbp_mrr_t = rbp_left_get(a_type, a_field, rbp_mrr_t); \ + if (rbp_red_get(a_type, a_field, rbp_mrr_t)) { \ + rbp_black_set(a_type, a_field, rbp_mrr_t); \ + rbp_rotate_right(a_type, a_field, (a_node), (r_node)); \ + rbp_rotate_left(a_type, a_field, (a_node), rbp_mrr_t); \ + rbp_right_set(a_type, a_field, (r_node), rbp_mrr_t); \ + } else { \ + rbp_rotate_left(a_type, a_field, (a_node), (r_node)); \ + } \ + } \ +} while (0) + +#define rb_insert(a_type, a_field, a_cmp, a_tree, a_node) do { \ + a_type rbp_i_s; \ + a_type *rbp_i_g, *rbp_i_p, *rbp_i_c, *rbp_i_t, *rbp_i_u; \ + int rbp_i_cmp = 0; \ + rbp_i_g = &(a_tree)->rbt_nil; \ + rbp_left_set(a_type, a_field, &rbp_i_s, (a_tree)->rbt_root); \ + rbp_right_set(a_type, a_field, &rbp_i_s, &(a_tree)->rbt_nil); \ + rbp_black_set(a_type, a_field, &rbp_i_s); \ + rbp_i_p = &rbp_i_s; \ + rbp_i_c = (a_tree)->rbt_root; \ + /* Iteratively search down the tree for the insertion point, */\ + /* splitting 4-nodes as they are encountered. At the end of each */\ + /* iteration, rbp_i_g->rbp_i_p->rbp_i_c is a 3-level path down */\ + /* the tree, assuming a sufficiently deep tree. */\ + while (rbp_i_c != &(a_tree)->rbt_nil) { \ + rbp_i_t = rbp_left_get(a_type, a_field, rbp_i_c); \ + rbp_i_u = rbp_left_get(a_type, a_field, rbp_i_t); \ + if (rbp_red_get(a_type, a_field, rbp_i_t) \ + && rbp_red_get(a_type, a_field, rbp_i_u)) { \ + /* rbp_i_c is the top of a logical 4-node, so split it. */\ + /* This iteration does not move down the tree, due to the */\ + /* disruptiveness of node splitting. */\ + /* */\ + /* Rotate right. */\ + rbp_rotate_right(a_type, a_field, rbp_i_c, rbp_i_t); \ + /* Pass red links up one level. */\ + rbp_i_u = rbp_left_get(a_type, a_field, rbp_i_t); \ + rbp_black_set(a_type, a_field, rbp_i_u); \ + if (rbp_left_get(a_type, a_field, rbp_i_p) == rbp_i_c) { \ + rbp_left_set(a_type, a_field, rbp_i_p, rbp_i_t); \ + rbp_i_c = rbp_i_t; \ + } else { \ + /* rbp_i_c was the right child of rbp_i_p, so rotate */\ + /* left in order to maintain the left-leaning */\ + /* invariant. */\ + assert(rbp_right_get(a_type, a_field, rbp_i_p) \ + == rbp_i_c); \ + rbp_right_set(a_type, a_field, rbp_i_p, rbp_i_t); \ + rbp_lean_left(a_type, a_field, rbp_i_p, rbp_i_u); \ + if (rbp_left_get(a_type, a_field, rbp_i_g) == rbp_i_p) {\ + rbp_left_set(a_type, a_field, rbp_i_g, rbp_i_u); \ + } else { \ + assert(rbp_right_get(a_type, a_field, rbp_i_g) \ + == rbp_i_p); \ + rbp_right_set(a_type, a_field, rbp_i_g, rbp_i_u); \ + } \ + rbp_i_p = rbp_i_u; \ + rbp_i_cmp = (a_cmp)((a_node), rbp_i_p); \ + if (rbp_i_cmp < 0) { \ + rbp_i_c = rbp_left_get(a_type, a_field, rbp_i_p); \ + } else { \ + assert(rbp_i_cmp > 0); \ + rbp_i_c = rbp_right_get(a_type, a_field, rbp_i_p); \ + } \ + continue; \ + } \ + } \ + rbp_i_g = rbp_i_p; \ + rbp_i_p = rbp_i_c; \ + rbp_i_cmp = (a_cmp)((a_node), rbp_i_c); \ + if (rbp_i_cmp < 0) { \ + rbp_i_c = rbp_left_get(a_type, a_field, rbp_i_c); \ + } else { \ + assert(rbp_i_cmp > 0); \ + rbp_i_c = rbp_right_get(a_type, a_field, rbp_i_c); \ + } \ + } \ + /* rbp_i_p now refers to the node under which to insert. */\ + rbp_node_new(a_type, a_field, a_tree, (a_node)); \ + if (rbp_i_cmp > 0) { \ + rbp_right_set(a_type, a_field, rbp_i_p, (a_node)); \ + rbp_lean_left(a_type, a_field, rbp_i_p, rbp_i_t); \ + if (rbp_left_get(a_type, a_field, rbp_i_g) == rbp_i_p) { \ + rbp_left_set(a_type, a_field, rbp_i_g, rbp_i_t); \ + } else if (rbp_right_get(a_type, a_field, rbp_i_g) == rbp_i_p) {\ + rbp_right_set(a_type, a_field, rbp_i_g, rbp_i_t); \ + } \ + } else { \ + rbp_left_set(a_type, a_field, rbp_i_p, (a_node)); \ + } \ + /* Update the root and make sure that it is black. */\ + (a_tree)->rbt_root = rbp_left_get(a_type, a_field, &rbp_i_s); \ + rbp_black_set(a_type, a_field, (a_tree)->rbt_root); \ +} while (0) + +#define rb_remove(a_type, a_field, a_cmp, a_tree, a_node) do { \ + a_type rbp_r_s; \ + a_type *rbp_r_p, *rbp_r_c, *rbp_r_xp, *rbp_r_t, *rbp_r_u; \ + int rbp_r_cmp; \ + rbp_left_set(a_type, a_field, &rbp_r_s, (a_tree)->rbt_root); \ + rbp_right_set(a_type, a_field, &rbp_r_s, &(a_tree)->rbt_nil); \ + rbp_black_set(a_type, a_field, &rbp_r_s); \ + rbp_r_p = &rbp_r_s; \ + rbp_r_c = (a_tree)->rbt_root; \ + rbp_r_xp = &(a_tree)->rbt_nil; \ + /* Iterate down the tree, but always transform 2-nodes to 3- or */\ + /* 4-nodes in order to maintain the invariant that the current */\ + /* node is not a 2-node. This allows simple deletion once a leaf */\ + /* is reached. Handle the root specially though, since there may */\ + /* be no way to convert it from a 2-node to a 3-node. */\ + rbp_r_cmp = (a_cmp)((a_node), rbp_r_c); \ + if (rbp_r_cmp < 0) { \ + rbp_r_t = rbp_left_get(a_type, a_field, rbp_r_c); \ + rbp_r_u = rbp_left_get(a_type, a_field, rbp_r_t); \ + if (rbp_red_get(a_type, a_field, rbp_r_t) == false \ + && rbp_red_get(a_type, a_field, rbp_r_u) == false) { \ + /* Apply standard transform to prepare for left move. */\ + rbp_move_red_left(a_type, a_field, rbp_r_c, rbp_r_t); \ + rbp_black_set(a_type, a_field, rbp_r_t); \ + rbp_left_set(a_type, a_field, rbp_r_p, rbp_r_t); \ + rbp_r_c = rbp_r_t; \ + } else { \ + /* Move left. */\ + rbp_r_p = rbp_r_c; \ + rbp_r_c = rbp_left_get(a_type, a_field, rbp_r_c); \ + } \ + } else { \ + if (rbp_r_cmp == 0) { \ + assert((a_node) == rbp_r_c); \ + if (rbp_right_get(a_type, a_field, rbp_r_c) \ + == &(a_tree)->rbt_nil) { \ + /* Delete root node (which is also a leaf node). */\ + if (rbp_left_get(a_type, a_field, rbp_r_c) \ + != &(a_tree)->rbt_nil) { \ + rbp_lean_right(a_type, a_field, rbp_r_c, rbp_r_t); \ + rbp_right_set(a_type, a_field, rbp_r_t, \ + &(a_tree)->rbt_nil); \ + } else { \ + rbp_r_t = &(a_tree)->rbt_nil; \ + } \ + rbp_left_set(a_type, a_field, rbp_r_p, rbp_r_t); \ + } else { \ + /* This is the node we want to delete, but we will */\ + /* instead swap it with its successor and delete the */\ + /* successor. Record enough information to do the */\ + /* swap later. rbp_r_xp is the a_node's parent. */\ + rbp_r_xp = rbp_r_p; \ + rbp_r_cmp = 1; /* Note that deletion is incomplete. */\ + } \ + } \ + if (rbp_r_cmp == 1) { \ + if (rbp_red_get(a_type, a_field, rbp_left_get(a_type, \ + a_field, rbp_right_get(a_type, a_field, rbp_r_c))) \ + == false) { \ + rbp_r_t = rbp_left_get(a_type, a_field, rbp_r_c); \ + if (rbp_red_get(a_type, a_field, rbp_r_t)) { \ + /* Standard transform. */\ + rbp_move_red_right(a_type, a_field, rbp_r_c, \ + rbp_r_t); \ + } else { \ + /* Root-specific transform. */\ + rbp_red_set(a_type, a_field, rbp_r_c); \ + rbp_r_u = rbp_left_get(a_type, a_field, rbp_r_t); \ + if (rbp_red_get(a_type, a_field, rbp_r_u)) { \ + rbp_black_set(a_type, a_field, rbp_r_u); \ + rbp_rotate_right(a_type, a_field, rbp_r_c, \ + rbp_r_t); \ + rbp_rotate_left(a_type, a_field, rbp_r_c, \ + rbp_r_u); \ + rbp_right_set(a_type, a_field, rbp_r_t, \ + rbp_r_u); \ + } else { \ + rbp_red_set(a_type, a_field, rbp_r_t); \ + rbp_rotate_left(a_type, a_field, rbp_r_c, \ + rbp_r_t); \ + } \ + } \ + rbp_left_set(a_type, a_field, rbp_r_p, rbp_r_t); \ + rbp_r_c = rbp_r_t; \ + } else { \ + /* Move right. */\ + rbp_r_p = rbp_r_c; \ + rbp_r_c = rbp_right_get(a_type, a_field, rbp_r_c); \ + } \ + } \ + } \ + if (rbp_r_cmp != 0) { \ + while (true) { \ + assert(rbp_r_p != &(a_tree)->rbt_nil); \ + rbp_r_cmp = (a_cmp)((a_node), rbp_r_c); \ + if (rbp_r_cmp < 0) { \ + rbp_r_t = rbp_left_get(a_type, a_field, rbp_r_c); \ + if (rbp_r_t == &(a_tree)->rbt_nil) { \ + /* rbp_r_c now refers to the successor node to */\ + /* relocate, and rbp_r_xp/a_node refer to the */\ + /* context for the relocation. */\ + if (rbp_left_get(a_type, a_field, rbp_r_xp) \ + == (a_node)) { \ + rbp_left_set(a_type, a_field, rbp_r_xp, \ + rbp_r_c); \ + } else { \ + assert(rbp_right_get(a_type, a_field, \ + rbp_r_xp) == (a_node)); \ + rbp_right_set(a_type, a_field, rbp_r_xp, \ + rbp_r_c); \ + } \ + rbp_left_set(a_type, a_field, rbp_r_c, \ + rbp_left_get(a_type, a_field, (a_node))); \ + rbp_right_set(a_type, a_field, rbp_r_c, \ + rbp_right_get(a_type, a_field, (a_node))); \ + rbp_color_set(a_type, a_field, rbp_r_c, \ + rbp_red_get(a_type, a_field, (a_node))); \ + if (rbp_left_get(a_type, a_field, rbp_r_p) \ + == rbp_r_c) { \ + rbp_left_set(a_type, a_field, rbp_r_p, \ + &(a_tree)->rbt_nil); \ + } else { \ + assert(rbp_right_get(a_type, a_field, rbp_r_p) \ + == rbp_r_c); \ + rbp_right_set(a_type, a_field, rbp_r_p, \ + &(a_tree)->rbt_nil); \ + } \ + break; \ + } \ + rbp_r_u = rbp_left_get(a_type, a_field, rbp_r_t); \ + if (rbp_red_get(a_type, a_field, rbp_r_t) == false \ + && rbp_red_get(a_type, a_field, rbp_r_u) == false) { \ + rbp_move_red_left(a_type, a_field, rbp_r_c, \ + rbp_r_t); \ + if (rbp_left_get(a_type, a_field, rbp_r_p) \ + == rbp_r_c) { \ + rbp_left_set(a_type, a_field, rbp_r_p, rbp_r_t);\ + } else { \ + rbp_right_set(a_type, a_field, rbp_r_p, \ + rbp_r_t); \ + } \ + rbp_r_c = rbp_r_t; \ + } else { \ + rbp_r_p = rbp_r_c; \ + rbp_r_c = rbp_left_get(a_type, a_field, rbp_r_c); \ + } \ + } else { \ + /* Check whether to delete this node (it has to be */\ + /* the correct node and a leaf node). */\ + if (rbp_r_cmp == 0) { \ + assert((a_node) == rbp_r_c); \ + if (rbp_right_get(a_type, a_field, rbp_r_c) \ + == &(a_tree)->rbt_nil) { \ + /* Delete leaf node. */\ + if (rbp_left_get(a_type, a_field, rbp_r_c) \ + != &(a_tree)->rbt_nil) { \ + rbp_lean_right(a_type, a_field, rbp_r_c, \ + rbp_r_t); \ + rbp_right_set(a_type, a_field, rbp_r_t, \ + &(a_tree)->rbt_nil); \ + } else { \ + rbp_r_t = &(a_tree)->rbt_nil; \ + } \ + if (rbp_left_get(a_type, a_field, rbp_r_p) \ + == rbp_r_c) { \ + rbp_left_set(a_type, a_field, rbp_r_p, \ + rbp_r_t); \ + } else { \ + rbp_right_set(a_type, a_field, rbp_r_p, \ + rbp_r_t); \ + } \ + break; \ + } else { \ + /* This is the node we want to delete, but we */\ + /* will instead swap it with its successor */\ + /* and delete the successor. Record enough */\ + /* information to do the swap later. */\ + /* rbp_r_xp is a_node's parent. */\ + rbp_r_xp = rbp_r_p; \ + } \ + } \ + rbp_r_t = rbp_right_get(a_type, a_field, rbp_r_c); \ + rbp_r_u = rbp_left_get(a_type, a_field, rbp_r_t); \ + if (rbp_red_get(a_type, a_field, rbp_r_u) == false) { \ + rbp_move_red_right(a_type, a_field, rbp_r_c, \ + rbp_r_t); \ + if (rbp_left_get(a_type, a_field, rbp_r_p) \ + == rbp_r_c) { \ + rbp_left_set(a_type, a_field, rbp_r_p, rbp_r_t);\ + } else { \ + rbp_right_set(a_type, a_field, rbp_r_p, \ + rbp_r_t); \ + } \ + rbp_r_c = rbp_r_t; \ + } else { \ + rbp_r_p = rbp_r_c; \ + rbp_r_c = rbp_right_get(a_type, a_field, rbp_r_c); \ + } \ + } \ + } \ + } \ + /* Update root. */\ + (a_tree)->rbt_root = rbp_left_get(a_type, a_field, &rbp_r_s); \ +} while (0) + +/* + * The rb_wrap() macro provides a convenient way to wrap functions around the + * cpp macros. The main benefits of wrapping are that 1) repeated macro + * expansion can cause code bloat, especially for rb_{insert,remove)(), and + * 2) type, linkage, comparison functions, etc. need not be specified at every + * call point. + */ + +#define rb_wrap(a_attr, a_prefix, a_tree_type, a_type, a_field, a_cmp) \ +a_attr void \ +a_prefix##new(a_tree_type *tree) { \ + rb_new(a_type, a_field, tree); \ +} \ +a_attr a_type * \ +a_prefix##first(a_tree_type *tree) { \ + a_type *ret; \ + rb_first(a_type, a_field, tree, ret); \ + return (ret); \ +} \ +a_attr a_type * \ +a_prefix##last(a_tree_type *tree) { \ + a_type *ret; \ + rb_last(a_type, a_field, tree, ret); \ + return (ret); \ +} \ +a_attr a_type * \ +a_prefix##next(a_tree_type *tree, a_type *node) { \ + a_type *ret; \ + rb_next(a_type, a_field, a_cmp, tree, node, ret); \ + return (ret); \ +} \ +a_attr a_type * \ +a_prefix##prev(a_tree_type *tree, a_type *node) { \ + a_type *ret; \ + rb_prev(a_type, a_field, a_cmp, tree, node, ret); \ + return (ret); \ +} \ +a_attr a_type * \ +a_prefix##search(a_tree_type *tree, a_type *key) { \ + a_type *ret; \ + rb_search(a_type, a_field, a_cmp, tree, key, ret); \ + return (ret); \ +} \ +a_attr a_type * \ +a_prefix##nsearch(a_tree_type *tree, a_type *key) { \ + a_type *ret; \ + rb_nsearch(a_type, a_field, a_cmp, tree, key, ret); \ + return (ret); \ +} \ +a_attr a_type * \ +a_prefix##psearch(a_tree_type *tree, a_type *key) { \ + a_type *ret; \ + rb_psearch(a_type, a_field, a_cmp, tree, key, ret); \ + return (ret); \ +} \ +a_attr void \ +a_prefix##insert(a_tree_type *tree, a_type *node) { \ + rb_insert(a_type, a_field, a_cmp, tree, node); \ +} \ +a_attr void \ +a_prefix##remove(a_tree_type *tree, a_type *node) { \ + rb_remove(a_type, a_field, a_cmp, tree, node); \ +} + +/* + * The iterators simulate recursion via an array of pointers that store the + * current path. This is critical to performance, since a series of calls to + * rb_{next,prev}() would require time proportional to (n lg n), whereas this + * implementation only requires time proportional to (n). + * + * Since the iterators cache a path down the tree, any tree modification may + * cause the cached path to become invalid. In order to continue iteration, + * use something like the following sequence: + * + * { + * a_type *node, *tnode; + * + * rb_foreach_begin(a_type, a_field, a_tree, node) { + * ... + * rb_next(a_type, a_field, a_cmp, a_tree, node, tnode); + * rb_remove(a_type, a_field, a_cmp, a_tree, node); + * rb_foreach_next(a_type, a_field, a_cmp, a_tree, tnode); + * ... + * } rb_foreach_end(a_type, a_field, a_tree, node) + * } + * + * Note that this idiom is not advised if every iteration modifies the tree, + * since in that case there is no algorithmic complexity improvement over a + * series of rb_{next,prev}() calls, thus making the setup overhead wasted + * effort. + */ + +#ifdef RB_NO_C99_VARARRAYS + /* + * Avoid using variable-length arrays, at the cost of using more stack space. + * Size the path arrays such that they are always large enough, even if a + * tree consumes all of memory. Since each node must contain a minimum of + * two pointers, there can never be more nodes than: + * + * 1 << ((SIZEOF_PTR<<3) - (SIZEOF_PTR_2POW+1)) + * + * Since the depth of a tree is limited to 3*lg(#nodes), the maximum depth + * is: + * + * (3 * ((SIZEOF_PTR<<3) - (SIZEOF_PTR_2POW+1))) + * + * This works out to a maximum depth of 87 and 180 for 32- and 64-bit + * systems, respectively (approximatly 348 and 1440 bytes, respectively). + */ +# define rbp_compute_f_height(a_type, a_field, a_tree) +# define rbp_f_height (3 * ((SIZEOF_PTR<<3) - (SIZEOF_PTR_2POW+1))) +# define rbp_compute_fr_height(a_type, a_field, a_tree) +# define rbp_fr_height (3 * ((SIZEOF_PTR<<3) - (SIZEOF_PTR_2POW+1))) +#else +# define rbp_compute_f_height(a_type, a_field, a_tree) \ + /* Compute the maximum possible tree depth (3X the black height). */\ + unsigned rbp_f_height; \ + rbp_black_height(a_type, a_field, a_tree, rbp_f_height); \ + rbp_f_height *= 3; +# define rbp_compute_fr_height(a_type, a_field, a_tree) \ + /* Compute the maximum possible tree depth (3X the black height). */\ + unsigned rbp_fr_height; \ + rbp_black_height(a_type, a_field, a_tree, rbp_fr_height); \ + rbp_fr_height *= 3; +#endif + +#define rb_foreach_begin(a_type, a_field, a_tree, a_var) { \ + rbp_compute_f_height(a_type, a_field, a_tree) \ + { \ + /* Initialize the path to contain the left spine. */\ + a_type *rbp_f_path[rbp_f_height]; \ + a_type *rbp_f_node; \ + bool rbp_f_synced = false; \ + unsigned rbp_f_depth = 0; \ + if ((a_tree)->rbt_root != &(a_tree)->rbt_nil) { \ + rbp_f_path[rbp_f_depth] = (a_tree)->rbt_root; \ + rbp_f_depth++; \ + while ((rbp_f_node = rbp_left_get(a_type, a_field, \ + rbp_f_path[rbp_f_depth-1])) != &(a_tree)->rbt_nil) { \ + rbp_f_path[rbp_f_depth] = rbp_f_node; \ + rbp_f_depth++; \ + } \ + } \ + /* While the path is non-empty, iterate. */\ + while (rbp_f_depth > 0) { \ + (a_var) = rbp_f_path[rbp_f_depth-1]; + +/* Only use if modifying the tree during iteration. */ +#define rb_foreach_next(a_type, a_field, a_cmp, a_tree, a_node) \ + /* Re-initialize the path to contain the path to a_node. */\ + rbp_f_depth = 0; \ + if (a_node != NULL) { \ + if ((a_tree)->rbt_root != &(a_tree)->rbt_nil) { \ + rbp_f_path[rbp_f_depth] = (a_tree)->rbt_root; \ + rbp_f_depth++; \ + rbp_f_node = rbp_f_path[0]; \ + while (true) { \ + int rbp_f_cmp = (a_cmp)((a_node), \ + rbp_f_path[rbp_f_depth-1]); \ + if (rbp_f_cmp < 0) { \ + rbp_f_node = rbp_left_get(a_type, a_field, \ + rbp_f_path[rbp_f_depth-1]); \ + } else if (rbp_f_cmp > 0) { \ + rbp_f_node = rbp_right_get(a_type, a_field, \ + rbp_f_path[rbp_f_depth-1]); \ + } else { \ + break; \ + } \ + assert(rbp_f_node != &(a_tree)->rbt_nil); \ + rbp_f_path[rbp_f_depth] = rbp_f_node; \ + rbp_f_depth++; \ + } \ + } \ + } \ + rbp_f_synced = true; + +#define rb_foreach_end(a_type, a_field, a_tree, a_var) \ + if (rbp_f_synced) { \ + rbp_f_synced = false; \ + continue; \ + } \ + /* Find the successor. */\ + if ((rbp_f_node = rbp_right_get(a_type, a_field, \ + rbp_f_path[rbp_f_depth-1])) != &(a_tree)->rbt_nil) { \ + /* The successor is the left-most node in the right */\ + /* subtree. */\ + rbp_f_path[rbp_f_depth] = rbp_f_node; \ + rbp_f_depth++; \ + while ((rbp_f_node = rbp_left_get(a_type, a_field, \ + rbp_f_path[rbp_f_depth-1])) != &(a_tree)->rbt_nil) { \ + rbp_f_path[rbp_f_depth] = rbp_f_node; \ + rbp_f_depth++; \ + } \ + } else { \ + /* The successor is above the current node. Unwind */\ + /* until a left-leaning edge is removed from the */\ + /* path, or the path is empty. */\ + for (rbp_f_depth--; rbp_f_depth > 0; rbp_f_depth--) { \ + if (rbp_left_get(a_type, a_field, \ + rbp_f_path[rbp_f_depth-1]) \ + == rbp_f_path[rbp_f_depth]) { \ + break; \ + } \ + } \ + } \ + } \ + } \ +} + +#define rb_foreach_reverse_begin(a_type, a_field, a_tree, a_var) { \ + rbp_compute_fr_height(a_type, a_field, a_tree) \ + { \ + /* Initialize the path to contain the right spine. */\ + a_type *rbp_fr_path[rbp_fr_height]; \ + a_type *rbp_fr_node; \ + bool rbp_fr_synced = false; \ + unsigned rbp_fr_depth = 0; \ + if ((a_tree)->rbt_root != &(a_tree)->rbt_nil) { \ + rbp_fr_path[rbp_fr_depth] = (a_tree)->rbt_root; \ + rbp_fr_depth++; \ + while ((rbp_fr_node = rbp_right_get(a_type, a_field, \ + rbp_fr_path[rbp_fr_depth-1])) != &(a_tree)->rbt_nil) { \ + rbp_fr_path[rbp_fr_depth] = rbp_fr_node; \ + rbp_fr_depth++; \ + } \ + } \ + /* While the path is non-empty, iterate. */\ + while (rbp_fr_depth > 0) { \ + (a_var) = rbp_fr_path[rbp_fr_depth-1]; + +/* Only use if modifying the tree during iteration. */ +#define rb_foreach_reverse_prev(a_type, a_field, a_cmp, a_tree, a_node) \ + /* Re-initialize the path to contain the path to a_node. */\ + rbp_fr_depth = 0; \ + if (a_node != NULL) { \ + if ((a_tree)->rbt_root != &(a_tree)->rbt_nil) { \ + rbp_fr_path[rbp_fr_depth] = (a_tree)->rbt_root; \ + rbp_fr_depth++; \ + rbp_fr_node = rbp_fr_path[0]; \ + while (true) { \ + int rbp_fr_cmp = (a_cmp)((a_node), \ + rbp_fr_path[rbp_fr_depth-1]); \ + if (rbp_fr_cmp < 0) { \ + rbp_fr_node = rbp_left_get(a_type, a_field, \ + rbp_fr_path[rbp_fr_depth-1]); \ + } else if (rbp_fr_cmp > 0) { \ + rbp_fr_node = rbp_right_get(a_type, a_field,\ + rbp_fr_path[rbp_fr_depth-1]); \ + } else { \ + break; \ + } \ + assert(rbp_fr_node != &(a_tree)->rbt_nil); \ + rbp_fr_path[rbp_fr_depth] = rbp_fr_node; \ + rbp_fr_depth++; \ + } \ + } \ + } \ + rbp_fr_synced = true; + +#define rb_foreach_reverse_end(a_type, a_field, a_tree, a_var) \ + if (rbp_fr_synced) { \ + rbp_fr_synced = false; \ + continue; \ + } \ + if (rbp_fr_depth == 0) { \ + /* rb_foreach_reverse_sync() was called with a NULL */\ + /* a_node. */\ + break; \ + } \ + /* Find the predecessor. */\ + if ((rbp_fr_node = rbp_left_get(a_type, a_field, \ + rbp_fr_path[rbp_fr_depth-1])) != &(a_tree)->rbt_nil) { \ + /* The predecessor is the right-most node in the left */\ + /* subtree. */\ + rbp_fr_path[rbp_fr_depth] = rbp_fr_node; \ + rbp_fr_depth++; \ + while ((rbp_fr_node = rbp_right_get(a_type, a_field, \ + rbp_fr_path[rbp_fr_depth-1])) != &(a_tree)->rbt_nil) {\ + rbp_fr_path[rbp_fr_depth] = rbp_fr_node; \ + rbp_fr_depth++; \ + } \ + } else { \ + /* The predecessor is above the current node. Unwind */\ + /* until a right-leaning edge is removed from the */\ + /* path, or the path is empty. */\ + for (rbp_fr_depth--; rbp_fr_depth > 0; rbp_fr_depth--) {\ + if (rbp_right_get(a_type, a_field, \ + rbp_fr_path[rbp_fr_depth-1]) \ + == rbp_fr_path[rbp_fr_depth]) { \ + break; \ + } \ + } \ + } \ + } \ + } \ +} + +#endif /* RB_H_ */ diff --git a/apilibs/kexbasen/kernel32/unikernel32.c b/apilibs/kexbasen/kernel32/unikernel32.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbasen/kexbasen.def b/apilibs/kexbasen/kexbasen.def old mode 100644 new mode 100755 diff --git a/apilibs/kexbasen/kexbasen.dsp b/apilibs/kexbasen/kexbasen.dsp old mode 100644 new mode 100755 index f535a92..c8af81d --- a/apilibs/kexbasen/kexbasen.dsp +++ b/apilibs/kexbasen/kexbasen.dsp @@ -53,7 +53,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shlwapi.lib shell32.lib rpcrt4.lib usp10.lib ../../common/KernelEx.lib ../../kexcrt/kexcrt.lib libc.lib delayimp.lib /nologo /dll /map /machine:I386 /nodefaultlib /OPT:NOWIN98 /DELAYLOAD:shell32.dll /DELAYLOAD:rpcrt4.dll /DELAYLOAD:usp10.dll /DELAYLOAD:comdlg32.dll /DELAYLOAD:winspool.drv /DELAYLOAD:shlwapi.dll +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shlwapi.lib shell32.lib rpcrt4.lib usp10.lib ../../common/KernelEx.lib ../../kexcrt/kexcrt.lib libc.lib delayimp.lib /nologo /dll /map /machine:I386 /nodefaultlib /OPT:NOWIN98 /DELAYLOAD:shell32.dll /DELAYLOAD:rpcrt4.dll /DELAYLOAD:usp10.dll /DELAYLOAD:comdlg32.dll /DELAYLOAD:winspool.drv # SUBTRACT LINK32 /pdb:none !ELSEIF "$(CFG)" == "KernelEx Base NonShared - Win32 Debug" @@ -80,7 +80,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shlwapi.lib shell32.lib rpcrt4.lib usp10.lib ../../common/KernelEx.lib ../../kexcrt/kexcrt.lib libc.lib delayimp.lib /nologo /dll /map /debug /machine:I386 /nodefaultlib /pdbtype:sept /OPT:NOWIN98 /DELAYLOAD:shell32.dll /DELAYLOAD:rpcrt4.dll /DELAYLOAD:usp10.dll /DELAYLOAD:comdlg32.dll /DELAYLOAD:winspool.drv /DELAYLOAD:shlwapi.dll +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shlwapi.lib shell32.lib rpcrt4.lib usp10.lib ../../common/KernelEx.lib ../../kexcrt/kexcrt.lib libc.lib delayimp.lib /nologo /dll /map /debug /machine:I386 /nodefaultlib /OPT:NOWIN98 /DELAYLOAD:shell32.dll /DELAYLOAD:rpcrt4.dll /DELAYLOAD:usp10.dll /DELAYLOAD:comdlg32.dll /DELAYLOAD:winspool.drv # SUBTRACT LINK32 /pdb:none !ENDIF @@ -105,6 +105,22 @@ SOURCE=.\kernel32\_kernel32_apilist.h # End Source File # Begin Source File +SOURCE=.\kernel32\allocator.c +# End Source File +# Begin Source File + +SOURCE=.\kernel32\DelayLoadFailureHook.c +# End Source File +# Begin Source File + +SOURCE=.\kernel32\ThreadPool.c +# End Source File +# Begin Source File + +SOURCE=.\kernel32\TlsExt.c +# End Source File +# Begin Source File + SOURCE=.\kernel32\unikernel32.c # End Source File # End Group @@ -193,11 +209,7 @@ SOURCE=.\shell32\_shell32_apilist.h # End Source File # Begin Source File -SOURCE=.\shell32\auxshlguid.h -# End Source File -# Begin Source File - -SOURCE=.\shell32\pidl.h +SOURCE=.\shell32\folderfix.h # End Source File # Begin Source File @@ -209,6 +221,10 @@ SOURCE=.\shell32\SHGetFolderPath.c # End Source File # Begin Source File +SOURCE=.\shell32\SHGetSpecialFolder_fix.c +# End Source File +# Begin Source File + SOURCE=.\shell32\unishell32.c # End Source File # End Group @@ -241,23 +257,31 @@ SOURCE=.\winspool\_winspool_apilist.h # End Source File # Begin Source File +SOURCE=.\winspool\_winspool_stubs.c +# End Source File +# Begin Source File + SOURCE=.\winspool\DefaultPrinter.c # End Source File +# Begin Source File + +SOURCE=.\winspool\uniwinspool.c +# End Source File # End Group -# Begin Group "shlwapi" +# Begin Group "shfolder" # PROP Default_Filter "" # Begin Source File -SOURCE=.\shlwapi\_shlwapi_apilist.c +SOURCE=.\shfolder\_shfolder_apilist.c # End Source File # Begin Source File -SOURCE=.\shlwapi\_shlwapi_apilist.h +SOURCE=.\shfolder\_shfolder_apilist.h # End Source File # Begin Source File -SOURCE=.\shlwapi\string.c +SOURCE=.\shfolder\shfolder.c # End Source File # End Group # Begin Source File @@ -266,7 +290,85 @@ SOURCE=.\common.c # End Source File # Begin Source File +SOURCE=.\dirlist + +!IF "$(CFG)" == "KernelEx Base NonShared - Win32 Release" + +# Begin Custom Build +WkspDir=. +ProjDir=. +InputPath=.\dirlist + +"&" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + if not exist $(WkspDir)\util\prep\Release\prep.exe goto error + $(WkspDir)\util\prep\Release\prep.exe "$(ProjDir)" + goto quit + :error + echo Error - compile PREP (Release) project first + echo 1 | choice /C:1 /N >NUL + :quit + +# End Custom Build + +!ELSEIF "$(CFG)" == "KernelEx Base NonShared - Win32 Debug" + +# Begin Custom Build +WkspDir=. +ProjDir=. +InputPath=.\dirlist + +"&" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + if not exist $(WkspDir)\util\prep\Release\prep.exe goto error + $(WkspDir)\util\prep\Release\prep.exe "$(ProjDir)" + goto quit + :error + echo Error - compile PREP (Release) project first + echo 1 | choice /C:1 /N >NUL + :quit + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + SOURCE=.\kexbasen.def + +!IF "$(CFG)" == "KernelEx Base NonShared - Win32 Release" + +# Begin Custom Build +OutDir=.\Release +WkspDir=. +InputPath=.\kexbasen.def + +"$(OutDir)\k32ord.lib" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cl /nologo /c /TC /DK32ORD_IMPLIB /Fo$(OutDir)\k32ord.obj "$(WkspDir)\common\k32ord.h" + link /DLL /NOENTRY /NOLOGO /IGNORE:4070 /MACHINE:IX86 /DEF:"$(WkspDir)\common\k32ord.def" /OUT:$(OutDir)\k32ord.dll /IMPLIB:$(OutDir)\k32ord.lib $(OutDir)\k32ord.obj + del $(OutDir)\k32ord.exp + del $(OutDir)\k32ord.obj + del $(OutDir)\k32ord.dll + +# End Custom Build + +!ELSEIF "$(CFG)" == "KernelEx Base NonShared - Win32 Debug" + +# Begin Custom Build +OutDir=.\Debug +WkspDir=. +InputPath=.\kexbasen.def + +"$(OutDir)\k32ord.lib" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cl /nologo /c /TC /DK32ORD_IMPLIB /Fo$(OutDir)\k32ord.obj "$(WkspDir)\common\k32ord.h" + link /DLL /NOENTRY /NOLOGO /IGNORE:4070 /MACHINE:IX86 /DEF:"$(WkspDir)\common\k32ord.def" /OUT:$(OutDir)\k32ord.dll /IMPLIB:$(OutDir)\k32ord.lib $(OutDir)\k32ord.obj + del $(OutDir)\k32ord.exp + del $(OutDir)\k32ord.obj + del $(OutDir)\k32ord.dll + +# End Custom Build + +!ENDIF + # End Source File # Begin Source File @@ -274,6 +376,10 @@ SOURCE=.\main.c # End Source File # Begin Source File +SOURCE=.\shlord.c +# End Source File +# Begin Source File + SOURCE=.\unifwd.c # End Source File # End Group @@ -286,6 +392,19 @@ SOURCE=.\common.h # End Source File # Begin Source File +SOURCE=..\..\common\k32ord.def +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=..\..\common\k32ord.h +# End Source File +# Begin Source File + +SOURCE=.\shlord.h +# End Source File +# Begin Source File + SOURCE=.\unifwd.h # End Source File # End Group diff --git a/apilibs/kexbasen/kexbasen.rc b/apilibs/kexbasen/kexbasen.rc old mode 100644 new mode 100755 index 035024d..25cda97 --- a/apilibs/kexbasen/kexbasen.rc +++ b/apilibs/kexbasen/kexbasen.rc @@ -74,7 +74,7 @@ BEGIN VALUE "FileDescription", "KernelEx Base Non-shared Api Library\0" VALUE "FileVersion", _RCVERSION_ "\0" VALUE "InternalName", "kexbasen\0" - VALUE "LegalCopyright", "Copyright © 2009, Xeno86\0" + VALUE "LegalCopyright", "Copyright © 2009-2010, Xeno86\0" VALUE "LegalTrademarks", "\0" VALUE "OriginalFilename", "kexbasen.dll\0" VALUE "PrivateBuild", "\0" diff --git a/apilibs/kexbasen/main.c b/apilibs/kexbasen/main.c old mode 100644 new mode 100755 index b3cc881..80ff953 --- a/apilibs/kexbasen/main.c +++ b/apilibs/kexbasen/main.c @@ -30,7 +30,7 @@ #include "shell32/_shell32_apilist.h" #include "rpcrt4/_rpcrt4_apilist.h" #include "winspool/_winspool_apilist.h" -#include "shlwapi/_shlwapi_apilist.h" +#include "shfolder/_shfolder_apilist.h" //#include "/__apilist.h" static apilib_api_table api_table[10]; @@ -45,7 +45,7 @@ static void fill_apitable() api_table[5] = apitable_shell32; api_table[6] = apitable_rpcrt4; api_table[7] = apitable_winspool; - api_table[8] = apitable_shlwapi; + api_table[8] = apitable_shfolder; //last entry is null terminator } @@ -57,9 +57,19 @@ const apilib_api_table* get_api_table() return api_table; } -BOOL init() +static BOOL init() { - return common_init() && init_kernel32() && init_gdi32() && init_user32() && init_advapi32() && init_comdlg32() && init_shell32() && init_rpcrt4() && init_winspool() && init_shlwapi(); + return common_init() && init_kernel32() && init_gdi32() && init_user32() && init_advapi32() && init_comdlg32() && init_shell32() && init_rpcrt4() && init_winspool() && init_shfolder(); +} + +static void uninit() +{ + uninit_kernel32(); +} + +static void detach() +{ + detach_kernel32(); } BOOL APIENTRY DllMain(HINSTANCE instance, DWORD reason, BOOL load_static) @@ -67,13 +77,14 @@ BOOL APIENTRY DllMain(HINSTANCE instance, DWORD reason, BOOL load_static) switch (reason) { case DLL_PROCESS_ATTACH: -// kexDebugPrint("KernelEx Base Non-shared library reporting in action!\n"); - DisableThreadLibraryCalls(instance); if (!init()) return FALSE; break; case DLL_PROCESS_DETACH: -// kexDebugPrint("KernelEx Base Non-shared library signing off!\n"); + uninit(); + break; + case DLL_THREAD_DETACH: + detach(); break; } return TRUE; diff --git a/apilibs/kexbasen/resource.h b/apilibs/kexbasen/resource.h old mode 100644 new mode 100755 diff --git a/apilibs/kexbasen/rpcrt4/_rpcrt4_apilist.c b/apilibs/kexbasen/rpcrt4/_rpcrt4_apilist.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbasen/rpcrt4/_rpcrt4_apilist.h b/apilibs/kexbasen/rpcrt4/_rpcrt4_apilist.h old mode 100644 new mode 100755 diff --git a/apilibs/kexbasen/rpcrt4/unirpcrt4.c b/apilibs/kexbasen/rpcrt4/unirpcrt4.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbasen/shell32/SHGetFolderLocation.c b/apilibs/kexbasen/shell32/SHGetFolderLocation.c old mode 100644 new mode 100755 index fb616b4..f67f497 --- a/apilibs/kexbasen/shell32/SHGetFolderLocation.c +++ b/apilibs/kexbasen/shell32/SHGetFolderLocation.c @@ -1,300 +1,89 @@ /* - * Path Functions + * KernelEx + * Copyright (C) 2009, Xeno86, Tihiy * - * Copyright 1998, 1999, 2000 Juergen Schmied - * Copyright 2004 Juan Lang + * This file is part of KernelEx source code. * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. + * KernelEx is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. + * KernelEx is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */ -#ifdef _MSC_VER -#pragma warning(disable:4002) -#define TRACE() ((void)0) -#define TRACE_() ((void)0) -#define WARN() ((void)0) -#else -#define TRACE(...) do {} while(0) -#define TRACE_(x) TRACE -#define WARN(...) do {} while(0) -#endif - -#define _WIN32_IE 0x0500 - #include -#include -#include "auxshlguid.h" -#include "pidl.h" -#include +#include #include "common.h" #include "_shell32_apilist.h" -/************************************************************************** - * - * internal functions - * - * ### 1. section creating pidls ### - * - ************************************************************************* - */ -LPITEMIDLIST _ILAlloc(PIDLTYPE type, unsigned int size) +typedef HRESULT (WINAPI *SHGetFolderLocation_t)(HWND, int, HANDLE, DWORD, LPVOID*); + +HRESULT WINAPI SHGetFolderLocation_impl( + HWND hwndOwner, + int nFolder, + HANDLE hToken, + DWORD dwReserved, + LPVOID *ppidl +) { - LPITEMIDLIST pidlOut = NULL; + if (!ppidl) + return E_INVALIDARG; + if (dwReserved) + return E_INVALIDARG; - pidlOut = (LPITEMIDLIST) SHAlloc(size + 5); - if(pidlOut) - { - LPPIDLDATA pData; - LPITEMIDLIST pidlNext; + HRESULT hr = SHGetSpecialFolderLocation_fix(hwndOwner, nFolder, ppidl); + if (!SUCCEEDED(hr)) + { + char szPath[MAX_PATH]; - ZeroMemory(pidlOut, size + 5); - pidlOut->mkid.cb = size + 3; - - pData = _ILGetDataPointer(pidlOut); - if (pData) - pData->type = type; - - pidlNext = ILGetNext(pidlOut); - if (pidlNext) - pidlNext->mkid.cb = 0x00; - TRACE("-- (pidl=%p, size=%u)\n", pidlOut, size); - } - - return pidlOut; + hr = SHGetFolderPathA_new(hwndOwner, nFolder, hToken, SHGFP_TYPE_CURRENT, szPath); + if (SUCCEEDED(hr)) + { + DWORD attributes = 0; + hr = SHILCreateFromPath((LPWSTR)szPath, (LPITEMIDLIST*)ppidl, &attributes); + } + else if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) + { + /* unlike SHGetFolderPath, SHGetFolderLocation in shell32 + * version 6.0 returns E_FAIL for nonexistent paths + */ + hr = E_FAIL; + } + } + if (*ppidl) + hr = NOERROR; + return hr; } -LPITEMIDLIST _ILCreateDesktop() +static SHGetFolderLocation_t dld() { - LPITEMIDLIST ret; - - TRACE("()\n"); - ret = (LPITEMIDLIST) SHAlloc(2); - if (ret) - ret->mkid.cb = 0; - return ret; + HMODULE h = GetModuleHandle("SHELL32"); + SHGetFolderLocation_t pfn = (SHGetFolderLocation_t) + GetProcAddress(h, "SHGetFolderLocation"); + if (!pfn) + pfn = SHGetFolderLocation_impl; + return pfn; } -LPITEMIDLIST _ILCreateMyComputer() -{ - TRACE("()\n"); - return _ILCreateGuid(PT_GUID, &CLSID_MyComputer); -} - -LPITEMIDLIST _ILCreateMyDocuments() -{ - TRACE("()\n"); - return _ILCreateGuid(PT_GUID, &CLSID_MyDocuments); -} - -LPITEMIDLIST _ILCreateIExplore() -{ - TRACE("()\n"); - return _ILCreateGuid(PT_GUID, &CLSID_Internet); -} - -LPITEMIDLIST _ILCreateControlPanel() -{ - LPITEMIDLIST parent = _ILCreateGuid(PT_GUID, &CLSID_MyComputer), ret = NULL; - - TRACE("()\n"); - if (parent) - { - LPITEMIDLIST cpl = _ILCreateGuid(PT_SHELLEXT, &CLSID_ControlPanel); - - if (cpl) - { - ret = ILCombine(parent, cpl); - SHFree(cpl); - } - SHFree(parent); - } - return ret; -} - -LPITEMIDLIST _ILCreatePrinters() -{ - LPITEMIDLIST parent = _ILCreateGuid(PT_GUID, &CLSID_MyComputer), ret = NULL; - - TRACE("()\n"); - if (parent) - { - LPITEMIDLIST printers = _ILCreateGuid(PT_YAGUID, &CLSID_Printers); - - if (printers) - { - ret = ILCombine(parent, printers); - SHFree(printers); - } - SHFree(parent); - } - return ret; -} - -LPITEMIDLIST _ILCreateNetwork() -{ - TRACE("()\n"); - return _ILCreateGuid(PT_GUID, &CLSID_NetworkPlaces); -} - -LPITEMIDLIST _ILCreateBitBucket() -{ - TRACE("()\n"); - return _ILCreateGuid(PT_GUID, &CLSID_RecycleBin); -} - -LPITEMIDLIST _ILCreateGuid(PIDLTYPE type, const IID *guid) -{ - LPITEMIDLIST pidlOut; - - if (type == PT_SHELLEXT || type == PT_GUID || type == PT_YAGUID) - { - pidlOut = _ILAlloc(type, sizeof(GUIDStruct)); - if (pidlOut) - { - LPPIDLDATA pData = _ILGetDataPointer(pidlOut); - - memcpy(&(pData->u.guid.guid), guid, sizeof(GUID)); - TRACE("-- create GUID-pidl %s\n", - debugstr_guid(&(pData->u.guid.guid))); - } - } - else - { - WARN("%d: invalid type for GUID\n", type); - pidlOut = NULL; - } - return pidlOut; -} - -/************************************************************************** - * - * ### 4. getting pointers to parts of pidls ### - * - ************************************************************************** - * _ILGetDataPointer() - */ -LPPIDLDATA _ILGetDataPointer(LPCITEMIDLIST pidl) -{ - if(pidl && pidl->mkid.cb != 0x00) - return (LPPIDLDATA) &(pidl->mkid.abID); - return NULL; -} - -/************************************************************************* - * SHGetFolderLocation [SHELL32.@] - * - * Gets the folder locations from the registry and creates a pidl. - * - * PARAMS - * hwndOwner [I] - * nFolder [I] CSIDL_xxxxx - * hToken [I] token representing user, or NULL for current user, or -1 for - * default user - * dwReserved [I] must be zero - * ppidl [O] PIDL of a special folder - * - * RETURNS - * Success: S_OK - * Failure: Standard OLE-defined error result, S_FALSE or E_INVALIDARG - * - * NOTES - * Creates missing reg keys and directories. - * Mostly forwards to SHGetFolderPathW, but a few values of nFolder return - * virtual folders that are handled here. - */ /* MAKE_EXPORT SHGetFolderLocation_new=SHGetFolderLocation */ HRESULT WINAPI SHGetFolderLocation_new( HWND hwndOwner, int nFolder, HANDLE hToken, DWORD dwReserved, - LPVOID *_ppidl) + LPVOID *ppidl +) { - LPITEMIDLIST *ppidl = (LPITEMIDLIST*) _ppidl; - HRESULT hr = E_INVALIDARG; - - TRACE("%p 0x%08x %p 0x%08lx %p\n", - hwndOwner, nFolder, hToken, dwReserved, ppidl); - - if (!ppidl) - return E_INVALIDARG; - if (dwReserved) - return E_INVALIDARG; - - /* The virtual folders' locations are not user-dependent */ - *ppidl = NULL; - switch (nFolder) - { - case CSIDL_DESKTOP: - *ppidl = _ILCreateDesktop(); - break; - - case CSIDL_PERSONAL: - *ppidl = _ILCreateMyDocuments(); - break; - - case CSIDL_INTERNET: - *ppidl = _ILCreateIExplore(); - break; - - case CSIDL_CONTROLS: - *ppidl = _ILCreateControlPanel(); - break; - - case CSIDL_PRINTERS: - *ppidl = _ILCreatePrinters(); - break; - - case CSIDL_BITBUCKET: - *ppidl = _ILCreateBitBucket(); - break; - - case CSIDL_DRIVES: - *ppidl = _ILCreateMyComputer(); - break; - - case CSIDL_NETWORK: - *ppidl = _ILCreateNetwork(); - break; - - default: - { - char szPath[MAX_PATH]; - - hr = SHGetFolderPathA_new(hwndOwner, nFolder, hToken, - SHGFP_TYPE_CURRENT, szPath); - if (SUCCEEDED(hr)) - { - DWORD attributes=0; - - TRACE("Value=%s\n", debugstr_w(szPath)); - hr = SHILCreateFromPath((LPWSTR)szPath, ppidl, &attributes); - } - else if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) - { - /* unlike SHGetFolderPath, SHGetFolderLocation in shell32 - * version 6.0 returns E_FAIL for nonexistent paths - */ - hr = E_FAIL; - } - } - } - if(*ppidl) - hr = NOERROR; - - TRACE("-- (new pidl %p)\n",*ppidl); - return hr; + static SHGetFolderLocation_t SHGetFolderLocation_pfn; + if (!SHGetFolderLocation_pfn) + SHGetFolderLocation_pfn = dld(); + return SHGetFolderLocation_pfn(hwndOwner, nFolder, hToken, dwReserved, ppidl); } - diff --git a/apilibs/kexbasen/shell32/SHGetFolderPath.c b/apilibs/kexbasen/shell32/SHGetFolderPath.c old mode 100644 new mode 100755 index 485420e..6f9621b --- a/apilibs/kexbasen/shell32/SHGetFolderPath.c +++ b/apilibs/kexbasen/shell32/SHGetFolderPath.c @@ -20,14 +20,13 @@ */ #include +#include #include "kexcoresdk.h" +#include "folderfix.h" typedef HRESULT (WINAPI *SHGetFolderPathA_t)(HWND, int, HANDLE, DWORD, LPSTR); typedef HRESULT (WINAPI *SHGetFolderPathW_t)(HWND, int, HANDLE, DWORD, LPWSTR); -static SHGetFolderPathA_t SHGetFolderPathA_pfn = (SHGetFolderPathA_t)-1; -static SHGetFolderPathW_t SHGetFolderPathW_pfn = (SHGetFolderPathW_t)-1; - static PROC LoadShfolderProc(const char* proc) { static const char ShfolderFn[] = "SHFOLDER.DLL"; @@ -39,20 +38,14 @@ static PROC LoadShfolderProc(const char* proc) //first try with shell32 if (!hShell32) - { - hShell32 = GetModuleHandle(Shell32Fn); - if (!hShell32) hShell32 = LoadLibrary(Shell32Fn); - } + hShell32 = LoadLibrary(Shell32Fn); if (hShell32) ret = kexGetProcAddress(hShell32, proc); //fallback to shfolder if (!ret) { - if (!hShfolder) - { - hShfolder = GetModuleHandle(ShfolderFn); - if (!hShfolder) hShfolder = LoadLibrary(ShfolderFn); - } + if (!hShfolder) + hShfolder = LoadLibrary(ShfolderFn); if (hShfolder) ret = kexGetProcAddress(hShfolder, proc); } SetLastError(lasterr); @@ -62,19 +55,23 @@ static PROC LoadShfolderProc(const char* proc) /* MAKE_EXPORT SHGetFolderPathA_new=SHGetFolderPathA */ HRESULT WINAPI SHGetFolderPathA_new(HWND hwndOwner, int nFolder, HANDLE hToken, DWORD dwFlags, LPSTR pszPath) { + static SHGetFolderPathA_t SHGetFolderPathA_pfn = (SHGetFolderPathA_t)-1; if (SHGetFolderPathA_pfn == (void*)-1) SHGetFolderPathA_pfn = (SHGetFolderPathA_t) LoadShfolderProc("SHGetFolderPathA"); if (SHGetFolderPathA_pfn == NULL) return E_NOTIMPL; + nFolder = folder_fix(nFolder); return SHGetFolderPathA_pfn(hwndOwner, nFolder, hToken, dwFlags, pszPath); } /* MAKE_EXPORT SHGetFolderPathW_new=SHGetFolderPathW */ HRESULT WINAPI SHGetFolderPathW_new(HWND hwndOwner, int nFolder, HANDLE hToken, DWORD dwFlags, LPWSTR pszPath) { + static SHGetFolderPathW_t SHGetFolderPathW_pfn = (SHGetFolderPathW_t)-1; if (SHGetFolderPathW_pfn == (void*)-1) SHGetFolderPathW_pfn = (SHGetFolderPathW_t) LoadShfolderProc("SHGetFolderPathW"); if (SHGetFolderPathW_pfn == NULL) return E_NOTIMPL; + nFolder = folder_fix(nFolder); return SHGetFolderPathW_pfn(hwndOwner, nFolder, hToken, dwFlags, pszPath); } diff --git a/apilibs/kexbasen/shell32/SHGetSpecialFolder_fix.c b/apilibs/kexbasen/shell32/SHGetSpecialFolder_fix.c new file mode 100755 index 0000000..2c08db3 --- /dev/null +++ b/apilibs/kexbasen/shell32/SHGetSpecialFolder_fix.c @@ -0,0 +1,47 @@ +/* + * KernelEx + * Copyright (C) 2009, Xeno86 + * + * This file is part of KernelEx source code. + * + * KernelEx is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. + * + * KernelEx is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include "folderfix.h" + +/* MAKE_EXPORT SHGetSpecialFolderLocation_fix=SHGetSpecialFolderLocation */ +HRESULT WINAPI SHGetSpecialFolderLocation_fix(HWND hwndOwner, int nFolder, LPVOID *_ppidl) +{ + LPITEMIDLIST *ppidl = (LPITEMIDLIST*) _ppidl; + // explorer shouldn't receive this because of start menu bug which displays entries twice + if (GetModuleHandle("EXPLORER.EXE") == NULL) + nFolder = folder_fix(nFolder); + return SHGetSpecialFolderLocation(hwndOwner, nFolder, ppidl); +} + +/* MAKE_EXPORT SHGetSpecialFolderPathA_fix=SHGetSpecialFolderPathA */ +BOOL WINAPI SHGetSpecialFolderPathA_fix(HWND hwndOwner, LPSTR lpszPath, int nFolder, BOOL fCreate) +{ + nFolder = folder_fix(nFolder); + return SHGetSpecialFolderPathA(hwndOwner, lpszPath, nFolder, fCreate); +} + +/* MAKE_EXPORT SHGetSpecialFolderPathW_fix=SHGetSpecialFolderPathW */ +BOOL WINAPI SHGetSpecialFolderPathW_fix(HWND hwndOwner, LPWSTR lpszPath, int nFolder, BOOL fCreate) +{ + nFolder = folder_fix(nFolder); + return SHGetSpecialFolderPathW(hwndOwner, lpszPath, nFolder, fCreate); +} diff --git a/apilibs/kexbasen/shell32/_shell32_apilist.c b/apilibs/kexbasen/shell32/_shell32_apilist.c old mode 100644 new mode 100755 index 080751b..eb91d29 --- a/apilibs/kexbasen/shell32/_shell32_apilist.c +++ b/apilibs/kexbasen/shell32/_shell32_apilist.c @@ -42,6 +42,9 @@ static const apilib_named_api shell32_named_apis[] = DECL_API("SHGetFolderPathA", SHGetFolderPathA_new), DECL_API("SHGetFolderPathW", SHGetFolderPathW_new), DECL_API("SHGetNewLinkInfoW", SHGetNewLinkInfoW_fwd), + DECL_API("SHGetSpecialFolderLocation", SHGetSpecialFolderLocation_fix), + DECL_API("SHGetSpecialFolderPathA", SHGetSpecialFolderPathA_fix), + DECL_API("SHGetSpecialFolderPathW", SHGetSpecialFolderPathW_fix), DECL_API("ShellAboutW", ShellAboutW_fwd), DECL_API("ShellExecuteExW", ShellExecuteExW_fwd), DECL_API("ShellExecuteW", ShellExecuteW_fwd), diff --git a/apilibs/kexbasen/shell32/_shell32_apilist.h b/apilibs/kexbasen/shell32/_shell32_apilist.h old mode 100644 new mode 100755 index b8866ca..f3514bb --- a/apilibs/kexbasen/shell32/_shell32_apilist.h +++ b/apilibs/kexbasen/shell32/_shell32_apilist.h @@ -28,9 +28,12 @@ BOOL init_shell32(); extern const apilib_api_table apitable_shell32; /*** AUTOGENERATED APILIST DECLARATIONS BEGIN ***/ -HRESULT WINAPI SHGetFolderLocation_new(HWND hwndOwner, int nFolder, HANDLE hToken, DWORD dwReserved, LPVOID *_ppidl); +HRESULT WINAPI SHGetFolderLocation_new(HWND hwndOwner, int nFolder, HANDLE hToken, DWORD dwReserved, LPVOID *ppidl); HRESULT WINAPI SHGetFolderPathA_new(HWND hwndOwner, int nFolder, HANDLE hToken, DWORD dwFlags, LPSTR pszPath); HRESULT WINAPI SHGetFolderPathW_new(HWND hwndOwner, int nFolder, HANDLE hToken, DWORD dwFlags, LPWSTR pszPath); +HRESULT WINAPI SHGetSpecialFolderLocation_fix(HWND hwndOwner, int nFolder, LPVOID *_ppidl); +BOOL WINAPI SHGetSpecialFolderPathA_fix(HWND hwndOwner, LPSTR lpszPath, int nFolder, BOOL fCreate); +BOOL WINAPI SHGetSpecialFolderPathW_fix(HWND hwndOwner, LPWSTR lpszPath, int nFolder, BOOL fCreate); FWDPROC DragQueryFileW_fwd; FWDPROC ExtractIconExW_fwd; FWDPROC ExtractIconW_fwd; diff --git a/apilibs/kexbasen/shell32/auxshlguid.h b/apilibs/kexbasen/shell32/auxshlguid.h deleted file mode 100644 index 02839bc..0000000 --- a/apilibs/kexbasen/shell32/auxshlguid.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef __AUX_SHLGUID_H -#define __AUX_SHLGUID_H - -#ifdef DEFINE_GUID -#undef DEFINE_GUID -#endif - -#define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ - const GUID name \ - = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } - -DEFINE_GUID(CLSID_NetworkPlaces, 0x208D2C60, 0x3AEA, 0x1069, 0xA2, 0xD7, 0x08, 0x00, 0x2B, 0x30, 0x30, 0x9D); -DEFINE_GUID(CLSID_NetworkDomain, 0x46e06680, 0x4bf0, 0x11d1, 0x83, 0xee, 0x00, 0xa0, 0xc9, 0x0d, 0xc8, 0x49); -DEFINE_GUID(CLSID_NetworkServer, 0xc0542a90, 0x4bf0, 0x11d1, 0x83, 0xee, 0x00, 0xa0, 0xc9, 0x0d, 0xc8, 0x49); -DEFINE_GUID(CLSID_NetworkShare, 0x54a754c0, 0x4bf0, 0x11d1, 0x83, 0xee, 0x00, 0xa0, 0xc9, 0x0d, 0xc8, 0x49); -DEFINE_GUID(CLSID_MyComputer, 0x20D04FE0, 0x3AEA, 0x1069, 0xA2, 0xD8, 0x08, 0x00, 0x2B, 0x30, 0x30, 0x9D); -DEFINE_GUID(CLSID_Internet, 0x871C5380, 0x42A0, 0x1069, 0xA2, 0xEA, 0x08, 0x00, 0x2B, 0x30, 0x30, 0x9D); -DEFINE_GUID(CLSID_ShellFSFolder, 0xF3364BA0, 0x65B9, 0x11CE, 0xA9, 0xBA, 0x00, 0xAA, 0x00, 0x4A, 0xE8, 0x37); -DEFINE_GUID(CLSID_RecycleBin, 0x645FF040, 0x5081, 0x101B, 0x9F, 0x08, 0x00, 0xAA, 0x00, 0x2F, 0x95, 0x4E); -DEFINE_GUID(CLSID_ControlPanel, 0x21EC2020, 0x3AEA, 0x1069, 0xA2, 0xDD, 0x08, 0x00, 0x2B, 0x30, 0x30, 0x9D); -DEFINE_GUID(CLSID_Printers, 0x2227A280, 0x3AEA, 0x1069, 0xA2, 0xDE, 0x08, 0x00, 0x2B, 0x30, 0x30, 0x9D); -DEFINE_GUID(CLSID_MyDocuments, 0x450d8fba, 0xad25, 0x11d0, 0x98, 0xa8, 0x08, 0x00, 0x36, 0x1b, 0x11, 0x03); - -#endif diff --git a/apilibs/kexbasen/shell32/folderfix.h b/apilibs/kexbasen/shell32/folderfix.h new file mode 100755 index 0000000..37505fa --- /dev/null +++ b/apilibs/kexbasen/shell32/folderfix.h @@ -0,0 +1,55 @@ +/* + * KernelEx + * Copyright (C) 2009, Xeno86 + * + * This file is part of KernelEx source code. + * + * KernelEx is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. + * + * KernelEx is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __FOLDERFIX_H +#define __FOLDERFIX_H + +/* + * The purpose of the fix is that the Start Menu in Windows 98 + * and Windows Me don't display any items from "All Users\Start Menu" folder. + * Thus the fix is to redirect CSIDL_COMMON_* to approperiate CSIDL_* folders. + * + * Interesingly Desktop displays icons from "All Users\Desktop"... + * + * This fix is applied to following functions: + * SHGetFolderPathA (both SHELL32 and SHFOLDER) + * SHGetFolderPathW (both SHELL32 and SHFOLDER) + * SHGetFolderLocation + * SHGetSpecialFolderPathA + * SHGetSpecialFolderPathW + * SHGetSpecialFolderLocation + */ + +inline int folder_fix(int nFolder) +{ + int nFolderFlags = nFolder & CSIDL_FLAG_MASK; + nFolder &= ~CSIDL_FLAG_MASK; + if (nFolder == CSIDL_COMMON_PROGRAMS) + nFolder = CSIDL_PROGRAMS; + else if (nFolder == CSIDL_COMMON_STARTMENU) + nFolder = CSIDL_STARTMENU; + else if (nFolder == CSIDL_COMMON_STARTUP) + nFolder = CSIDL_STARTUP; + nFolder |= nFolderFlags; + return nFolder; +} + +#endif diff --git a/apilibs/kexbasen/shell32/pidl.h b/apilibs/kexbasen/shell32/pidl.h deleted file mode 100644 index 6ef2138..0000000 --- a/apilibs/kexbasen/shell32/pidl.h +++ /dev/null @@ -1,286 +0,0 @@ -/* - * internal pidl functions - * - * Copyright 1998 Juergen Schmied - * Copyright 2004 Juan Lang - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - * - * NOTES: - * - * DO NOT use this definitions outside the shell32.dll ! - * - * The contents of a pidl should never used from a application - * directly. - * - * Undocumented: - * MS says: the abID of SHITEMID should be treated as binary data and not - * be interpreted by applications. Applies to everyone but MS itself. - * Word95 interprets the contents of abID (Filesize/Date) so we have to go - * for binary compatibility here. - */ - -#ifndef __WINE_PIDL_H -#define __WINE_PIDL_H - -#include - -#include "windef.h" -#include "winbase.h" -#include "winuser.h" -#include "shlobj.h" - -/* -* the pidl does cache fileattributes to speed up SHGetAttributes when -* displaying a big number of files. -* -* a pidl of NULL means the desktop -* -* The structure of the pidl seems to be a union. The first byte of the -* PIDLDATA desribes the type of pidl. -* -* object ! first byte / ! format ! living space -* ! size -* ---------------------------------------------------------------- -* my computer 0x1F/20 guid (2) (usual) -* network 0x1F guid -* bitbucket 0x1F guid -* drive 0x23/25 drive (usual) -* drive 0x25/25 drive (lnk/persistent) -* drive 0x29/25 drive -* shell extension 0x2E guid -* drive 0x2F drive (lnk/persistent) -* folder/file 0x30 folder/file (1) (lnk/persistent) -* folder 0x31 folder (usual) -* valueA 0x32 file (ANSI file name) -* valueW 0x34 file (Unicode file name) -* workgroup 0x41 network (3) -* computer 0x42 network (4) -* net provider 0x46 network -* whole network 0x47 network (5) -* MSITStore 0x61 htmlhlp (7) -* printers/ras connections 0x70 guid -* history/favorites 0xb1 file -* share 0xc3 network (6) -* -* guess: the persistent elements are non tracking -* -* (1) dummy byte is used, attributes are empty -* (2) IID_MyComputer = 20D04FE0L-3AEA-1069-A2D8-08002B30309D -* (3) two strings "workgroup" "Microsoft Network" -* (4) two strings "\\sirius" "Microsoft Network" -* (5) one string "Entire Network" -* (6) two strings "\\sirius\c" "Microsoft Network" -* (7) contains string "mk:@MSITStore:C:\path\file.chm::/path/filename.htm" -* GUID 871C5380-42A0-1069-A2EA-08002B30309D -*/ - -#define PT_CPLAPPLET 0x00 -#define PT_GUID 0x1F -#define PT_DRIVE 0x23 -#define PT_DRIVE2 0x25 -#define PT_DRIVE3 0x29 -#define PT_SHELLEXT 0x2E -#define PT_DRIVE1 0x2F -#define PT_FOLDER1 0x30 -#define PT_FOLDER 0x31 -#define PT_VALUE 0x32 -#define PT_VALUEW 0x34 -#define PT_WORKGRP 0x41 -#define PT_COMP 0x42 -#define PT_NETPROVIDER 0x46 -#define PT_NETWORK 0x47 -#define PT_IESPECIAL1 0x61 -#define PT_YAGUID 0x70 /* yet another guid.. */ -#define PT_IESPECIAL2 0xb1 -#define PT_SHARE 0xc3 - -#include "pshpack1.h" -typedef BYTE PIDLTYPE; - -typedef struct tagPIDLCPanelStruct -{ - BYTE dummy; /*01 is 0x00 */ - DWORD iconIdx; /*02 negative icon ID */ - WORD offsDispName; /*06*/ - WORD offsComment; /*08*/ - CHAR szName[1]; /*10*/ /* terminated by 0x00, followed by display name and comment string */ -} PIDLCPanelStruct; - -typedef struct tagGUIDStruct -{ - BYTE dummy; /* offset 01 is unknown */ - GUID guid; /* offset 02 */ -} GUIDStruct; - -typedef struct tagDriveStruct -{ - CHAR szDriveName[20]; /*01*/ - WORD unknown; /*21*/ -} DriveStruct; - -typedef struct tagFileStruct -{ - BYTE dummy; /*01 is 0x00 for files or dirs */ - DWORD dwFileSize; /*02*/ - WORD uFileDate; /*06*/ - WORD uFileTime; /*08*/ - WORD uFileAttribs; /*10*/ - CHAR szNames[1]; /*12*/ - /* Here are coming two strings. The first is the long name. - The second the dos name when needed or just 0x00 */ -} FileStruct; - -/* At least on WinXP, this struct is appended with 2-byte-alignment to FileStruct. There follows - * a WORD member after the wszName string, which gives the offset from the beginning of the PIDL - * to the FileStructW member. */ -typedef struct tagFileStructW { - WORD cbLen; - BYTE dummy1[6]; - WORD uCreationDate; - WORD uCreationTime; - WORD uLastAccessDate; - WORD uLastAccessTime; - BYTE dummy2[4]; - WCHAR wszName[1]; -} FileStructW; - -typedef struct tagValueW -{ - WCHAR name[1]; -} ValueWStruct; - -typedef struct tagPIDLDATA -{ PIDLTYPE type; /*00*/ - union - { - struct tagGUIDStruct guid; - struct tagDriveStruct drive; - struct tagFileStruct file; - struct - { WORD dummy; /*01*/ - CHAR szNames[1]; /*03*/ - } network; - struct - { WORD dummy; /*01*/ - DWORD dummy1; /*02*/ - CHAR szName[1]; /*06*/ /* terminated by 0x00 0x00 */ - } htmlhelp; - struct tagPIDLCPanelStruct cpanel; - struct tagValueW valueW; - }u; -} PIDLDATA, *LPPIDLDATA; -#include "poppack.h" - -/* - * getting special values from simple pidls - */ -DWORD _ILSimpleGetText (LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize); -DWORD _ILSimpleGetTextW (LPCITEMIDLIST pidl, LPWSTR pOut, UINT uOutSize); -BOOL _ILGetFileDate (LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize); -DWORD _ILGetFileSize (LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize); -BOOL _ILGetExtension (LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize); -void _ILGetFileType (LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize); -DWORD _ILGetFileAttributes (LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize); - -BOOL _ILGetFileDateTime (LPCITEMIDLIST pidl, FILETIME *ft); -DWORD _ILGetDrive (LPCITEMIDLIST, LPSTR, UINT); - -/* - * testing simple pidls - */ -BOOL _ILIsDesktop (LPCITEMIDLIST pidl); -BOOL _ILIsMyComputer (LPCITEMIDLIST pidl); -BOOL _ILIsDrive (LPCITEMIDLIST pidl); -BOOL _ILIsFolder (LPCITEMIDLIST pidl); -BOOL _ILIsValue (LPCITEMIDLIST pidl); -BOOL _ILIsSpecialFolder (LPCITEMIDLIST pidl); -BOOL _ILIsPidlSimple (LPCITEMIDLIST pidl); -BOOL _ILIsCPanelStruct (LPCITEMIDLIST pidl); -/* -static inline -BOOL _ILIsEqualSimple (LPCITEMIDLIST pidlA, LPCITEMIDLIST pidlB) -{ - return (pidlA->mkid.cb > 0 && !memcmp(pidlA, pidlB, pidlA->mkid.cb)) || - (!pidlA->mkid.cb && !pidlB->mkid.cb); -} -static inline -BOOL _ILIsEmpty (LPCITEMIDLIST pidl) { return _ILIsDesktop(pidl); } -*/ - -/* - * simple pidls - */ - -/* Basic PIDL constructor. Allocates size + 5 bytes, where: - * - two bytes are SHITEMID.cb - * - one byte is PIDLDATA.type - * - two bytes are the NULL PIDL terminator - * Sets type of the returned PIDL to type. - */ -LPITEMIDLIST _ILAlloc(PIDLTYPE type, unsigned int size); - -/* Creates a PIDL with guid format and type type, which must be one of PT_GUID, - * PT_SHELLEXT, or PT_YAGUID. - */ -LPITEMIDLIST _ILCreateGuid(PIDLTYPE type, const IID *guid); - -/* Like _ILCreateGuid, but using the string szGUID. */ -LPITEMIDLIST _ILCreateGuidFromStrA(LPCSTR szGUID); -LPITEMIDLIST _ILCreateGuidFromStrW(LPCWSTR szGUID); - -/* Commonly used PIDLs representing file system objects. */ -LPITEMIDLIST _ILCreateDesktop (void); -LPITEMIDLIST _ILCreateFromFindDataA(WIN32_FIND_DATAA *stffile); -LPITEMIDLIST _ILCreateFromFindDataW(WIN32_FIND_DATAW *stffile); -HRESULT _ILCreateFromPathA (LPCSTR szPath, LPITEMIDLIST* ppidl); -HRESULT _ILCreateFromPathW (LPCWSTR szPath, LPITEMIDLIST* ppidl); - -/* Other helpers */ -LPITEMIDLIST _ILCreateMyComputer (void); -LPITEMIDLIST _ILCreateMyDocuments (void); -LPITEMIDLIST _ILCreateIExplore (void); -LPITEMIDLIST _ILCreateControlPanel (void); -LPITEMIDLIST _ILCreatePrinters (void); -LPITEMIDLIST _ILCreateNetwork (void); -LPITEMIDLIST _ILCreateBitBucket (void); -LPITEMIDLIST _ILCreateDrive (LPCWSTR); - -/* - * helper functions (getting struct-pointer) - */ -LPPIDLDATA _ILGetDataPointer (LPCITEMIDLIST); -LPSTR _ILGetTextPointer (LPCITEMIDLIST); -LPSTR _ILGetSTextPointer (LPCITEMIDLIST); -IID *_ILGetGUIDPointer (LPCITEMIDLIST pidl); -FileStructW *_ILGetFileStructW (LPCITEMIDLIST pidl); - -/* - * debug helper - */ -void pdump (LPCITEMIDLIST pidl); -BOOL pcheck (LPCITEMIDLIST pidl); - -/* - * aPidl helper - */ -void _ILFreeaPidl(LPITEMIDLIST * apidl, UINT cidl); -LPITEMIDLIST * _ILCopyaPidl(LPCITEMIDLIST * apidlsrc, UINT cidl); -LPITEMIDLIST * _ILCopyCidaToaPidl(LPITEMIDLIST* pidl, LPIDA cida); - -BOOL WINAPI ILGetDisplayNameExA(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, LPSTR path, DWORD type); -BOOL WINAPI ILGetDisplayNameExW(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, LPWSTR path, DWORD type); - -#endif diff --git a/apilibs/kexbasen/shell32/unishell32.c b/apilibs/kexbasen/shell32/unishell32.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbasen/shlwapi/_shlwapi_apilist.c b/apilibs/kexbasen/shfolder/_shfolder_apilist.c old mode 100644 new mode 100755 similarity index 70% rename from apilibs/kexbasen/shlwapi/_shlwapi_apilist.c rename to apilibs/kexbasen/shfolder/_shfolder_apilist.c index 27d7fe6..029995f --- a/apilibs/kexbasen/shlwapi/_shlwapi_apilist.c +++ b/apilibs/kexbasen/shfolder/_shfolder_apilist.c @@ -21,26 +21,27 @@ #include "common.h" #include "kexcoresdk.h" -#include "_shlwapi_apilist.h" +#include "_shfolder_apilist.h" -BOOL init_shlwapi() +BOOL init_shfolder() { return TRUE; } -static const apilib_named_api shlwapi_named_apis[] = +static const apilib_named_api shfolder_named_apis[] = { /*** AUTOGENERATED APILIST NAMED EXPORTS BEGIN ***/ - DECL_API("StrCmpLogicalW", StrCmpLogicalW_new), + DECL_API("SHGetFolderPathA", SHFOLDER_SHGetFolderPathA_new), + DECL_API("SHGetFolderPathW", SHFOLDER_SHGetFolderPathW_new), /*** AUTOGENERATED APILIST NAMED EXPORTS END ***/ }; #if 0 -static const apilib_unnamed_api shlwapi_ordinal_apis[] = +static const apilib_unnamed_api shfolder_ordinal_apis[] = { /*** AUTOGENERATED APILIST ORDINAL EXPORTS BEGIN ***/ /*** AUTOGENERATED APILIST ORDINAL EXPORTS END ***/ }; #endif -const apilib_api_table apitable_shlwapi = DECL_TAB("SHLWAPI.DLL", shlwapi_named_apis, 0 /*shlwapi_ordinal_apis*/); +const apilib_api_table apitable_shfolder = DECL_TAB("SHFOLDER.DLL", shfolder_named_apis, 0 /*shfolder_ordinal_apis*/); diff --git a/apilibs/kexbasen/shlwapi/_shlwapi_apilist.h b/apilibs/kexbasen/shfolder/_shfolder_apilist.h old mode 100644 new mode 100755 similarity index 69% rename from apilibs/kexbasen/shlwapi/_shlwapi_apilist.h rename to apilibs/kexbasen/shfolder/_shfolder_apilist.h index 68bb5f5..1f08030 --- a/apilibs/kexbasen/shlwapi/_shlwapi_apilist.h +++ b/apilibs/kexbasen/shfolder/_shfolder_apilist.h @@ -19,16 +19,17 @@ * */ -#ifndef _SHLWAPI_APILIST_H -#define _SHLWAPI_APILIST_H +#ifndef _SHFOLDER_APILIST_H +#define _SHFOLDER_APILIST_H #include "kexcoresdk.h" -BOOL init_shlwapi(); -extern const apilib_api_table apitable_shlwapi; +BOOL init_shfolder(); +extern const apilib_api_table apitable_shfolder; /*** AUTOGENERATED APILIST DECLARATIONS BEGIN ***/ -INT WINAPI StrCmpLogicalW_new(LPCWSTR lpszStr, LPCWSTR lpszComp); +HRESULT WINAPI SHFOLDER_SHGetFolderPathA_new(HWND hwndOwner, int nFolder, HANDLE hToken, DWORD dwFlags, LPSTR pszPath); +HRESULT WINAPI SHFOLDER_SHGetFolderPathW_new(HWND hwndOwner, int nFolder, HANDLE hToken, DWORD dwFlags, LPWSTR pszPath); /*** AUTOGENERATED APILIST DECLARATIONS END ***/ #endif diff --git a/apilibs/kexbasen/shfolder/shfolder.c b/apilibs/kexbasen/shfolder/shfolder.c new file mode 100755 index 0000000..5718f78 --- /dev/null +++ b/apilibs/kexbasen/shfolder/shfolder.c @@ -0,0 +1,36 @@ +/* + * KernelEx + * Copyright (C) 2009, Xeno86 + * + * This file is part of KernelEx source code. + * + * KernelEx is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. + * + * KernelEx is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include "common.h" +#include "../shell32/_shell32_apilist.h" + +/* MAKE_EXPORT SHFOLDER_SHGetFolderPathA_new=SHGetFolderPathA */ +HRESULT WINAPI SHFOLDER_SHGetFolderPathA_new(HWND hwndOwner, int nFolder, HANDLE hToken, DWORD dwFlags, LPSTR pszPath) +{ + return SHGetFolderPathA_new(hwndOwner, nFolder, hToken, dwFlags, pszPath); +} + +/* MAKE_EXPORT SHFOLDER_SHGetFolderPathW_new=SHGetFolderPathW */ +HRESULT WINAPI SHFOLDER_SHGetFolderPathW_new(HWND hwndOwner, int nFolder, HANDLE hToken, DWORD dwFlags, LPWSTR pszPath) +{ + return SHGetFolderPathW_new(hwndOwner, nFolder, hToken, dwFlags, pszPath); +} diff --git a/apilibs/kexbases/Gdi32/gdi9x.h b/apilibs/kexbasen/shlord.c old mode 100644 new mode 100755 similarity index 54% rename from apilibs/kexbases/Gdi32/gdi9x.h rename to apilibs/kexbasen/shlord.c index ee65795..a395e8c --- a/apilibs/kexbases/Gdi32/gdi9x.h +++ b/apilibs/kexbasen/shlord.c @@ -1,59 +1,48 @@ -/* - * KernelEx - * - * Copyright (C) 2009, Tihiy - * This file is part of KernelEx source code. - * - * KernelEx is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; version 2 of the License. - * - * KernelEx is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#ifndef __GDI9X_H -#define __GDI9X_H - -#define LHE_DISCARDED 0x40 -#define LHE_FREEHANDLE 0xFF - -#define GDI_OBJTYPE_MASK 0x5FFF -#define GDI_OBJTYPE_DC 0x4F4D -#define GDI_OBJTYPE_DC_NO 0x4F4E - -#define ResetMapMode( hdc ) SetMapMode( hdc, GetMapMode(hdc) ) - -#pragma pack(push,1) - -typedef struct -{ - WORD wBlock; - BYTE bFlags; - BYTE bLocks; -} LHENTRY, *PLHENTRY; - -typedef struct -{ - WORD wZero; //+0 - WORD wType; //+2 - BYTE filler[0x80]; //+4 - WORD WindowExtX; //+84 - WORD WindowExtY; //+86 - BYTE filler2[4]; //+88 - WORD ViewportExtX; //+8C - WORD ViewportExtY; //+8E - BYTE filler3[4]; //+90 - WORD mapmode; //+94 -} DCOBJ, *PDCOBJ; - -#pragma pack(pop) - -#endif +/* + * KernelEx + * Copyright (C) 2009, Tihiy + * + * This file is part of KernelEx source code. + * + * KernelEx is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. + * + * KernelEx is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include "shlord.h" +#include "common.h" + +static HMODULE hShlwapi; + +void shlwapi_fatal_error(int funcnum) +{ + char msg[256]; + sprintf(msg, "kexbasen: Failed to get shlwapi proc: #%i",funcnum); + fatal_error(msg); +} + +PVOID WINAPI GetShlwapiProc(int funcnum) +{ + if (!hShlwapi) + { + hShlwapi = GetModuleHandle("shlwapi.dll"); + if (!hShlwapi) + hShlwapi = LoadLibrary("shlwapi.dll"); + } + PVOID proc = GetProcAddress(hShlwapi,(LPSTR)funcnum); + if (!proc) + shlwapi_fatal_error(funcnum); + return proc; +} diff --git a/apilibs/kexbasen/shlord.h b/apilibs/kexbasen/shlord.h new file mode 100755 index 0000000..852ce02 --- /dev/null +++ b/apilibs/kexbasen/shlord.h @@ -0,0 +1,27 @@ +/* + * KernelEx + * Copyright (C) 2008, Xeno86 + * + * This file is part of KernelEx source code. + * + * KernelEx is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. + * + * KernelEx is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __SHLORD_H +#define __SHLORD_H + +PVOID WINAPI GetShlwapiProc(int funcnum); + +#endif \ No newline at end of file diff --git a/apilibs/kexbasen/shlwapi/string.c b/apilibs/kexbasen/shlwapi/string.c deleted file mode 100644 index c34a6ef..0000000 --- a/apilibs/kexbasen/shlwapi/string.c +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Shlwapi string functions - * - * Copyright 1998 Juergen Schmied - * Copyright 2002 Jon Griffiths - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include -#pragma warning(disable:4002) -#define TRACE() - -EXTERN_C DECLSPEC_IMPORT BOOL WINAPI StrToIntExW(LPCWSTR lpszStr, DWORD dwFlags, LPINT lpiRet); -EXTERN_C DECLSPEC_IMPORT BOOL WINAPI ChrCmpIW(WCHAR ch1, WCHAR ch2); - -static int isdigitW(WCHAR wc) -{ - if (wc >= '0' && wc <= '9') - return 1; - return 0; -} - -/************************************************************************* - * StrCmpLogicalW [SHLWAPI.@] - * - * Compare two strings, ignoring case and comparing digits as numbers. - * - * PARAMS - * lpszStr [I] First string to compare - * lpszComp [I] Second string to compare - * iLen [I] Length to compare - * - * RETURNS - * TRUE If the strings are equal. - * FALSE Otherwise. - */ -/* MAKE_EXPORT StrCmpLogicalW_new=StrCmpLogicalW */ -INT WINAPI StrCmpLogicalW_new(LPCWSTR lpszStr, LPCWSTR lpszComp) -{ - INT iDiff; - - TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp)); - - if (lpszStr && lpszComp) - { - while (*lpszStr) - { - if (!*lpszComp) - return 1; - else if (isdigitW(*lpszStr)) - { - int iStr, iComp; - - if (!isdigitW(*lpszComp)) - return -1; - - /* Compare the numbers */ - StrToIntExW(lpszStr, 0, &iStr); - StrToIntExW(lpszComp, 0, &iComp); - - if (iStr < iComp) - return -1; - else if (iStr > iComp) - return 1; - - /* Skip */ - while (isdigitW(*lpszStr)) - lpszStr++; - while (isdigitW(*lpszComp)) - lpszComp++; - } - else if (isdigitW(*lpszComp)) - return 1; - else - { - iDiff = ChrCmpIW(*lpszStr,*lpszComp); - if (iDiff > 0) - return 1; - else if (iDiff < 0) - return -1; - - lpszStr++; - lpszComp++; - } - } - if (*lpszComp) - return -1; - } - return 0; -} - diff --git a/apilibs/kexbasen/unifwd.c b/apilibs/kexbasen/unifwd.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbasen/unifwd.h b/apilibs/kexbasen/unifwd.h old mode 100644 new mode 100755 diff --git a/apilibs/kexbasen/user32/_user32_apilist.c b/apilibs/kexbasen/user32/_user32_apilist.c old mode 100644 new mode 100755 index 73969e5..03517fb --- a/apilibs/kexbasen/user32/_user32_apilist.c +++ b/apilibs/kexbasen/user32/_user32_apilist.c @@ -33,23 +33,12 @@ static const apilib_named_api user32_named_apis[] = /*** AUTOGENERATED APILIST NAMED EXPORTS BEGIN ***/ DECL_API("AppendMenuW", AppendMenuW_fwd), DECL_API("BroadcastSystemMessageW", BroadcastSystemMessageW_fwd), - DECL_API("CallWindowProcW", CallWindowProcW_fwd), DECL_API("ChangeDisplaySettingsExW", ChangeDisplaySettingsExW_fwd), DECL_API("ChangeDisplaySettingsW", ChangeDisplaySettingsW_fwd), DECL_API("ChangeMenuW", ChangeMenuW_fwd), - DECL_API("CreateDialogIndirectParamW", CreateDialogIndirectParamW_fwd), - DECL_API("CreateDialogParamW", CreateDialogParamW_new), - DECL_API("CreateMDIWindowW", CreateMDIWindowW_fwd), - DECL_API("CreateWindowExW", CreateWindowExW_fwd), DECL_API("DdeCreateStringHandleW", DdeCreateStringHandleW_fwd), DECL_API("DdeInitializeW", DdeInitializeW_fwd), DECL_API("DdeQueryStringW", DdeQueryStringW_fwd), - DECL_API("DefDlgProcW", DefDlgProcW_fwd), - DECL_API("DefFrameProcW", DefFrameProcW_fwd), - DECL_API("DefMDIChildProcW", DefMDIChildProcW_fwd), - DECL_API("DefWindowProcW", DefWindowProcW_new), - DECL_API("DialogBoxIndirectParamW", DialogBoxIndirectParamW_fwd), - DECL_API("DialogBoxParamW", DialogBoxParamW_fwd), DECL_API("DlgDirListComboBoxW", DlgDirListComboBoxW_fwd), DECL_API("DlgDirListW", DlgDirListW_fwd), DECL_API("DlgDirSelectComboBoxExW", DlgDirSelectComboBoxExW_fwd), @@ -65,12 +54,8 @@ static const apilib_named_api user32_named_apis[] = DECL_API("FindWindowExW", FindWindowExW_fwd), DECL_API("FindWindowW", FindWindowW_fwd), DECL_API("GetAltTabInfoW", GetAltTabInfoW_fwd), - DECL_API("GetClassInfoExW", GetClassInfoExW_fwd), - DECL_API("GetClassInfoW", GetClassInfoW_fwd), - DECL_API("GetClassLongW", GetClassLongW_fwd), DECL_API("GetClassNameW", GetClassNameW_fwd), DECL_API("GetClipboardFormatNameW", GetClipboardFormatNameW_fwd), - DECL_API("GetDlgItemTextW", GetDlgItemTextW_fwd), DECL_API("GetKeyNameTextW", GetKeyNameTextW_fwd), DECL_API("GetKeyboardLayoutNameW", GetKeyboardLayoutNameW_fwd), DECL_API("GetMenuItemInfoW", GetMenuItemInfoW_fwd), @@ -78,13 +63,9 @@ static const apilib_named_api user32_named_apis[] = DECL_API("GetMonitorInfoW", GetMonitorInfoW_fwd), DECL_API("GetPropW", GetPropW_fwd), DECL_API("GetTabbedTextExtentW", GetTabbedTextExtentW_fwd), - DECL_API("GetWindowLongW", GetWindowLongW_fwd), - DECL_API("GetWindowTextLengthW", GetWindowTextLengthW_fwd), - DECL_API("GetWindowTextW", GetWindowTextW_fwd), DECL_API("GrayStringW", GrayStringW_fwd), DECL_API("InsertMenuItemW", InsertMenuItemW_fwd), DECL_API("InsertMenuW", InsertMenuW_fwd), - DECL_API("IsWindowUnicode", IsWindowUnicode_fwd), DECL_API("LoadAcceleratorsW", LoadAcceleratorsW_fwd), DECL_API("LoadBitmapW", LoadBitmapW_fwd), DECL_API("LoadCursorFromFileW", LoadCursorFromFileW_fwd), @@ -98,30 +79,14 @@ static const apilib_named_api user32_named_apis[] = DECL_API("MapVirtualKeyW", MapVirtualKeyW_fwd), DECL_API("MessageBoxIndirectW", MessageBoxIndirectW_fwd), DECL_API("ModifyMenuW", ModifyMenuW_fwd), - DECL_API("PostMessageW", PostMessageW_fwd), - DECL_API("PostThreadMessageW", PostThreadMessageW_fwd), - DECL_API("RegisterClassExW", RegisterClassExW_fwd), - DECL_API("RegisterClassW", RegisterClassW_fwd), DECL_API("RegisterClipboardFormatW", RegisterClipboardFormatW_fwd), DECL_API("RegisterDeviceNotificationW", RegisterDeviceNotificationW_fwd), DECL_API("RegisterWindowMessageW", RegisterWindowMessageW_fwd), DECL_API("RemovePropW", RemovePropW_fwd), - DECL_API("SendDlgItemMessageW", SendDlgItemMessageW_fwd), - DECL_API("SendMessageCallbackW", SendMessageCallbackW_fwd), - DECL_API("SendMessageTimeoutW", SendMessageTimeoutW_fwd), - DECL_API("SendMessageW", SendMessageW_fwd), - DECL_API("SendNotifyMessageW", SendNotifyMessageW_fwd), - DECL_API("SetClassLongW", SetClassLongW_fwd), - DECL_API("SetDlgItemTextW", SetDlgItemTextW_fwd), DECL_API("SetMenuItemInfoW", SetMenuItemInfoW_fwd), DECL_API("SetPropW", SetPropW_fwd), - DECL_API("SetWindowLongW", SetWindowLongW_fwd), - DECL_API("SetWindowTextW", SetWindowTextW_fwd), - DECL_API("SetWindowsHookExW", SetWindowsHookExW_fwd), - DECL_API("SetWindowsHookW", SetWindowsHookW_fwd), DECL_API("SystemParametersInfoW", SystemParametersInfoW_fwd), DECL_API("TabbedTextOutW", TabbedTextOutW_fwd), - DECL_API("UnregisterClassW", UnregisterClassW_fwd), DECL_API("VkKeyScanExW", VkKeyScanExW_fwd), DECL_API("VkKeyScanW", VkKeyScanW_fwd), DECL_API("WinHelpW", WinHelpW_fwd), diff --git a/apilibs/kexbasen/user32/_user32_apilist.h b/apilibs/kexbasen/user32/_user32_apilist.h old mode 100644 new mode 100755 index 99b6088..1e722b2 --- a/apilibs/kexbasen/user32/_user32_apilist.h +++ b/apilibs/kexbasen/user32/_user32_apilist.h @@ -30,21 +30,12 @@ extern const apilib_api_table apitable_user32; /*** AUTOGENERATED APILIST DECLARATIONS BEGIN ***/ FWDPROC AppendMenuW_fwd; FWDPROC BroadcastSystemMessageW_fwd; -FWDPROC CallWindowProcW_fwd; FWDPROC ChangeDisplaySettingsExW_fwd; FWDPROC ChangeDisplaySettingsW_fwd; FWDPROC ChangeMenuW_fwd; -FWDPROC CreateDialogIndirectParamW_fwd; -FWDPROC CreateMDIWindowW_fwd; -FWDPROC CreateWindowExW_fwd; FWDPROC DdeCreateStringHandleW_fwd; FWDPROC DdeInitializeW_fwd; FWDPROC DdeQueryStringW_fwd; -FWDPROC DefDlgProcW_fwd; -FWDPROC DefFrameProcW_fwd; -FWDPROC DefMDIChildProcW_fwd; -FWDPROC DialogBoxIndirectParamW_fwd; -FWDPROC DialogBoxParamW_fwd; FWDPROC DlgDirListComboBoxW_fwd; FWDPROC DlgDirListW_fwd; FWDPROC DlgDirSelectComboBoxExW_fwd; @@ -60,12 +51,8 @@ FWDPROC EnumPropsW_fwd; FWDPROC FindWindowExW_fwd; FWDPROC FindWindowW_fwd; FWDPROC GetAltTabInfoW_fwd; -FWDPROC GetClassInfoExW_fwd; -FWDPROC GetClassInfoW_fwd; -FWDPROC GetClassLongW_fwd; FWDPROC GetClassNameW_fwd; FWDPROC GetClipboardFormatNameW_fwd; -FWDPROC GetDlgItemTextW_fwd; FWDPROC GetKeyboardLayoutNameW_fwd; FWDPROC GetKeyNameTextW_fwd; FWDPROC GetMenuItemInfoW_fwd; @@ -73,13 +60,9 @@ FWDPROC GetMenuStringW_fwd; FWDPROC GetMonitorInfoW_fwd; FWDPROC GetPropW_fwd; FWDPROC GetTabbedTextExtentW_fwd; -FWDPROC GetWindowLongW_fwd; -FWDPROC GetWindowTextLengthW_fwd; -FWDPROC GetWindowTextW_fwd; FWDPROC GrayStringW_fwd; FWDPROC InsertMenuItemW_fwd; FWDPROC InsertMenuW_fwd; -FWDPROC IsWindowUnicode_fwd; FWDPROC LoadAcceleratorsW_fwd; FWDPROC LoadBitmapW_fwd; FWDPROC LoadCursorFromFileW_fwd; @@ -93,37 +76,19 @@ FWDPROC MapVirtualKeyExW_fwd; FWDPROC MapVirtualKeyW_fwd; FWDPROC MessageBoxIndirectW_fwd; FWDPROC ModifyMenuW_fwd; -FWDPROC PostMessageW_fwd; -FWDPROC PostThreadMessageW_fwd; -FWDPROC RegisterClassExW_fwd; -FWDPROC RegisterClassW_fwd; FWDPROC RegisterClipboardFormatW_fwd; FWDPROC RegisterDeviceNotificationW_fwd; FWDPROC RegisterWindowMessageW_fwd; FWDPROC RemovePropW_fwd; -FWDPROC SendDlgItemMessageW_fwd; -FWDPROC SendMessageCallbackW_fwd; -FWDPROC SendMessageTimeoutW_fwd; -FWDPROC SendMessageW_fwd; -FWDPROC SendNotifyMessageW_fwd; -FWDPROC SetClassLongW_fwd; -FWDPROC SetDlgItemTextW_fwd; FWDPROC SetMenuItemInfoW_fwd; FWDPROC SetPropW_fwd; -FWDPROC SetWindowLongW_fwd; -FWDPROC SetWindowsHookExW_fwd; -FWDPROC SetWindowsHookW_fwd; -FWDPROC SetWindowTextW_fwd; FWDPROC SystemParametersInfoW_fwd; FWDPROC TabbedTextOutW_fwd; -FWDPROC UnregisterClassW_fwd; FWDPROC VkKeyScanExW_fwd; FWDPROC VkKeyScanW_fwd; FWDPROC WinHelpW_fwd; FWDPROC wsprintfW_fwd; FWDPROC wvsprintfW_fwd; -HWND WINAPI CreateDialogParamW_new(HINSTANCE hInstance, LPCSTR lpTemplateName, HWND hWndParent, DLGPROC lpDialogFunc, LPARAM dwInitParam); -LRESULT WINAPI DefWindowProcW_new(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); /*** AUTOGENERATED APILIST DECLARATIONS END ***/ #endif diff --git a/apilibs/kexbasen/user32/uniuser32.c b/apilibs/kexbasen/user32/uniuser32.c old mode 100644 new mode 100755 index bfbe1eb..e8adf3c --- a/apilibs/kexbasen/user32/uniuser32.c +++ b/apilibs/kexbasen/user32/uniuser32.c @@ -25,50 +25,12 @@ FORWARD_TO_UNICOWS(AppendMenuW); FORWARD_TO_UNICOWS(BroadcastSystemMessageW); -FORWARD_TO_UNICOWS(CallWindowProcW); FORWARD_TO_UNICOWS(ChangeDisplaySettingsExW); FORWARD_TO_UNICOWS(ChangeDisplaySettingsW); FORWARD_TO_UNICOWS(ChangeMenuW); -FORWARD_TO_UNICOWS(CreateDialogIndirectParamW); - -static BOOL CALLBACK SetUnicode(HWND hwnd, LPARAM lParam) -{ - return SendMessage(hwnd, CCM_SETUNICODEFORMAT, TRUE, 0); -} - -/* MAKE_EXPORT CreateDialogParamW_new=CreateDialogParamW */ -HWND WINAPI CreateDialogParamW_new(HINSTANCE hInstance, LPCSTR lpTemplateName, HWND hWndParent, DLGPROC lpDialogFunc, LPARAM dwInitParam) -{ - typedef HWND (WINAPI *CreateDialogParamW_t)(HINSTANCE, LPCSTR, HWND, DLGPROC, LPARAM); - static CreateDialogParamW_t g_DialogParamW; - HWND hDlg; - if (!g_DialogParamW) g_DialogParamW = (CreateDialogParamW_t) GetUnicowsAddress("CreateDialogParamW"); - hDlg = g_DialogParamW(hInstance, lpTemplateName, hWndParent, lpDialogFunc, dwInitParam); - if (hDlg) EnumChildWindows(hDlg, SetUnicode, 0); - return hDlg; -} - -FORWARD_TO_UNICOWS(CreateMDIWindowW); -FORWARD_TO_UNICOWS(CreateWindowExW); FORWARD_TO_UNICOWS(DdeCreateStringHandleW); FORWARD_TO_UNICOWS(DdeInitializeW); FORWARD_TO_UNICOWS(DdeQueryStringW); -FORWARD_TO_UNICOWS(DefDlgProcW); -FORWARD_TO_UNICOWS(DefFrameProcW); -FORWARD_TO_UNICOWS(DefMDIChildProcW); - -/* MAKE_EXPORT DefWindowProcW_new=DefWindowProcW */ -LRESULT WINAPI DefWindowProcW_new(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) -{ - typedef LRESULT (WINAPI *DefWindowProcW_t)(HWND, UINT, WPARAM, LPARAM); - static DefWindowProcW_t g_DefProcW; - if (!g_DefProcW) g_DefProcW = (DefWindowProcW_t) GetUnicowsAddress("DefWindowProcW"); - if (Msg == WM_NOTIFYFORMAT && lParam == NF_QUERY && IsWindowUnicode(hWnd)) return NFR_UNICODE; - return g_DefProcW(hWnd, Msg, wParam, lParam); -} - -FORWARD_TO_UNICOWS(DialogBoxIndirectParamW); -FORWARD_TO_UNICOWS(DialogBoxParamW); FORWARD_TO_UNICOWS(DlgDirListComboBoxW); FORWARD_TO_UNICOWS(DlgDirListW); FORWARD_TO_UNICOWS(DlgDirSelectComboBoxExW); @@ -84,12 +46,8 @@ FORWARD_TO_UNICOWS(EnumPropsW); FORWARD_TO_UNICOWS(FindWindowExW); FORWARD_TO_UNICOWS(FindWindowW); FORWARD_TO_UNICOWS(GetAltTabInfoW); -FORWARD_TO_UNICOWS(GetClassInfoExW); -FORWARD_TO_UNICOWS(GetClassInfoW); -FORWARD_TO_UNICOWS(GetClassLongW); FORWARD_TO_UNICOWS(GetClassNameW); FORWARD_TO_UNICOWS(GetClipboardFormatNameW); -FORWARD_TO_UNICOWS(GetDlgItemTextW); FORWARD_TO_UNICOWS(GetKeyboardLayoutNameW); FORWARD_TO_UNICOWS(GetKeyNameTextW); FORWARD_TO_UNICOWS(GetMenuItemInfoW); @@ -97,13 +55,9 @@ FORWARD_TO_UNICOWS(GetMenuStringW); FORWARD_TO_UNICOWS(GetMonitorInfoW); FORWARD_TO_UNICOWS(GetPropW); FORWARD_TO_UNICOWS(GetTabbedTextExtentW); -FORWARD_TO_UNICOWS(GetWindowLongW); -FORWARD_TO_UNICOWS(GetWindowTextLengthW); -FORWARD_TO_UNICOWS(GetWindowTextW); FORWARD_TO_UNICOWS(GrayStringW); FORWARD_TO_UNICOWS(InsertMenuItemW); FORWARD_TO_UNICOWS(InsertMenuW); -FORWARD_TO_UNICOWS(IsWindowUnicode); FORWARD_TO_UNICOWS(LoadAcceleratorsW); FORWARD_TO_UNICOWS(LoadBitmapW); FORWARD_TO_UNICOWS(LoadCursorFromFileW); @@ -117,30 +71,14 @@ FORWARD_TO_UNICOWS(MapVirtualKeyExW); FORWARD_TO_UNICOWS(MapVirtualKeyW); FORWARD_TO_UNICOWS(MessageBoxIndirectW); FORWARD_TO_UNICOWS(ModifyMenuW); -FORWARD_TO_UNICOWS(PostMessageW); -FORWARD_TO_UNICOWS(PostThreadMessageW); -FORWARD_TO_UNICOWS(RegisterClassExW); -FORWARD_TO_UNICOWS(RegisterClassW); FORWARD_TO_UNICOWS(RegisterClipboardFormatW); FORWARD_TO_UNICOWS(RegisterDeviceNotificationW); FORWARD_TO_UNICOWS(RegisterWindowMessageW); FORWARD_TO_UNICOWS(RemovePropW); -FORWARD_TO_UNICOWS(SendDlgItemMessageW); -FORWARD_TO_UNICOWS(SendMessageCallbackW); -FORWARD_TO_UNICOWS(SendMessageTimeoutW); -FORWARD_TO_UNICOWS(SendMessageW); -FORWARD_TO_UNICOWS(SendNotifyMessageW); -FORWARD_TO_UNICOWS(SetClassLongW); -FORWARD_TO_UNICOWS(SetDlgItemTextW); FORWARD_TO_UNICOWS(SetMenuItemInfoW); FORWARD_TO_UNICOWS(SetPropW); -FORWARD_TO_UNICOWS(SetWindowLongW); -FORWARD_TO_UNICOWS(SetWindowsHookExW); -FORWARD_TO_UNICOWS(SetWindowsHookW); -FORWARD_TO_UNICOWS(SetWindowTextW); FORWARD_TO_UNICOWS(SystemParametersInfoW); FORWARD_TO_UNICOWS(TabbedTextOutW); -FORWARD_TO_UNICOWS(UnregisterClassW); FORWARD_TO_UNICOWS(VkKeyScanExW); FORWARD_TO_UNICOWS(VkKeyScanW); FORWARD_TO_UNICOWS(WinHelpW); diff --git a/apilibs/kexbasen/winspool/DefaultPrinter.c b/apilibs/kexbasen/winspool/DefaultPrinter.c old mode 100644 new mode 100755 index 1413285..83baaf3 --- a/apilibs/kexbasen/winspool/DefaultPrinter.c +++ b/apilibs/kexbasen/winspool/DefaultPrinter.c @@ -63,8 +63,9 @@ BOOL WINAPI GetDefaultPrinterW(LPWSTR bufW, LPDWORD sizeW) if (ret) { *sizeW = ABUFtoW(buf, sizeA, *sizeW); - if (!ret) - *sizeW = ABUFtoW(buf, sizeA, 0); + if (*sizeW) + return TRUE; + *sizeW = ABUFtoW(buf, sizeA, 0); } return FALSE; } diff --git a/apilibs/kexbasen/winspool/_winspool_apilist.c b/apilibs/kexbasen/winspool/_winspool_apilist.c old mode 100644 new mode 100755 index f29a0fc..d28f6ca --- a/apilibs/kexbasen/winspool/_winspool_apilist.c +++ b/apilibs/kexbasen/winspool/_winspool_apilist.c @@ -31,8 +31,36 @@ BOOL init_winspool() static const apilib_named_api winspool_named_apis[] = { /*** AUTOGENERATED APILIST NAMED EXPORTS BEGIN ***/ + DECL_API("AddJobW", AddJobW_fwd), + DECL_API("AddMonitorW", AddMonitorW_fwd), + DECL_API("AddPortW", AddPortW_fwd), + DECL_API("AddPrintProcessorW", AddPrintProcessorW_fwd), + DECL_API("AddPrintProvidorW", AddPrintProvidorW_fwd), + DECL_API("AddPrinterDriverW", AddPrinterDriverW_fwd), + DECL_API("AddPrinterW", AddPrinterW_fwd), + DECL_API("AdvancedDocumentPropertiesW", AdvancedDocumentPropertiesW_fwd), + DECL_API("ConfigurePortW", ConfigurePortW_fwd), + DECL_API("DeleteMonitorW", DeleteMonitorW_fwd), + DECL_API("DeletePortW", DeletePortW_fwd), + DECL_API("DeletePrintProcessorW", DeletePrintProcessorW_fwd), + DECL_API("DeletePrintProvidorW", DeletePrintProvidorW_fwd), + DECL_API("DeletePrinterDriverW", DeletePrinterDriverW_fwd), + DECL_API("DeviceCapabilitiesW", DeviceCapabilitiesW_fwd), + DECL_API("DocumentPropertiesW", DocumentPropertiesW_fwd), DECL_API("GetDefaultPrinterA", GetDefaultPrinterA), DECL_API("GetDefaultPrinterW", GetDefaultPrinterW), + DECL_API("GetPrintProcessorDirectoryW", GetPrintProcessorDirectoryW_fwd), + DECL_API("GetPrinterDataExA", GetPrinterDataExA_stub), + DECL_API("GetPrinterDataExW", GetPrinterDataExW_stub), + DECL_API("GetPrinterDriverDirectoryW", GetPrinterDriverDirectoryW_fwd), + DECL_API("OpenPrinterW", OpenPrinterW_fwd), + DECL_API("ResetPrinterW", ResetPrinterW_fwd), + DECL_API("SetJobW", SetJobW_fwd), + DECL_API("SetPrinterDataExA", SetPrinterDataExA_stub), + DECL_API("SetPrinterDataExW", SetPrinterDataExW_stub), + DECL_API("SetPrinterDataW", SetPrinterDataW_fwd), + DECL_API("SetPrinterW", SetPrinterW_fwd), + DECL_API("StartDocPrinterW", StartDocPrinterW_fwd), /*** AUTOGENERATED APILIST NAMED EXPORTS END ***/ }; diff --git a/apilibs/kexbasen/winspool/_winspool_apilist.h b/apilibs/kexbasen/winspool/_winspool_apilist.h old mode 100644 new mode 100755 index 898c2fc..2e3e170 --- a/apilibs/kexbasen/winspool/_winspool_apilist.h +++ b/apilibs/kexbasen/winspool/_winspool_apilist.h @@ -30,6 +30,34 @@ extern const apilib_api_table apitable_winspool; /*** AUTOGENERATED APILIST DECLARATIONS BEGIN ***/ BOOL WINAPI GetDefaultPrinterA(LPSTR buf, LPDWORD size); BOOL WINAPI GetDefaultPrinterW(LPWSTR bufW, LPDWORD sizeW); +STUB GetPrinterDataExA_stub; +STUB GetPrinterDataExW_stub; +STUB SetPrinterDataExA_stub; +STUB SetPrinterDataExW_stub; +FWDPROC AddJobW_fwd; +FWDPROC AddMonitorW_fwd; +FWDPROC AddPortW_fwd; +FWDPROC AddPrinterDriverW_fwd; +FWDPROC AddPrinterW_fwd; +FWDPROC AddPrintProcessorW_fwd; +FWDPROC AddPrintProvidorW_fwd; +FWDPROC AdvancedDocumentPropertiesW_fwd; +FWDPROC ConfigurePortW_fwd; +FWDPROC DeleteMonitorW_fwd; +FWDPROC DeletePortW_fwd; +FWDPROC DeletePrinterDriverW_fwd; +FWDPROC DeletePrintProcessorW_fwd; +FWDPROC DeletePrintProvidorW_fwd; +FWDPROC DeviceCapabilitiesW_fwd; +FWDPROC DocumentPropertiesW_fwd; +FWDPROC GetPrinterDriverDirectoryW_fwd; +FWDPROC GetPrintProcessorDirectoryW_fwd; +FWDPROC OpenPrinterW_fwd; +FWDPROC ResetPrinterW_fwd; +FWDPROC SetJobW_fwd; +FWDPROC SetPrinterDataW_fwd; +FWDPROC SetPrinterW_fwd; +FWDPROC StartDocPrinterW_fwd; /*** AUTOGENERATED APILIST DECLARATIONS END ***/ #endif diff --git a/apilibs/kexbasen/winspool/_winspool_stubs.c b/apilibs/kexbasen/winspool/_winspool_stubs.c new file mode 100755 index 0000000..e9b75bf --- /dev/null +++ b/apilibs/kexbasen/winspool/_winspool_stubs.c @@ -0,0 +1,27 @@ +/* + * KernelEx + * Copyright (C) 2010, Tihiy + * + * This file is part of KernelEx source code. + * + * KernelEx is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. + * + * KernelEx is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "common.h" + +UNIMPL_FUNC(GetPrinterDataExA, 7); +UNIMPL_FUNC(GetPrinterDataExW, 7); +UNIMPL_FUNC(SetPrinterDataExA, 6); +UNIMPL_FUNC(SetPrinterDataExW, 6); diff --git a/apilibs/kexbasen/winspool/uniwinspool.c b/apilibs/kexbasen/winspool/uniwinspool.c new file mode 100755 index 0000000..233f808 --- /dev/null +++ b/apilibs/kexbasen/winspool/uniwinspool.c @@ -0,0 +1,67 @@ +/* + * KernelEx + * Copyright (C) 2010, Tihiy + * + * This file is part of KernelEx source code. + * + * KernelEx is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. + * + * KernelEx is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include "unifwd.h" + +//AddForm - not supported +FORWARD_TO_UNICOWS(AddJobW); +FORWARD_TO_UNICOWS(AddMonitorW); +FORWARD_TO_UNICOWS(AddPortW); +//AddPrinterConnection - not supported +FORWARD_TO_UNICOWS(AddPrinterDriverW); +FORWARD_TO_UNICOWS(AddPrinterW); +FORWARD_TO_UNICOWS(AddPrintProcessorW); +FORWARD_TO_UNICOWS(AddPrintProvidorW); //lol providor +FORWARD_TO_UNICOWS(AdvancedDocumentPropertiesW); +FORWARD_TO_UNICOWS(ConfigurePortW); +//DeleteForm - not supported +FORWARD_TO_UNICOWS(DeleteMonitorW); +FORWARD_TO_UNICOWS(DeletePortW); +//DeletePrinterConnection - not supported +FORWARD_TO_UNICOWS(DeletePrinterDriverW); +FORWARD_TO_UNICOWS(DeletePrintProcessorW); +FORWARD_TO_UNICOWS(DeletePrintProvidorW); +FORWARD_TO_UNICOWS(DeviceCapabilitiesW); +FORWARD_TO_UNICOWS(DocumentPropertiesW); +//EnumForms - not supported +//EnumJobsW - not implemented +//EnumMonitorsW - not implemented +//EnumPortsW - not implemented +//EnumPrinterDriversW - not implemented +//EnumPrintersW - not implemented +//EnumPrintProcessorDatatypesW - not implemented +//EnumPrintProcessorsW - not implemented +//GetForm - not supported +//GetJobW - not implemented +//GetPrinterDataW - not implemented +FORWARD_TO_UNICOWS(GetPrinterDriverDirectoryW); +//GetPrinterDriverW - not implemented +//GetPrinterW - not implemented +FORWARD_TO_UNICOWS(GetPrintProcessorDirectoryW); +FORWARD_TO_UNICOWS(OpenPrinterW); +FORWARD_TO_UNICOWS(ResetPrinterW); +//SetForm - not supported +FORWARD_TO_UNICOWS(SetJobW); +//SetPrinterDataW - not implemented +FORWARD_TO_UNICOWS(SetPrinterDataW); //lol lazy bastards +FORWARD_TO_UNICOWS(SetPrinterW); +FORWARD_TO_UNICOWS(StartDocPrinterW); diff --git a/apilibs/kexbases/Advapi32/OpenSCManager_stub.c b/apilibs/kexbases/Advapi32/OpenSCManager_stub.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/Advapi32/RegDisablePredefinedCache.c b/apilibs/kexbases/Advapi32/RegDisablePredefinedCache.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/Advapi32/RegOpenCurrentUser.c b/apilibs/kexbases/Advapi32/RegOpenCurrentUser.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/Advapi32/RtlGenRandom.c b/apilibs/kexbases/Advapi32/RtlGenRandom.c new file mode 100755 index 0000000..ae9a0bb --- /dev/null +++ b/apilibs/kexbases/Advapi32/RtlGenRandom.c @@ -0,0 +1,58 @@ +/* + * KernelEx + * Copyright (C) 2009 Tihiy + * Copyright (C) 1999 George Marsaglia + * + * This file is part of KernelEx source code. + * + * KernelEx is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. + * + * KernelEx is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include + +#define znew ((z=36969*(z&65535)+(z>>16))<<16) +#define wnew ((w=18000*(w&65535)+(w>>16))&65535) +#define MWC (znew+wnew) +#define SHR3 (jsr=(jsr=(jsr=jsr^(jsr<<17))^(jsr>>13))^(jsr<<5)) +#define CONG (jcong=69069*jcong+1234567) +#define KISS ((MWC^CONG)+SHR3) + +/* Global static variables: */ +static unsigned long z=362436069, w=521288629, jsr=123456789, jcong=380116160; + +/* MAKE_EXPORT SystemFunction036_new=SystemFunction036 */ +BOOL WINAPI SystemFunction036_new(PVOID pbBuffer, ULONG dwLen) +{ + static BOOL bInit = FALSE; + ULONG i; + PUCHAR cBuffer = (PUCHAR) pbBuffer; + + if (!pbBuffer || !dwLen) + return FALSE; + if (!bInit) //init once + { + z = GetTickCount(); + w = GetCurrentThreadId(); + jsr = GetCurrentProcessId(); + jcong = GetSysColor(COLOR_BACKGROUND); + bInit = TRUE; + } + for (i=0;i * Copyright 2003 CodeWeavers Inc. (Ulrich Czekalla) * Copyright 2007 Xeno86 + * Copyright 2009 Tihiy * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -122,7 +123,6 @@ OpenThreadToken_new( HANDLE ThreadHandle, DWORD DesiredAccess, { FIXME("OpenThreadToken(0x%08x,0x08lx,0x%08x,%p): stub\n", ThreadHandle,DesiredAccess, OpenAsSelf, TokenHandle); - if (OpenAsSelf) return FALSE; //shlwapi hack *(int*)TokenHandle = 0xcafe; return TRUE; } @@ -454,7 +454,7 @@ CopySid_new( DWORD nDestinationSidLength, PSID pDestinationSid, PSID pSourceSid (nDestinationSidLength < GetLengthSid_new(pSourceSid))) return FALSE; - if (nDestinationSidLength < (((SID*)pSourceSid)->SubAuthorityCount*4+8)) + if (nDestinationSidLength < (((SID*)pSourceSid)->SubAuthorityCount*4u+8)) return FALSE; memmove(pDestinationSid, pSourceSid, ((SID*)pSourceSid)->SubAuthorityCount*4+8); @@ -549,8 +549,11 @@ InitializeSid_new ( int i; SID* pisid=(SID*)pSid; - if (nSubAuthorityCount >= SID_MAX_SUB_AUTHORITIES) - return FALSE; + if (!pSid || nSubAuthorityCount >= SID_MAX_SUB_AUTHORITIES) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } pisid->Revision = SID_REVISION; pisid->SubAuthorityCount = nSubAuthorityCount; @@ -897,17 +900,18 @@ SetSecurityDescriptorDacl_new ( } if (!daclpresent) - { lpsd->Control &= ~SE_DACL_PRESENT; - return TRUE; + { + lpsd->Control &= ~SE_DACL_PRESENT; + return TRUE; } lpsd->Control |= SE_DACL_PRESENT; lpsd->Dacl = dacl; if (dacldefaulted) - lpsd->Control |= SE_DACL_DEFAULTED; + lpsd->Control |= SE_DACL_DEFAULTED; else - lpsd->Control &= ~SE_DACL_DEFAULTED; + lpsd->Control &= ~SE_DACL_DEFAULTED; return TRUE; } @@ -994,9 +998,87 @@ MakeSelfRelativeSD_new( IN PSECURITY_DESCRIPTOR pSelfRelativeSecurityDescriptor, IN OUT LPDWORD lpdwBufferLength) { - FIXME("MakeSelfRelativeSD(%p,%p,%p(%lu))\n", pAbsoluteSecurityDescriptor, - pSelfRelativeSecurityDescriptor, lpdwBufferLength,*lpdwBufferLength); - return TRUE; + DWORD offsetRel; + ULONG length; + SECURITY_DESCRIPTOR* pAbs = (SECURITY_DESCRIPTOR*)pAbsoluteSecurityDescriptor; + SECURITY_DESCRIPTOR_RELATIVE* pRel = (SECURITY_DESCRIPTOR_RELATIVE*)pSelfRelativeSecurityDescriptor; + + TRACE(" %p %p %p(%d)\n", pAbs, pRel, lpdwBufferLength, + lpdwBufferLength ? *lpdwBufferLength: -1); + + if (!lpdwBufferLength || !pAbs || !pRel) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + length = GetSecurityDescriptorLength_new(pAbs); + if (*lpdwBufferLength < length) + { + *lpdwBufferLength = length; + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return FALSE; + } + + if (pAbs->Control & SE_SELF_RELATIVE) + { + memcpy(pRel, pAbs, length); + return TRUE; + } + + pRel->Revision = pAbs->Revision; + pRel->Sbz1 = pAbs->Sbz1; + pRel->Control = pAbs->Control | SE_SELF_RELATIVE; + + offsetRel = sizeof(SECURITY_DESCRIPTOR_RELATIVE); + if (pAbs->Owner) + { + pRel->Owner = offsetRel; + length = GetLengthSid_new(pAbs->Owner); + memcpy((LPBYTE)pRel + offsetRel, pAbs->Owner, length); + offsetRel += length; + } + else + { + pRel->Owner = 0; + } + + if (pAbs->Group) + { + pRel->Group = offsetRel; + length = GetLengthSid_new(pAbs->Group); + memcpy((LPBYTE)pRel + offsetRel, pAbs->Group, length); + offsetRel += length; + } + else + { + pRel->Group = 0; + } + + if (pAbs->Sacl) + { + pRel->Sacl = offsetRel; + length = pAbs->Sacl->AclSize; + memcpy((LPBYTE)pRel + offsetRel, pAbs->Sacl, length); + offsetRel += length; + } + else + { + pRel->Sacl = 0; + } + + if (pAbs->Dacl) + { + pRel->Dacl = offsetRel; + length = pAbs->Dacl->AclSize; + memcpy((LPBYTE)pRel + offsetRel, pAbs->Dacl, length); + } + else + { + pRel->Dacl = 0; + } + + return TRUE; } /****************************************************************************** @@ -1013,10 +1095,10 @@ BOOL WINAPI GetSecurityDescriptorControl_new ( PSECURITY_DESCRIPTOR pSecurityDe *lpdwRevision = lpsd->Revision; if (*lpdwRevision != SECURITY_DESCRIPTOR_REVISION) - { - SetLastError(ERROR_UNKNOWN_REVISION); - return FALSE; - } + { + SetLastError(ERROR_UNKNOWN_REVISION); + return FALSE; + } *pControl = lpsd->Control; @@ -1053,8 +1135,8 @@ BOOL WINAPI InitializeAcl_new(PACL acl, DWORD size, DWORD rev) } memset(acl,'\0',sizeof(ACL)); - acl->AclRevision = rev; - acl->AclSize = size; + acl->AclRevision = (UCHAR)rev; + acl->AclSize = (USHORT)size; acl->AceCount = 0; return TRUE; } @@ -1274,11 +1356,11 @@ LookupAccountSidW_new( name_use); if (accountSize) *accountSize = lstrlenW(ac)+1; - if (account && (*accountSize > lstrlenW(ac))) + if (account && (*accountSize > (DWORD)lstrlenW(ac))) lstrcpyW(account, ac); if (domainSize) *domainSize = lstrlenW(dm)+1; - if (domain && (*domainSize > lstrlenW(dm))) + if (domain && (*domainSize > (DWORD)lstrlenW(dm))) lstrcpyW(domain,dm); if (name_use) *name_use = SidTypeUser; @@ -1318,37 +1400,6 @@ SetFileSecurityW_new( LPCWSTR lpFileName, return TRUE; } -#if 0 /* unneeded ?? */ -/****************************************************************************** - * QueryWindows31FilesMigration [ADVAPI32.@] - * - * PARAMS - * x1 [] - */ -BOOL WINAPI -QueryWindows31FilesMigration( DWORD x1 ) -{ - FIXME("(%ld):stub\n",x1); - return TRUE; -} - -/****************************************************************************** - * SynchronizeWindows31FilesAndWindowsNTRegistry [ADVAPI32.@] - * - * PARAMS - * x1 [] - * x2 [] - * x3 [] - * x4 [] - */ -BOOL WINAPI -SynchronizeWindows31FilesAndWindowsNTRegistry( DWORD x1, DWORD x2, DWORD x3, - DWORD x4 ) -{ - FIXME("(0x%08lx,0x%08lx,0x%08lx,0x%08lx):stub\n",x1,x2,x3,x4); - return TRUE; -} -#endif #if 0 /* LSA disabled */ /****************************************************************************** @@ -1468,19 +1519,6 @@ LsaClose(IN LSA_HANDLE ObjectHandle) return 0xc0000000; } #endif -/****************************************************************************** - * NotifyBootConfigStatus [ADVAPI32.@] - * - * PARAMS - * x1 [] - */ -/* MAKE_EXPORT NotifyBootConfigStatus_new=NotifyBootConfigStatus */ -BOOL WINAPI -NotifyBootConfigStatus_new( BOOL x1 ) -{ - FIXME("NotifyBootConfigStatus(0x%08x):stub\n",x1); - return TRUE; -} /****************************************************************************** * RevertToSelf [ADVAPI32.@] @@ -1578,10 +1616,60 @@ BOOL WINAPI AddAccessAllowedAce_new( /* MAKE_EXPORT GetAce_new=GetAce */ BOOL WINAPI GetAce_new(PACL pAcl,DWORD dwAceIndex,LPVOID *pAce ) { - FIXME("GetAce(%p,%ld,%p),stub!\n",pAcl,dwAceIndex,pAce); + PACE_HEADER ace; + + TRACE("(%p,%d,%p)\n",pAcl,dwAceIndex,pAce); + + if (!pAcl || !pAce || dwAceIndex >= pAcl->AceCount) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + ace = (PACE_HEADER)(pAcl + 1); + for (;dwAceIndex;dwAceIndex--) + ace = (PACE_HEADER)(((BYTE*)ace)+ace->AceSize); + + *pAce = ace; + return TRUE; } +/****************************************************************************** + * DeleteAce [ADVAPI32.@] + */ +/* MAKE_EXPORT DeleteAce_new=DeleteAce */ +BOOL WINAPI DeleteAce_new(PACL pAcl, DWORD dwAceIndex) +{ + PACE_HEADER pAce; + + if (!GetAce_new(pAcl,dwAceIndex,(LPVOID*)&pAce)) return FALSE; + + PACE_HEADER pcAce; + DWORD len = 0; + + /* skip over the ACE we are deleting */ + pcAce = (PACE_HEADER)(((BYTE*)pAce)+pAce->AceSize); + dwAceIndex++; + + /* calculate the length of the rest */ + for (; dwAceIndex < pAcl->AceCount; dwAceIndex++) + { + len += pcAce->AceSize; + pcAce = (PACE_HEADER)(((BYTE*)pcAce) + pcAce->AceSize); + } + + /* slide them all backwards */ + memmove(pAce, ((BYTE*)pAce)+pAce->AceSize, len); + pAcl->AceCount--; + + TRACE("pAcl=%p dwAceIndex=%d status=0x%08x\n", pAcl, dwAceIndex, status); + + return TRUE; +} + + + /************************************************************************* * CreateRestrictedToken [ADVAPI32.@] */ @@ -1608,6 +1696,8 @@ BOOL WINAPI CreateRestrictedToken_new( /* MAKE_EXPORT CreateWellKnownSid_new=CreateWellKnownSid */ BOOL WINAPI CreateWellKnownSid_new( DWORD WellKnownSidType, PSID DomainSid, PSID pSid, DWORD* cbSid) { - FIXME("CreateWellKnownSid(%ld,%p,%p,%p,%p),stub!\n",WellKnownSidType,DomainSid,pSid,cbSid); - return TRUE; + FIXME("CreateWellKnownSid(%ld,%p,%p,%p,%p),mostly stub!\n",WellKnownSidType,DomainSid,pSid,cbSid); + //BUGBUG what to do with cbSid? out sid size there? + SID_IDENTIFIER_AUTHORITY localSidAuthority = {SECURITY_NT_AUTHORITY}; + return InitializeSid_new(pSid, &localSidAuthority, 1); } diff --git a/apilibs/kexbases/Advapi32/uniadvapi32.c b/apilibs/kexbases/Advapi32/uniadvapi32.c old mode 100644 new mode 100755 index 44d12fb..a217cb1 --- a/apilibs/kexbases/Advapi32/uniadvapi32.c +++ b/apilibs/kexbases/Advapi32/uniadvapi32.c @@ -1,6 +1,7 @@ /* * KernelEx - * Copyright (C) 2008, Xeno86 + * Copyright (C) 2008-2009, Xeno86 + * Copyright (C) 2009, Tihiy * * This file is part of KernelEx source code. * @@ -17,7 +18,7 @@ * along with GNU Make; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * - */ + */ #include "common.h" @@ -31,83 +32,138 @@ LONG WINAPI RegQueryValueExW_new(HKEY hKey, LPCWSTR lpValueNameW, LPDWORD lpRese BYTE* ptr = stackbuf; BYTE* heapbuf = NULL; DWORD bufsize = sizeof(stackbuf); + DWORD strsize; if ((lpData && !lpcbData) || lpReserved) return ERROR_INVALID_PARAMETER; - if (!lpData && lpcbData) *lpcbData = 0; //try with stack buffer first - if (lpValueNameW) + ALLOC_WtoA(lpValueName); + ret = RegQueryValueExA(hKey, lpValueNameA, lpReserved, &type, ptr, &bufsize); + if (lpType) *lpType = type; + + //retry with dynamic buffer + if (ret == ERROR_MORE_DATA) { - ALLOC_WtoA(lpValueName); + ptr = heapbuf = (BYTE*) HeapAlloc(GetProcessHeap(), 0, bufsize); + if (!heapbuf) + { + return ERROR_NOT_ENOUGH_MEMORY; + } ret = RegQueryValueExA(hKey, lpValueNameA, lpReserved, &type, ptr, &bufsize); - if (lpType) *lpType = type; - if (lpcbData && type != REG_SZ && bufsize > *lpcbData) - { - *lpcbData = bufsize; - return ERROR_MORE_DATA; - } - //retry with dynamic buffer - if (ret == ERROR_MORE_DATA) - { - ptr = heapbuf = (BYTE*) HeapAlloc(GetProcessHeap(), 0, bufsize); - if (!heapbuf) - { - return ERROR_NOT_ENOUGH_MEMORY; - } - ret = RegQueryValueExA(hKey, lpValueNameA, lpReserved, &type, ptr, &bufsize); - } - } - else - { - ret = RegQueryValueExA(hKey, 0, lpReserved, &type, ptr, &bufsize); - if (lpType) *lpType = type; - if (lpcbData && type != REG_SZ && bufsize > *lpcbData) - { - *lpcbData = bufsize; - return ERROR_MORE_DATA; - } - //retry with dynamic buffer - if (ret == ERROR_MORE_DATA) - { - ptr = heapbuf = (BYTE*) HeapAlloc(GetProcessHeap(), 0, bufsize); - if (!heapbuf) - { - return ERROR_NOT_ENOUGH_MEMORY; - } - ret = RegQueryValueExA(hKey, 0, lpReserved, &type, ptr, &bufsize); - } - } - if (ret != ERROR_SUCCESS) goto _end; - - if (type == REG_SZ) - { - if (lpcbData) - { - DWORD gle = GetLastError(); - int written = MultiByteToWideChar(CP_ACP, 0, (LPSTR) ptr, -1, - (LPWSTR)lpData, lpData ? (*lpcbData >> 1) : 0); - if (!written) - { - ret = GetLastError(); - if (ret == ERROR_INSUFFICIENT_BUFFER) - { - *lpcbData = MultiByteToWideChar(CP_ACP, 0, (LPSTR) ptr, - -1, NULL, 0) << 1; - ret = ERROR_MORE_DATA; - } - SetLastError(gle); - goto _end; - } - *lpcbData = written << 1; - } - } - else - { - if (lpData) memcpy(lpData, ptr, bufsize); - if (lpcbData) *lpcbData = bufsize; } -_end: + if (ret == ERROR_SUCCESS && lpcbData) //copy data + { + switch(type) { + case REG_SZ: + case REG_EXPAND_SZ: + case REG_MULTI_SZ: + strsize = MultiByteToWideChar(CP_ACP,0,(LPSTR)ptr,bufsize,NULL,NULL)*sizeof(WCHAR); + if (lpData) + { + if (*lpcbData +#include "GdiObjects.h" +#include "k32ord.h" +#include "kexcoresdk.h" + +static BOOL blockkexgdiobj; +static WORD g_GDILH_addr; +static DWORD g_GdiBase; + +#define REBASEGDI(x) ((PVOID)( g_GdiBase + LOWORD((DWORD)(x)) )) +#define REBASEGDIHIGH(x) ( g_GdiBase + (DWORD)(x) ) + +#define GDIHEAP32BASE 0x10000 +#define GDIHEAP32TOP 0x20000 + +BOOL InitGDIObjects(void) +{ + g_GdiBase = MapSL( LoadLibrary16("gdi") << 16 ); + g_GDILH_addr = ((PINSTANCE16)g_GdiBase)->pLocalHeap; + blockkexgdiobj = (BOOL)GetProcAddress(GetModuleHandle("rp10.dll"),"blockkexgdiobj"); + return (BOOL)g_GdiBase; +} + +PGDIOBJ16 GetGDIObjectPtr( HGDIOBJ hgdiobj ) +{ + WORD wHandle = (WORD)hgdiobj; + if ( wHandle & 1 ) return NULL; //all gdi handles end in b10 or b00, not b01 + if ( wHandle & 3 ) //64K heap + { + PLHENTRY entry = (PLHENTRY)REBASEGDI( wHandle ); + if ( wHandle <= g_GDILH_addr || entry->bFlags == LHE_FREEHANDLE || entry->wBlock <= g_GDILH_addr ) + return NULL; //deleted or invalid handle + if ( entry->bFlags & LHE_DISCARDED ) //discarded DC + { + if ( entry->wBlock & 3 ) return NULL; //they have to divide by 4 + return GetGDIObjectPtr( (HGDIOBJ)entry->wBlock ); //recurse + } + else + { + return (PGDIOBJ16)REBASEGDI(entry->wBlock); + } + } + else //high heap + __try + { + if ( wHandle < 0x80 ) return NULL; //high heap handles start with 0x80 + if ( wHandle > *(WORD*)REBASEGDIHIGH( GDIHEAP32BASE + 0x70 ) ) return NULL; //max hadle value there + DWORD* high = (DWORD*)REBASEGDIHIGH( GDIHEAP32BASE + wHandle ); + if ( *high < GDIHEAP32TOP ) return NULL; //points to invalid handle memory + PGDIOBJ16 ret = (PGDIOBJ16)REBASEGDIHIGH( *high ); + if ( ret->wType == 0 ) return NULL; //points to invalid object memory + return ret; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return NULL; + } +} + +static DWORD SwitchGDIObjectType( PGDIOBJ16 obj ) +{ + __try + { + switch ( obj->wType & GDI_TYPEMASK ) + { + case GDI_TYPE_PEN: + return OBJ_PEN; + case GDI_TYPE_BRUSH: + return OBJ_BRUSH; + case GDI_TYPE_FONT: + return OBJ_FONT; + case GDI_TYPE_PAL: + return OBJ_PAL; + case GDI_TYPE_BITMAP: + return OBJ_BITMAP; + case GDI_TYPE_REGION: + return OBJ_REGION; + case GDI_TYPE_DC: + { + PDCOBJ dcobj = (PDCOBJ)obj; + if ( dcobj->enhmetadc ) return OBJ_ENHMETADC; + if ( dcobj->dcFlags & 1 ) return OBJ_MEMDC; + //fall down + } + case GDI_TYPE_DCX: + case GDI_TYPE_DCY: + return OBJ_DC; + case GDI_TYPE_METADC: + return OBJ_METADC; + case GDI_TYPE_ENHMETA: + return OBJ_ENHMETAFILE; + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + //too bad + } + return 0; +} + + +/* MAKE_EXPORT GetObjectType_fix=GetObjectType */ +DWORD WINAPI GetObjectType_fix( HGDIOBJ hgdiobj ) +{ + if (blockkexgdiobj) return GetObjectType(hgdiobj); + //GetObjectType is rewritten in order to boost it's correctness and speed: + //constantly throwing page/segfaults is very bad on virtual machines. + PGDIOBJ16 obj = GetGDIObjectPtr( hgdiobj ); + DWORD result = 0; + if ( obj ) + { + GrabWin16Lock(); + result = SwitchGDIObjectType( obj ); + ReleaseWin16Lock(); + } + else //still, can be metafile selector + { + WORD wHandle = (WORD)hgdiobj; + if ( (wHandle & 6) == 6 ) //test for ldt selector + { + LDT_ENTRY selector; + GetThreadSelectorEntry( GetCurrentThread(), wHandle, &selector ); + if ( selector.HighWord.Bits.Type == 3 ) + result = GetObjectType(hgdiobj); //resort to gdi32 + } + } + if ( !result ) SetLastError( ERROR_INVALID_HANDLE ); + return result; +} + +/* MAKE_EXPORT DeleteObject_fix=DeleteObject */ +BOOL WINAPI DeleteObject_fix( HGDIOBJ hObject ) +{ + if (blockkexgdiobj) return DeleteObject(hObject); + PGDIOBJ16 obj = GetGDIObjectPtr( hObject ); + if ( !obj || !SwitchGDIObjectType(obj) ) return FALSE; + DWORD violated = 0; + if ( obj->wOwner ) //not system objects + { + if (obj->wType == GDI_TYPE_FONT && ((PFONTOBJ16)obj)->wSelCount >= SEL_FONT_ONCE ) + { + DBGPRINTF(("somebody is trying to delete selected font %p\n",hObject)); + violated = GDI_TYPE_FONT; + } + if (obj->wType == GDI_TYPE_BITMAP && ((PBITMAPOBJ16)obj)->wSelCount == SEL_BITMAP_ONCE ) + { + DBGPRINTF(("somebody is trying to delete selected bitmap %p\n",hObject)); + violated = GDI_TYPE_BITMAP; + } + } + BOOL ret = DeleteObject( hObject ); + if ( violated == GDI_TYPE_FONT ) + ((PFONTOBJ16)obj)->wSelCount |= SEL_FONT_DEL; + else if ( violated == GDI_TYPE_BITMAP ) + ((PBITMAPOBJ16)obj)->wSelCount |= SEL_BITMAP_DEL; + return ret; +} + +/* MAKE_EXPORT SelectObject_fix=SelectObject */ +HGDIOBJ WINAPI SelectObject_fix( HDC hdc, HGDIOBJ hgdiobj ) +{ + if (blockkexgdiobj) return SelectObject(hdc,hgdiobj); + //9x should do this + if ( !hdc ) SetLastError(ERROR_INVALID_HANDLE); + if ( !hdc || !hgdiobj ) return NULL; + HGDIOBJ ret; + ret = SelectObject( hdc, hgdiobj ); + PGDIOBJ16 obj = GetGDIObjectPtr( ret ); + if ( obj && obj->wOwner ) + { + if ( obj->wType == GDI_TYPE_FONT && ((PFONTOBJ16)obj)->wSelCount == SEL_FONT_DEL ) + { + DBGPRINTF(("deleting font %p on unselecting\n",ret)); + DeleteObject(ret); + } + if ( obj->wType == GDI_TYPE_BITMAP && ((PBITMAPOBJ16)obj)->wSelCount == SEL_BITMAP_DEL ) + { + ((PBITMAPOBJ16)obj)->wSelCount = 0; + DBGPRINTF(("deleting bitmap %p on unselecting\n",ret)); + DeleteObject(ret); + } + } + return ret; +} + +/* MAKE_EXPORT DeleteDC_fix=DeleteDC */ +BOOL WINAPI DeleteDC_fix( HDC hdc ) +{ + if (blockkexgdiobj) return DeleteDC(hdc); + BOOL ret; + PGDIOBJ16 obj = GetGDIObjectPtr( hdc ); + if ( !obj || !SwitchGDIObjectType(obj) ) return FALSE; + HGDIOBJ fnt = GetCurrentObject(hdc,OBJ_FONT); + HGDIOBJ bmp = GetCurrentObject(hdc,OBJ_BITMAP); + ret = DeleteDC(hdc); + if (ret) + { + PFONTOBJ16 fntobj = (PFONTOBJ16)GetGDIObjectPtr(fnt); + PBITMAPOBJ16 bitmapobj = (PBITMAPOBJ16)GetGDIObjectPtr(bmp); + if (fntobj && fntobj->wOwner && fntobj->wType == GDI_TYPE_FONT && fntobj->wSelCount == SEL_FONT_DEL) + { + DBGPRINTF(("deleting font %p on dc cleanup\n",fnt)); + DeleteObject(fnt); + } + if (bitmapobj && bitmapobj->header.wOwner && bitmapobj->header.wType == GDI_TYPE_BITMAP && bitmapobj->wSelCount == SEL_BITMAP_DEL) + { + bitmapobj->wSelCount = 0; + DBGPRINTF(("deleting bitmap %p on dc cleanup\n",bmp)); + DeleteObject(bmp); + } + } + return ret; +} + +/* MAKE_EXPORT CreateDIBSection_fix=CreateDIBSection */ +HBITMAP WINAPI CreateDIBSection_fix( + HDC hdc, // handle to DC + BITMAPINFO *pbmi, // bitmap data + UINT iUsage, // data type indicator + VOID **ppvBits, // bit values + HANDLE hSection, // handle to file mapping object + DWORD dwOffset // offset to bitmap bit values +) +{ + if (pbmi && pbmi->bmiHeader.biSize == sizeof(BITMAPINFO)) //9x does not forgive + pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); //9x does not forget + return CreateDIBSection(hdc,pbmi,iUsage,ppvBits,hSection,dwOffset); +} diff --git a/apilibs/kexbases/Gdi32/GdiObjects.h b/apilibs/kexbases/Gdi32/GdiObjects.h new file mode 100755 index 0000000..c14fd2e --- /dev/null +++ b/apilibs/kexbases/Gdi32/GdiObjects.h @@ -0,0 +1,140 @@ +/* + * KernelEx + * + * Copyright (C) 2009, Tihiy + * This file is part of KernelEx source code. + * + * KernelEx is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. + * + * KernelEx is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __GDI9X_H +#define __GDI9X_H + +//those are in thunilay +void GrabWin16Lock(); +void ReleaseWin16Lock(); + +#define LHE_DISCARDED 0x40 +#define LHE_MUTATED 0x80 +#define LHE_FREEHANDLE 0xFF + +#define GDI_TYPEMASK 0x5FFF +#define GDI_TYPE_PEN 0x4F47 +#define GDI_TYPE_BRUSH 0x4F48 +#define GDI_TYPE_FONT 0x4F49 +#define GDI_TYPE_PAL 0x4F4A +#define GDI_TYPE_BITMAP 0x4F4B +#define GDI_TYPE_REGION 0x4F4C +#define GDI_TYPE_DC 0x4F4D +#define GDI_TYPE_DCX 0x4F4E +#define GDI_TYPE_DCY 0x4F4F +#define GDI_TYPE_METADC 0x4F51 +#define GDI_TYPE_ENHMETA 0x4F52 + +#define SEL_FONT_ONCE 0x4 +#define SEL_FONT_DEL 0x2 +#define SEL_BITMAP_ONCE 0x01 +#define SEL_BITMAP_DEL 0x10 + +#define ResetMapMode( hdc ) SetMapMode( hdc, GetMapMode(hdc) ) + +#pragma pack(push,1) + +typedef struct +{ + WORD bDoesntExist; + DWORD dwOldSSSP; + WORD pLocalHeap; + WORD pAtomTable; + WORD pStackTop; + WORD pStackMin; + WORD pStackBottom; +} INSTANCE16, *PINSTANCE16; + +typedef struct +{ + WORD wBlock; + BYTE bFlags; + BYTE bLocks; +} LHENTRY, *PLHENTRY; + +typedef struct +{ + WORD wZero; //+0 + WORD wType; //+2 + DWORD dwNumber; //+4 + DWORD dwSpecific; //+8 + WORD wOwner; //+C +} GDIOBJ16, *PGDIOBJ16; + +typedef struct +{ + GDIOBJ16 header; + WORD wGlobalBitmap; //+14 + WORD wSelCount; //+16 + WORD wHDC; //+18 + WORD wGlobalBitmapInfo; //+20 + DWORD dwReservedShit; //+22 + WORD wBitmapStuff; //+26 + WORD wDeviceStuff; //+28 + WORD wBitmapType; //+30 + WORD wLogColorSpace; //+32 +} BITMAPOBJ16, *PBITMAPOBJ16; + +typedef struct +{ + WORD wZero; //+0 + WORD wType; //+2 + DWORD dwStuff; //+4 + WORD wReserved; //+8 (not used?) + WORD wSelCount; //+A + WORD wOwner; //+C +} FONTOBJ16, *PFONTOBJ16; + +typedef struct +{ + WORD wZero; //+0 + WORD wType; //+2 + DWORD dwNumber; //+4 + DWORD dwBrushStuff; //+8 + WORD wOwner; //+C + DWORD dcFlags; //+E + DWORD stuff[3]; //+12 + WORD wBitmapHandle; //+1E + DWORD stuff2[4]; //+20 + WORD dummy2; //+30 + WORD wGlobalBitmapSelector; //+32 + WORD dummy; //+34 + WORD wGlobalBitmap; //+36 + BYTE skip1[0x4C]; //+38 + WORD WindowExtX; //+84 + WORD WindowExtY; //+86 + BYTE filler2[4]; //+88 + WORD ViewportExtX; //+8C + WORD ViewportExtY; //+8E + BYTE filler3[4]; //+90 + WORD mapmode; //+94 + BYTE filler4[0x68]; //+96 + DWORD lockFlags; //+FE + DWORD skip2; //+102 + WORD enhmetadc; //+106 +} DCOBJ, *PDCOBJ; + +#pragma pack(pop) + +PGDIOBJ16 GetGDIObjectPtr( HGDIOBJ hgdiobj ); +#define GetDCObj(x) (PDCOBJ)GetGDIObjectPtr(x) + +#endif diff --git a/apilibs/kexbases/Gdi32/GetGlyphOutlineA_fix.c b/apilibs/kexbases/Gdi32/GetGlyphOutlineA_fix.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/Gdi32/TextOut.c b/apilibs/kexbases/Gdi32/TextOut.c old mode 100644 new mode 100755 index 7681ce9..7c6862b --- a/apilibs/kexbases/Gdi32/TextOut.c +++ b/apilibs/kexbases/Gdi32/TextOut.c @@ -28,8 +28,7 @@ #include #include -#include "gdi9x.h" -#include "k32ord.h" +#include "GdiObjects.h" #ifdef _MSC_VER #ifdef __cplusplus @@ -42,11 +41,6 @@ __declspec(selectany) int _fltused=1; #define ETO_PDY 0x2000 #endif -static DWORD g_GdiBase; -#define REBASEGDI(x) ( g_GdiBase + (DWORD)(x) ) - - - /* MAKE_EXPORT GetFontUnicodeRanges_new=GetFontUnicodeRanges */ DWORD WINAPI GetFontUnicodeRanges_new( HDC hdc, @@ -93,29 +87,6 @@ int WINAPI GetRandomRgn_NT( return result; } -PDCOBJ GetDCObj( HDC hDC ) -{ - PDCOBJ retobj; - PLHENTRY entry; - if (!hDC) return NULL; - if (!g_GdiBase) g_GdiBase = MapSL( LoadLibrary16("gdi") << 16 ); - entry = (PLHENTRY)REBASEGDI(LOWORD(hDC)); - if ( !entry->wBlock || entry->bFlags == LHE_FREEHANDLE ) return NULL; - if ( entry->bFlags & LHE_DISCARDED ) - { - if ( entry->wBlock & 3 ) return NULL; //32-bit handles have to divide by 4 - DWORD* highDC = (DWORD*)REBASEGDI( 0x10000 + entry->wBlock ); - if ( IsBadReadPtr(highDC,sizeof(DWORD)) ) return NULL; //oops dead handle - retobj = (PDCOBJ)REBASEGDI(*highDC); - if ( IsBadReadPtr(retobj,sizeof(DCOBJ)) ) return NULL; //oops?! - } - else - retobj = (PDCOBJ)REBASEGDI(entry->wBlock); - WORD checktype = (retobj->wType & GDI_OBJTYPE_MASK); - if ( checktype != GDI_OBJTYPE_DC && checktype != GDI_OBJTYPE_DC_NO ) return NULL; - return retobj; -} - void floattofrac( float f, int* m, int* d) { float absf = f > 0 ? f : -f; diff --git a/apilibs/kexbases/Gdi32/_gdi32_apilist.c b/apilibs/kexbases/Gdi32/_gdi32_apilist.c old mode 100644 new mode 100755 index de1eecf..8cee67d --- a/apilibs/kexbases/Gdi32/_gdi32_apilist.c +++ b/apilibs/kexbases/Gdi32/_gdi32_apilist.c @@ -20,12 +20,13 @@ */ #include "common.h" -#include "kexcoresdk.h" #include "_gdi32_apilist.h" +BOOL InitGDIObjects(void); + BOOL init_gdi32() { - return TRUE; + return InitGDIObjects(); } /* @@ -40,14 +41,23 @@ static const apilib_named_api gdi32_named_apis[] = DECL_API("AddFontResourceExA", AddFontResourceExA_new), DECL_API("AddFontResourceExW", AddFontResourceExW_new), DECL_API("AddFontResourceW", AddFontResourceW_new), + DECL_API("CreateDIBSection", CreateDIBSection_fix), + DECL_API("DeleteDC", DeleteDC_fix), + DECL_API("DeleteObject", DeleteObject_fix), + DECL_API("EnumFontFamiliesExA", EnumFontFamiliesExA_new), DECL_API("EnumFontFamiliesExW", EnumFontFamiliesExW_new), DECL_API("EnumFontFamiliesW", EnumFontFamiliesW_new), + DECL_API("ExtCreatePen", ExtCreatePen_fix), DECL_API("ExtTextOutA", ExtTextOutA_new), DECL_API("ExtTextOutW", ExtTextOutW_new), DECL_API("GetCharWidth32A", GetCharWidthA), DECL_API("GetCharWidth32W", GetCharWidthW), + DECL_API("GetDCBrushColor", GetDCBrushColor_stub), + DECL_API("GetDCPenColor", GetDCPenColor_stub), DECL_API("GetFontUnicodeRanges", GetFontUnicodeRanges_new), DECL_API("GetGlyphOutlineA", GetGlyphOutlineA_fix), + DECL_API("GetObjectType", GetObjectType_fix), + DECL_API("GetObjectW", GetObjectW_new), DECL_API("GetRandomRgn", GetRandomRgn_NT), DECL_API("GetTextMetricsA", GetTextMetricsA_NT), DECL_API("GetWorldTransform", GetWorldTransform_NT), @@ -58,6 +68,7 @@ static const apilib_named_api gdi32_named_apis[] = DECL_API("RemoveFontResourceExA", RemoveFontResourceExA_new), DECL_API("RemoveFontResourceExW", RemoveFontResourceExW_new), DECL_API("RemoveFontResourceW", RemoveFontResourceW_new), + DECL_API("SelectObject", SelectObject_fix), DECL_API("SetDCBrushColor", SetDCBrushColor_stub), DECL_API("SetDCPenColor", SetDCPenColor_stub), DECL_API("SetGraphicsMode", SetGraphicsMode_NT), diff --git a/apilibs/kexbases/Gdi32/_gdi32_apilist.h b/apilibs/kexbases/Gdi32/_gdi32_apilist.h old mode 100644 new mode 100755 index e8acf87..aff0543 --- a/apilibs/kexbases/Gdi32/_gdi32_apilist.h +++ b/apilibs/kexbases/Gdi32/_gdi32_apilist.h @@ -30,6 +30,11 @@ extern const apilib_api_table apitable_gdi32; /*** AUTOGENERATED APILIST DECLARATIONS BEGIN ***/ INT WINAPI AddFontResourceExA_new(LPCSTR str, DWORD fl, PVOID pdv); BOOL WINAPI RemoveFontResourceExA_new(LPCSTR str, DWORD fl, PVOID pdv); +DWORD WINAPI GetObjectType_fix(HGDIOBJ hgdiobj); +BOOL WINAPI DeleteObject_fix(HGDIOBJ hObject); +HGDIOBJ WINAPI SelectObject_fix(HDC hdc, HGDIOBJ hgdiobj); +BOOL WINAPI DeleteDC_fix(HDC hdc); +HBITMAP WINAPI CreateDIBSection_fix(HDC hdc, BITMAPINFO *pbmi, UINT iUsage, VOID **ppvBits, HANDLE hSection, DWORD dwOffset); DWORD WINAPI GetGlyphOutlineA_fix(HDC hdc, UINT uChar, UINT uFormat, LPGLYPHMETRICS lpgm, DWORD cbBuffer, LPVOID lpvBuffer, CONST MAT2 *lpmat2); DWORD WINAPI GetFontUnicodeRanges_new(HDC hdc, LPGLYPHSET lpgs); int WINAPI SetGraphicsMode_NT(HDC hdc, int iMode); @@ -46,14 +51,19 @@ BOOL WINAPI PolyTextOutA_new(HDC hdc, const POLYTEXTA *pptxt, INT cStrings); BOOL WINAPI PolyTextOutW_new(HDC hdc, const POLYTEXTW *pptxt, INT cStrings); STUB SetDCBrushColor_stub; STUB SetDCPenColor_stub; +STUB GetDCBrushColor_stub; +STUB GetDCPenColor_stub; STUB AddFontMemResourceEx_stub; STUB RemoveFontMemResourceEx_stub; INT WINAPI AddFontResourceExW_new(LPCWSTR strW, DWORD fl, PVOID pdv); INT WINAPI AddFontResourceW_new(LPCWSTR strW); +int WINAPI EnumFontFamiliesExA_new(HDC hdc, LPLOGFONTA pLogfontA, FONTENUMPROCA pEnumFontFamExProc, LPARAM lParam, DWORD dwFlags); int WINAPI EnumFontFamiliesExW_new(HDC hdc, LPLOGFONTW pLogfontW, FONTENUMPROCW pEnumFontFamExProc, LPARAM lParam, DWORD dwFlags); int WINAPI EnumFontFamiliesW_new(HDC hdc, LPCWSTR lpszFamily, FONTENUMPROCW lpEnumFontFamProc, LPARAM lParam); BOOL WINAPI RemoveFontResourceExW_new(LPCWSTR strW, DWORD fl, PVOID pdv); BOOL WINAPI RemoveFontResourceW_new(LPCWSTR strW); +HPEN WINAPI ExtCreatePen_fix(DWORD dwPenStyle, DWORD dwWidth, CONST LOGBRUSH *lplb, DWORD dwStyleCount, CONST DWORD *lpStyle); +int WINAPI GetObjectW_new(HGDIOBJ hgdiobj, int cbBuffer, LPVOID lpvObject); /*** AUTOGENERATED APILIST DECLARATIONS END ***/ #endif diff --git a/apilibs/kexbases/Gdi32/_gdi32_stubs.c b/apilibs/kexbases/Gdi32/_gdi32_stubs.c old mode 100644 new mode 100755 index be8d11b..3feb2fa --- a/apilibs/kexbases/Gdi32/_gdi32_stubs.c +++ b/apilibs/kexbases/Gdi32/_gdi32_stubs.c @@ -23,5 +23,7 @@ UNIMPL_FUNC(SetDCBrushColor, 2); UNIMPL_FUNC(SetDCPenColor, 2); +UNIMPL_FUNC(GetDCBrushColor, 1); +UNIMPL_FUNC(GetDCPenColor, 1); UNIMPL_FUNC(AddFontMemResourceEx, 4); UNIMPL_FUNC(RemoveFontMemResourceEx, 1); diff --git a/apilibs/kexbases/Gdi32/unigdi32.c b/apilibs/kexbases/Gdi32/unigdi32.c old mode 100644 new mode 100755 index a6e0e64..0748774 --- a/apilibs/kexbases/Gdi32/unigdi32.c +++ b/apilibs/kexbases/Gdi32/unigdi32.c @@ -1,6 +1,7 @@ /* * KernelEx * Copyright (C) 2009, Xeno86 + * Copyright (C) 2009, Tihiy * * This file is part of KernelEx source code. * @@ -17,7 +18,7 @@ * along with GNU Make; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * - */ + */ #include "common.h" #include "_gdi32_apilist.h" @@ -63,14 +64,14 @@ static int CALLBACK EnumFontFamExConv(const LOGFONTA *plfA, fontW->elfLogFont.lfFaceName, LF_FACESIZE); fontW->elfLogFont.lfFaceName[LF_FACESIZE - 1] = 0; MultiByteToWideChar(CP_ACP, 0, (LPCSTR) fontA->elfFullName, -1, - fontW->elfFullName, LF_FULLFACESIZE); - fontW->elfFullName[LF_FULLFACESIZE - 1] = 0; - MultiByteToWideChar(CP_ACP, 0, (LPCSTR) fontA->elfStyle, -1, - fontW->elfStyle, LF_FACESIZE); - fontW->elfStyle[LF_FACESIZE - 1] = 0; - MultiByteToWideChar(CP_ACP, 0, (LPCSTR) fontA->elfScript, -1, - fontW->elfScript, LF_FACESIZE); - fontW->elfScript[LF_FACESIZE - 1] = 0; + fontW->elfFullName, LF_FULLFACESIZE); + fontW->elfFullName[LF_FULLFACESIZE - 1] = 0; + MultiByteToWideChar(CP_ACP, 0, (LPCSTR) fontA->elfStyle, -1, + fontW->elfStyle, LF_FACESIZE); + fontW->elfStyle[LF_FACESIZE - 1] = 0; + MultiByteToWideChar(CP_ACP, 0, (LPCSTR) fontA->elfScript, -1, + fontW->elfScript, LF_FACESIZE); + fontW->elfScript[LF_FACESIZE - 1] = 0; tmW->ntmTm.tmHeight = tmA->ntmTm.tmHeight; tmW->ntmTm.tmAscent = tmA->ntmTm.tmAscent; @@ -115,16 +116,43 @@ static int CALLBACK EnumFontFamExConv(const LOGFONTA *plfA, return pef->EnumProcW((LOGFONTW*) &elfeW, (TEXTMETRICW*) &ntmeW, FontType, pef->lParam); } +/* Surprise surprise! + * logfont* is optional in EnumFontFamiliesEx on NT + * and means - all fonts, all charsets + */ + +/* MAKE_EXPORT EnumFontFamiliesExA_new=EnumFontFamiliesExA */ +int WINAPI EnumFontFamiliesExA_new(HDC hdc, LPLOGFONTA pLogfontA, + FONTENUMPROCA pEnumFontFamExProc, LPARAM lParam, DWORD dwFlags) +{ + LOGFONTA logfont; + if (!pLogfontA) + { + memset(&logfont, 0, sizeof(logfont)); + logfont.lfCharSet = DEFAULT_CHARSET; + pLogfontA = &logfont; + } + return EnumFontFamiliesExA(hdc, pLogfontA, pEnumFontFamExProc, lParam, dwFlags); +} + /* MAKE_EXPORT EnumFontFamiliesExW_new=EnumFontFamiliesExW */ int WINAPI EnumFontFamiliesExW_new(HDC hdc, LPLOGFONTW pLogfontW, FONTENUMPROCW pEnumFontFamExProc, LPARAM lParam, DWORD dwFlags) { EnumFamilies_t ef; LOGFONTA logfont; - memcpy(&logfont, pLogfontW, sizeof(LOGFONTA) - LF_FACESIZE); - WideCharToMultiByte(CP_ACP, 0, pLogfontW->lfFaceName, -1, logfont.lfFaceName, - LF_FACESIZE, NULL, NULL); - logfont.lfFaceName[LF_FACESIZE - 1] = '\0'; + if (pLogfontW) + { + memcpy(&logfont, pLogfontW, sizeof(LOGFONTA) - LF_FACESIZE); + WideCharToMultiByte(CP_ACP, 0, pLogfontW->lfFaceName, -1, logfont.lfFaceName, + LF_FACESIZE, NULL, NULL); + logfont.lfFaceName[LF_FACESIZE - 1] = '\0'; + } + else + { + memset(&logfont, 0, sizeof(logfont)); + logfont.lfCharSet = DEFAULT_CHARSET; + } ef.EnumProcW = pEnumFontFamExProc; ef.lParam = lParam; return EnumFontFamiliesExA(hdc, &logfont, EnumFontFamExConv, (LPARAM) &ef, dwFlags); @@ -165,3 +193,35 @@ BOOL WINAPI RemoveFontResourceW_new(LPCWSTR strW) file_ALLOC_WtoA(str); return RemoveFontResourceA(strA); } + +/* MAKE_EXPORT ExtCreatePen_fix=ExtCreatePen */ +HPEN WINAPI ExtCreatePen_fix( + DWORD dwPenStyle, // pen style + DWORD dwWidth, // pen width + CONST LOGBRUSH *lplb, // brush attributes + DWORD dwStyleCount, // length of custom style array + CONST DWORD *lpStyle // custom style array +) +{ + dwPenStyle &= ~PS_USERSTYLE; + return ExtCreatePen(dwPenStyle,dwWidth,lplb,dwStyleCount,lpStyle); +} + +/* MAKE_EXPORT GetObjectW_new=GetObjectW */ +int WINAPI GetObjectW_new( + HGDIOBJ hgdiobj, // handle to graphics object + int cbBuffer, // size of buffer for object information + LPVOID lpvObject // buffer for object information +) +{ + int type = GetObjectType_fix(hgdiobj); + if (type != OBJ_FONT) return GetObjectA(hgdiobj,cbBuffer,lpvObject); + if (!lpvObject) return sizeof(LOGFONTW); + LOGFONTA fontA = {0}; + LOGFONTW fontW = {0}; + if (!GetObjectA(hgdiobj,sizeof(LOGFONTA),&fontA)) return 0; //err not font + memcpy(&fontW,&fontA,FIELD_OFFSET(LOGFONTA,lfFaceName)); + MultiByteToWideChar(CP_ACP,0,fontA.lfFaceName,-1,fontW.lfFaceName,LF_FACESIZE); + memcpy(lpvObject,&fontW,cbBuffer); + return cbBuffer; +} diff --git a/apilibs/kexbases/Kernel32/CopyFileEx.c b/apilibs/kexbases/Kernel32/CopyFileEx.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/Kernel32/CreateThread_fix.c b/apilibs/kexbases/Kernel32/CreateThread_fix.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/Kernel32/DeleteCriticalSection.c b/apilibs/kexbases/Kernel32/DeleteCriticalSection.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/Kernel32/FileApis_fix.c b/apilibs/kexbases/Kernel32/FileApis_fix.c old mode 100644 new mode 100755 index f3aef18..ca499e3 --- a/apilibs/kexbases/Kernel32/FileApis_fix.c +++ b/apilibs/kexbases/Kernel32/FileApis_fix.c @@ -1,6 +1,6 @@ /* * KernelEx - * Copyright (C) 2008-2009, Xeno86 + * Copyright (C) 2008-2009, Xeno86, Tihiy * * This file is part of KernelEx source code. * @@ -38,6 +38,8 @@ HANDLE WINAPI CreateFileA_fix(LPCSTR lpFileName, DWORD dwDesiredAccess, if (oldaccess & FILE_EXECUTE) dwDesiredAccess |= GENERIC_EXECUTE; } + //FILE_SHARE_DELETE is not supported + dwShareMode &= ~FILE_SHARE_DELETE; // hTemplate has to be NULL on 9x hTemplateFile = NULL; // special case: overlapped I/O @@ -69,17 +71,22 @@ BOOL WINAPI ReadFile_fix(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRe if (lpOverlapped && GetLastError() == ERROR_INVALID_PARAMETER) { LONG high = lpOverlapped->OffsetHigh; - DWORD nr; SetLastError(lasterr); if ((SetFilePointer(hFile, lpOverlapped->Offset, &high, FILE_BEGIN) - == (DWORD)-1 && GetLastError() != NO_ERROR) || - (ReadFile(hFile, lpBuffer, nNumberOfBytesToRead, &nr, 0) && !nr)) - { - SetLastError(ERROR_HANDLE_EOF); - return FALSE; - } - *lpNumberOfBytesRead = nr; - return TRUE; + == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR)) + return FALSE; + ResetEvent(lpOverlapped->hEvent); + lpOverlapped->Internal = STATUS_PENDING; + lpOverlapped->InternalHigh = 0; + BOOL result = + ReadFile(hFile, lpBuffer, nNumberOfBytesToRead, &lpOverlapped->InternalHigh, 0); + lasterr = GetLastError(); + lpOverlapped->Internal = STATUS_WAIT_0; + SetEvent(lpOverlapped->hEvent); + SetLastError(lasterr); + if (lpNumberOfBytesRead) + *lpNumberOfBytesRead = lpOverlapped->InternalHigh; + return result; } return FALSE; } @@ -99,9 +106,79 @@ BOOL WINAPI WriteFile_fix(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesTo LONG high = lpOverlapped->OffsetHigh; SetLastError(lasterr); if ((SetFilePointer(hFile, lpOverlapped->Offset, &high, FILE_BEGIN) - == (DWORD)-1 && GetLastError() != NO_ERROR)) + == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR)) return FALSE; - return WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, 0); + ResetEvent(lpOverlapped->hEvent); + lpOverlapped->Internal = STATUS_PENDING; + lpOverlapped->InternalHigh = 0; + BOOL result = + WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, &lpOverlapped->InternalHigh, 0); + lasterr = GetLastError(); + lpOverlapped->Internal = STATUS_WAIT_0; + SetEvent(lpOverlapped->hEvent); + SetLastError(lasterr); + if (lpNumberOfBytesWritten) + *lpNumberOfBytesWritten = lpOverlapped->InternalHigh; + return result; } return FALSE; } + +/* MAKE_EXPORT GetTempFileNameA_fix=GetTempFileNameA */ +UINT WINAPI GetTempFileNameA_fix(LPCSTR lpPathName, LPCSTR lpPrefixString, UINT uUnique, LPTSTR lpTempFileName) +{ + static int g_tempprefix = 0; + + if (!lpPathName) + lpPathName = "\\"; + if (!lpPrefixString) + { + char temppref[2]; + g_tempprefix++; + g_tempprefix %= 5; + temppref[0] = '0' + g_tempprefix; + temppref[1] = '\0'; + lpPrefixString = temppref; + } + return GetTempFileNameA(lpPathName,lpPrefixString,uUnique,lpTempFileName); +} + +/* MAKE_EXPORT GetDiskFreeSpaceA_fix=GetDiskFreeSpaceA */ +BOOL WINAPI GetDiskFreeSpaceA_fix(LPCSTR lpRootPathName, LPDWORD lpSectorsPerCluster, + LPDWORD lpBytesPerSector, LPDWORD lpNumberOfFreeClusters, + LPDWORD lpTotalNumberOfClusters) +{ + char newRootPath[4] = { "X:\\" }; + if (lstrlenA(lpRootPathName) == 2 && lpRootPathName[1] == ':') //GetDiskFreeSpace fails on paths like C: + { + newRootPath[0] = lpRootPathName[0]; + lpRootPathName = newRootPath; + } + BOOL ret = GetDiskFreeSpaceA(lpRootPathName,lpSectorsPerCluster,lpBytesPerSector,lpNumberOfFreeClusters,lpTotalNumberOfClusters); + if (!ret) //more suprisingly, it may fail on paths with two extensions (e.g. c:\game.exe.lnk) + { + char shortPath[MAX_PATH]; + if (GetShortPathName(lpRootPathName,shortPath,MAX_PATH)) + { + //GetDiskFreeSpace will still fail on short path name, so we check drive root, having path validated + newRootPath[0] = shortPath[0]; + ret = GetDiskFreeSpaceA(newRootPath,lpSectorsPerCluster,lpBytesPerSector,lpNumberOfFreeClusters,lpTotalNumberOfClusters); + } + } + return ret; +} + +/* MAKE_EXPORT GetDiskFreeSpaceExA_fix=GetDiskFreeSpaceExA */ +BOOL WINAPI GetDiskFreeSpaceExA_fix(LPCSTR lpDirectoryName, PULARGE_INTEGER lpFreeBytesAvailable, + PULARGE_INTEGER lpTotalNumberOfBytes, PULARGE_INTEGER lpTotalNumberOfFreeBytes) +{ + //GetDiskFreeSpaceEx does not fail on paths like C: but still fails on on paths with two extensions + BOOL ret = GetDiskFreeSpaceExA(lpDirectoryName,lpFreeBytesAvailable,lpTotalNumberOfBytes,lpTotalNumberOfFreeBytes); + if (!ret) + { + char shortPath[MAX_PATH]; + if (GetShortPathName(lpDirectoryName,shortPath,MAX_PATH)) + ret = GetDiskFreeSpaceExA(shortPath,lpFreeBytesAvailable,lpTotalNumberOfBytes,lpTotalNumberOfFreeBytes); + } + return ret; +} diff --git a/apilibs/kexbases/Kernel32/GetConsoleWindow.c b/apilibs/kexbases/Kernel32/GetConsoleWindow.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/Kernel32/GetFileSizeEx.c b/apilibs/kexbases/Kernel32/GetFileSizeEx.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/Kernel32/GetModuleHandleEx.c b/apilibs/kexbases/Kernel32/GetModuleHandleEx.c new file mode 100755 index 0000000..46ae874 --- /dev/null +++ b/apilibs/kexbases/Kernel32/GetModuleHandleEx.c @@ -0,0 +1,73 @@ +/* + * KernelEx + * Copyright (C) 2009 Tihiy + * + * This file is part of KernelEx source code. + * + * KernelEx is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. + * + * KernelEx is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0600 + +#include +#include "common.h" + +/* MAKE_EXPORT GetModuleHandleExA_new=GetModuleHandleExA */ +BOOL WINAPI GetModuleHandleExA_new( + DWORD dwFlags, + LPCSTR lpModuleName, + HMODULE* phModule +) +{ + char buf[MAX_PATH]; + if (!phModule) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + *phModule = NULL; + if (dwFlags & GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS) + { + MEMORY_BASIC_INFORMATION mbi; + if (!VirtualQuery(lpModuleName,&mbi,sizeof(mbi))) return FALSE; + *phModule = (HMODULE)mbi.AllocationBase; + } + else + *phModule = GetModuleHandleA(lpModuleName); + if (*phModule == NULL || !GetModuleFileNameA(*phModule,buf,MAX_PATH)) + { + *phModule = NULL; + return FALSE; + } + if (!(dwFlags & GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT)) + LoadLibraryA(buf); + + return TRUE; +} + +/* MAKE_EXPORT GetModuleHandleExW_new=GetModuleHandleExW */ +BOOL WINAPI GetModuleHandleExW_new( + DWORD dwFlags, + LPCWSTR lpModuleNameW, + HMODULE* phModule +) +{ + if (dwFlags & GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS) + return GetModuleHandleExA_new(dwFlags,(LPSTR)lpModuleNameW,phModule); + ALLOC_WtoA(lpModuleName); + return GetModuleHandleExA_new(dwFlags,lpModuleNameA,phModule); +} + diff --git a/apilibs/kexbases/Kernel32/GlobalMemoryStatusEx.c b/apilibs/kexbases/Kernel32/GlobalMemoryStatusEx.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/Kernel32/HeapLocks.c b/apilibs/kexbases/Kernel32/HeapLocks.c old mode 100644 new mode 100755 index 79dda98..0beb527 --- a/apilibs/kexbases/Kernel32/HeapLocks.c +++ b/apilibs/kexbases/Kernel32/HeapLocks.c @@ -49,3 +49,25 @@ BOOL WINAPI HeapUnlock_new( LeaveCriticalSection((CRITICAL_SECTION*)((DWORD)hHeap+0x50)); return TRUE; } + +#define ISPOINTER(h) (((ULONG_PTR)(h)&2)==0) + +/* MAKE_EXPORT GlobalLock_fix=GlobalLock */ +LPVOID WINAPI GlobalLock_fix( + HGLOBAL hMem // address of the global memory object +) +{ + if (ISPOINTER(hMem)) + return IsBadReadPtr(hMem, 1) ? NULL : hMem; + return GlobalLock(hMem); +} + +/* MAKE_EXPORT GlobalUnlock_fix=GlobalUnlock */ +BOOL WINAPI GlobalUnlock_fix( + HGLOBAL hMem // handle to the global memory object +) +{ + if (ISPOINTER(hMem)) + return TRUE; + return GlobalUnlock(hMem); +} diff --git a/apilibs/kexbases/Kernel32/InitializeCriticalSectionAndSpinCount.c b/apilibs/kexbases/Kernel32/InitializeCriticalSectionAndSpinCount.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/Kernel32/IsProcessorFeaturePresent.c b/apilibs/kexbases/Kernel32/IsProcessorFeaturePresent.c old mode 100644 new mode 100755 diff --git a/core/storage.h b/apilibs/kexbases/Kernel32/IsWow64Process.c old mode 100644 new mode 100755 similarity index 75% rename from core/storage.h rename to apilibs/kexbases/Kernel32/IsWow64Process.c index 5fa4bf7..21238b4 --- a/core/storage.h +++ b/apilibs/kexbases/Kernel32/IsWow64Process.c @@ -19,18 +19,13 @@ * */ -#ifndef __STORAGE_H -#define __STORAGE_H +#include -class storage +/* MAKE_EXPORT IsWow64Process_new=IsWow64Process */ +BOOL WINAPI IsWow64Process_new(HANDLE hProcess, PBOOL Wow64Process) { -public: - int size; - void* data[1]; //dummy table - - static const int storage_size; - static storage* get_storage(bool alloc); - static void return_storage(); -}; - -#endif + if (!Wow64Process) + return FALSE; + *Wow64Process = FALSE; + return TRUE; +} diff --git a/apilibs/kexbases/Kernel32/Jobs.c b/apilibs/kexbases/Kernel32/Jobs.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/Kernel32/KEXVersion.c b/apilibs/kexbases/Kernel32/KEXVersion.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/Kernel32/LockFileEx.c b/apilibs/kexbases/Kernel32/LockFileEx.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/Kernel32/MapViewOfFile.c b/apilibs/kexbases/Kernel32/MapViewOfFile.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/Kernel32/MoveFileExA.c b/apilibs/kexbases/Kernel32/MoveFileExA.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/Kernel32/MoveFileWithProgressA.c b/apilibs/kexbases/Kernel32/MoveFileWithProgressA.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/Kernel32/OpenThread.c b/apilibs/kexbases/Kernel32/OpenThread.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/Kernel32/RemoteDesktop.c b/apilibs/kexbases/Kernel32/RemoteDesktop.c new file mode 100755 index 0000000..c9c1ab2 --- /dev/null +++ b/apilibs/kexbases/Kernel32/RemoteDesktop.c @@ -0,0 +1,47 @@ +/* + * KernelEx + * Copyright (C) 2009, Xeno86 + * + * This file is part of KernelEx source code. + * + * KernelEx is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. + * + * KernelEx is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/********************************/ +/* Remote Desktop Services APIs */ +/********************************/ + +#include + +/* MAKE_EXPORT ProcessIdToSessionId_new=ProcessIdToSessionId */ +BOOL WINAPI ProcessIdToSessionId_new(DWORD dwProcessId, DWORD *pSessionId) +{ + if (!pSessionId) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + /* Process not running under RDS session */ + *pSessionId = 0; + return TRUE; +} + +/* MAKE_EXPORT WTSGetActiveConsoleSessionId_new=WTSGetActiveConsoleSessionId */ +DWORD WINAPI WTSGetActiveConsoleSessionId_new(void) +{ + /* local session */ + return 0; +} diff --git a/apilibs/kexbases/Kernel32/SetFilePointerEx.c b/apilibs/kexbases/Kernel32/SetFilePointerEx.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/Kernel32/ThreadPool.c b/apilibs/kexbases/Kernel32/ThreadPool.c deleted file mode 100644 index e9ab60d..0000000 --- a/apilibs/kexbases/Kernel32/ThreadPool.c +++ /dev/null @@ -1,51 +0,0 @@ -/* - * KernelEx - * Copyright (C) 2008, Tihiy - * - * This file is part of KernelEx source code. - * - * KernelEx is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; version 2 of the License. - * - * KernelEx is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include - -/* COMPLETE SHIT. PORT WINE HERE */ - -/* MAKE_EXPORT RegisterWaitForSingleObject_new=RegisterWaitForSingleObject */ -BOOL WINAPI RegisterWaitForSingleObject_new(PHANDLE phNewWaitObject, HANDLE hObject, PVOID Callback, PVOID Context, ULONG dwMilliseconds, ULONG dwFlags) -{ - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; -} - -/* MAKE_EXPORT RegisterWaitForSingleObjectEx_new=RegisterWaitForSingleObjectEx */ -HANDLE WINAPI RegisterWaitForSingleObjectEx_new(HANDLE hObject, - PVOID Callback, PVOID Context, - ULONG dwMilliseconds, ULONG dwFlags) -{ - return 0; -} - -/* MAKE_EXPORT UnregisterWait_new=UnregisterWait */ -BOOL WINAPI UnregisterWait_new(HANDLE WaitHandle) -{ - return WaitHandle != 0; -} - -/* MAKE_EXPORT UnregisterWaitEx_new=UnregisterWaitEx */ -BOOL WINAPI UnregisterWaitEx_new(HANDLE WaitHandle, HANDLE CompletionEvent) -{ - return WaitHandle != 0; -} diff --git a/apilibs/kexbases/Kernel32/TryEnterCriticalSection.c b/apilibs/kexbases/Kernel32/TryEnterCriticalSection.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/Kernel32/VirtualAllocEx.c b/apilibs/kexbases/Kernel32/VirtualAllocEx.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/Kernel32/_kernel32_apilist.c b/apilibs/kexbases/Kernel32/_kernel32_apilist.c old mode 100644 new mode 100755 index f74b829..82b4ba1 --- a/apilibs/kexbases/Kernel32/_kernel32_apilist.c +++ b/apilibs/kexbases/Kernel32/_kernel32_apilist.c @@ -30,7 +30,6 @@ http://17slon.com/blogs/gabr/2007/02/four-ways-to-detect-vista.html void get_cpuinfo(); BOOL init_tryentercritsec(); -BOOL init_openthread(); BOOL init_kernel32() { @@ -82,6 +81,8 @@ static const apilib_named_api kernel32_named_apis[] = DECL_API("GetConsoleWindow", GetConsoleWindow_new), DECL_API("GetCurrentDirectoryW", GetCurrentDirectoryW_new), DECL_API("GetDefaultCommConfigW", GetDefaultCommConfigW_new), + DECL_API("GetDiskFreeSpaceA", GetDiskFreeSpaceA_fix), + DECL_API("GetDiskFreeSpaceExA", GetDiskFreeSpaceExA_fix), DECL_API("GetDiskFreeSpaceExW", GetDiskFreeSpaceExW_new), DECL_API("GetDiskFreeSpaceW", GetDiskFreeSpaceW_new), DECL_API("GetEnvironmentStringsW", GetEnvironmentStringsW_new), @@ -91,8 +92,11 @@ static const apilib_named_api kernel32_named_apis[] = DECL_API("GetFullPathNameW", GetFullPathNameW_new), DECL_API("GetLongPathNameW", GetLongPathNameW_new), DECL_API("GetModuleFileNameW", GetModuleFileNameW_new), + DECL_API("GetModuleHandleExA", GetModuleHandleExA_new), + DECL_API("GetModuleHandleExW", GetModuleHandleExW_new), DECL_API("GetModuleHandleW", GetModuleHandleW_new), DECL_API("GetNativeSystemInfo", GetSystemInfo), + DECL_API("GetProcessIoCounters", GetProcessIoCounters_stub), DECL_API("GetShortPathNameW", GetShortPathNameW_new), DECL_API("GetStartupInfoW", GetStartupInfoW_new), DECL_API("GetStringTypeExW", GetStringTypeExW_new), @@ -101,6 +105,7 @@ static const apilib_named_api kernel32_named_apis[] = DECL_API("GetSystemDirectoryW", GetSystemDirectoryW_new), DECL_API("GetSystemWindowsDirectoryA", GetWindowsDirectoryA), DECL_API("GetSystemWindowsDirectoryW", GetWindowsDirectoryW_new), + DECL_API("GetTempFileNameA", GetTempFileNameA_fix), DECL_API("GetTempFileNameW", GetTempFileNameW_new), DECL_API("GetTempPathW", GetTempPathW_new), DECL_API("GetUserDefaultUILanguage", GetUserDefaultUILanguage_new), @@ -139,13 +144,17 @@ static const apilib_named_api kernel32_named_apis[] = DECL_API("GlobalAddAtomW", GlobalAddAtomW_new), DECL_API("GlobalFindAtomW", GlobalFindAtomW_new), DECL_API("GlobalGetAtomNameW", GlobalGetAtomNameW_new), + DECL_API("GlobalLock", GlobalLock_fix), DECL_API("GlobalMemoryStatusEx", GlobalMemoryStatusEx_new), + DECL_API("GlobalUnlock", GlobalUnlock_fix), DECL_API("HeapLock", HeapLock_new), + DECL_API("HeapSetInformation", HeapSetInformation_stub), DECL_API("HeapUnlock", HeapUnlock_new), DECL_API("InitializeCriticalSectionAndSpinCount", InitializeCriticalSectionAndSpinCount_new), DECL_API("IsProcessInJob", IsProcessInJob_new), DECL_API("IsProcessorFeaturePresent", IsProcessorFeaturePresent_new), DECL_API("IsValidLanguageGroup", IsValidLanguageGroup_stub), + DECL_API("IsWow64Process", IsWow64Process_new), DECL_API("KEXVersion", KEXVersion), DECL_API("LCMapStringW", LCMapStringW_new), DECL_API("LoadLibraryExW", LoadLibraryExW_new), @@ -166,15 +175,14 @@ static const apilib_named_api kernel32_named_apis[] = DECL_API("OutputDebugStringW", OutputDebugStringW_new), DECL_API("Process32FirstW", Process32FirstW_new), DECL_API("Process32NextW", Process32NextW_new), + DECL_API("ProcessIdToSessionId", ProcessIdToSessionId_new), DECL_API("QueryInformationJobObject", QueryInformationJobObject_new), - DECL_API("QueueUserWorkItem", QueueUserWorkItem_stub), DECL_API("ReadFile", ReadFile_fix), - DECL_API("RegisterWaitForSingleObject", RegisterWaitForSingleObject_new), - DECL_API("RegisterWaitForSingleObjectEx", RegisterWaitForSingleObjectEx_new), DECL_API("RemoveDirectoryW", RemoveDirectoryW_new), DECL_API("ReplaceFileA", ReplaceFileA_stub), DECL_API("ReplaceFileW", ReplaceFileW_stub), DECL_API("RestoreLastError", SetLastError), + DECL_API("RtlCaptureStackBackTrace", RtlCaptureStackBackTrace_stub), DECL_API("SearchPathW", SearchPathW_new), DECL_API("SetConsoleTitleW", SetConsoleTitleW_new), DECL_API("SetCurrentDirectoryW", SetCurrentDirectoryW_new), @@ -183,8 +191,6 @@ static const apilib_named_api kernel32_named_apis[] = DECL_API("SetInformationJobObject", SetInformationJobObject_new), DECL_API("TerminateJobObject", TerminateJobObject_new), DECL_API("TryEnterCriticalSection", TryEnterCriticalSection_new), - DECL_API("UnregisterWait", UnregisterWait_new), - DECL_API("UnregisterWaitEx", UnregisterWaitEx_new), DECL_API("VerLanguageNameW", VerLanguageNameW_new), DECL_API("VerSetConditionMask", VerSetConditionMask_new), DECL_API("VerifyVersionInfoA", VerifyVersionInfoA_NT2K), @@ -199,6 +205,7 @@ static const apilib_named_api kernel32_named_apis[] = DECL_API("VerifyVersionInfoW", VerifyVersionInfoW_WIN2K8), DECL_API("VirtualAllocEx", VirtualAllocEx_new), DECL_API("VirtualFreeEx", VirtualFreeEx_new), + DECL_API("WTSGetActiveConsoleSessionId", WTSGetActiveConsoleSessionId_new), DECL_API("WideCharToMultiByte", WideCharToMultiByte_new), DECL_API("WriteFile", WriteFile_fix), DECL_API("lstrcmpW", lstrcmpW_new), diff --git a/apilibs/kexbases/Kernel32/_kernel32_apilist.h b/apilibs/kexbases/Kernel32/_kernel32_apilist.h old mode 100644 new mode 100755 index 9e76ab6..16295dc --- a/apilibs/kexbases/Kernel32/_kernel32_apilist.h +++ b/apilibs/kexbases/Kernel32/_kernel32_apilist.h @@ -35,13 +35,21 @@ void WINAPI DeleteCriticalSection_new(PCRITICAL_SECTION lpCriticalSection); HANDLE WINAPI CreateFileA_fix(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDistribution, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); BOOL WINAPI ReadFile_fix(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped); BOOL WINAPI WriteFile_fix(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped); +UINT WINAPI GetTempFileNameA_fix(LPCSTR lpPathName, LPCSTR lpPrefixString, UINT uUnique, LPTSTR lpTempFileName); +BOOL WINAPI GetDiskFreeSpaceA_fix(LPCSTR lpRootPathName, LPDWORD lpSectorsPerCluster, LPDWORD lpBytesPerSector, LPDWORD lpNumberOfFreeClusters, LPDWORD lpTotalNumberOfClusters); +BOOL WINAPI GetDiskFreeSpaceExA_fix(LPCSTR lpDirectoryName, PULARGE_INTEGER lpFreeBytesAvailable, PULARGE_INTEGER lpTotalNumberOfBytes, PULARGE_INTEGER lpTotalNumberOfFreeBytes); HWND WINAPI GetConsoleWindow_new(); BOOL WINAPI GetFileSizeEx_new(HANDLE hFile, PLARGE_INTEGER lpFileSize); +BOOL WINAPI GetModuleHandleExA_new(DWORD dwFlags, LPCSTR lpModuleName, HMODULE* phModule); +BOOL WINAPI GetModuleHandleExW_new(DWORD dwFlags, LPCWSTR lpModuleNameW, HMODULE* phModule); BOOL WINAPI GlobalMemoryStatusEx_new(LPMEMORYSTATUSEX lpmemex); BOOL WINAPI HeapLock_new(HANDLE hHeap); BOOL WINAPI HeapUnlock_new(HANDLE hHeap); +LPVOID WINAPI GlobalLock_fix(HGLOBAL hMem); +BOOL WINAPI GlobalUnlock_fix(HGLOBAL hMem); BOOL WINAPI InitializeCriticalSectionAndSpinCount_new(LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount); BOOL WINAPI IsProcessorFeaturePresent_new(DWORD feature); +BOOL WINAPI IsWow64Process_new(HANDLE hProcess, PBOOL Wow64Process); HANDLE WINAPI CreateJobObjectA_new(LPSECURITY_ATTRIBUTES sa, LPCSTR name); HANDLE WINAPI CreateJobObjectW_new(LPSECURITY_ATTRIBUTES sa, LPCWSTR name); BOOL WINAPI TerminateJobObject_new(HANDLE job, UINT exit_code); @@ -57,21 +65,21 @@ LPVOID WINAPI MapViewOfFileEx_new(HANDLE hFileMappingObject, DWORD dwDesiredAcce BOOL WINAPI MoveFileExA_new(LPCSTR lpExistingFileNameA, LPCSTR lpNewFileNameA, DWORD dwFlags); BOOL WINAPI MoveFileWithProgressA_new(LPCSTR lpExistingFileName, LPCSTR lpNewFileName, LPPROGRESS_ROUTINE lpProgressRoutine, LPVOID lpData, DWORD dwFlags); HANDLE WINAPI OpenThread_new(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId); +BOOL WINAPI ProcessIdToSessionId_new(DWORD dwProcessId, DWORD *pSessionId); +DWORD WINAPI WTSGetActiveConsoleSessionId_new(void); BOOL WINAPI SetFilePointerEx_new(HANDLE hFile, LARGE_INTEGER liDistanceToMove, PLARGE_INTEGER lpNewFilePointer, DWORD dwMoveMethod); -BOOL WINAPI RegisterWaitForSingleObject_new(PHANDLE phNewWaitObject, HANDLE hObject, PVOID Callback, PVOID Context, ULONG dwMilliseconds, ULONG dwFlags); -HANDLE WINAPI RegisterWaitForSingleObjectEx_new(HANDLE hObject, PVOID Callback, PVOID Context, ULONG dwMilliseconds, ULONG dwFlags); -BOOL WINAPI UnregisterWait_new(HANDLE WaitHandle); -BOOL WINAPI UnregisterWaitEx_new(HANDLE WaitHandle, HANDLE CompletionEvent); BOOL WINAPI TryEnterCriticalSection_new(CRITICAL_SECTION* cs); LPVOID WINAPI VirtualAllocEx_new(HANDLE hProcess, LPVOID lpAddress, DWORD dwSize, DWORD flAllocationType, DWORD flProtect); BOOL WINAPI VirtualFreeEx_new(HANDLE hProcess, LPVOID lpAddress, DWORD dwSize, DWORD dwFreeType); STUB CreateHardLinkA_stub; STUB CreateHardLinkW_stub; STUB IsValidLanguageGroup_stub; -STUB QueueUserWorkItem_stub; STUB ReplaceFileA_stub; STUB ReplaceFileW_stub; STUB FindFirstFileExW_stub; +STUB HeapSetInformation_stub; +STUB GetProcessIoCounters_stub; +STUB RtlCaptureStackBackTrace_stub; INT WINAPI CompareStringW_new(LCID lcid, DWORD style, LPCWSTR str1, INT len1, LPCWSTR str2, INT len2); BOOL WINAPI GetStringTypeW_new(DWORD type, LPCWSTR src, INT count, LPWORD chartype); BOOL WINAPI GetStringTypeExW_new(LCID locale, DWORD type, LPCWSTR src, INT count, LPWORD chartype); diff --git a/apilibs/kexbases/Kernel32/_kernel32_stubs.c b/apilibs/kexbases/Kernel32/_kernel32_stubs.c old mode 100644 new mode 100755 index ec4fa01..8f5a267 --- a/apilibs/kexbases/Kernel32/_kernel32_stubs.c +++ b/apilibs/kexbases/Kernel32/_kernel32_stubs.c @@ -24,7 +24,9 @@ UNIMPL_FUNC(CreateHardLinkA, 3); UNIMPL_FUNC(CreateHardLinkW, 3); UNIMPL_FUNC(IsValidLanguageGroup, 2); -UNIMPL_FUNC(QueueUserWorkItem, 3); UNIMPL_FUNC(ReplaceFileA, 6); UNIMPL_FUNC(ReplaceFileW, 6); UNIMPL_FUNC(FindFirstFileExW, 6); +UNIMPL_FUNC(HeapSetInformation, 4); +UNIMPL_FUNC(GetProcessIoCounters, 2); +UNIMPL_FUNC(RtlCaptureStackBackTrace, 4); diff --git a/apilibs/kexbases/Kernel32/locale.c b/apilibs/kexbases/Kernel32/locale.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/Kernel32/locale_casemap.c b/apilibs/kexbases/Kernel32/locale_casemap.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/Kernel32/locale_collation.c b/apilibs/kexbases/Kernel32/locale_collation.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/Kernel32/locale_fold.c b/apilibs/kexbases/Kernel32/locale_fold.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/Kernel32/locale_sortkey.c b/apilibs/kexbases/Kernel32/locale_sortkey.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/Kernel32/locale_unicode.h b/apilibs/kexbases/Kernel32/locale_unicode.h old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/Kernel32/locale_wctype.c b/apilibs/kexbases/Kernel32/locale_wctype.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/Kernel32/uilang.c b/apilibs/kexbases/Kernel32/uilang.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/Kernel32/unikernel32.c b/apilibs/kexbases/Kernel32/unikernel32.c old mode 100644 new mode 100755 index f9fa66e..5c29b31 --- a/apilibs/kexbases/Kernel32/unikernel32.c +++ b/apilibs/kexbases/Kernel32/unikernel32.c @@ -17,7 +17,7 @@ * along with GNU Make; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * - */ + */ #define _WIN32_WINDOWS 0x0410 #define ENABLE_FILEAPIS @@ -25,12 +25,12 @@ #include #include "_kernel32_apilist.h" -//MAKE_EXPORT AddAtomW_new=AddAtomW -ATOM WINAPI AddAtomW_new(LPCWSTR strW) +//MAKE_EXPORT AddAtomW_new=AddAtomW +ATOM WINAPI AddAtomW_new(LPCWSTR strW) { - ALLOC_WtoA(str); - return AddAtomA(strA); -} + ALLOC_WtoA(str); + return AddAtomA(strA); +} /* something seems to be wrong with this and I don't know what INT WINAPI CompareStringW_new(LCID lcid, DWORD style, @@ -102,14 +102,14 @@ INT WINAPI CompareStringW_new(LCID lcid, DWORD style, */ //MAKE_EXPORT CopyFileExW_new=CopyFileExW -BOOL WINAPI CopyFileExW_new(LPCWSTR lpExistingFileNameW, LPCWSTR lpNewFileNameW, LPPROGRESS_ROUTINE lpProgressRoutine, LPVOID lpData, LPBOOL pbCancel, DWORD dwCopyFlags) +BOOL WINAPI CopyFileExW_new(LPCWSTR lpExistingFileNameW, LPCWSTR lpNewFileNameW, LPPROGRESS_ROUTINE lpProgressRoutine, LPVOID lpData, LPBOOL pbCancel, DWORD dwCopyFlags) { file_GetCP(); file_ALLOC_WtoA(lpExistingFileName); file_ALLOC_WtoA(lpNewFileName); return CopyFileExA_new(lpExistingFileNameA, lpNewFileNameA, - lpProgressRoutine, lpData, pbCancel, dwCopyFlags); -} + lpProgressRoutine, lpData, pbCancel, dwCopyFlags); +} //MAKE_EXPORT CopyFileW_new=CopyFileW BOOL WINAPI CopyFileW_new(LPCWSTR lpExistingFileNameW, LPCWSTR lpNewFileNameW, BOOL bFailIfExists) @@ -146,7 +146,7 @@ HANDLE WINAPI CreateFileW_new(LPCWSTR strW, DWORD access, DWORD sharemode, return CreateFileA_fix(strA, access, sharemode, secattr, creatdistr, flags, temp); } -//MAKE_EXPORT DefineDosDeviceW_new=DefineDosDeviceW +//MAKE_EXPORT DefineDosDeviceW_new=DefineDosDeviceW BOOL WINAPI DefineDosDeviceW_new(DWORD dwFlags, LPCWSTR lpDeviceNameW, LPCWSTR lpTargetPathW) { @@ -164,12 +164,12 @@ BOOL WINAPI DeleteFileW_new(LPCWSTR lpFileNameW) return DeleteFileA(lpFileNameA); } -//MAKE_EXPORT FindAtomW_new=FindAtomW -ATOM WINAPI FindAtomW_new(LPCWSTR strW) -{ - ALLOC_WtoA(str); - return FindAtomA(strA); -} +//MAKE_EXPORT FindAtomW_new=FindAtomW +ATOM WINAPI FindAtomW_new(LPCWSTR strW) +{ + ALLOC_WtoA(str); + return FindAtomA(strA); +} //MAKE_EXPORT FindFirstChangeNotificationW_new=FindFirstChangeNotificationW HANDLE WINAPI FindFirstChangeNotificationW_new(LPCWSTR pathW, BOOL watchsubtree, DWORD filter) @@ -221,31 +221,31 @@ BOOL WINAPI FindNextFileW_new(HANDLE handle, LPWIN32_FIND_DATAW dataW) } //MAKE_EXPORT FindResourceExW_new=FindResourceExW -HRSRC WINAPI FindResourceExW_new(HMODULE hModule, LPCWSTR typeW, LPCWSTR nameW, WORD lang) -{ - LPSTR nameA, typeA; - +HRSRC WINAPI FindResourceExW_new(HMODULE hModule, LPCWSTR typeW, LPCWSTR nameW, WORD lang) +{ + LPSTR nameA, typeA; + if (HIWORD(nameW)) - { + { _ALLOC_WtoA(name); - } + } else - nameA = (LPSTR) nameW; - + nameA = (LPSTR) nameW; + if (HIWORD(typeW)) { _ALLOC_WtoA(type); - } + } else - typeA = (LPSTR) typeW; - - return FindResourceExA(hModule, typeA, nameA, lang); + typeA = (LPSTR) typeW; + + return FindResourceExA(hModule, typeA, nameA, lang); } //MAKE_EXPORT FindResourceW_new=FindResourceW -HRSRC WINAPI FindResourceW_new(HINSTANCE hModule, LPCWSTR name, LPCWSTR type) -{ - return FindResourceExW_new(hModule, type, name, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)); +HRSRC WINAPI FindResourceW_new(HINSTANCE hModule, LPCWSTR name, LPCWSTR type) +{ + return FindResourceExW_new(hModule, type, name, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)); } //MAKE_EXPORT FreeEnvironmentStringsW_new=FreeEnvironmentStringsW @@ -302,7 +302,7 @@ BOOL WINAPI GetDiskFreeSpaceExW_new(LPCWSTR lpDirectoryNameW, PULARGE_INTEGER lp { file_GetCP(); file_ALLOC_WtoA(lpDirectoryName); - return GetDiskFreeSpaceExA(lpDirectoryNameA, lpFreeBytesAvailableToCaller, lpTotalNumberOfBytes, lpTotalNumberOfFreeBytes); + return GetDiskFreeSpaceExA_fix(lpDirectoryNameA, lpFreeBytesAvailableToCaller, lpTotalNumberOfBytes, lpTotalNumberOfFreeBytes); } //MAKE_EXPORT GetDiskFreeSpaceW_new=GetDiskFreeSpaceW @@ -310,7 +310,7 @@ BOOL WINAPI GetDiskFreeSpaceW_new(LPCWSTR lpRootPathNameW, LPDWORD lpSectorsPerC { file_GetCP(); file_ALLOC_WtoA(lpRootPathName); - return GetDiskFreeSpaceA(lpRootPathNameA, lpSectorsPerCluster, lpBytesPerSector, lpNumberOfFreeClusters, lpTotalNumberOfClusters); + return GetDiskFreeSpaceA_fix(lpRootPathNameA, lpSectorsPerCluster, lpBytesPerSector, lpNumberOfFreeClusters, lpTotalNumberOfClusters); } //MAKE_EXPORT GetEnvironmentStringsW_new=GetEnvironmentStringsW @@ -510,7 +510,7 @@ UINT WINAPI GetTempFileNameW_new(LPCWSTR lpPathNameW, LPCWSTR lpPrefixStringW, U file_GetCP(); file_ALLOC_WtoA(lpPathName); file_ALLOC_WtoA(lpPrefixString); - ret = GetTempFileNameA(lpPathNameA, lpPrefixStringA, uUnique, lpTempFileNameA); + ret = GetTempFileNameA_fix(lpPathNameA, lpPrefixStringA, uUnique, lpTempFileNameA); if (ret) { file_AtoW(lpTempFileName, MAX_PATH); @@ -566,30 +566,30 @@ UINT WINAPI GetWindowsDirectoryW_new(LPWSTR lpBufferW, UINT uSize) return ret; } -//MAKE_EXPORT GlobalAddAtomW_new=GlobalAddAtomW -ATOM WINAPI GlobalAddAtomW_new(LPCWSTR strW) -{ - ALLOC_WtoA(str); - return GlobalAddAtomA(strA); -} +//MAKE_EXPORT GlobalAddAtomW_new=GlobalAddAtomW +ATOM WINAPI GlobalAddAtomW_new(LPCWSTR strW) +{ + ALLOC_WtoA(str); + return GlobalAddAtomA(strA); +} //MAKE_EXPORT GlobalFindAtomW_new=GlobalFindAtomW -ATOM WINAPI GlobalFindAtomW_new(LPCWSTR strW) -{ - ALLOC_WtoA(str); - return GlobalFindAtomA(strA); -} +ATOM WINAPI GlobalFindAtomW_new(LPCWSTR strW) +{ + ALLOC_WtoA(str); + return GlobalFindAtomA(strA); +} -//MAKE_EXPORT GlobalGetAtomNameW_new=GlobalGetAtomNameW -UINT WINAPI GlobalGetAtomNameW_new(ATOM atom, LPWSTR bufferW, int size) -{ - UINT ret; +//MAKE_EXPORT GlobalGetAtomNameW_new=GlobalGetAtomNameW +UINT WINAPI GlobalGetAtomNameW_new(ATOM atom, LPWSTR bufferW, int size) +{ + UINT ret; ALLOC_A(buffer, size * acp_mcs); ret = GlobalGetAtomNameA(atom, bufferA, size * acp_mcs); - if (ret) + if (ret) ret = ABUFtoW(buffer, ret + 1, size); - if (ret) ret--; - return ret; + if (ret) ret--; + return ret; } //MAKE_EXPORT LoadLibraryW_new=LoadLibraryW @@ -606,7 +606,7 @@ HINSTANCE WINAPI LoadLibraryExW_new(LPCWSTR lpLibFileNameW, HANDLE hFile, DWORD file_GetCP(); file_ALLOC_WtoA(lpLibFileName); return LoadLibraryExA(lpLibFileNameA, hFile, dwFlags); -} +} //MAKE_EXPORT Module32FirstW_new=Module32FirstW BOOL WINAPI Module32FirstW_new(HANDLE hSnapshot, LPMODULEENTRY32W lpmeW) @@ -617,10 +617,10 @@ BOOL WINAPI Module32FirstW_new(HANDLE hSnapshot, LPMODULEENTRY32W lpmeW) WCHAR* szModuleW = lpmeW->szModule; WCHAR* szExePathW = lpmeW->szExePath; - if (lpmeW->dwSize < sizeof(MODULEENTRY32W)) - { - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; + if (lpmeW->dwSize < sizeof(MODULEENTRY32W)) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; } lpmeW->dwSize = sizeof(MODULEENTRY32); @@ -645,10 +645,10 @@ BOOL WINAPI Module32NextW_new(HANDLE hSnapshot, LPMODULEENTRY32W lpmeW) WCHAR* szModuleW = lpmeW->szModule; WCHAR* szExePathW = lpmeW->szExePath; - if (lpmeW->dwSize < sizeof(MODULEENTRY32W)) - { - SetLastError(ERROR_INVALID_DATA); - return FALSE; + if (lpmeW->dwSize < sizeof(MODULEENTRY32W)) + { + SetLastError(ERROR_INVALID_DATA); + return FALSE; } lpmeW->dwSize = sizeof(MODULEENTRY32); @@ -664,7 +664,7 @@ BOOL WINAPI Module32NextW_new(HANDLE hSnapshot, LPMODULEENTRY32W lpmeW) return ret; } -//MAKE_EXPORT MoveFileExW_new=MoveFileExW +//MAKE_EXPORT MoveFileExW_new=MoveFileExW BOOL WINAPI MoveFileExW_new(LPCWSTR existingfileW, LPCWSTR newfileW, DWORD flags) { file_GetCP(); @@ -682,7 +682,7 @@ BOOL WINAPI MoveFileW_new(LPCWSTR existingfileW, LPCWSTR newfileW) return MoveFileA(existingfileA, newfileA); } -//MAKE_EXPORT MoveFileWithProgressW_new=MoveFileWithProgressW +//MAKE_EXPORT MoveFileWithProgressW_new=MoveFileWithProgressW BOOL WINAPI MoveFileWithProgressW_new(LPCWSTR existingfileW, LPCWSTR newfileW, LPPROGRESS_ROUTINE lpProgressRoutine, LPVOID lpData, DWORD dwFlags) { file_GetCP(); @@ -699,16 +699,16 @@ void WINAPI OutputDebugStringW_new(LPCWSTR strW) } //MAKE_EXPORT Process32FirstW_new=Process32FirstW -BOOL WINAPI Process32FirstW_new(HANDLE hSnapshot, LPPROCESSENTRY32W lppeW) +BOOL WINAPI Process32FirstW_new(HANDLE hSnapshot, LPPROCESSENTRY32W lppeW) { BOOL ret; char szExeFileA[MAX_PATH]; WCHAR* szExeFileW = lppeW->szExeFile; if (lppeW->dwSize < sizeof(PROCESSENTRY32W)) - { - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; } lppeW->dwSize = sizeof(PROCESSENTRY32); @@ -723,16 +723,16 @@ BOOL WINAPI Process32FirstW_new(HANDLE hSnapshot, LPPROCESSENTRY32W lppeW) } //MAKE_EXPORT Process32NextW_new=Process32NextW -BOOL WINAPI Process32NextW_new(HANDLE hSnapshot, LPPROCESSENTRY32W lppeW) +BOOL WINAPI Process32NextW_new(HANDLE hSnapshot, LPPROCESSENTRY32W lppeW) { BOOL ret; char szExeFileA[MAX_PATH]; WCHAR* szExeFileW = lppeW->szExeFile; if (lppeW->dwSize < sizeof(PROCESSENTRY32W)) - { - SetLastError(ERROR_INVALID_DATA); - return FALSE; + { + SetLastError(ERROR_INVALID_DATA); + return FALSE; } lppeW->dwSize = sizeof(PROCESSENTRY32); @@ -787,14 +787,14 @@ DWORD WINAPI SearchPathW_new(LPCWSTR lpPathW, LPCWSTR lpFileNameW, LPCWSTR lpExt return ret; } -//MAKE_EXPORT SetConsoleTitleW_new=SetConsoleTitleW -BOOL WINAPI SetConsoleTitleW_new(LPCWSTR strW) -{ - ALLOC_WtoA(str); - return SetConsoleTitleA(strA); +//MAKE_EXPORT SetConsoleTitleW_new=SetConsoleTitleW +BOOL WINAPI SetConsoleTitleW_new(LPCWSTR strW) +{ + ALLOC_WtoA(str); + return SetConsoleTitleA(strA); } -//MAKE_EXPORT SetCurrentDirectoryW_new=SetCurrentDirectoryW +//MAKE_EXPORT SetCurrentDirectoryW_new=SetCurrentDirectoryW BOOL WINAPI SetCurrentDirectoryW_new(LPCWSTR lpPathNameW) { file_GetCP(); @@ -854,7 +854,7 @@ LPWSTR WINAPI lstrcpynW_new(LPWSTR dst, LPCWSTR src, INT n) __except (EXCEPTION_EXECUTE_HANDLER) { SetLastError(ERROR_INVALID_PARAMETER); - return 0; + return NULL; } - return ret; + return ret; } diff --git a/apilibs/kexbases/Kernel32/version.c b/apilibs/kexbases/Kernel32/version.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/Kernel32/volume.c b/apilibs/kexbases/Kernel32/volume.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/Kernel32/widecharconv.c b/apilibs/kexbases/Kernel32/widecharconv.c old mode 100644 new mode 100755 index 225b06a..d8eca87 --- a/apilibs/kexbases/Kernel32/widecharconv.c +++ b/apilibs/kexbases/Kernel32/widecharconv.c @@ -25,6 +25,11 @@ #define CP_THREAD_ACP 3 #endif +#ifndef WC_ERR_INVALID_CHARS +#define WC_ERR_INVALID_CHARS 0x0080 +#endif + + /* MAKE_EXPORT WideCharToMultiByte_new=WideCharToMultiByte */ int WINAPI WideCharToMultiByte_new( UINT CodePage, @@ -39,6 +44,8 @@ int WINAPI WideCharToMultiByte_new( { if (CodePage == CP_THREAD_ACP) CodePage = CP_ACP; + else if (CodePage == CP_UTF8 || CodePage == CP_UTF7) + dwFlags &= ~WC_ERR_INVALID_CHARS; return WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, lpMultiByteStr, cchMultiByte, lpDefaultChar, lpUsedDefaultChar); } @@ -55,6 +62,8 @@ int WINAPI MultiByteToWideChar_new( { if (CodePage == CP_THREAD_ACP) CodePage = CP_ACP; + else if (CodePage == CP_UTF8 || CodePage == CP_UTF7) + dwFlags &= ~MB_ERR_INVALID_CHARS; return MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cchMultiByte, lpWideCharStr, cchWideChar); } diff --git a/apilibs/kexbases/User32/CallWindowProcA_fix.c b/apilibs/kexbases/User32/CallWindowProcA_fix.c deleted file mode 100644 index e22e230..0000000 --- a/apilibs/kexbases/User32/CallWindowProcA_fix.c +++ /dev/null @@ -1,50 +0,0 @@ -/* - * KernelEx - * Copyright (C) 2008, Xeno86 - * Copyright (C) 2008, Tihiy - * - * This file is part of KernelEx source code. - * - * KernelEx is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; version 2 of the License. - * - * KernelEx is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include - -__declspec(naked) -/* MAKE_EXPORT CallWindowProcA_fix=CallWindowProcA */ -LRESULT WINAPI CallWindowProcA_fix(WNDPROC lpPrevWndFunc, HWND hWnd, - UINT Msg, WPARAM wParam, LPARAM lParam) -{ - static const char unicows_str[] = "unicows.dll"; - static const char callwindowproca_str[] = "CallWindowProcA"; - - /* We shouldn't write it in C because some weird programs depend - * on CallWindowProc calling function directly! - */ -__asm { - mov eax, [esp+4] ;lpPrevWndFunc - and eax, 0x7FFFFFF0 - cmp eax, 0x7FFFFFF0 - je UNI - jmp dword ptr [CallWindowProcA] -UNI: - push offset unicows_str - call dword ptr [GetModuleHandleA] - push offset callwindowproca_str - push eax - call dword ptr [GetProcAddress] - jmp eax - } -} diff --git a/apilibs/kexbases/User32/DisableProcessWindowsGhosting.c b/apilibs/kexbases/User32/DisableProcessWindowsGhosting.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/User32/EnableWindow.c b/apilibs/kexbases/User32/EnableWindow.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/User32/ForegroundWindow.c b/apilibs/kexbases/User32/ForegroundWindow.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/User32/GetAncestor.c b/apilibs/kexbases/User32/GetAncestor.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/User32/GetMouseMovePointsEx.c b/apilibs/kexbases/User32/GetMouseMovePointsEx.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/User32/GetNextDlgTabItem_fix.c b/apilibs/kexbases/User32/GetNextDlgTabItem_fix.c new file mode 100755 index 0000000..147a8eb --- /dev/null +++ b/apilibs/kexbases/User32/GetNextDlgTabItem_fix.c @@ -0,0 +1,50 @@ +/* + * KernelEx + * Copyright (C) 2009, Tihiy + * + * This file is part of KernelEx source code. + * + * KernelEx is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. + * + * KernelEx is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include + +/* Here we have fix for retarded situation. + * 9x stucks trying to get next control in dialog to tab + * when there is only one control on dialog, and it has tab-able + * child windows (WS_EX_CONTROLPARENT), and if it's disabled or hidden, + * user.exe crashes with stack overflow, silently or soundly. + * More proper fix would be to scan whole dialog and enable/show at least + * one such window, since GetNextDlgTabItem also happens internally. + * However, likely it won't be this function and our case works for + * Winamp ML. + */ + + +/* MAKE_EXPORT GetNextDlgTabItem_fix=GetNextDlgTabItem */ +HWND WINAPI GetNextDlgTabItem_fix( + HWND hDlg, // handle to dialog box + HWND hCtl, // handle to known control + BOOL bPrevious // direction flag +) +{ + HWND hTestCtl = hCtl; + if (!hTestCtl) hTestCtl = GetWindow(hDlg,GW_CHILD); + if ( hTestCtl && !GetWindow(hTestCtl,GW_HWNDNEXT) + && ( !IsWindowVisible(hTestCtl) || !IsWindowEnabled(hTestCtl) ) + && ( GetWindowLong(hTestCtl,GWL_EXSTYLE) & WS_EX_CONTROLPARENT ) ) return hCtl; + + return GetNextDlgTabItem(hDlg,hCtl,bPrevious); +} diff --git a/apilibs/kexbases/User32/IsHungAppWindow.c b/apilibs/kexbases/User32/IsHungAppWindow.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/User32/LockWorkStation.c b/apilibs/kexbases/User32/LockWorkStation.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/User32/MapVirtualKey_fix.c b/apilibs/kexbases/User32/MapVirtualKey_fix.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/User32/SendMessage_fix.c b/apilibs/kexbases/User32/SendMessage_fix.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/User32/UberUSER.c b/apilibs/kexbases/User32/UberUSER.c deleted file mode 100644 index 177e37a..0000000 --- a/apilibs/kexbases/User32/UberUSER.c +++ /dev/null @@ -1,134 +0,0 @@ -/* - * KernelEx - * - * Copyright 1993 Alexandre Julliard - * 1997 Alex Korobka - * Copyright 2002,2003 Shachar Shemesh - * Copyright 2003 CodeWeavers Inc. (Ulrich Czekalla) - * - * Copyright (C) 2008, Tihiy - * This file is part of KernelEx source code. - * - * KernelEx is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; version 2 of the License. - * - * KernelEx is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include - -static const char c_szUnicows[]="unicows.dll"; -static const char c_szUnicowsProp[]="GodotMemoryBlock"; - -static int WINAPI GetCPFromLocale(LCID Locale) -{ - int cp; - Locale = Locale & 0xFFFF; //we can assume that HKL == LCID in 9x... i hope :) - if (GetLocaleInfoA(Locale,LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER,(LPSTR)&cp,sizeof(int))) - return cp; - else - return CP_ACP; -} - -/* MAKE_EXPORT ToUnicodeEx_new=ToUnicodeEx */ -int WINAPI ToUnicodeEx_new( - UINT wVirtKey, - UINT wScanCode, - const PBYTE lpKeyState, - LPWSTR pwszBuff, - int cchBuff, - UINT wFlags, - HKL dwhkl -) -{ - int result; - WORD asciibuf[4]; - char ansibuf[4]; - if (!lpKeyState || !pwszBuff) - { - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - result = ToAsciiEx(wVirtKey,wScanCode,lpKeyState,asciibuf,wFlags,dwhkl); - if (result && cchBuff) - { - int i; - for (i = 0; i < result; i++) ansibuf[i]=(char)asciibuf[i]; - MultiByteToWideChar(GetCPFromLocale((LCID)dwhkl),0,ansibuf,result,pwszBuff,cchBuff); - } - return result; -} - -/* MAKE_EXPORT ToUnicode_new=ToUnicode */ -int WINAPI ToUnicode_new( - UINT wVirtKey, - UINT wScanCode, - const PBYTE lpKeyState, - LPWSTR pwszBuff, - int cchBuff, - UINT wFlags -) -{ - return ToUnicodeEx_new(wVirtKey,wScanCode,lpKeyState,pwszBuff,cchBuff,wFlags,GetKeyboardLayout(GetCurrentThreadId())); -} - -/* MAKE_EXPORT GetLastInputInfo_new=GetLastInputInfo */ -BOOL WINAPI GetLastInputInfo_new( - PLASTINPUTINFO plii // last input event -) -{ - if ( !plii ) return FALSE; - plii->dwTime = GetTickCount() - 123; - return TRUE; -} - -/* MAKE_EXPORT GetMessageW_new=GetMessageW */ -BOOL WINAPI GetMessageW_new( - LPMSG lpMsg, // message information - HWND hWnd, // handle to window - UINT wMsgFilterMin, // first message - UINT wMsgFilterMax // last message -) -{ - BOOL result; - /* HACKHACK ALERT: don't bother calling MSLU. We know how it works already. Win speed instead! */ - result = GetMessageA(lpMsg,hWnd,wMsgFilterMin,wMsgFilterMax); - if (lpMsg && lpMsg->message == WM_CHAR && lpMsg->wParam > 0x7Fu && lpMsg->wParam <= 0xFFu && IsWindow(lpMsg->hwnd) && GetPropA(lpMsg->hwnd,c_szUnicowsProp)) - { - WCHAR unichar; - char ansichar = lpMsg->wParam; - MultiByteToWideChar(GetCPFromLocale((LCID)GetKeyboardLayout(GetCurrentThreadId())),0,&ansichar,1,&unichar,1); - lpMsg->wParam = (WORD) unichar; - } - return result; -} - -/* This fix is mainly for Winamp. Proper fix would be to hook SetWindowLongA too, but it's too hard and still, - MSLU would fail to deliver right ANSI functions. Forget it! -*/ - -/* MAKE_EXPORT GetWindowLongA_new=GetWindowLongA */ -LONG WINAPI GetWindowLongA_new(HWND hWnd, int nIndex) -{ - LONG ret = GetWindowLongA( hWnd, nIndex ); - if ( nIndex == GWL_WNDPROC && ret & 0x80000000 && GetPropA(hWnd, c_szUnicowsProp) ) - { - typedef HRESULT (WINAPI *GWLU) (HWND hWnd, int nIndex); - GWLU GetWindowLongAU = (GWLU)GetProcAddress( GetModuleHandleA(c_szUnicows), "GetWindowLongA" ); - if ( GetWindowLongAU ) - { - LONG retU = GetWindowLongAU( hWnd, nIndex ); - if ( retU ) return retU; - } - } - return ret; -} diff --git a/apilibs/kexbases/User32/UpdateLayeredWindow.c b/apilibs/kexbases/User32/UpdateLayeredWindow.c old mode 100644 new mode 100755 index b3560bc..082f483 --- a/apilibs/kexbases/User32/UpdateLayeredWindow.c +++ b/apilibs/kexbases/User32/UpdateLayeredWindow.c @@ -1,6 +1,8 @@ /* * KernelEx + * * Copyright (C) 2008, Tihiy + * * This file is part of KernelEx source code. * * KernelEx is free software; you can redistribute it and/or modify @@ -33,13 +35,26 @@ BOOL WINAPI UpdateLayeredWindow_new( DWORD dwFlags // options ) { - //pretty dumb stub for Firefox - if ( hdcSrc && psize && pptSrc ) + BOOL ret = FALSE; + if ( (GetWindowLong(hwnd,GWL_EXSTYLE) & WS_EX_LAYERED) && hdcSrc && pptSrc ) { + RECT rc; + GetWindowRect(hwnd,&rc); + if (pptDst) + { + OffsetRect(&rc,-rc.left,-rc.top); + OffsetRect(&rc,pptDst->x,pptDst->y); + } + if (psize) + { + rc.right = rc.left + psize->cx; + rc.bottom = rc.top + psize->cy; + } + MoveWindow(hwnd,rc.left,rc.top,rc.right-rc.left,rc.bottom-rc.top,FALSE); HDC hdc = GetDC( hwnd ); - BitBlt( hdc, 0, 0, psize->cx, psize->cy, hdcSrc, pptSrc->x, pptSrc->y, SRCCOPY ); - ReleaseDC( hwnd, hdc ); + OffsetRect(&rc,-rc.left,-rc.top); + ret = BitBlt(hdc,0,0,rc.right-rc.left,rc.bottom-rc.top,hdcSrc,pptSrc->x,pptSrc->y,SRCCOPY); + ReleaseDC(hwnd,hdc); } - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; + return ret; } diff --git a/apilibs/kexbases/User32/_user32_apilist.c b/apilibs/kexbases/User32/_user32_apilist.c old mode 100644 new mode 100755 index 9c01a76..234e689 --- a/apilibs/kexbases/User32/_user32_apilist.c +++ b/apilibs/kexbases/User32/_user32_apilist.c @@ -22,6 +22,7 @@ #include "common.h" #include "kexcoresdk.h" #include "_user32_apilist.h" +#include "thuni_layer.h" IsHungThread_t IsHungThread_pfn; DrawCaptionTempA_t DrawCaptionTempA_pfn; @@ -34,19 +35,26 @@ BOOL init_user32() DrawCaptionTempA_pfn = (DrawCaptionTempA_t)GetProcAddress(hUser32, "DrawCaptionTempA"); GetMouseMovePoints_pfn = (GetMouseMovePoints_t)GetProcAddress(hUser32, "GetMouseMovePoints"); - return IsHungThread_pfn && DrawCaptionTempA_pfn && GetMouseMovePoints_pfn; + return IsHungThread_pfn && DrawCaptionTempA_pfn && GetMouseMovePoints_pfn && InitUniThunkLayer(); } -/* - * MAKE_EXPORT RealGetWindowClass=RealGetWindowClassA - * MAKE_EXPORT GetAltTabInfo=GetAltTabInfoA - * MAKE_EXPORT PeekMessageA=PeekMessageW - * MAKE_EXPORT DispatchMessageA=DispatchMessageW - * MAKE_EXPORT IsDialogMessageA=IsDialogMessageW - * MAKE_EXPORT TranslateAcceleratorA=TranslateAcceleratorW +/* APIs which don't require Unicode implementations in thuni model + * MAKE_EXPORT CallMsgFilterA=CallMsgFilterW * MAKE_EXPORT CopyAcceleratorTableA=CopyAcceleratorTableW * MAKE_EXPORT CreateAcceleratorTableA=CreateAcceleratorTableW - * MAKE_EXPORT CallMsgFilterA=CallMsgFilterW + * MAKE_EXPORT DispatchMessageA=DispatchMessageW + * MAKE_EXPORT IsDialogMessageA=IsDialogMessageW + * MAKE_EXPORT GetAltTabInfo=GetAltTabInfoA + * MAKE_EXPORT RealGetWindowClass=RealGetWindowClassA + * MAKE_EXPORT SetWindowsHookExA=SetWindowsHookExW + * MAKE_EXPORT SetWindowsHookA=SetWindowsHookW + * MAKE_EXPORT TranslateAcceleratorA=TranslateAcceleratorW + */ + +/* Shell hook APIs. Can be implemented with shell, + * but would be too sensitive for cruel world. + * MAKE_EXPORT IsWindow=DeregisterShellHookWindow + * MAKE_EXPORT IsWindow=RegisterShellHookWindow */ static const apilib_named_api user32_named_apis[] = @@ -55,6 +63,7 @@ static const apilib_named_api user32_named_apis[] = DECL_API("AllowSetForegroundWindow", AllowSetForegroundWindow_98), DECL_API("CallMsgFilterW", CallMsgFilterA), DECL_API("CallWindowProcA", CallWindowProcA_fix), + DECL_API("CallWindowProcW", CallWindowProcW_new), DECL_API("CharLowerBuffW", CharLowerBuffW_new), DECL_API("CharLowerW", CharLowerW_new), DECL_API("CharNextExW", CharNextExW_new), @@ -67,22 +76,44 @@ static const apilib_named_api user32_named_apis[] = DECL_API("CharUpperW", CharUpperW_new), DECL_API("CopyAcceleratorTableW", CopyAcceleratorTableA), DECL_API("CreateAcceleratorTableW", CreateAcceleratorTableA), + DECL_API("CreateDialogIndirectParamW", CreateDialogIndirectParamW_NEW), + DECL_API("CreateDialogParamW", CreateDialogParamW_NEW), + DECL_API("CreateMDIWindowW", CreateMDIWindowW_NEW), + DECL_API("CreateWindowExW", CreateWindowExW_NEW), + DECL_API("CreateWindowW", CreateWindowW_NEW), + DECL_API("DefDlgProcW", DefDlgProcW_NEW), + DECL_API("DefFrameProcW", DefFrameProcW_NEW), + DECL_API("DefMDIChildProcW", DefMDIChildProcW_NEW), + DECL_API("DefWindowProcW", DefWindowProcW_NEW), + DECL_API("DeregisterShellHookWindow", IsWindow), + DECL_API("DialogBoxIndirectParamW", DialogBoxIndirectParamW_NEW), + DECL_API("DialogBoxParamW", DialogBoxParamW_NEW), DECL_API("DisableProcessWindowsGhosting", DisableProcessWindowsGhosting_new), DECL_API("DispatchMessageW", DispatchMessageA), DECL_API("DrawCaptionTempW", DrawCaptionTempW_new), DECL_API("EnableWindow", EnableWindow_new), DECL_API("GetAltTabInfoA", GetAltTabInfo), DECL_API("GetAncestor", GetAncestor_fix), - DECL_API("GetLastInputInfo", GetLastInputInfo_new), - DECL_API("GetMessageW", GetMessageW_new), + DECL_API("GetClassInfoExW", GetClassInfoExW_NEW), + DECL_API("GetClassInfoW", GetClassInfoW_NEW), + DECL_API("GetClassLongW", GetClassLongW_NEW), + DECL_API("GetDlgItemTextW", GetDlgItemTextW_NEW), + DECL_API("GetLastInputInfo", GetLastInputInfo_NEW), + DECL_API("GetMessageA", GetMessageA_NEW), + DECL_API("GetMessageW", GetMessageW_NEW), DECL_API("GetMouseMovePointsEx", GetMouseMovePointsEx_98), - DECL_API("GetWindowLongA", GetWindowLongA_new), + DECL_API("GetNextDlgTabItem", GetNextDlgTabItem_fix), + DECL_API("GetWindowLongA", GetWindowLongA_NEW), + DECL_API("GetWindowLongW", GetWindowLongW_NEW), + DECL_API("GetWindowTextLengthW", GetWindowTextLengthW_NEW), + DECL_API("GetWindowTextW", GetWindowTextW_NEW), DECL_API("IsCharAlphaNumericW", IsCharAlphaNumericW_new), DECL_API("IsCharAlphaW", IsCharAlphaW_new), DECL_API("IsCharLowerW", IsCharLowerW_new), DECL_API("IsCharUpperW", IsCharUpperW_new), DECL_API("IsDialogMessageW", IsDialogMessageA), DECL_API("IsHungAppWindow", IsHungAppWindow_new), + DECL_API("IsWindowUnicode", IsWindowUnicode_NEW), DECL_API("LoadStringW", LoadStringW_new), DECL_API("LockSetForegroundWindow", LockSetForegroundWindow_98), DECL_API("LockWorkStation", LockWorkStation_new), @@ -90,14 +121,33 @@ static const apilib_named_api user32_named_apis[] = DECL_API("MapVirtualKeyExA", MapVirtualKeyExA_new), DECL_API("OemToCharBuffW", OemToCharBuffW_new), DECL_API("OemToCharW", OemToCharW_new), - DECL_API("PeekMessageW", PeekMessageA), + DECL_API("PeekMessageA", PeekMessageA_NEW), + DECL_API("PeekMessageW", PeekMessageW_NEW), + DECL_API("PostMessageW", PostMessageW_NEW), + DECL_API("PostThreadMessageW", PostThreadMessageW_NEW), DECL_API("RealGetWindowClassA", RealGetWindowClass), DECL_API("RealGetWindowClassW", RealGetWindowClassW_new), + DECL_API("RegisterClassExW", RegisterClassExW_NEW), + DECL_API("RegisterClassW", RegisterClassW_NEW), + DECL_API("RegisterShellHookWindow", IsWindow), + DECL_API("SendDlgItemMessageW", SendDlgItemMessageW_NEW), DECL_API("SendMessageA", SendMessageA_fix), + DECL_API("SendMessageCallbackW", SendMessageCallbackW_NEW), + DECL_API("SendMessageTimeoutW", SendMessageTimeoutW_NEW), + DECL_API("SendMessageW", SendMessageW_NEW), + DECL_API("SendNotifyMessageW", SendNotifyMessageW_NEW), + DECL_API("SetClassLongW", SetClassLongW_NEW), + DECL_API("SetDlgItemTextW", SetDlgItemTextW_NEW), DECL_API("SetLayeredWindowAttributes", SetLayeredWindowAttributes_stub), + DECL_API("SetWindowLongA", SetWindowLongA_NEW), + DECL_API("SetWindowLongW", SetWindowLongW_NEW), + DECL_API("SetWindowTextW", SetWindowTextW_NEW), + DECL_API("SetWindowsHookExW", SetWindowsHookExA), + DECL_API("SetWindowsHookW", SetWindowsHookA), DECL_API("ToUnicode", ToUnicode_new), DECL_API("ToUnicodeEx", ToUnicodeEx_new), DECL_API("TranslateAcceleratorW", TranslateAcceleratorA), + DECL_API("UnregisterClassW", UnregisterClassW_NEW), DECL_API("UpdateLayeredWindow", UpdateLayeredWindow_new), /*** AUTOGENERATED APILIST NAMED EXPORTS END ***/ }; diff --git a/apilibs/kexbases/User32/_user32_apilist.h b/apilibs/kexbases/User32/_user32_apilist.h old mode 100644 new mode 100755 index 228ac0b..55a62b3 --- a/apilibs/kexbases/User32/_user32_apilist.h +++ b/apilibs/kexbases/User32/_user32_apilist.h @@ -46,23 +46,18 @@ BOOL init_user32(); extern const apilib_api_table apitable_user32; /*** AUTOGENERATED APILIST DECLARATIONS BEGIN ***/ -LRESULT WINAPI CallWindowProcA_fix(WNDPROC lpPrevWndFunc, HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); void __stdcall DisableProcessWindowsGhosting_new(void); BOOL WINAPI EnableWindow_new(HWND hWnd, BOOL bEnable); BOOL WINAPI AllowSetForegroundWindow_98(DWORD procid); BOOL WINAPI LockSetForegroundWindow_98(UINT lockcode); HWND APIENTRY GetAncestor_fix(HWND hwnd, UINT gaFlags); int WINAPI GetMouseMovePointsEx_98(UINT size, LPMOUSEMOVEPOINT ptin, LPMOUSEMOVEPOINT ptout, int count, DWORD res); +HWND WINAPI GetNextDlgTabItem_fix(HWND hDlg, HWND hCtl, BOOL bPrevious); BOOL WINAPI IsHungAppWindow_new(HWND hWnd); BOOL WINAPI LockWorkStation_new(void); UINT WINAPI MapVirtualKeyA_new(UINT uCode, UINT uMapType); UINT WINAPI MapVirtualKeyExA_new(UINT uCode, UINT uMapType, HKL dwhkl); LRESULT WINAPI SendMessageA_fix(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); -int WINAPI ToUnicodeEx_new(UINT wVirtKey, UINT wScanCode, const PBYTE lpKeyState, LPWSTR pwszBuff, int cchBuff, UINT wFlags, HKL dwhkl); -int WINAPI ToUnicode_new(UINT wVirtKey, UINT wScanCode, const PBYTE lpKeyState, LPWSTR pwszBuff, int cchBuff, UINT wFlags); -BOOL WINAPI GetLastInputInfo_new(PLASTINPUTINFO plii); -BOOL WINAPI GetMessageW_new(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax); -LONG WINAPI GetWindowLongA_new(HWND hWnd, int nIndex); BOOL WINAPI UpdateLayeredWindow_new(HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize, HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend, DWORD dwFlags); STUB SetLayeredWindowAttributes_stub; LPWSTR WINAPI CharNextExW_new(WORD codepage, LPCWSTR ptr, DWORD flags); @@ -81,6 +76,50 @@ BOOL WINAPI IsCharLowerW_new(WCHAR x); BOOL WINAPI IsCharUpperW_new(WCHAR x); BOOL WINAPI IsCharAlphaNumericW_new(WCHAR x); BOOL WINAPI IsCharAlphaW_new(WCHAR x); +LONG WINAPI GetWindowLongA_NEW(HWND hWnd, int nIndex); +BOOL WINAPI IsWindowUnicode_NEW(HWND hWnd); +LONG WINAPI SetWindowLongA_NEW(HWND hWnd, int nIndex, LONG dwNewLong); +LONG WINAPI GetWindowLongW_NEW(HWND hWnd, int nIndex); +LONG WINAPI SetWindowLongW_NEW(HWND hWnd, int nIndex, LONG dwNewLong); +DWORD WINAPI GetClassLongW_NEW(HWND hWnd, int nIndex); +DWORD WINAPI SetClassLongW_NEW(HWND hWnd, int nIndex, LONG dwNewLong); +ATOM WINAPI RegisterClassExW_NEW(CONST WNDCLASSEXW *lpwcx); +ATOM WINAPI RegisterClassW_NEW(CONST WNDCLASSW *lpwcx); +ATOM WINAPI GetClassInfoExW_NEW(HINSTANCE hinst, LPCWSTR lpszClass, WNDCLASSEXW *lpwcx); +ATOM WINAPI GetClassInfoW_NEW(HINSTANCE hinst, LPCWSTR lpszClass, WNDCLASSW *wc); +HWND WINAPI CreateWindowExW_NEW(DWORD dwExStyle, LPCWSTR lpClassName, LPCWSTR lpWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam); +HWND WINAPI CreateWindowW_NEW(LPCWSTR lpClassName, LPCWSTR lpWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam); +HWND WINAPI CreateMDIWindowW_NEW(LPCWSTR lpClassName, LPCWSTR lpWindowName, DWORD dwStyle, int X, int Y, int nWidth, int nHeight, HWND hWndParent, HINSTANCE hInstance, LPARAM lParam); +HWND WINAPI CreateDialogParamW_NEW(HINSTANCE hInstance, LPCTSTR lpTemplateName, HWND hWndParent, DLGPROC lpDialogFunc, LPARAM dwInitParam); +HWND WINAPI CreateDialogIndirectParamW_NEW(HINSTANCE hInstance, LPCDLGTEMPLATE lpTemplate, HWND hWndParent, DLGPROC lpDialogFunc, LPARAM lParamInit); +INT_PTR WINAPI DialogBoxParamW_NEW(HINSTANCE hInstance, LPCWSTR lpTemplateName, HWND hWndParent, DLGPROC lpDialogFunc, LPARAM dwInitParam); +INT_PTR WINAPI DialogBoxIndirectParamW_NEW(HINSTANCE hInstance, LPCDLGTEMPLATE hDialogTemplate, HWND hWndParent, DLGPROC lpDialogFunc, LPARAM dwInitParam); +LRESULT WINAPI SendMessageW_NEW(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); +LRESULT WINAPI DefWindowProcW_NEW(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); +BOOL WINAPI SetWindowTextW_NEW(HWND hWnd, LPCWSTR lpString); +BOOL WINAPI SetDlgItemTextW_NEW(HWND hDlg, int nIDDlgItem, LPCWSTR lpString); +LRESULT WINAPI SendDlgItemMessageW_NEW(HWND hDlg, int nIDDlgItem, UINT Msg, WPARAM wParam, LPARAM lParam); +int WINAPI GetWindowTextW_NEW(HWND hWnd, LPWSTR lpString, int nMaxCount); +int WINAPI GetDlgItemTextW_NEW(HWND hDlg, int nIDDlgItem, LPWSTR lpString, int nMaxCount); +int WINAPI GetWindowTextLengthW_NEW(HWND hWnd); +BOOL WINAPI UnregisterClassW_NEW(LPCWSTR lpClassName, HINSTANCE hInstance); +BOOL WINAPI SendMessageCallbackW_NEW(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam, SENDASYNCPROC lpCallBack, DWORD dwData); +LRESULT WINAPI SendMessageTimeoutW_NEW(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam, UINT fuFlags, UINT uTimeout, LPDWORD lpdwResult); +LRESULT WINAPI CallWindowProcA_fix(WNDPROC lpPrevWndFunc, HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); +LRESULT WINAPI CallWindowProcW_new(WNDPROC lpPrevWndFunc, HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); +LRESULT WINAPI DefDlgProcW_NEW(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); +LRESULT WINAPI DefMDIChildProcW_NEW(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); +LRESULT WINAPI PostMessageW_NEW(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); +LRESULT WINAPI SendNotifyMessageW_NEW(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); +LRESULT WINAPI PostThreadMessageW_NEW(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); +LRESULT WINAPI DefFrameProcW_NEW(HWND hWnd, HWND hWndMDIClient, UINT uMsg, WPARAM wParam, LPARAM lParam); +BOOL WINAPI GetMessageA_NEW(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax); +BOOL WINAPI PeekMessageA_NEW(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg); +BOOL WINAPI GetMessageW_NEW(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax); +BOOL WINAPI PeekMessageW_NEW(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg); +BOOL WINAPI GetLastInputInfo_NEW(PLASTINPUTINFO plii); +int WINAPI ToUnicodeEx_new(UINT wVirtKey, UINT wScanCode, const PBYTE lpKeyState, LPWSTR pwszBuff, int cchBuff, UINT wFlags, HKL dwhkl); +int WINAPI ToUnicode_new(UINT wVirtKey, UINT wScanCode, const PBYTE lpKeyState, LPWSTR pwszBuff, int cchBuff, UINT wFlags); BOOL WINAPI DrawCaptionTempW_new(HWND hwnd, HDC hdc, const RECT *rect, HFONT hFont, HICON hIcon, LPCWSTR strW, UINT uFlags); int WINAPI LoadStringW_new(HINSTANCE hInstance, UINT uID, LPWSTR lpBuffer, int nBufferMax); UINT WINAPI RealGetWindowClassW_new(HWND hwnd, LPWSTR pszTypeW, UINT cchType); diff --git a/apilibs/kexbases/User32/_user32_stubs.c b/apilibs/kexbases/User32/_user32_stubs.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/User32/hwnd9x.h b/apilibs/kexbases/User32/hwnd9x.h new file mode 100755 index 0000000..5df8397 --- /dev/null +++ b/apilibs/kexbases/User32/hwnd9x.h @@ -0,0 +1,110 @@ +/* + * KernelEx + * Copyright (C) Matt Pietrek 1995 + * Copyright (C) 2009 Tihiy + * + * This file is part of KernelEx source code. + * + * KernelEx is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. + * + * KernelEx is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include + +#ifndef _HWND32_H +#define _HWND32_H + +#pragma pack (1) +typedef struct _RECTS +{ + SHORT left; + SHORT top; + SHORT right; + SHORT bottom; +} RECTS, *PRECTS, *LPRECTS; + +typedef struct _WND +{ + struct _WND *spwndNext; // 00h (GW_HWNDNEXT) HWND of next sibling window + struct _WND *spwndChild; // 04h (GW_CHILD) First child window + struct _WND *spwndParent; // 08h Parent window handle + struct _WND *spwndOwner; // 0Ch Owning window handle + RECTS rcWindow; // 10h Rectangle describing entire window + RECTS rcClient; // 18h Rectangle for client area of window + WORD hQueue; // 20h Application message queue handle + WORD hrgnUpdate; // 22h window region needing an update + WORD wndClass; // 24h handle to an INTWNDCLASS + WORD hInstance; // 26h hInstance of creating application + WNDPROC lpfnWndProc; // 28h Window procedure address + DWORD dwFlags; // 2Ch internal state flags + DWORD style; // 30h WS_XXX style flags + DWORD ExStyle; // 34h WS_EX_XXX extended style flags + DWORD moreFlags; // 38h flags + HANDLE spmenu; // 3Ch GetDlgCtrlId or hMenu + WORD windowTextOffset; // 40h Offset of the window's text in atom heap + WORD scrollBar; // 42h DWORD associated with the scroll bars + WORD properties; // 44h Handle for first window property + WORD hWnd16; // 46h Actual HWND value for this window + struct _WND *lastActive; // 48h Last active owned popup window + HANDLE hMenuSystem; // 4Ch handle to the system menu + DWORD un1; // 50h + WORD un2; // 54h + WORD classAtom; // 56h See also offs. 2 in the field 24 struct ptr +} WND, *PWND; + + +typedef struct _MSGQUEUE +{ + WORD nextQueue; // 00h next queue in the list + WORD hTask; // 02h Task that this queue is associated with + WORD headMsg; // 04h Near ptr to head of linked list of QUEUEMSGs + WORD tailMsg; // 06h Near ptr to end of list of QUEUEMSGs + WORD lastMsg; // 08h Near ptr to last msg retrieved (not really!) + WORD cMsgs; // 0Ah Number of messages (not really for win98?) + BYTE un1; // 0Ch ??? + BYTE sig[3]; // 0Dh "MJT" (Jon Thomason?) + WORD npPerQueue; // 10h 16 bit offset in USER DGROUP to PERQUEUEDATA + // type == LT_USER_VWININFO??? + WORD un2; // 12h ??? + WORD un2_5; // 14h ?? + WORD npProcess; // 16h near pointer in USER DGROUP to a QUEUEPROCESSDATA + DWORD un3[3]; // 18h ??? + DWORD messageTime;// 24h retrieved by GetMessageTime() + DWORD messagePos; // 28h retrived by GetMessagePos() + WORD un4; // 2Ch ??? (seems to always be 0) + WORD lastMsg2; // 2Eh Near ptr to last retrieved QUEUEMSG + DWORD extraInfo; // 30h returned by GetMessageExtraInfo() + DWORD un5[2]; // 34h ??? + DWORD threadId; // 3Ch See GetWindowProcessThreadId + WORD un6; // 40h ?? + WORD expWinVer; // 42h Version of Windows this app expects + DWORD un7; // 44h ??? + WORD ChangeBits; // 48h high order word returned by GetQueueStatus + WORD WakeBits; // 4Ah low order word returned by GetQueueStatus + WORD WakeMask; // 4Ch The QS_xxx bits that GetMessage/PeekMessage are + // waiting for + WORD un8; // 4Eh ??? + WORD hQueueSend; // 50h App that's in SendMessage to this queue + DWORD un9; // 52h ??? + WORD sig2; // 56h "HQ" + HKL hkl; // 58h current thread HKL (keyboard layout) + DWORD un10[3]; // 5Ch ??? filler + WORD block1; // 5Eh+0Ah block for SendMessageA (hook?) + WORD un11; // 5Eh+0Ah+2 ??? filler + DWORD un12[3]; // 5Eh+0Ah+4 ??? filler + WORD block2; // 5Eh+1Ah block for SendMessageA (event?) +} MSGQUEUE, *PMSGQUEUE; +#pragma pack() + +#endif diff --git a/apilibs/kexbases/User32/lstr.c b/apilibs/kexbases/User32/lstr.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/User32/thuni_conv.c b/apilibs/kexbases/User32/thuni_conv.c new file mode 100755 index 0000000..cf6570a --- /dev/null +++ b/apilibs/kexbases/User32/thuni_conv.c @@ -0,0 +1,436 @@ +/* + * KernelEx + * Copyright 1995 Martin von Loewis + * Copyright 1996 Alexandre Julliard + * Copyright 2009 Tihiy + * + * This file is part of KernelEx source code. + * + * KernelEx is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. + * + * KernelEx is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include "thuni_layer.h" +#include "thuni_macro.h" +#include "thuni_thunk.h" + + +__declspec(naked) +LRESULT WINAPI CallWindowProc_stdcall( WNDPROC lpPrevWndFunc, HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) +{ +__asm { + push ebp + mov ebp, esp + push edi + push esi + push ebx + sub esp, 12 + push [ebp+24] + push [ebp+20] + push [ebp+16] + push [ebp+12] + mov eax, [ebp+8] + call eax + lea esp, [ebp-12] + pop ebx + pop esi + pop edi + leave + ret 20 + } +} + +int GetCPFromLocale(LCID Locale) +{ + int cp; + Locale = LOWORD(Locale); + if (GetLocaleInfoA(Locale,LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER,(LPSTR)&cp,sizeof(int))) + return cp; + else + return CP_ACP; +} + +static UINT GetCurrentKeyboardCP() +{ + return GetCPFromLocale((LCID)GetKeyboardLayout(0)); +} + +WPARAM wparam_AtoW( HWND hwnd, UINT message, WPARAM wParam, BOOL messDBCS ) +{ + WPARAM newwParam = wParam; + switch(message) + { + case WM_CHAR: + /* WM_CHAR is magic: a DBCS char can be sent/posted as two consecutive WM_CHAR + * messages, in which case the first char is stored, and the conversion + * to Unicode only takes place once the second char is sent/posted. + */ + if (messDBCS) + { + if ( wParam>127 && wParam<256 ) + { + UCHAR charsA[2]; + int ch = 0; + UINT codepage = GetCurrentKeyboardCP(); + BYTE firstchar = (BYTE)GetPropA(hwnd, c_szDBCSProp); + if ( firstchar ) //first dbcs char stored? + { + ch = 1; + charsA[0] = firstchar; + RemovePropA( hwnd, c_szDBCSProp ); + } + else + { + if ( IsDBCSLeadByteEx(codepage, wParam) ) + { + SetPropA( hwnd, c_szDBCSProp, (HANDLE)wParam ); //store first char + return 0L; + } + } + charsA[ch] = wParam; + ch++; + MultiByteToWideChar( codepage, 0, (LPSTR)charsA, ch, (LPWSTR)&newwParam, 1 ); + } + return newwParam; + } + /* else fall through */ + case WM_CHARTOITEM: + case EM_SETPASSWORDCHAR: + case WM_DEADCHAR: + case WM_SYSCHAR: + case WM_SYSDEADCHAR: + case WM_MENUCHAR: + { + if (wParam>127 && wParam<256) + MultiByteToWideChar( GetCurrentKeyboardCP(), 0, (LPSTR)&wParam, 2, (LPWSTR)&newwParam, 1 ); + break; + } + case WM_IME_CHAR: + { + UCHAR dbcs[2]; + dbcs[0]=HIBYTE(wParam); + dbcs[1]=LOBYTE(wParam); + MultiByteToWideChar( GetCurrentKeyboardCP(), 0, (LPSTR)dbcs, 2, (LPWSTR)&newwParam, 1 ); + break; + } + } + return newwParam; +} + +WPARAM wparam_WtoA( UINT message, WPARAM wParam ) +{ + WPARAM newwParam = wParam & 0xFFFF00FF; + switch(message) + { + case WM_CHAR: + case WM_CHARTOITEM: + case EM_SETPASSWORDCHAR: + case WM_DEADCHAR: + case WM_SYSCHAR: + case WM_SYSDEADCHAR: + case WM_MENUCHAR: + { + BOOL fail; + if (wParam>127) + WideCharToMultiByte( GetCurrentKeyboardCP(), WC_NO_BEST_FIT_CHARS, (LPWSTR)&wParam, 1, (LPSTR)&newwParam, 2, NULL, &fail ); + if (fail) return wParam; + break; + } + case WM_IME_CHAR: + { + WideCharToMultiByte( GetCurrentKeyboardCP(), 0, (LPWSTR)&wParam, 1, (LPSTR)&newwParam, 2, NULL, NULL ); + newwParam = MAKEWPARAM(MAKEWORD(HIBYTE(newwParam),LOBYTE(newwParam)),HIWORD(newwParam)); + break; + } + } + return newwParam; +} + + +/********************************************************************** + * Wine WINPROC_TestLBForStr + * + * Return TRUE if the lparam is a string + */ +static BOOL TestLBForStr( HWND hwnd, UINT msg ) +{ + DWORD style = GetWindowLongA( hwnd, GWL_STYLE ); + if (msg <= CB_MSGMAX) + return (!(style & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) || (style & CBS_HASSTRINGS)); + else + return (!(style & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE)) || (style & LBS_HASSTRINGS)); + +} + +/********************************************************************** +* Call an Ansi window procedure, translating args from Unicode to Ansi. +* 9x control wise, CallWindowProcA must be used instead of direct call. +*/ +LRESULT WINAPI CallProcAnsiWithUnicode( WNDPROC callback, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) + { + case WM_CREATE: + case WM_NCCREATE: + { + if (!VALID_PTR(lParam)) return CallWindowProcA(callback,hwnd,msg,wParam,lParam); + + LPCREATESTRUCTW csW = (LPCREATESTRUCTW)lParam; + CREATESTRUCTA csA; + LPMDICREATESTRUCTW mcsW = (LPMDICREATESTRUCTW)csW->lpCreateParams; + MDICREATESTRUCTA mcsA; + + CopyMemory(&csA, csW, sizeof(CREATESTRUCT)); + STACK_WtoA(csW->lpszName,csA.lpszName); + STACK_WtoA(csW->lpszClass,csA.lpszClass); + + if ( GetWindowLongA(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD && VALID_PTR(mcsW) ) + { + //mmm test, i can't understand Wine + CopyMemory(&mcsA, mcsW, sizeof(MDICREATESTRUCT)); + STACK_WtoA(mcsW->szClass,mcsA.szClass); + STACK_WtoA(mcsW->szTitle,mcsA.szTitle); + csA.lpCreateParams = &mcsA; + } + return CallWindowProcA(callback,hwnd,msg,wParam,(LPARAM)&csA); + } + case WM_MDICREATE: + { + if (!VALID_PTR(lParam)) return CallWindowProcA(callback,hwnd,msg,wParam,lParam); + + LPMDICREATESTRUCTW mcsW = (LPMDICREATESTRUCTW)lParam; + MDICREATESTRUCTA mcsA; + CopyMemory(&mcsA, mcsW, sizeof(MDICREATESTRUCT)); + STACK_WtoA(mcsW->szClass,mcsA.szClass); + STACK_WtoA(mcsW->szTitle,mcsA.szTitle); + return CallWindowProcA(callback,hwnd,msg,wParam,(LPARAM)&mcsA); + } + case LB_GETTEXT: + case CB_GETLBTEXT: + if (lParam && TestLBForStr( hwnd, msg )) + { + LPSTR textA; + int len = CallWindowProcA( callback, hwnd, msg == LB_GETTEXT ? LB_GETTEXTLEN : CB_GETLBTEXTLEN, wParam, 0 ); + ABUFFER_ALLOC(textA,len); + LRESULT ret = CallWindowProcA( callback, hwnd, msg, wParam,(LPARAM)textA ); + ABUFFER_toW(textA,lParam,len); + BUFFER_FREE(textA); + return ret; + } + break; + case WM_ASKCBFORMATNAME: + case WM_GETTEXT: + { + if ( !lParam ) return 0L; + if ( !wParam ) //no text + { + *(LPWSTR)(lParam) = 0; + return 0L; + } + LPSTR textA; + ABUFFER_ALLOC(textA,wParam); + LRESULT ret = CallWindowProcA( callback, hwnd, msg, wParam,(LPARAM)textA ); + ABUFFER_toW(textA,lParam,wParam); + BUFFER_FREE(textA); + return ret; + } + case EM_GETLINE: + { + WORD len = *(WORD *)lParam; + LPSTR textA; + ABUFFER_ALLOC(textA,len); + *(WORD *)textA = len; + LRESULT ret = CallWindowProcA( callback, hwnd, msg, wParam,(LPARAM)textA ); + ABUFFER_toW(textA,lParam,len); + BUFFER_FREE(textA); + return ret; + } + case LB_ADDSTRING: + case LB_INSERTSTRING: + case LB_FINDSTRING: + case LB_FINDSTRINGEXACT: + case LB_SELECTSTRING: + case CB_ADDSTRING: + case CB_INSERTSTRING: + case CB_FINDSTRING: + case CB_FINDSTRINGEXACT: + case CB_SELECTSTRING: + if ( !lParam || !TestLBForStr( hwnd, msg ) ) break; + /* fall through */ + case WM_WININICHANGE: + case WM_DEVMODECHANGE: + if ( IsBadReadPtr((LPWSTR)lParam, sizeof(WCHAR)) ) break; //i don't trust those two!! + case CB_DIR: + case LB_DIR: + case LB_ADDFILE: + case EM_REPLACESEL: + case WM_SETTEXT: + { + LPSTR textA; + STACK_WtoA( lParam, textA ); + return CallWindowProcA(callback,hwnd,msg,wParam,(LPARAM)textA); + } + case WM_CHAR: + { + if ( !HIWORD(wParam) && LOWORD(wParam)>127 ) + { + LRESULT ret; + UCHAR charsA[2]; //don't use char! + BOOL fail = FALSE; + int ch = WideCharToMultiByte( GetCurrentKeyboardCP(), WC_NO_BEST_FIT_CHARS, (LPWSTR)&wParam, 1, (LPSTR)charsA, 2, NULL, &fail ); + if ( fail ) break; //can't translate, game over + ret = CallWindowProcA(callback,hwnd,msg,charsA[0],lParam); + if ( ch==2 ) CallWindowProcA(callback,hwnd,msg,charsA[1],lParam); + return ret; + } + break; + } + case WM_CHARTOITEM: + case EM_SETPASSWORDCHAR: + case WM_DEADCHAR: + case WM_SYSCHAR: + case WM_SYSDEADCHAR: + case WM_MENUCHAR: + case WM_IME_CHAR: + wParam = wparam_WtoA( msg, wParam ); + break; + } + return CallWindowProcA(callback,hwnd,msg,wParam,lParam); +} + +/********************************************************************** +* Call an Unicode window procedure, translating args from Ansi to Unicode. +* No need to use CallWindowProcA since callback can't be 16-bit thunk, +* but using CallWindowProc_stdcall since we adapt to buggy W functions. +*/ +LRESULT WINAPI CallProcUnicodeWithAnsi( WNDPROC callback, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) + { + case WM_CREATE: + case WM_NCCREATE: + { + if (!VALID_PTR(lParam)) return CallWindowProc_stdcall(callback,hwnd,msg,wParam,lParam); + + LPCREATESTRUCTA csA = (LPCREATESTRUCTA)lParam; + CREATESTRUCTW csW; + LPMDICREATESTRUCTA mcsA = (LPMDICREATESTRUCTA)csA->lpCreateParams; + MDICREATESTRUCTW mcsW; + + CopyMemory(&csW, csA, sizeof(CREATESTRUCT)); + STACK_AtoW(csA->lpszName,csW.lpszName); + STACK_AtoW(csA->lpszClass,csW.lpszClass); + + if ( GetWindowLongA(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD && VALID_PTR(mcsA) ) + { + CopyMemory(&mcsW, mcsA, sizeof(MDICREATESTRUCT)); + STACK_AtoW(mcsA->szClass,mcsW.szClass); + STACK_AtoW(mcsA->szTitle,mcsW.szTitle); + csW.lpCreateParams = &mcsW; + } + return CallWindowProc_stdcall(callback,hwnd,msg,wParam,(LPARAM)&csW); + } + case WM_MDICREATE: + { + if (!VALID_PTR(lParam)) return CallWindowProc_stdcall(callback,hwnd,msg,wParam,lParam); + + LPMDICREATESTRUCTA mcsA = (LPMDICREATESTRUCTA)lParam; + MDICREATESTRUCTW mcsW; + CopyMemory(&mcsW, mcsA, sizeof(MDICREATESTRUCT)); + STACK_AtoW(mcsA->szClass,mcsW.szClass); + STACK_AtoW(mcsA->szTitle,mcsW.szTitle); + return CallWindowProc_stdcall(callback,hwnd,msg,wParam,(LPARAM)&mcsW); + } + case LB_GETTEXT: + case CB_GETLBTEXT: + if (lParam && TestLBForStr( hwnd, msg )) + { + LPWSTR textW; + int len = CallWindowProc_stdcall( callback,hwnd, msg == LB_GETTEXT ? LB_GETTEXTLEN : CB_GETLBTEXTLEN, wParam, 0 ); + WBUFFER_ALLOC(textW,len); + LRESULT ret = CallWindowProc_stdcall( callback, hwnd, msg, wParam,(LPARAM)textW ); + WBUFFER_toA(textW, lParam, len+1); + BUFFER_FREE(textW); + return ret; + } + break; + case WM_ASKCBFORMATNAME: + case WM_GETTEXT: + { + if ( !lParam ) return 0L; + if ( !wParam ) //no text + { + *(LPWSTR)(lParam) = 0; + return 0L; + } + LPWSTR textW; + WBUFFER_ALLOC(textW,wParam); + LRESULT ret = CallWindowProc_stdcall( callback, hwnd, msg, wParam,(LPARAM)textW ); + WBUFFER_toA(textW,lParam,wParam); + BUFFER_FREE(textW); + return ret; + } + case EM_GETLINE: + { + WORD len = *(WORD *)lParam; + LPWSTR textW; + WBUFFER_ALLOC(textW,len); + *(WORD *)textW = len; + LRESULT ret = CallWindowProc_stdcall( callback, hwnd, msg, wParam,(LPARAM)textW ); + WBUFFER_toA(textW,lParam,len); + BUFFER_FREE(textW); + return ret; + } + case LB_ADDSTRING: + case LB_INSERTSTRING: + case LB_FINDSTRING: + case LB_FINDSTRINGEXACT: + case LB_SELECTSTRING: + case CB_ADDSTRING: + case CB_INSERTSTRING: + case CB_FINDSTRING: + case CB_FINDSTRINGEXACT: + case CB_SELECTSTRING: + if ( !lParam || !TestLBForStr( hwnd, msg ) ) break; + /* fall through */ + case WM_WININICHANGE: + case WM_DEVMODECHANGE: + if ( IsBadReadPtr((LPSTR)lParam, sizeof(CHAR)) ) break; //i don't trust those two!! + case CB_DIR: + case LB_DIR: + case LB_ADDFILE: + case EM_REPLACESEL: + case WM_SETTEXT: + { + LPWSTR textW; + STACK_AtoW( lParam, textW ); + return CallWindowProc_stdcall(callback,hwnd,msg,wParam,(LPARAM)textW); + } + case WM_CHAR: + case WM_CHARTOITEM: + case EM_SETPASSWORDCHAR: + case WM_DEADCHAR: + case WM_SYSCHAR: + case WM_SYSDEADCHAR: + case WM_MENUCHAR: + case WM_IME_CHAR: + { + wParam = wparam_AtoW( hwnd, msg, wParam, TRUE ); + } + break; + } + return CallWindowProc_stdcall(callback,hwnd,msg,wParam,lParam); +} + diff --git a/apilibs/kexbases/User32/thuni_layer.c b/apilibs/kexbases/User32/thuni_layer.c new file mode 100755 index 0000000..5904335 --- /dev/null +++ b/apilibs/kexbases/User32/thuni_layer.c @@ -0,0 +1,646 @@ +/* + * KernelEx Thunking Unicode Layer + * + * Copyright (C) 2009, Tihiy + * + * This file is part of KernelEx source code. + * + * KernelEx is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. + * + * KernelEx is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include "k32ord.h" +#include "thuni_thunk.h" +#include "thuni_layer.h" +#include "thuni_macro.h" + +static GCQ_API GetCurrentThreadQueue; +static HTOP_API HWNDtoPWND; + +static LPCRITICAL_SECTION pWin16Mutex; +static CRITICAL_SECTION wndproc_cs; + +static HMODULE g_hUser32; + +#define SetWinCreateEvent(proc) SetWinEventHook(EVENT_OBJECT_CREATE, EVENT_OBJECT_CREATE, g_hUser32, (WINEVENTPROC)(proc), GetCurrentProcessId(), GetCurrentThreadId(), WINEVENT_INCONTEXT) + +BOOL InitUniThunkLayer() +{ + g_hUser32 = GetModuleHandleA("user32"); + /* Returns current thread hQueue 32-bit pointer */ + GetCurrentThreadQueue = (GCQ_API) RELTOABS( (DWORD)GetMessageExtraInfo + 7 ); + /* IsWindow returns PWND */ + HWNDtoPWND = (HTOP_API)IsWindow; + + _GetpWin16Lock( &pWin16Mutex ); + InitializeCriticalSection( &wndproc_cs ); + MakeCriticalSectionGlobal( &wndproc_cs ); + + return TRUE; +} + +void GrabWin16Lock() +{ + _EnterSysLevel(pWin16Mutex); +} + +void ReleaseWin16Lock() +{ + _LeaveSysLevel(pWin16Mutex); +} + +static WNDPROC WINAPI _GetWindowProc32(PWND pwnd) +{ + if ( !pwnd ) return NULL; + if ( !IS32BITWIN(pwnd) ) return NULL; + PTHUNK16 proc32 = (PTHUNK16)MapSL( (DWORD)pwnd->lpfnWndProc ); + if ( !proc32 ) return NULL; + if ( proc32->push1 != pushl16_code ) return NULL; //NOT 16-bit pushl? + return proc32->proc; +} + +static PMSGQUEUE _GetWindowQueue(PWND pwnd) +{ + return pwnd ? (PMSGQUEUE)MapSL( (DWORD)pwnd->hQueue << 16 ) : NULL; +} + +static void _SetWindowUnicode(PWND pwnd, BOOL bUnicode) +{ + if ( pwnd ) + { + if (bUnicode) + pwnd->ExStyle |= WS_EX_UNICODE; + else + pwnd->ExStyle &= ~WS_EX_UNICODE; + } +} + +BOOL IsWindowReallyUnicode(HWND hwnd) +{ + /* window is really unicode if it has unicode procedure */ + PWND pwnd = HWNDtoPWND(hwnd); + if ( pwnd && IS32BITWIN(pwnd) ) + { + THUNKPROC proc = (THUNKPROC)_GetWindowProc32( pwnd ); + if ( proc && proc->sign == wtoa_code && IsValidThunk(proc) ) return TRUE; + } + return FALSE; +} + +/* maybe we'll export this for comdlg32 */ +void WINAPI SetWindowUnicode(HWND hWnd, BOOL bUnicode) +{ + GrabWin16Lock(); + _SetWindowUnicode( HWNDtoPWND(hWnd), bUnicode ); + ReleaseWin16Lock(); +} + +/* MAKE_EXPORT GetWindowLongA_NEW=GetWindowLongA */ +LONG WINAPI GetWindowLongA_NEW(HWND hWnd, int nIndex) +{ + LONG ret = GetWindowLongA( hWnd, nIndex ); + if (nIndex == GWL_EXSTYLE) ret = ret & ~WS_EX_UNICODE; //mask out our flag + return ret; +} + +/* MAKE_EXPORT IsWindowUnicode_NEW=IsWindowUnicode */ +BOOL WINAPI IsWindowUnicode_NEW( HWND hWnd ) +{ + return GetWindowLongA(hWnd, GWL_EXSTYLE) & WS_EX_UNICODE ? TRUE : FALSE; +} + +/* MAKE_EXPORT SetWindowLongA_NEW=SetWindowLongA */ +LONG WINAPI SetWindowLongA_NEW(HWND hWnd, int nIndex, LONG dwNewLong) +{ + BOOL WasUnicode = FALSE; + LONG ret; + if ( nIndex == GWL_EXSTYLE ) + { + WasUnicode = IsWindowUnicode_NEW( hWnd ); + dwNewLong &= ~WS_EX_UNICODE; //don't let reset nor see unicode flag!!! + } + ret = SetWindowLongA( hWnd, nIndex, dwNewLong ); + if ( WasUnicode ) + SetWindowUnicode( hWnd, TRUE ); //restore unicode flag if someone changed ExStyle + if ( nIndex == GWL_WNDPROC && ret ) + SetWindowUnicode( hWnd, FALSE ); //remove 'Unicode' flag + return ret; +} + + + +/********************************************************************** +* allocate a thunk, AtoW / WtoA +*/ +static WNDPROC AllocWndProc( PROCESS_THUNKS thunks, WNDPROC oldproc, BOOL AtoW ) +{ + int thunk_number = thunks->count; + if (thunk_number == CHUNK_THUNKS) //if chunk is full, grow chunk list (thunks points to last chunk) + { + thunks = GrowProcessThunks(thunks); + DBGPRINTF(("Thunks array has grown (new chunk %p)\n",thunks)); + if (!thunks) return oldproc; + thunk_number = 0; + } + DWORD thunkfunc = AtoW ? (DWORD)CallProcAnsiWithUnicode : (DWORD)CallProcUnicodeWithAnsi; //logic is inverted!!! AtoW=Unicode2Ansi, vice versa + thunks->array[thunk_number].sign = AtoW ? atow_code : wtoa_code; + thunks->array[thunk_number].pop_eax = pop_eax_code; + thunks->array[thunk_number].push_func = push_func_code; + thunks->array[thunk_number].proc = oldproc; + thunks->array[thunk_number].push_eax = push_eax_code; + thunks->array[thunk_number].jmp_func = jmp_func_code; + thunks->array[thunk_number].relay_offset = thunkfunc - (DWORD)&thunks->array[thunk_number].relay_offset - sizeof(DWORD); + thunks->count++; + + return (WNDPROC)&thunks->array[thunk_number]; +} + +/* Window procedure conversions */ + +/* ConvertWndProc W<->A are using per-process + * growable array of executable code thunks. + * The rules are simple: + * WToA(procW) = procA, AToW(procA) = procW + * WToA(procA) or AToW(procW) are invalid, + * but we fix this case too. + */ + +static WNDPROC ConvertWndProcWToA( WNDPROC ProcW ) +{ + int i; + WNDPROC ret = NULL; + THUNKPROC thunk = (THUNKPROC)ProcW; + if ( !HIWORD(ProcW) ) return ProcW; + if ( thunk->sign == atow_code && IsValidThunk(thunk) ) return thunk->proc; + if ( thunk->sign == wtoa_code && IsValidThunk(thunk) ) return ProcW; //invalid + if ( ProcW == DefWindowProcW_NEW ) return DefWindowProcA; + if ( ProcW == DefDlgProcW_NEW ) return DefDlgProcA; + if ( ProcW == DefMDIChildProcW_NEW ) return DefMDIChildProcA; + EnterCriticalSection( &wndproc_cs ); + PROCESS_THUNKS procthunks = GetProcessThunks(); + while (true) + { + for ( i=0; icount; i++) + { + if ( procthunks->array[i].proc == ProcW && procthunks->array[i].sign == wtoa_code ) + { + //we have an WtoA thunk already + ret = (WNDPROC)&procthunks->array[i]; + break; + } + } + if (ret || !procthunks->nextChunk) break; + procthunks = procthunks->nextChunk; + } + if ( !ret ) ret = AllocWndProc( procthunks, ProcW, FALSE ); + LeaveCriticalSection( &wndproc_cs ); + return ret; +} + +static WNDPROC ConvertWndProcAToW( WNDPROC ProcA ) +{ + int i; + WNDPROC ret = NULL; + THUNKPROC thunk = (THUNKPROC)ProcA; + if ( !HIWORD(ProcA) ) return ProcA; + if ( thunk->sign == wtoa_code && IsValidThunk(thunk) ) return thunk->proc; + if ( thunk->sign == atow_code && IsValidThunk(thunk) ) return ProcA; //invalid + if ( ProcA == DefWindowProcA ) return DefWindowProcW_NEW; + if ( ProcA == DefDlgProcA ) return DefDlgProcW_NEW; + if ( ProcA == DefMDIChildProcA ) return DefMDIChildProcW_NEW; + EnterCriticalSection( &wndproc_cs ); + PROCESS_THUNKS procthunks = GetProcessThunks(); + while (true) + { + for ( i=0; icount; i++) + { + if ( procthunks->array[i].proc == ProcA && procthunks->array[i].sign == atow_code ) + { + //we have an WtoA thunk already + ret = (WNDPROC)&procthunks->array[i]; + break; + } + } + if (ret || !procthunks->nextChunk) break; + procthunks = procthunks->nextChunk; + } + if ( !ret ) ret = AllocWndProc( procthunks, ProcA, TRUE ); + LeaveCriticalSection( &wndproc_cs ); + return ret; +} + +/* MAKE_EXPORT GetWindowLongW_NEW=GetWindowLongW */ +LONG WINAPI GetWindowLongW_NEW(HWND hWnd, int nIndex) +{ + LONG ret = GetWindowLongA_NEW(hWnd, nIndex); + if ( nIndex == GWL_WNDPROC ) + { + if ( !ISOURPROCESSHWND(hWnd) ) + { + SetLastError(ERROR_ACCESS_DENIED); + return 0L; + } + DBGPRINTF(("GetWindowProcW: %p(A) -> %p(W)\n",ret,ConvertWndProcAToW((WNDPROC)ret))); + ret = (LONG)ConvertWndProcAToW( (WNDPROC)ret ); + } + return ret; +} + +/* MAKE_EXPORT SetWindowLongW_NEW=SetWindowLongW */ +LONG WINAPI SetWindowLongW_NEW(HWND hWnd, int nIndex, LONG dwNewLong) +{ + LONG ret; + if ( nIndex == GWL_WNDPROC ) + { + if ( !ISOURPROCESSHWND(hWnd) ) + { + SetLastError(ERROR_ACCESS_DENIED); + return 0L; + } + DBGPRINTF(("SetWindowProcW[(%p)new]: %p(W) => %p(A)\n",hWnd,dwNewLong,ConvertWndProcWToA((WNDPROC)dwNewLong))); + dwNewLong = (LONG)ConvertWndProcWToA( (WNDPROC)dwNewLong ); + } + + ret = SetWindowLongA_NEW( hWnd, nIndex, dwNewLong ); + + if ( nIndex == GWL_WNDPROC && ret ) //oh, you're unicode subclassed! + { + DBGPRINTF(("SetWindowProcW[(%p)old]: %p(A) => %p(W)\n",hWnd,ret,ConvertWndProcAToW((WNDPROC)ret))); + SetWindowUnicode( hWnd, TRUE ); + ret = (LONG)ConvertWndProcAToW( (WNDPROC)ret ); + } + return ret; +} + +/* Class manipulation functions*/ + +/* MAKE_EXPORT GetClassLongW_NEW=GetClassLongW */ +DWORD WINAPI GetClassLongW_NEW(HWND hWnd, int nIndex) +{ + DWORD ret = GetClassLongA(hWnd, nIndex); + if ( nIndex == GCL_WNDPROC ) + { + if ( !ISOURPROCESSHWND(hWnd) ) + { + SetLastError(ERROR_ACCESS_DENIED); + return 0L; + } + ret = (DWORD)ConvertWndProcAToW( (WNDPROC)ret ); + } + return ret; +} + +/* MAKE_EXPORT SetClassLongW_NEW=SetClassLongW */ +DWORD WINAPI SetClassLongW_NEW(HWND hWnd, int nIndex, LONG dwNewLong) +{ + DWORD ret; + if ( nIndex == GCL_WNDPROC ) + { + if ( !ISOURPROCESSHWND(hWnd) ) + { + SetLastError(ERROR_ACCESS_DENIED); + return 0L; + } + dwNewLong = (DWORD)ConvertWndProcWToA( (WNDPROC)dwNewLong ); + } + ret = SetClassLongA( hWnd, nIndex, dwNewLong ); + if ( nIndex == GCL_WNDPROC && ret ) + ret = (DWORD)ConvertWndProcAToW( (WNDPROC)ret ); + return ret; +} + +/* MAKE_EXPORT RegisterClassExW_NEW=RegisterClassExW */ +ATOM WINAPI RegisterClassExW_NEW( CONST WNDCLASSEXW *lpwcx ) +{ + WNDCLASSEXA wnda; + if ( !lpwcx || !HIWORD(lpwcx->lpfnWndProc) ) return FALSE; + CopyMemory( &wnda, lpwcx, sizeof(WNDCLASSEXA)); + STACK_WtoA(lpwcx->lpszClassName, wnda.lpszClassName); + STACK_WtoA(lpwcx->lpszMenuName, wnda.lpszMenuName); + wnda.lpfnWndProc = ConvertWndProcWToA( wnda.lpfnWndProc ); + return RegisterClassExA(&wnda); +} + +/* MAKE_EXPORT RegisterClassW_NEW=RegisterClassW */ +ATOM WINAPI RegisterClassW_NEW( CONST WNDCLASSW *lpwcx ) +{ + WNDCLASSEXW wndw; + wndw.cbSize = sizeof(WNDCLASSEXW); + wndw.style = lpwcx->style; + wndw.lpfnWndProc = lpwcx->lpfnWndProc; + wndw.cbClsExtra = lpwcx->cbClsExtra; + wndw.cbWndExtra = lpwcx->cbWndExtra; + wndw.hInstance = lpwcx->hInstance; + wndw.hIcon = lpwcx->hIcon; + wndw.hCursor = lpwcx->hCursor; + wndw.hbrBackground = lpwcx->hbrBackground; + wndw.lpszMenuName = lpwcx->lpszMenuName; + wndw.lpszClassName = lpwcx->lpszClassName; + wndw.hIconSm = NULL; + return RegisterClassExW_NEW( &wndw ); +} + +//Those two are both ATOMs +/* MAKE_EXPORT GetClassInfoExW_NEW=GetClassInfoExW */ +ATOM WINAPI GetClassInfoExW_NEW(HINSTANCE hinst, LPCWSTR lpszClass, WNDCLASSEXW *lpwcx) +{ + LPSTR lpszClassA; + STACK_WtoA(lpszClass, lpszClassA); + ATOM ret = GetClassInfoExA( hinst, lpszClassA, (WNDCLASSEXA*)lpwcx ); + if ( ret ) + { + lpwcx->lpfnWndProc = ConvertWndProcAToW( lpwcx->lpfnWndProc ); + //lpwcx->lpszClassName = lpszClass; + /* BUGBUG this is not correct behavior. lpszClassName/lpszMenuName have to be + * permanent pointers! Maybe it can be solved with static buffer like MSLU does. + */ + } + return ret; +} + +/* MAKE_EXPORT GetClassInfoW_NEW=GetClassInfoW */ +ATOM WINAPI GetClassInfoW_NEW(HINSTANCE hinst, LPCWSTR lpszClass, WNDCLASSW *wc) +{ + WNDCLASSEXW wcex; + wcex.cbSize = sizeof(WNDCLASS); + ATOM ret = GetClassInfoExW_NEW( hinst, lpszClass, &wcex ); + if (ret && wc) + { + wc->style = wcex.style; + wc->lpfnWndProc = wcex.lpfnWndProc; + wc->cbClsExtra = wcex.cbClsExtra; + wc->cbWndExtra = wcex.cbWndExtra; + wc->hInstance = wcex.hInstance; + wc->hIcon = wcex.hIcon; + wc->hCursor = wcex.hCursor; + wc->hbrBackground = wcex.hbrBackground; + wc->lpszMenuName = wcex.lpszMenuName; + wc->lpszClassName = wcex.lpszClassName; + } + return ret; +} + +/* Unicode flagging */ +static void CALLBACK UnicodeEvent( HWINEVENTHOOK hWinEventHook, DWORD event, HWND hwnd, LONG idObject, LONG idChild, DWORD dwEventThread, DWORD dwmsEventTime ) +{ + if ( idObject != OBJID_WINDOW ) return; + //NOTE: we don't grab Win16Lock!! we touch windows only belonging to current thread. + BOOL isUnicode = FALSE; + PWND pwnd = HWNDtoPWND(hwnd); + if ( !pwnd ) return; //wtf + if ( !IS32BITWIN(pwnd) ) + isUnicode = TRUE; //16-bit window, will be Unicode + else + { + THUNKPROC proc = (THUNKPROC)_GetWindowProc32( pwnd ); + if ( (DWORD)proc & 0x80000000 || (proc && proc->sign == wtoa_code && IsValidThunk(proc)) ) //shared control or Unicode thunk + isUnicode = TRUE; + } + if ( isUnicode ) _SetWindowUnicode( pwnd, TRUE ); + if ( isUnicode ) SendMessage( hwnd, CCM_SETUNICODEFORMAT, TRUE, 0 ); +} + +/* Window creation functions */ + +/* MAKE_EXPORT CreateWindowExW_NEW=CreateWindowExW */ +HWND WINAPI CreateWindowExW_NEW(DWORD dwExStyle, LPCWSTR lpClassName, LPCWSTR lpWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam) +{ + LPSTR lpClassNameA; + LPSTR lpWindowNameA; + HWINEVENTHOOK uniEvent; + HWND ret; + + STACK_WtoA(lpClassName, lpClassNameA); + STACK_WtoA(lpWindowName, lpWindowNameA); + uniEvent = SetWinCreateEvent(UnicodeEvent); + ret = CreateWindowExA(dwExStyle,lpClassNameA,lpWindowNameA,dwStyle,x,y,nWidth,nHeight,hWndParent,hMenu,hInstance,lpParam); + UnhookWinEvent(uniEvent); + return ret; +} + +/* MAKE_EXPORT CreateWindowW_NEW=CreateWindowW */ +HWND WINAPI CreateWindowW_NEW( LPCWSTR lpClassName, LPCWSTR lpWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam) +{ + return CreateWindowExW_NEW(0, lpClassName,lpWindowName,dwStyle,x,y,nWidth,nHeight,hWndParent,hMenu,hInstance,lpParam); +} + +/* MAKE_EXPORT CreateMDIWindowW_NEW=CreateMDIWindowW */ +HWND WINAPI CreateMDIWindowW_NEW( LPCWSTR lpClassName, LPCWSTR lpWindowName, DWORD dwStyle, + int X, int Y, int nWidth, int nHeight, HWND hWndParent, HINSTANCE hInstance, LPARAM lParam) +{ + LPSTR lpClassNameA; + LPSTR lpWindowNameA; + HWINEVENTHOOK uniEvent; + HWND ret; + + STACK_WtoA(lpClassName, lpClassNameA); + STACK_WtoA(lpWindowName, lpWindowNameA); + uniEvent = SetWinCreateEvent(UnicodeEvent); + ret = CreateMDIWindowA(lpClassNameA,lpWindowNameA,dwStyle,X,Y,nWidth,nHeight,hWndParent,hInstance,lParam); + UnhookWinEvent(uniEvent); + return ret; +} + +/* MAKE_EXPORT CreateDialogParamW_NEW=CreateDialogParamW */ +HWND WINAPI CreateDialogParamW_NEW( HINSTANCE hInstance, LPCTSTR lpTemplateName, HWND hWndParent, DLGPROC lpDialogFunc, LPARAM dwInitParam) +{ + LPSTR lpTemplateNameA; + HWINEVENTHOOK uniEvent; + HWND ret; + + STACK_WtoA(lpTemplateName, lpTemplateNameA); + uniEvent = SetWinCreateEvent(UnicodeEvent); + DBGPRINTF(("CreateDialogParamW started (proc %p), eventhook %p\n",lpDialogFunc,uniEvent)); + ret = CreateDialogParamA( hInstance, lpTemplateNameA, hWndParent, lpDialogFunc, dwInitParam ); + DBGPRINTF(("CreateDialogParamW finished: %p\n",ret)); + UnhookWinEvent(uniEvent); + return ret; +} + +/* MAKE_EXPORT CreateDialogIndirectParamW_NEW=CreateDialogIndirectParamW */ +HWND WINAPI CreateDialogIndirectParamW_NEW( HINSTANCE hInstance, LPCDLGTEMPLATE lpTemplate, HWND hWndParent, DLGPROC lpDialogFunc, LPARAM lParamInit) +{ + HWINEVENTHOOK uniEvent; + HWND ret; + + uniEvent = SetWinCreateEvent(UnicodeEvent); + DBGPRINTF(("CreateDialogIndirectParamW started (proc %p), eventhook %p\n",lpDialogFunc,uniEvent)); + ret = CreateDialogIndirectParamA( hInstance, lpTemplate, hWndParent, lpDialogFunc, lParamInit ); + UnhookWinEvent(uniEvent); + return ret; +} + +/* MAKE_EXPORT DialogBoxParamW_NEW=DialogBoxParamW */ +INT_PTR WINAPI DialogBoxParamW_NEW( HINSTANCE hInstance, LPCWSTR lpTemplateName, HWND hWndParent, DLGPROC lpDialogFunc, LPARAM dwInitParam) +{ + LPSTR lpTemplateNameA; + HWINEVENTHOOK uniEvent; + INT_PTR ret; + + STACK_WtoA( lpTemplateName, lpTemplateNameA ); + uniEvent = SetWinCreateEvent(UnicodeEvent); + DBGPRINTF(("DialogBoxParamW started (proc %p), eventhook %p\n",lpDialogFunc,uniEvent)); + ret = DialogBoxParamA( hInstance, lpTemplateNameA, hWndParent, lpDialogFunc, dwInitParam ); + UnhookWinEvent(uniEvent); + return ret; +} + +/* MAKE_EXPORT DialogBoxIndirectParamW_NEW=DialogBoxIndirectParamW */ +INT_PTR WINAPI DialogBoxIndirectParamW_NEW( HINSTANCE hInstance, LPCDLGTEMPLATE hDialogTemplate, HWND hWndParent, DLGPROC lpDialogFunc, LPARAM dwInitParam) +{ + HWINEVENTHOOK uniEvent; + INT_PTR ret; + + + uniEvent = SetWinCreateEvent(UnicodeEvent); + DBGPRINTF(("DialogBoxIndirectParamW started (proc %p), eventhook %p\n",lpDialogFunc,uniEvent)); + ret = DialogBoxIndirectParamA( hInstance, hDialogTemplate, hWndParent, lpDialogFunc, dwInitParam ); + UnhookWinEvent(uniEvent); + return ret; +} + + +/* MAKE_EXPORT SendMessageW_NEW=SendMessageW */ +LRESULT WINAPI SendMessageW_NEW( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) +{ + if ( hWnd && LOWORD(hWnd)!=0xFFFF ) //broadcasts won't work + { + /* If window is in the same thread, sent message directly + * BUGBUG: take global message filter (Spy++) into account somehow + */ + WNDPROC procW = NULL; + GrabWin16Lock(); + PWND pwnd = HWNDtoPWND(hWnd); + if ( pwnd ) + { + PMSGQUEUE msgq = _GetWindowQueue(pwnd); + PMSGQUEUE ourmsgq = GetCurrentThreadQueue(); + if ( ourmsgq == msgq && !msgq->block1 && !msgq->block2 ) //hooray! we're in the same queue and can be 32-bit! + procW = ConvertWndProcAToW( _GetWindowProc32(pwnd) ); + } + ReleaseWin16Lock(); + if ( procW ) + { + //DBGPRINTF(("SendMessageW [DIRECT]: %p, %p, %p, %p\n",hWnd, Msg, wParam, lParam)); + return CallWindowProc_stdcall( procW, hWnd, Msg, wParam, lParam ); + } + } + //DBGPRINTF(("SendMessageW [THUNK]: %p, %p, %p, %p\n",hWnd, Msg, wParam, lParam)); + return CallProcAnsiWithUnicode( (WNDPROC)SendMessageA_fix, hWnd, Msg, wParam, lParam ); +} + +/* MAKE_EXPORT DefWindowProcW_NEW=DefWindowProcW */ +LRESULT WINAPI DefWindowProcW_NEW( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) +{ + return CallProcAnsiWithUnicode( DefWindowProcA, hWnd, Msg, wParam, lParam ); +} + +/* MAKE_EXPORT SetWindowTextW_NEW=SetWindowTextW */ +BOOL WINAPI SetWindowTextW_NEW( HWND hWnd, LPCWSTR lpString) +{ + if ( !hWnd || !lpString ) return FALSE; + if ( !ISOURPROCESSHWND(hWnd) ) + { + SetLastError(ERROR_ACCESS_DENIED); + return FALSE; + } + return SendMessageW_NEW( hWnd, WM_SETTEXT, 0, (LPARAM)lpString ); +} + +/* MAKE_EXPORT SetDlgItemTextW_NEW=SetDlgItemTextW */ +BOOL WINAPI SetDlgItemTextW_NEW( HWND hDlg, int nIDDlgItem, LPCWSTR lpString ) +{ + return SetWindowTextW_NEW( GetDlgItem(hDlg, nIDDlgItem), lpString ); +} + +/* MAKE_EXPORT SendDlgItemMessageW_NEW=SendDlgItemMessageW */ +LRESULT WINAPI SendDlgItemMessageW_NEW( HWND hDlg, int nIDDlgItem, UINT Msg, WPARAM wParam, LPARAM lParam ) +{ + HWND hCtl = GetDlgItem(hDlg, nIDDlgItem); + if ( hCtl ) + return SendMessageW_NEW( hCtl, Msg, wParam, lParam ); + return 0L; +} + +/* MAKE_EXPORT GetWindowTextW_NEW=GetWindowTextW */ +int WINAPI GetWindowTextW_NEW( HWND hWnd, LPWSTR lpString, int nMaxCount) +{ + if ( !lpString || nMaxCount<=0 ) return 0; //NT does not set error here + if ( !IsWindow(hWnd) ) + { + SetLastError(ERROR_INVALID_WINDOW_HANDLE); + return 0; + } + if ( ISOURPROCESSHWND(hWnd) ) + return SendMessageW_NEW( hWnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString ); + else + return DefWindowProcW_NEW( hWnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString ); +} + +/* MAKE_EXPORT GetDlgItemTextW_NEW=GetDlgItemTextW */ +int WINAPI GetDlgItemTextW_NEW( HWND hDlg, int nIDDlgItem, LPWSTR lpString, int nMaxCount) +{ + hDlg = GetDlgItem(hDlg, nIDDlgItem); + if (hDlg) + return GetWindowTextW_NEW( hDlg , lpString, nMaxCount ); + //NULL in fail case + *lpString = WCHAR(0); + return 0; +} + +/* MAKE_EXPORT GetWindowTextLengthW_NEW=GetWindowTextLengthW */ +int WINAPI GetWindowTextLengthW_NEW( HWND hWnd ) +{ + return GetWindowTextLengthA(hWnd); //BUGBUG looks like i care about DBCS? +} + +/* MAKE_EXPORT UnregisterClassW_NEW=UnregisterClassW */ +BOOL WINAPI UnregisterClassW_NEW( LPCWSTR lpClassName, HINSTANCE hInstance) +{ + LPCSTR lpClassNameA; + STACK_WtoA(lpClassName, lpClassNameA); + return UnregisterClassA( lpClassNameA, hInstance ); +} + +/* Those functions were born ugly */ + +/* MAKE_EXPORT SendMessageCallbackW_NEW=SendMessageCallbackW */ +BOOL WINAPI SendMessageCallbackW_NEW( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam, SENDASYNCPROC lpCallBack, DWORD dwData) +{ + //TODO: add WM_CHAR and alike conversion? + return SendMessageCallbackA( hWnd, Msg, wParam, lParam, lpCallBack, dwData); +} + +LRESULT WINAPI SendMessageTimeoutW_Helper( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) +{ + PSMTIMEOUT_THUNK psm = (PSMTIMEOUT_THUNK)GetMessageExtraInfo(); + return SendMessageTimeoutA(hWnd,Msg,wParam,lParam,psm->fuFlags,psm->uTimeout,psm->lpdwResult); +} + +/* MAKE_EXPORT SendMessageTimeoutW_NEW=SendMessageTimeoutW */ +LRESULT WINAPI SendMessageTimeoutW_NEW( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam, UINT fuFlags, UINT uTimeout, LPDWORD lpdwResult) +{ + LONG saveExtraInfo = GetMessageExtraInfo(); + SMTIMEOUT_THUNK smt; + smt.fuFlags = fuFlags; + smt.lpdwResult = lpdwResult; + smt.uTimeout = uTimeout; + SetMessageExtraInfo((LONG)&smt); + LRESULT ret = CallProcAnsiWithUnicode(SendMessageTimeoutW_Helper,hWnd,Msg,wParam,lParam); + SetMessageExtraInfo(saveExtraInfo); + return ret; +} + diff --git a/apilibs/kexbases/User32/thuni_layer.h b/apilibs/kexbases/User32/thuni_layer.h new file mode 100755 index 0000000..fb6d561 --- /dev/null +++ b/apilibs/kexbases/User32/thuni_layer.h @@ -0,0 +1,44 @@ +#include "hwnd9x.h" + +static const char c_szDBCSProp[]="kexDBCS"; + + +static DWORD GetWindowProcessId( HWND hwnd ) +{ + DWORD procID = 0; + GetWindowThreadProcessId( hwnd, &procID ); + return procID; +} + +#define ISOURPROCESSHWND(hwnd) ( GetWindowProcessId(hwnd) == GetCurrentProcessId() ) + +#define WS_EX_UNICODE 0x80000000 +#define WF_EX_WIN32 0x02000000 +#define WF_M_DIALOG 0x2 + +#define IS32BITWIN(pwnd) (pwnd->dwFlags & WF_EX_WIN32) +#define ISDIALOG(pwnd) (pwnd->moreFlags & WF_M_DIALOG) + +typedef PMSGQUEUE (WINAPI *GCQ_API) (); +typedef PWND (WINAPI *HTOP_API) (HWND hwnd); + +#define RELTOABS(x) ( (DWORD)(x) + *(DWORD*)(x) + 4 ) + +int GetCPFromLocale(LCID Locale); + +LRESULT WINAPI CallWindowProc_stdcall( WNDPROC lpPrevWndFunc, HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); + +WPARAM wparam_AtoW( HWND hwnd, UINT message, WPARAM wParam, BOOL messDBCS ); +WPARAM wparam_WtoA( UINT message, WPARAM wParam ); + +LRESULT WINAPI CallProcUnicodeWithAnsi( WNDPROC callback, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); +LRESULT WINAPI CallProcAnsiWithUnicode( WNDPROC callback, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); + +LRESULT WINAPI DefWindowProcW_NEW( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); +LRESULT WINAPI DefDlgProcW_NEW( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); +LRESULT WINAPI DefMDIChildProcW_NEW( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); +BOOL IsWindowReallyUnicode(HWND hwnd); + +LRESULT WINAPI SendMessageA_fix(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); + +BOOL InitUniThunkLayer(); diff --git a/apilibs/kexbases/User32/thuni_macro.h b/apilibs/kexbases/User32/thuni_macro.h new file mode 100755 index 0000000..b0166f6 --- /dev/null +++ b/apilibs/kexbases/User32/thuni_macro.h @@ -0,0 +1,85 @@ +/* + * KernelEx + * + * Copyright (C) 2009, Tihiy + * + * This file is part of KernelEx source code. + * + * KernelEx is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. + * + * KernelEx is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include "kexcoresdk.h" + +#ifndef __THUNIMACRO_H +#define __THUNIMACRO_H + +#define VALID_PTR(x) (HIWORD(x)) + +#define MAX_STACK 512 + +//In macroses: convert A<->W on stack +#define STACK_WtoA(strW,strA) \ + strA = (LPSTR)strW; \ + if HIWORD(strW) \ + { \ + int c = lstrlenW((LPWSTR)strW); \ + c = (c+1)*2; \ + strA = (LPSTR)alloca(c); \ + WideCharToMultiByte(CP_ACP, 0, (LPWSTR)strW, -1, (LPSTR)strA, c, NULL, NULL); \ + } + +#define STACK_AtoW(strA,strW) \ + strW = (LPWSTR)strA; \ + if (HIWORD(strA)) \ + { \ + int c = lstrlenA((LPSTR)strA); \ + c++; \ + strW = (LPWSTR)alloca(c*sizeof(WCHAR)); \ + MultiByteToWideChar(CP_ACP, 0, (LPSTR)strA, -1, (LPWSTR)strW, c); \ + } + +//Out macroses: allocate buffer, call W>-W +#define ABUFFER_ALLOC(buffer,len) \ + int buffer##size = ((len+1) * 2); \ + LPSTR buffer##heap = NULL; \ + if (buffer##size>MAX_STACK) \ + { \ + buffer##heap = (LPSTR)HeapAlloc(GetProcessHeap(),0,buffer##size); \ + buffer = buffer##heap; \ + } \ + else \ + buffer = (LPSTR)alloca( buffer##size ); \ + *buffer='\0'; + +#define WBUFFER_ALLOC(buffer,len) \ + int buffer##size = ((len+1) * sizeof(WCHAR)); \ + LPWSTR buffer##heap = NULL; \ + if (buffer##size>MAX_STACK) \ + { \ + buffer##heap = (LPWSTR)HeapAlloc(GetProcessHeap(),0,buffer##size); \ + buffer = buffer##heap; \ + } \ + else \ + buffer = (LPWSTR)alloca( buffer##size ); \ + *buffer='\0'; + +#define ABUFFER_toW(bufferA,bufferW,lenW) MultiByteToWideChar(CP_ACP, 0, bufferA, -1, (LPWSTR)bufferW, lenW); +#define WBUFFER_toA(bufferW,bufferA,lenA) WideCharToMultiByte(CP_ACP, 0, bufferW, -1, (LPSTR)bufferA, lenA, NULL, NULL); + +#define BUFFER_FREE(buffer) \ + if ( buffer##heap ) HeapFree(GetProcessHeap(),0,buffer##heap); \ + +#endif diff --git a/apilibs/kexbases/User32/thuni_proc.c b/apilibs/kexbases/User32/thuni_proc.c new file mode 100755 index 0000000..08b19c8 --- /dev/null +++ b/apilibs/kexbases/User32/thuni_proc.c @@ -0,0 +1,205 @@ +/* + * KernelEx + * + * Copyright (C) 2009, Tihiy + * + * This file is part of KernelEx source code. + * + * KernelEx is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. + * + * KernelEx is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include "thuni_macro.h" +#include "thuni_thunk.h" +#include "thuni_layer.h" + +static DWORD g_LastInputTime; + +__declspec(naked) +/* MAKE_EXPORT CallWindowProcA_fix=CallWindowProcA */ +LRESULT WINAPI CallWindowProcA_fix(WNDPROC lpPrevWndFunc, HWND hWnd, + UINT Msg, WPARAM wParam, LPARAM lParam) +{ + /* We shouldn't write it in C because some weird programs depend + * on CallWindowProc calling function directly! */ +__asm { + mov ecx, [esp+4] ;lpPrevWndFunc + jecxz FAIL + jmp dword ptr [CallWindowProcA] +FAIL: + xor eax,eax + ret 20 + } +} + + +/* MAKE_EXPORT CallWindowProcW_new=CallWindowProcW */ +LRESULT WINAPI CallWindowProcW_new( WNDPROC lpPrevWndFunc, HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) +{ + if ( !lpPrevWndFunc ) return 0L; + THUNKPROC testthunk = (THUNKPROC)lpPrevWndFunc; + if ( testthunk->sign == wtoa_code && IsValidThunk(testthunk) ) + lpPrevWndFunc = testthunk->proc; + return CallWindowProc_stdcall( lpPrevWndFunc, hWnd, Msg, wParam, lParam ); +} + +/* BORING default Unicode window procedures */ + +/* MAKE_EXPORT DefDlgProcW_NEW=DefDlgProcW */ +LRESULT WINAPI DefDlgProcW_NEW( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) +{ + return CallProcAnsiWithUnicode( DefDlgProcA, hWnd, Msg, wParam, lParam ); +} + +/* MAKE_EXPORT DefMDIChildProcW_NEW=DefMDIChildProcW */ +LRESULT WINAPI DefMDIChildProcW_NEW( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) +{ + return CallProcAnsiWithUnicode( DefMDIChildProcA, hWnd, Msg, wParam, lParam ); +} + +/* those APIs won't need conversion for any but WM_CHAR msg */ +/* MAKE_EXPORT PostMessageW_NEW=PostMessageW */ +LRESULT WINAPI PostMessageW_NEW( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) +{ + return CallProcAnsiWithUnicode( (WNDPROC)PostMessageA, hWnd, Msg, wParam, lParam ); +} + +/* MAKE_EXPORT SendNotifyMessageW_NEW=SendNotifyMessageW */ +LRESULT WINAPI SendNotifyMessageW_NEW( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) +{ + return CallProcAnsiWithUnicode( (WNDPROC)SendNotifyMessageA, hWnd, Msg, wParam, lParam ); +} + +/* MAKE_EXPORT PostThreadMessageW_NEW=PostThreadMessageW */ +LRESULT WINAPI PostThreadMessageW_NEW( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) +{ + //BUGBUG removeme + return CallProcAnsiWithUnicode( (WNDPROC)PostThreadMessageA, hWnd, Msg, wParam, lParam ); +} + +/* MAKE_EXPORT DefFrameProcW_NEW=DefFrameProcW */ +LRESULT WINAPI DefFrameProcW_NEW( HWND hWnd, HWND hWndMDIClient, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) { + case WM_SETTEXT: + { + LPSTR textA; + STACK_WtoA( lParam, textA ); + return DefFrameProcA( hWnd, hWndMDIClient, uMsg, wParam, (LPARAM)textA ); + } + case WM_NCACTIVATE: + case WM_COMMAND: + case WM_SYSCOMMAND: + case WM_SIZE: + case WM_SETFOCUS: + case WM_NEXTMENU: + case WM_MENUCHAR: + return DefFrameProcA( hWnd, hWndMDIClient, uMsg, wParam, lParam ); + default: + return DefWindowProcW_NEW( hWnd, uMsg, wParam, lParam ); + } +} + +/* MAKE_EXPORT GetMessageA_NEW=GetMessageA */ +BOOL WINAPI GetMessageA_NEW( LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax) +{ + BOOL ret; + if ( !lpMsg ) return -1; //9x fails to check that + ret = GetMessageA( lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax ); + if ( ret && ((lpMsg->message>=WM_KEYFIRST && lpMsg->message<=WM_KEYLAST)||(lpMsg->message>=WM_MOUSEFIRST && lpMsg->message<=WM_MOUSELAST)) ) + g_LastInputTime = GetTickCount(); + return ret; +} + +/* MAKE_EXPORT PeekMessageA_NEW=PeekMessageA */ +BOOL WINAPI PeekMessageA_NEW( LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg) +{ + BOOL ret; + if ( !lpMsg ) return FALSE; //9x fails to check that + ret = PeekMessageA( lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg ); + if ( ret && ((lpMsg->message>=WM_KEYFIRST && lpMsg->message<=WM_KEYLAST)||(lpMsg->message>=WM_MOUSEFIRST && lpMsg->message<=WM_MOUSELAST)) ) + g_LastInputTime = GetTickCount(); + return ret; +} + +/* MAKE_EXPORT GetMessageW_NEW=GetMessageW */ +BOOL WINAPI GetMessageW_NEW( LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax) +{ + BOOL ret = GetMessageA_NEW( lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax ); + if ( ret == 1 && lpMsg->message == WM_CHAR && IsWindowReallyUnicode(lpMsg->hwnd) ) + { + lpMsg->wParam = wparam_AtoW( NULL, lpMsg->message, lpMsg->wParam, FALSE ); + } + return ret; +} + +/* MAKE_EXPORT PeekMessageW_NEW=PeekMessageW */ +BOOL WINAPI PeekMessageW_NEW( LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg) +{ + BOOL ret = PeekMessageA_NEW( lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg ); + if ( ret == 1 && lpMsg->message == WM_CHAR && IsWindowReallyUnicode(lpMsg->hwnd) ) + lpMsg->wParam = wparam_AtoW( NULL, lpMsg->message, lpMsg->wParam, FALSE ); + return ret; +} + +/* MAKE_EXPORT GetLastInputInfo_NEW=GetLastInputInfo */ +BOOL WINAPI GetLastInputInfo_NEW( PLASTINPUTINFO plii ) +{ + if ( !plii ) return FALSE; + plii->dwTime = g_LastInputTime; + return TRUE; +} + +/* MAKE_EXPORT ToUnicodeEx_new=ToUnicodeEx */ +int WINAPI ToUnicodeEx_new( + UINT wVirtKey, + UINT wScanCode, + const PBYTE lpKeyState, + LPWSTR pwszBuff, + int cchBuff, + UINT wFlags, + HKL dwhkl +) +{ + int result; + WORD asciibuf[4]; + char ansibuf[4]; + if (!lpKeyState || !pwszBuff) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + result = ToAsciiEx(wVirtKey,wScanCode,lpKeyState,asciibuf,wFlags,dwhkl); + if (result && cchBuff) + { + int i; + for (i = 0; i < result; i++) ansibuf[i]=(char)asciibuf[i]; + MultiByteToWideChar(GetCPFromLocale((LCID)dwhkl),0,ansibuf,result,pwszBuff,cchBuff); + } + return result; +} + +/* MAKE_EXPORT ToUnicode_new=ToUnicode */ +int WINAPI ToUnicode_new( + UINT wVirtKey, + UINT wScanCode, + const PBYTE lpKeyState, + LPWSTR pwszBuff, + int cchBuff, + UINT wFlags +) +{ + return ToUnicodeEx_new(wVirtKey,wScanCode,lpKeyState,pwszBuff,cchBuff,wFlags,GetKeyboardLayout(GetCurrentThreadId())); +} diff --git a/apilibs/kexbases/User32/thuni_thunk.c b/apilibs/kexbases/User32/thuni_thunk.c new file mode 100755 index 0000000..3628756 --- /dev/null +++ b/apilibs/kexbases/User32/thuni_thunk.c @@ -0,0 +1,26 @@ +#include +#include "thuni_thunk.h" +#include "kexcoresdk.h" + +static int thunindex = -1; + +PROCESS_THUNKS GetProcessThunks() +{ + if (thunindex == -1) + thunindex = kexPsAllocIndex(); + LPVOID secret = kexPsGetValue(thunindex); + if (! secret ) //initialize thunks + { + secret = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(THUNKS_STRUCT)); + kexPsSetValue(thunindex,secret); + } + return (PROCESS_THUNKS)secret; +} + +PROCESS_THUNKS GrowProcessThunks(PROCESS_THUNKS lastChunk) +{ + PROCESS_THUNKS newChunk = (PROCESS_THUNKS)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(THUNKS_STRUCT)); + if (newChunk) + lastChunk->nextChunk = newChunk; + return newChunk; +} \ No newline at end of file diff --git a/apilibs/kexbases/User32/thuni_thunk.h b/apilibs/kexbases/User32/thuni_thunk.h new file mode 100755 index 0000000..51c9e8b --- /dev/null +++ b/apilibs/kexbases/User32/thuni_thunk.h @@ -0,0 +1,63 @@ +#ifndef __THUNITHUNK_H +#define __THUNITHUNK_H + +/* winproc thunks, look a bit like Wine ones */ +#define atow_code 0xC987 /*xchg ecx,ecx*/ +#define wtoa_code 0xDB87 /*xchg ebx,ebx*/ +#define pop_eax_code 0x58 +#define push_eax_code 0x50 +#define push_func_code 0x68 +#define jmp_func_code 0xE9 +#define CHUNK_THUNKS 60 /*so THUNKS_STRUCT is around 1KB*/ + +#define pushl16_code 0x6866 + +#include "pshpack1.h" +typedef struct +{ + WORD sign; /* xchg reg, reg*/ + BYTE pop_eax; /* pop eax (return address) */ + BYTE push_func; /* push $proc */ + WNDPROC proc; + BYTE push_eax; /* push eax */ + BYTE jmp_func; /* jmp relay*/ + DWORD relay_offset; /* _call_wndproc */ + WORD padding16; /* total size 16 */ +} WINPROC_THUNK, *THUNKPROC; + +typedef struct THUNKS_STRUCT +{ + int count; + struct THUNKS_STRUCT* nextChunk; + WINPROC_THUNK array[CHUNK_THUNKS]; +} THUNKS_STRUCT, *PROCESS_THUNKS; + +typedef struct +{ + WORD push1; /* push16 */ + WNDPROC proc; + WORD push2; + DWORD type; /* thunk variant */ +} THUNK16, *PTHUNK16; + +typedef struct +{ + UINT fuFlags; + UINT uTimeout; + LPDWORD lpdwResult; +} SMTIMEOUT_THUNK, *PSMTIMEOUT_THUNK; + +#include "poppack.h" + +/* looks like thunk? */ +__forceinline +static BOOL IsValidThunk( THUNKPROC proc ) +{ + if ( proc->pop_eax == pop_eax_code && proc->jmp_func == jmp_func_code ) return TRUE; + return FALSE; +} + +PROCESS_THUNKS GetProcessThunks(); +PROCESS_THUNKS GrowProcessThunks(PROCESS_THUNKS lastChunk); + +#endif diff --git a/apilibs/kexbases/User32/uniuser32.c b/apilibs/kexbases/User32/uniuser32.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/comdlg32/PrintDlgEx.c b/apilibs/kexbases/comdlg32/PrintDlgEx.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/comdlg32/_comdlg32_apilist.c b/apilibs/kexbases/comdlg32/_comdlg32_apilist.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/comdlg32/_comdlg32_apilist.h b/apilibs/kexbases/comdlg32/_comdlg32_apilist.h old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/common.c b/apilibs/kexbases/common.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/common.h b/apilibs/kexbases/common.h old mode 100644 new mode 100755 index 04cc26c..5f9560f --- a/apilibs/kexbases/common.h +++ b/apilibs/kexbases/common.h @@ -42,12 +42,12 @@ char* file_fixWprefix(char* in); #endif #ifdef __GNUC__ -#define UNIMPL_FUNC(name,params) \ - __asm__( ".text\n" \ - ".globl _" #name "_stub@0\n" \ - "_" #name "_new@0:\n\t" \ - "xor %eax, %eax\n\t" \ - "movb $" #params ", %cl\n\t" \ +#define UNIMPL_FUNC(name,params) \ + __asm__( ".text\n" \ + ".globl _" #name "_stub@0\n" \ + "_" #name "_stub@0:\n\t" \ + "xor %eax, %eax\n\t" \ + "movb $" #params ", %cl\n\t" \ "jmp _CommonUnimpStub@0\n\t" \ ) #else @@ -67,7 +67,7 @@ char* file_fixWprefix(char* in); const WCHAR* p; \ int c; \ for (p = str##W ; *p ; p++); \ - c = (int) p - (int) str##W; \ + c = p - str##W + 1; \ c *= acp_mcs; \ str##A = (char*) alloca(c); \ WtoA(str, c) @@ -100,7 +100,7 @@ char* file_fixWprefix(char* in); const WCHAR* p; \ int c; \ for (p = str##W ; *p ; p++); \ - c = (int) p - (int) str##W; \ + c = p - str##W + 1; \ c *= acp_mcs; \ str##A = (char*) alloca(c); \ file_WtoA(str, c); \ diff --git a/apilibs/kexbases/dirlist b/apilibs/kexbases/dirlist old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/kexbases.def b/apilibs/kexbases/kexbases.def old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/kexbases.dsp b/apilibs/kexbases/kexbases.dsp old mode 100644 new mode 100755 index c63b277..0e2f78d --- a/apilibs/kexbases/kexbases.dsp +++ b/apilibs/kexbases/kexbases.dsp @@ -80,7 +80,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib version.lib ../../common/KernelEx.lib ../../kexcrt/kexcrt.lib libc.lib /nologo /dll /map /debug /machine:I386 /nodefaultlib /pdbtype:sept /ignore:4092 /OPT:NOWIN98 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib version.lib ../../common/KernelEx.lib ../../kexcrt/kexcrt.lib libc.lib /nologo /dll /map /debug /machine:I386 /nodefaultlib /ignore:4092 /OPT:NOWIN98 # SUBTRACT LINK32 /pdb:none !ENDIF @@ -133,6 +133,10 @@ SOURCE=.\Kernel32\GetFileSizeEx.c # End Source File # Begin Source File +SOURCE=.\Kernel32\GetModuleHandleEx.c +# End Source File +# Begin Source File + SOURCE=.\Kernel32\GlobalMemoryStatusEx.c # End Source File # Begin Source File @@ -149,6 +153,10 @@ SOURCE=.\Kernel32\IsProcessorFeaturePresent.c # End Source File # Begin Source File +SOURCE=.\Kernel32\IsWow64Process.c +# End Source File +# Begin Source File + SOURCE=.\Kernel32\Jobs.c # End Source File # Begin Source File @@ -205,11 +213,11 @@ SOURCE=.\Kernel32\OpenThread.c # End Source File # Begin Source File -SOURCE=.\Kernel32\SetFilePointerEx.c +SOURCE=.\Kernel32\RemoteDesktop.c # End Source File # Begin Source File -SOURCE=.\Kernel32\ThreadPool.c +SOURCE=.\Kernel32\SetFilePointerEx.c # End Source File # Begin Source File @@ -257,10 +265,6 @@ SOURCE=.\User32\_user32_stubs.c # End Source File # Begin Source File -SOURCE=.\User32\CallWindowProcA_fix.c -# End Source File -# Begin Source File - SOURCE=.\User32\DisableProcessWindowsGhosting.c # End Source File # Begin Source File @@ -281,6 +285,14 @@ SOURCE=.\User32\GetMouseMovePointsEx.c # End Source File # Begin Source File +SOURCE=.\User32\GetNextDlgTabItem_fix.c +# End Source File +# Begin Source File + +SOURCE=.\User32\hwnd9x.h +# End Source File +# Begin Source File + SOURCE=.\User32\IsHungAppWindow.c # End Source File # Begin Source File @@ -301,7 +313,31 @@ SOURCE=.\User32\SendMessage_fix.c # End Source File # Begin Source File -SOURCE=.\User32\UberUSER.c +SOURCE=.\User32\thuni_conv.c +# End Source File +# Begin Source File + +SOURCE=.\User32\thuni_layer.c +# End Source File +# Begin Source File + +SOURCE=.\User32\thuni_layer.h +# End Source File +# Begin Source File + +SOURCE=.\User32\thuni_macro.h +# End Source File +# Begin Source File + +SOURCE=.\User32\thuni_proc.c +# End Source File +# Begin Source File + +SOURCE=.\User32\thuni_thunk.c +# End Source File +# Begin Source File + +SOURCE=.\User32\thuni_thunk.h # End Source File # Begin Source File @@ -333,7 +369,11 @@ SOURCE=.\Gdi32\FontResourceExA.c # End Source File # Begin Source File -SOURCE=.\Gdi32\gdi9x.h +SOURCE=.\Gdi32\GdiObjects.c +# End Source File +# Begin Source File + +SOURCE=.\Gdi32\GdiObjects.h # End Source File # Begin Source File @@ -377,6 +417,10 @@ SOURCE=.\Advapi32\RegOpenCurrentUser.c # End Source File # Begin Source File +SOURCE=.\Advapi32\RtlGenRandom.c +# End Source File +# Begin Source File + SOURCE=.\Advapi32\security.c # End Source File # Begin Source File @@ -450,6 +494,49 @@ SOURCE=.\common.c # End Source File # Begin Source File +SOURCE=.\dirlist + +!IF "$(CFG)" == "KernelEx Base Shared - Win32 Release" + +# Begin Custom Build +WkspDir=. +ProjDir=. +InputPath=.\dirlist + +"&" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + if not exist $(WkspDir)\util\prep\Release\prep.exe goto error + $(WkspDir)\util\prep\Release\prep.exe "$(ProjDir)" + goto quit + :error + echo Error - compile PREP (Release) project first + echo 1 | choice /C:1 /N >NUL + :quit + +# End Custom Build + +!ELSEIF "$(CFG)" == "KernelEx Base Shared - Win32 Debug" + +# Begin Custom Build +WkspDir=. +ProjDir=. +InputPath=.\dirlist + +"&" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + if not exist $(WkspDir)\util\prep\Release\prep.exe goto error + $(WkspDir)\util\prep\Release\prep.exe "$(ProjDir)" + goto quit + :error + echo Error - compile PREP (Release) project first + echo 1 | choice /C:1 /N >NUL + :quit + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + SOURCE=.\kexbases.def !IF "$(CFG)" == "KernelEx Base Shared - Win32 Release" diff --git a/apilibs/kexbases/kexbases.rc b/apilibs/kexbases/kexbases.rc old mode 100644 new mode 100755 index 61f4723..ab3e888 --- a/apilibs/kexbases/kexbases.rc +++ b/apilibs/kexbases/kexbases.rc @@ -74,7 +74,7 @@ BEGIN VALUE "FileDescription", "KernelEx Base Shared Api Library\0" VALUE "FileVersion", _RCVERSION_ "\0" VALUE "InternalName", "kexbases\0" - VALUE "LegalCopyright", "Copyright © 2009, Xeno86\0" + VALUE "LegalCopyright", "Copyright © 2009-2010, Xeno86\0" VALUE "LegalTrademarks", "\0" VALUE "OriginalFilename", "kexbases.dll\0" VALUE "PrivateBuild", "\0" diff --git a/apilibs/kexbases/main.c b/apilibs/kexbases/main.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/resource.h b/apilibs/kexbases/resource.h old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/shell32/CommandLineToArgvW.c b/apilibs/kexbases/shell32/CommandLineToArgvW.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/shell32/IsUserAnAdmin.c b/apilibs/kexbases/shell32/IsUserAnAdmin.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/shell32/_shell32_apilist.c b/apilibs/kexbases/shell32/_shell32_apilist.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/shell32/_shell32_apilist.h b/apilibs/kexbases/shell32/_shell32_apilist.h old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/shell32/_shell32_stubs.c b/apilibs/kexbases/shell32/_shell32_stubs.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/version/_version_apilist.c b/apilibs/kexbases/version/_version_apilist.c old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/version/_version_apilist.h b/apilibs/kexbases/version/_version_apilist.h old mode 100644 new mode 100755 diff --git a/apilibs/kexbases/version/universion.c b/apilibs/kexbases/version/universion.c old mode 100644 new mode 100755 diff --git a/apilibs/settings.reg b/apilibs/settings.reg old mode 100644 new mode 100755 index f219457..b6253cd --- a/apilibs/settings.reg +++ b/apilibs/settings.reg @@ -5,16 +5,24 @@ REGEDIT4 [HKEY_LOCAL_MACHINE\Software\KernelEx\AppSettings\Configs] "*\\KERNELEX\\VERIFY.EXE"="DCFG1" "*\\UNICOWS.DLL"="DCFG1" +"*\\MFC*U.DLL"="WINXP" +;-Firefox "*\\FIREFOX SETUP 3*.EXE"="WINXP" "*FIREFOX\\UNINSTALL\\HELPER.EXE"="WINXP" "*\\FIREFOX*PRE*.INSTALLER.EXE"="WINXP" "*\\XUL.DLL"="WINXP" "*\\FIREFOX.EXE"="DCFG1" "*\\SEAMONKEY.EXE"="DCFG1" -"*\\MFC*U.DLL"="WINXP" ;-Java "*\\JAVA.EXE"="DCFG1" "*\\JAVAW.EXE"="DCFG1" +;-GIMP +"*\\BIN\\GIMP-2.6.EXE"="WIN2K" +"*\\GIMP-2.6*-SETUP.EXE"="WIN2K" +;-Webkit +"*\\QTWEBKIT4.DLL"="WINXP" +;-AbiWord +"*\\BIN\\ABIWORD.EXE"="VISTA" [HKEY_LOCAL_MACHINE\Software\KernelEx\AppSettings\Flags] ;DISABLE KERNELEX FOR: @@ -31,6 +39,8 @@ REGEDIT4 "*\\SHLWAPI.DLL"=dword:00000001 "*\\MSVCRT.DLL"=- "*\\SPOOL32.EXE"=dword:00000001 +"*\\WS2_32.DLL"=dword:00000001 +"*\\USP10.DLL"=dword:00000001 ;-OpenGL drivers "*\\OPENGL32.DLL"=dword:00000001 "*\\ATIO9XXX.DLL"=dword:00000001 @@ -44,4 +54,5 @@ REGEDIT4 "*\\PBSVS.DLL"=dword:00000001 ;-DirectX installer "*\\DXSETUP.EXE"=dword:00000001 +"*\\DXWEBSETUP.EXE"=dword:00000001 diff --git a/auxiliary/auxiliary.dsp b/auxiliary/auxiliary.dsp old mode 100644 new mode 100755 diff --git a/auxiliary/makefile b/auxiliary/makefile old mode 100644 new mode 100755 diff --git a/auxiliary/makefile.msv b/auxiliary/makefile.msv old mode 100644 new mode 100755 index 00ff187..204a8d3 --- a/auxiliary/makefile.msv +++ b/auxiliary/makefile.msv @@ -14,6 +14,9 @@ all : cd psapi @$(MAKE) /nologo /f makefile.msv $@ cd .. + cd userenv + @$(MAKE) /nologo /f makefile.msv $@ + cd .. clean : cd msimg32 @@ -31,6 +34,9 @@ clean : cd psapi @$(MAKE) /nologo /f makefile.msv $@ cd .. + cd userenv + @$(MAKE) /nologo /f makefile.msv $@ + cd .. ide : all clean -@if exist Release\NUL rd Release diff --git a/auxiliary/msimg32/makefile b/auxiliary/msimg32/makefile old mode 100644 new mode 100755 diff --git a/auxiliary/msimg32/makefile.msv b/auxiliary/msimg32/makefile.msv old mode 100644 new mode 100755 diff --git a/auxiliary/msimg32/msimg32.c b/auxiliary/msimg32/msimg32.c old mode 100644 new mode 100755 index 7154082..aa15850 --- a/auxiliary/msimg32/msimg32.c +++ b/auxiliary/msimg32/msimg32.c @@ -63,7 +63,7 @@ BOOL WINAPI AlphaBlend_NEW( HDC hdcDest, // handle to destination DC BLENDFUNCTION blendFunction // alpha-blending function ) { - unsigned int i, srcalpha, dstalpha; + unsigned int srcalpha, dstalpha; BITMAPINFO bmi; HBITMAP srcBM, dstBM, dcBM; HDC srcDC, dstDC; @@ -102,6 +102,7 @@ BOOL WINAPI AlphaBlend_NEW( HDC hdcDest, // handle to destination DC //workwork if ( !(blendFunction.AlphaFormat & AC_SRC_ALPHA) ) //no alpha channel { + int i; srcalpha = blendFunction.SourceConstantAlpha; dstalpha = 255 - srcalpha; for (i = 0; i < (nWidthDest*nHeightDest); i++) @@ -116,6 +117,7 @@ BOOL WINAPI AlphaBlend_NEW( HDC hdcDest, // handle to destination DC } else { + int i; unsigned int tmp; srcalpha = blendFunction.SourceConstantAlpha; for (i = 0; i < (nWidthDest*nHeightDest); i++) diff --git a/auxiliary/msimg32/msimg32.def b/auxiliary/msimg32/msimg32.def old mode 100644 new mode 100755 diff --git a/auxiliary/msimg32/msimgme.rc b/auxiliary/msimg32/msimgme.rc old mode 100644 new mode 100755 diff --git a/auxiliary/pdh/kord.def b/auxiliary/pdh/kord.def old mode 100644 new mode 100755 diff --git a/auxiliary/pdh/makefile b/auxiliary/pdh/makefile old mode 100644 new mode 100755 diff --git a/auxiliary/pdh/makefile.msv b/auxiliary/pdh/makefile.msv old mode 100644 new mode 100755 diff --git a/auxiliary/pdh/pdh.c b/auxiliary/pdh/pdh.c old mode 100644 new mode 100755 diff --git a/auxiliary/pdh/pdh.def b/auxiliary/pdh/pdh.def old mode 100644 new mode 100755 diff --git a/auxiliary/psapi/makefile b/auxiliary/psapi/makefile old mode 100644 new mode 100755 diff --git a/auxiliary/psapi/makefile.msv b/auxiliary/psapi/makefile.msv old mode 100644 new mode 100755 diff --git a/auxiliary/psapi/psapi.c b/auxiliary/psapi/psapi.c old mode 100644 new mode 100755 diff --git a/auxiliary/psapi/psapi.def b/auxiliary/psapi/psapi.def old mode 100644 new mode 100755 diff --git a/auxiliary/userenv/makefile.msv b/auxiliary/userenv/makefile.msv new file mode 100755 index 0000000..12d50ba --- /dev/null +++ b/auxiliary/userenv/makefile.msv @@ -0,0 +1,33 @@ +# Makefile for Microsoft Visual C++ Compiler (MSVC) + +OBJ = userenv.obj +RES = +DEF = /DEF:userenv.def +BIN = ..\userenv.dll +LIBS = -nodefaultlib kernel32.lib gdi32.lib shell32.lib shlwapi.lib +LDFLAGS = /DLL /OPT:NOWIN98 /ENTRY:DllMain@12 +CFLAGS = /W3 /O2 /Oi /FD +CXXFLAGS = $(CFLAGS) + +all : $(BIN) + -@if exist $(BIN:.dll=.exp) del $(BIN:.dll=.exp) + -@if exist $(BIN:.dll=.lib) del $(BIN:.dll=.lib) + +.PHONY : clean +clean : + -@if exist *.obj del *.obj + -@if exist *.idb del *.idb + -@if exist *.res del *.res + +realclean : clean + -@if exist $(BIN) del $(BIN) + +$(BIN) : $(OBJ) $(RES) + link /nologo $(LDFLAGS) $(DEF) /OUT:$(BIN) $(LIBS) $(OBJ) $(RES) + +.c.obj : + cl /nologo $(CFLAGS) /c /Fo$@ $< + +.cpp.obj : + cl /nologo $(CXXFLAGS) /c /Fo$@ $< + diff --git a/auxiliary/userenv/userenv.c b/auxiliary/userenv/userenv.c new file mode 100755 index 0000000..70d7825 --- /dev/null +++ b/auxiliary/userenv/userenv.c @@ -0,0 +1,202 @@ +/* + * Implementation of userenv.dll + * + * Copyright 2006 Mike McCormack for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include + + +#ifdef _MSC_VER + +#pragma warning(disable:4002) +#define TRACE() +#define FIXME() + +#else + +#define TRACE(x,args...) debug_output(__func__,x,args) +#define FIXME(x,args...) TRACE("FIXME: "x,args) + +#endif + +//WINE_DEFAULT_DEBUG_CHANNEL( userenv ); + +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + TRACE("%p %d %p\n", hinstDLL, fdwReason, lpvReserved); + + switch (fdwReason) + { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(hinstDLL); + break; + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} + +BOOL WINAPI CreateEnvironmentBlock( LPVOID* lpEnvironment, + HANDLE hToken, BOOL bInherit ) +{ + FIXME("%p %p %d\n", lpEnvironment, hToken, bInherit ); + return FALSE; +} + +BOOL WINAPI DestroyEnvironmentBlock( LPVOID lpEnvironment ) +{ + FIXME("%p\n", lpEnvironment); + return FALSE; +} + +BOOL WINAPI ExpandEnvironmentStringsForUserA( HANDLE hToken, LPCSTR lpSrc, + LPSTR lpDest, DWORD dwSize ) +{ + BOOL ret; + + TRACE("%p %s %p %d\n", hToken, debugstr_a(lpSrc), lpDest, dwSize); + + ret = ExpandEnvironmentStringsA( lpSrc, lpDest, dwSize ); + TRACE("<- %s\n", debugstr_a(lpDest)); + return ret; +} + +BOOL WINAPI ExpandEnvironmentStringsForUserW( HANDLE hToken, LPCWSTR lpSrc, + LPWSTR lpDest, DWORD dwSize ) +{ + BOOL ret; + + TRACE("%p %s %p %d\n", hToken, debugstr_w(lpSrc), lpDest, dwSize); + + ret = ExpandEnvironmentStringsW( lpSrc, lpDest, dwSize ); + TRACE("<- %s\n", debugstr_w(lpDest)); + return ret; +} + +static int getsubdirpath(int nFolder, LPSTR lpBuffer, LPSTR lpSubDir) +{ + if ( FAILED(SHGetSpecialFolderPathA(NULL,lpBuffer,CSIDL_APPDATA,TRUE)) ) + return 0; + PathAppendA(lpBuffer,lpSubDir); + return lstrlenA(lpBuffer) + 1; +} + +static int GetSpecialSubdirPathA(int nFolder, LPSTR lpSubDir, LPSTR lpDir, LPDWORD lpcchSize ) +{ + char buffer[MAX_PATH]; + DWORD bufsize = getsubdirpath(nFolder,buffer,lpSubDir); + if (!lpDir || !lpcchSize || !bufsize) return 0; + if (*lpcchSizehProfile = HKEY_CURRENT_USER; + return TRUE; +} + +BOOL WINAPI LoadUserProfileW( HANDLE hToken, LPPROFILEINFOW lpProfileInfo ) +{ + FIXME("%p %p\n", hToken, lpProfileInfo ); + lpProfileInfo->hProfile = HKEY_CURRENT_USER; + return TRUE; +} + +BOOL WINAPI RegisterGPNotification( HANDLE event, BOOL machine ) +{ + FIXME("%p %d\n", event, machine ); + return TRUE; +} + +BOOL WINAPI UnregisterGPNotification( HANDLE event ) +{ + FIXME("%p\n", event ); + return TRUE; +} + +BOOL WINAPI UnloadUserProfile( HANDLE hToken, HANDLE hProfile ) +{ + FIXME("(%p, %p): stub\n", hToken, hProfile); + return FALSE; +} diff --git a/auxiliary/userenv/userenv.def b/auxiliary/userenv/userenv.def new file mode 100755 index 0000000..13c4d04 --- /dev/null +++ b/auxiliary/userenv/userenv.def @@ -0,0 +1,18 @@ +LIBRARY userenv.dll BASE=0x7D0A0000 +EXPORTS + CreateEnvironmentBlock + DestroyEnvironmentBlock + ExpandEnvironmentStringsForUserA + ExpandEnvironmentStringsForUserW + GetAllUsersProfileDirectoryA + GetAllUsersProfileDirectoryW + GetProfilesDirectoryA + GetProfilesDirectoryW + GetProfileType + GetUserProfileDirectoryA + GetUserProfileDirectoryW + LoadUserProfileA + LoadUserProfileW + RegisterGPNotification + UnloadUserProfile + UnregisterGPNotification diff --git a/auxiliary/uxtheme/kord.def b/auxiliary/uxtheme/kord.def old mode 100644 new mode 100755 diff --git a/auxiliary/uxtheme/makefile b/auxiliary/uxtheme/makefile old mode 100644 new mode 100755 diff --git a/auxiliary/uxtheme/makefile.msv b/auxiliary/uxtheme/makefile.msv old mode 100644 new mode 100755 index 1c17c6b..f912162 --- a/auxiliary/uxtheme/makefile.msv +++ b/auxiliary/uxtheme/makefile.msv @@ -1,10 +1,10 @@ # Makefile for Microsoft Visual C++ Compiler (MSVC) -OBJ = kord.lib uxtheme.obj +OBJ = kord.lib uxtheme.obj metric.obj RES = DEF = /DEF:uxtheme.def BIN = ..\uxtheme.dll -LIBS = -nodefaultlib kernel32.lib gdi32.lib +LIBS = -nodefaultlib kernel32.lib gdi32.lib user32.lib LDFLAGS = /DLL /OPT:NOWIN98 /ENTRY:DllMain@12 CFLAGS = /W3 /O2 /Oi /FD CXXFLAGS = $(CFLAGS) diff --git a/auxiliary/uxtheme/metric.c b/auxiliary/uxtheme/metric.c new file mode 100755 index 0000000..2b5257e --- /dev/null +++ b/auxiliary/uxtheme/metric.c @@ -0,0 +1,125 @@ +/* + * Win32 5.1 Theme metrics + * + * Copyright (C) 2003 Kevin Koltzau + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define UNICODE +#define _WIN32_WINNT 0x0501 +#include +#include +#include + +#ifndef TMT_FIRSTCOLOR +#define TMT_FIRSTCOLOR TMT_SCROLLBAR +#endif + +#pragma warning(disable:4273) + +/*********************************************************************** + * GetThemeSysBool (UXTHEME.@) + * MAKE_EXPORT GetThemeSysBool=GetThemeSysBool + */ +BOOL WINAPI GetThemeSysBool(HTHEME hTheme, int iBoolID) +{ + SetLastError(0); + if(iBoolID == TMT_FLATMENUS) { + return FALSE; + } + else { + SetLastError(STG_E_INVALIDPARAMETER); + } + return FALSE; +} + +/*********************************************************************** + * GetThemeSysColor (UXTHEME.@) + * MAKE_EXPORT GetThemeSysColor=GetThemeSysColor + */ +COLORREF WINAPI GetThemeSysColor(HTHEME hTheme, int iColorID) +{ + SetLastError(0); + return GetSysColor(iColorID - TMT_FIRSTCOLOR); +} + +/*********************************************************************** + * GetThemeSysColorBrush (UXTHEME.@) + * MAKE_EXPORT GetThemeSysColorBrush=GetThemeSysColorBrush + */ +HBRUSH WINAPI GetThemeSysColorBrush(HTHEME hTheme, int iColorID) +{ + return CreateSolidBrush(GetThemeSysColor(hTheme, iColorID)); +} + +/*********************************************************************** + * GetThemeSysFont (UXTHEME.@) + * MAKE_EXPORT GetThemeSysFont=GetThemeSysFont + */ +HRESULT WINAPI GetThemeSysFont(HTHEME hTheme, int iFontID, LOGFONTW *plf) +{ + HRESULT hr = S_OK; + + if(iFontID == TMT_ICONTITLEFONT) { + if(!SystemParametersInfoW(SPI_GETICONTITLELOGFONT, sizeof(LOGFONTW), &plf, 0)) + return HRESULT_FROM_WIN32(GetLastError()); + } + else { + NONCLIENTMETRICSW ncm; + LOGFONTW *font = NULL; + ncm.cbSize = sizeof(NONCLIENTMETRICSW); + if(!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICSW), &ncm, 0)) + return HRESULT_FROM_WIN32(GetLastError()); + switch(iFontID) { + case TMT_CAPTIONFONT: font = &ncm.lfCaptionFont; break; + case TMT_SMALLCAPTIONFONT: font = &ncm.lfSmCaptionFont; break; + case TMT_MENUFONT: font = &ncm.lfMenuFont; break; + case TMT_STATUSFONT: font = &ncm.lfStatusFont; break; + case TMT_MSGBOXFONT: font = &ncm.lfMessageFont; break; + } + if(font) *plf = *font; + else hr = STG_E_INVALIDPARAMETER; + } + return hr; +} + +/*********************************************************************** + * GetThemeSysInt (UXTHEME.@) + * MAKE_EXPORT GetThemeSysInt=GetThemeSysInt + */ +HRESULT WINAPI GetThemeSysInt(HTHEME hTheme, int iIntID, int *piValue) +{ + return E_HANDLE; +} + +/*********************************************************************** + * GetThemeSysSize (UXTHEME.@) + * MAKE_EXPORT GetThemeSysSize=GetThemeSysSize + */ +int WINAPI GetThemeSysSize(HTHEME hTheme, int iSizeID) +{ + return GetSystemMetrics(iSizeID); +} + +/*********************************************************************** + * GetThemeSysString (UXTHEME.@) + * MAKE_EXPORT GetThemeSysString=GetThemeSysString + */ +HRESULT WINAPI GetThemeSysString(HTHEME hTheme, int iStringID, + LPWSTR pszStringBuff, int cchMaxStringChars) +{ + return E_HANDLE; +} diff --git a/auxiliary/uxtheme/uxtheme.c b/auxiliary/uxtheme/uxtheme.c old mode 100644 new mode 100755 index fbb1ff8..b7ba024 --- a/auxiliary/uxtheme/uxtheme.c +++ b/auxiliary/uxtheme/uxtheme.c @@ -1,6 +1,6 @@ /* * KernelEx - * Copyright (C) 2008, Xeno86 + * Copyright (C) 2008-2009, Xeno86 * * This file is part of KernelEx source code. * @@ -21,86 +21,70 @@ #include -int WINAPI CommonUnimpStub(void); - -#ifdef __GNUC__ -#define UNIMPL_FUNC(name,params) \ - __asm__( ".text\n" \ - ".globl _" #name "@0\n" \ - "_" #name "_new@0:\n\t" \ - "xor %eax, %eax\n\t" \ - "movb $" #params ", %cl\n\t" \ - "jmp _CommonUnimpStub@0\n\t" \ - ) -#else -#define UNIMPL_FUNC(name,params) \ - int __declspec(naked) __stdcall name() \ +#define UNIMPL_FUNC(name,params,val) \ + unsigned long __declspec(naked) __stdcall name() \ { \ - __asm xor eax,eax \ - __asm mov cl, params \ - __asm jmp CommonUnimpStub \ + __asm mov eax, val \ + __asm ret 4*params \ } -#endif -BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +#define _E_NOTIMPL 0x80004001 + +BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, BOOL bLoadStatic) { if (fdwReason == DLL_PROCESS_ATTACH) - { - OSVERSIONINFO osv; - osv.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - GetVersionEx(&osv); - if (osv.dwMajorVersion < 5 || (osv.dwMajorVersion == 5 && osv.dwMinorVersion == 0)) - return FALSE; + { + if (!bLoadStatic) + { + OSVERSIONINFO osv; + osv.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&osv); + if (osv.dwMajorVersion < 5) + return FALSE; + } DisableThreadLibraryCalls(hinstDLL); - } + } return TRUE; } -UNIMPL_FUNC(CloseThemeData, 1); -UNIMPL_FUNC(DrawThemeBackground, 6); -UNIMPL_FUNC(DrawThemeBackgroundEx, 6); -UNIMPL_FUNC(DrawThemeEdge, 8); -UNIMPL_FUNC(DrawThemeIcon, 7); -UNIMPL_FUNC(DrawThemeParentBackground, 3); -UNIMPL_FUNC(DrawThemeText, 9); -UNIMPL_FUNC(EnableThemeDialogTexture, 2); -UNIMPL_FUNC(EnableTheming, 1); -UNIMPL_FUNC(GetCurrentThemeName, 6); -UNIMPL_FUNC(GetThemeAppProperties, 0); -UNIMPL_FUNC(GetThemeBackgroundContentRect, 6); -UNIMPL_FUNC(GetThemeBackgroundExtent, 6); -UNIMPL_FUNC(GetThemeBackgroundRegion, 6); -UNIMPL_FUNC(GetThemeBool, 5); -UNIMPL_FUNC(GetThemeColor, 5); -UNIMPL_FUNC(GetThemeDocumentationProperty, 4); -UNIMPL_FUNC(GetThemeEnumValue, 5); -UNIMPL_FUNC(GetThemeFilename, 6); -UNIMPL_FUNC(GetThemeFont, 6); -UNIMPL_FUNC(GetThemeInt, 5); -UNIMPL_FUNC(GetThemeIntList, 5); -UNIMPL_FUNC(GetThemeMargins, 7); -UNIMPL_FUNC(GetThemeMetric, 6); -UNIMPL_FUNC(GetThemePartSize, 7); -UNIMPL_FUNC(GetThemePosition, 5); -UNIMPL_FUNC(GetThemePropertyOrigin, 5); -UNIMPL_FUNC(GetThemeRect, 5); -UNIMPL_FUNC(GetThemeString, 6); -UNIMPL_FUNC(GetThemeSysBool, 2); -UNIMPL_FUNC(GetThemeSysColor, 2); -UNIMPL_FUNC(GetThemeSysColorBrush, 2); -UNIMPL_FUNC(GetThemeSysFont, 3); -UNIMPL_FUNC(GetThemeSysInt, 3); -UNIMPL_FUNC(GetThemeSysSize, 2); -UNIMPL_FUNC(GetThemeSysString, 4); -UNIMPL_FUNC(GetThemeTextExtent, 9); -UNIMPL_FUNC(GetThemeTextMetrics, 5); -UNIMPL_FUNC(GetWindowTheme, 1); -UNIMPL_FUNC(HitTestThemeBackground, 10); -UNIMPL_FUNC(IsAppThemed, 0); -UNIMPL_FUNC(IsThemeActive, 0); -UNIMPL_FUNC(IsThemeBackgroundPartiallyTransparent, 3); -UNIMPL_FUNC(IsThemeDialogTextureEnabled, 1); -UNIMPL_FUNC(IsThemePartDefined, 3); -UNIMPL_FUNC(OpenThemeData, 2); -UNIMPL_FUNC(SetThemeAppProperties, 1); -UNIMPL_FUNC(SetWindowTheme, 3); +UNIMPL_FUNC(CloseThemeData, 1, _E_NOTIMPL); +UNIMPL_FUNC(DrawThemeBackground, 6, _E_NOTIMPL); +UNIMPL_FUNC(DrawThemeBackgroundEx, 6, _E_NOTIMPL); +UNIMPL_FUNC(DrawThemeEdge, 8, _E_NOTIMPL); +UNIMPL_FUNC(DrawThemeIcon, 7, _E_NOTIMPL); +UNIMPL_FUNC(DrawThemeParentBackground, 3, _E_NOTIMPL); +UNIMPL_FUNC(DrawThemeText, 9, _E_NOTIMPL); +UNIMPL_FUNC(EnableThemeDialogTexture, 2, _E_NOTIMPL); +UNIMPL_FUNC(EnableTheming, 1, _E_NOTIMPL); +UNIMPL_FUNC(GetCurrentThemeName, 6, _E_NOTIMPL); +UNIMPL_FUNC(GetThemeAppProperties, 0, 0); +UNIMPL_FUNC(GetThemeBackgroundContentRect, 6, _E_NOTIMPL); +UNIMPL_FUNC(GetThemeBackgroundExtent, 6, _E_NOTIMPL); +UNIMPL_FUNC(GetThemeBackgroundRegion, 6, _E_NOTIMPL); +UNIMPL_FUNC(GetThemeBool, 5, _E_NOTIMPL); +UNIMPL_FUNC(GetThemeColor, 5, _E_NOTIMPL); +UNIMPL_FUNC(GetThemeDocumentationProperty, 4, _E_NOTIMPL); +UNIMPL_FUNC(GetThemeEnumValue, 5, _E_NOTIMPL); +UNIMPL_FUNC(GetThemeFilename, 6, _E_NOTIMPL); +UNIMPL_FUNC(GetThemeFont, 6, _E_NOTIMPL); +UNIMPL_FUNC(GetThemeInt, 5, _E_NOTIMPL); +UNIMPL_FUNC(GetThemeIntList, 5, _E_NOTIMPL); +UNIMPL_FUNC(GetThemeMargins, 7, _E_NOTIMPL); +UNIMPL_FUNC(GetThemeMetric, 6, _E_NOTIMPL); +UNIMPL_FUNC(GetThemePartSize, 7, _E_NOTIMPL); +UNIMPL_FUNC(GetThemePosition, 5, _E_NOTIMPL); +UNIMPL_FUNC(GetThemePropertyOrigin, 5, _E_NOTIMPL); +UNIMPL_FUNC(GetThemeRect, 5, _E_NOTIMPL); +UNIMPL_FUNC(GetThemeString, 6, _E_NOTIMPL); +UNIMPL_FUNC(GetThemeTextExtent, 9, _E_NOTIMPL); +UNIMPL_FUNC(GetThemeTextMetrics, 5, _E_NOTIMPL); +UNIMPL_FUNC(GetWindowTheme, 1, 0); +UNIMPL_FUNC(HitTestThemeBackground, 10, _E_NOTIMPL); +UNIMPL_FUNC(IsAppThemed, 0, FALSE); +UNIMPL_FUNC(IsThemeActive, 0, FALSE); +UNIMPL_FUNC(IsThemeBackgroundPartiallyTransparent, 3, FALSE); +UNIMPL_FUNC(IsThemeDialogTextureEnabled, 1, FALSE); +UNIMPL_FUNC(IsThemePartDefined, 3, FALSE); +UNIMPL_FUNC(OpenThemeData, 2, 0); +UNIMPL_FUNC(SetThemeAppProperties, 1, 0); +UNIMPL_FUNC(SetWindowTheme, 3, _E_NOTIMPL); diff --git a/auxiliary/uxtheme/uxtheme.def b/auxiliary/uxtheme/uxtheme.def old mode 100644 new mode 100755 diff --git a/auxiliary/wtsapi32/makefile b/auxiliary/wtsapi32/makefile old mode 100644 new mode 100755 diff --git a/auxiliary/wtsapi32/makefile.msv b/auxiliary/wtsapi32/makefile.msv old mode 100644 new mode 100755 diff --git a/auxiliary/wtsapi32/wtsapi32.c b/auxiliary/wtsapi32/wtsapi32.c old mode 100644 new mode 100755 diff --git a/auxiliary/wtsapi32/wtsapi32.def b/auxiliary/wtsapi32/wtsapi32.def old mode 100644 new mode 100755 diff --git a/auxiliary/wtsapi32/wtsapi32.h b/auxiliary/wtsapi32/wtsapi32.h old mode 100644 new mode 100755 diff --git a/common/is_sorted.hpp b/common/is_sorted.hpp old mode 100644 new mode 100755 diff --git a/common/k32ord.def b/common/k32ord.def old mode 100644 new mode 100755 index 3de691e..658ef18 --- a/common/k32ord.def +++ b/common/k32ord.def @@ -10,6 +10,7 @@ EXPORTS VxDCall6 @6 NONAME VxDCall7 @7 NONAME VxDCall8 @8 NONAME + _GetpWin16Lock @93 NONAME _EnterSysLevel @97 NONAME _LeaveSysLevel @98 NONAME MakeCriticalSectionGlobal diff --git a/common/k32ord.h b/common/k32ord.h old mode 100644 new mode 100755 index ad3a5f7..b617880 --- a/common/k32ord.h +++ b/common/k32ord.h @@ -43,6 +43,7 @@ extern "C" { #endif +MAKE_HEADER(void __stdcall _GetpWin16Lock(CRITICAL_SECTION** cs)) MAKE_HEADER(void __stdcall _EnterSysLevel(CRITICAL_SECTION* cs)) MAKE_HEADER(void __stdcall _LeaveSysLevel(CRITICAL_SECTION* cs)) diff --git a/common/kexcoresdk.h b/common/kexcoresdk.h old mode 100644 new mode 100755 index 6fa7624..656e44e --- a/common/kexcoresdk.h +++ b/common/kexcoresdk.h @@ -113,7 +113,20 @@ _KEXCOREIMP unsigned long kexGetKEXVersion(); _KEXCOREIMP int kexIsDebugCore(); -/** kexDebugPrint - output debug information +/** DBGPRINTF - convenience macro for including debug messages only in debugs. + * + * Sample usage: DBGPRINTF(("This is a test %d %s\n", 1, "ttt")); + */ +#ifndef KEXCORE_EXPORTS +#ifndef _DEBUG +#define DBGPRINTF(x) do { } while (0) +#else +#define DBGPRINTF(x) kexDebugPrint x +#endif +#endif + + +/** kexDebugPrint - output debug message * * Parameters are compatible with printf command, * maximum output length is limited to 256 bytes. @@ -149,30 +162,67 @@ _KEXCOREIMP HANDLE kexOpenThread(DWORD dwDesiredAccess, BOOL bInheritHandle, DWO _KEXCOREIMP BOOL kexAreExtensionsEnabled(); +/** KernelEx resolver flags. */ +#define KRF_KEX_DISABLE 1 /* disable KernelEx API extensions for this module */ +#define KRF_OVERRIDE_PROC_MOD 2 /* use same configuration and flags for all modules in a process */ +#define KRF_LOG_APIS 4 /* enable API tracing */ +#define KRF_NO_INHERIT 16 /* don't inherit configuration and flags to child processes */ +#define KRF_VALID_FLAG 128 /* denotes that flags field is valid */ + + /** kexGetModuleSettings - Retrieve per module settings. * * @param module Module path. - * @param conf_name Receives configuration name, has to be at least 256 bytes long. - * @param ldr_flags Receives flags. + * @param conf_name Receives configuration name, buffer has to be at least 256 bytes long. + * @param mod_flags Receives resolver flags. */ _KEXCOREIMP void kexGetModuleSettings(const char* module, - char* conf_name, BYTE* ldr_flags); + char* conf_name, DWORD* mod_flags); /** kexSetModuleSettings - Set per module settings. * * @param module Module path. * @param conf_name Configuration name to be set for the module. - * @param ldr_flags Flags to be set for the module. + * @param mod_flags Resolver flags to be set for the module. */ _KEXCOREIMP void kexSetModuleSettings(const char* module, - const char* conf_name, BYTE ldr_flags); + const char* conf_name, DWORD mod_flags); /** kexFlushAppSettings - Reloads all module settings from registy. */ _KEXCOREIMP void kexFlushAppSettings(void); +/** kexPsAllocIndex - Reserve process storage entry. + * + * @return Index to access process storage. + */ +_KEXCOREIMP int kexPsAllocIndex(void); + + +/** kexPsGetValue - Get process value associated with tag. + * + * @param index Index allocated with kexPsAllocIndex. + */ +_KEXCOREIMP void* kexPsGetValue(int index); + + +/** kexPsSetValue - Set process value associated with tag. + * + * @param index Index allocated with kexPsAllocIndex. + * @param value Any data, pass zero to free storage associated with tag. + */ +_KEXCOREIMP int kexPsSetValue(int index, void* value); + + +/** kexGetK32Lock - obtain pointer to Kernel32 lock object. + * + * @return Pointer to Kernel32 lock object. + */ +_KEXCOREIMP void* kexGetK32Lock(); + + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/common/linear_table.hpp b/common/linear_table.hpp new file mode 100755 index 0000000..aef37af --- /dev/null +++ b/common/linear_table.hpp @@ -0,0 +1,74 @@ +#ifndef __LINEAR_TABLE_HPP +#define __LINEAR_TABLE_HPP + +#include + +template +class linear_table +{ +public: + linear_table() + { + m_count = 0; + } + + void free(const _Key& _k) + { + for (int i = 0 ; i < m_count ; i++) + if (m_data[i].k == _k) + { + std::copy(m_data + i + 1, m_data + m_count, m_data + i); + --m_count; + break; + } + } + + _Value get(const _Key& _k) + { + for (int i = 0 ; i < m_count ; i++) + if (m_data[i].k == _k) + return m_data[i].v; + return 0; + } + + bool set(const _Key& _k, const _Value& _v) + { + for (int i = 0 ; i < m_count ; i++) + if (m_data[i].k == _k) + { + m_data[i].v = _v; + return true; + } + // alloc if there's no such key in table + if (!alloc(_k)) + return false; + m_data[get_count() - 1].v = _v; + return true; + } + + int get_count() + { + return m_count; + } + +protected: + bool alloc(const _Key& _k) + { + if (m_count == _N) + return false; + m_data[m_count].k = _k; + m_data[m_count].v = 0; + ++m_count; + return true; + } + +private: + int m_count; + struct + { + _Key k; + _Value v; + } m_data[_N]; +}; + +#endif diff --git a/common/msvc_quirks.h b/common/msvc_quirks.h new file mode 100755 index 0000000..bc91203 --- /dev/null +++ b/common/msvc_quirks.h @@ -0,0 +1,41 @@ +/* + * KernelEx + * Copyright (C) 2009, Xeno86 + * + * This file is part of KernelEx source code. + * + * KernelEx is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. + * + * KernelEx is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/** @file + * This file contains workarounds for compiler bugs. + * This file is included in every file MSVC compiles via forced includes /FI flag. + */ + +#ifndef __MSVC_QUIRKS_H +#define __MSVC_QUIRKS_H + +/* MSVC 6.0 quirks */ +#if defined(_MSC_VER) && _MSC_VER < 1201 + +/* MSVC 6.0 for-loop workaround. */ +#define for if (0); else for + +/* disable "identifier was truncated to '255' characters in the debug information" */ +#pragma warning(disable:4786) + +#endif /* MSVC 6.0 quirks */ + +#endif diff --git a/common/pemanip.cpp b/common/pemanip.cpp old mode 100644 new mode 100755 diff --git a/common/pemanip.h b/common/pemanip.h old mode 100644 new mode 100755 diff --git a/common/sstring.hpp b/common/sstring.hpp old mode 100644 new mode 100755 diff --git a/common/stdint.h b/common/stdint.h new file mode 100755 index 0000000..5bcce62 --- /dev/null +++ b/common/stdint.h @@ -0,0 +1,184 @@ +/* ISO C9x 7.18 Integer types + * Based on ISO/IEC SC22/WG14 9899 Committee draft (SC22 N2794) + * + * THIS SOFTWARE IS NOT COPYRIGHTED + * + * Contributor: Danny Smith + * + * This source code is offered for use in the public domain. You may + * use, modify or distribute it freely. + * + * This code is distributed in the hope that it will be useful but + * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY + * DISCLAIMED. This includes but is not limited to warranties of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Date: 2000-12-02 + */ + + +#ifndef _STDINT_H +#define _STDINT_H +#define __need_wint_t +#define __need_wchar_t +#include + +/* 7.18.1.1 Exact-width integer types */ +typedef signed char int8_t; +typedef unsigned char uint8_t; +typedef short int16_t; +typedef unsigned short uint16_t; +typedef int int32_t; +typedef unsigned uint32_t; +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; + +/* 7.18.1.2 Minimum-width integer types */ +typedef signed char int_least8_t; +typedef unsigned char uint_least8_t; +typedef short int_least16_t; +typedef unsigned short uint_least16_t; +typedef int int_least32_t; +typedef unsigned uint_least32_t; +typedef __int64 int_least64_t; +typedef unsigned __int64 uint_least64_t; + +/* 7.18.1.3 Fastest minimum-width integer types + * Not actually guaranteed to be fastest for all purposes + * Here we use the exact-width types for 8 and 16-bit ints. + */ +typedef char int_fast8_t; +typedef unsigned char uint_fast8_t; +typedef short int_fast16_t; +typedef unsigned short uint_fast16_t; +typedef int int_fast32_t; +typedef unsigned int uint_fast32_t; +typedef __int64 int_fast64_t; +typedef unsigned __int64 uint_fast64_t; + +/* 7.18.1.4 Integer types capable of holding object pointers */ +typedef int intptr_t; +typedef unsigned uintptr_t; + +/* 7.18.1.5 Greatest-width integer types */ +typedef __int64 intmax_t; +typedef unsigned __int64 uintmax_t; + +/* 7.18.2 Limits of specified-width integer types */ +#if !defined ( __cplusplus) || defined (__STDC_LIMIT_MACROS) + +/* 7.18.2.1 Limits of exact-width integer types */ +#define INT8_MIN (-128) +#define INT16_MIN (-32768) +#define INT32_MIN (-2147483647 - 1) +#define INT64_MIN (-9223372036854775807LL - 1) + +#define INT8_MAX 127 +#define INT16_MAX 32767 +#define INT32_MAX 2147483647 +#define INT64_MAX 9223372036854775807LL + +#define UINT8_MAX 0xff /* 255U */ +#define UINT16_MAX 0xffff /* 65535U */ +#define UINT32_MAX 0xffffffff /* 4294967295U */ +#define UINT64_MAX 0xffffffffffffffffULL /* 18446744073709551615ULL */ + +/* 7.18.2.2 Limits of minimum-width integer types */ +#define INT_LEAST8_MIN INT8_MIN +#define INT_LEAST16_MIN INT16_MIN +#define INT_LEAST32_MIN INT32_MIN +#define INT_LEAST64_MIN INT64_MIN + +#define INT_LEAST8_MAX INT8_MAX +#define INT_LEAST16_MAX INT16_MAX +#define INT_LEAST32_MAX INT32_MAX +#define INT_LEAST64_MAX INT64_MAX + +#define UINT_LEAST8_MAX UINT8_MAX +#define UINT_LEAST16_MAX UINT16_MAX +#define UINT_LEAST32_MAX UINT32_MAX +#define UINT_LEAST64_MAX UINT64_MAX + +/* 7.18.2.3 Limits of fastest minimum-width integer types */ +#define INT_FAST8_MIN INT8_MIN +#define INT_FAST16_MIN INT16_MIN +#define INT_FAST32_MIN INT32_MIN +#define INT_FAST64_MIN INT64_MIN + +#define INT_FAST8_MAX INT8_MAX +#define INT_FAST16_MAX INT16_MAX +#define INT_FAST32_MAX INT32_MAX +#define INT_FAST64_MAX INT64_MAX + +#define UINT_FAST8_MAX UINT8_MAX +#define UINT_FAST16_MAX UINT16_MAX +#define UINT_FAST32_MAX UINT32_MAX +#define UINT_FAST64_MAX UINT64_MAX + +/* 7.18.2.4 Limits of integer types capable of holding + object pointers */ +#define INTPTR_MIN INT32_MIN +#define INTPTR_MAX INT32_MAX +#define UINTPTR_MAX UINT32_MAX + +/* 7.18.2.5 Limits of greatest-width integer types */ +#define INTMAX_MIN INT64_MIN +#define INTMAX_MAX INT64_MAX +#define UINTMAX_MAX UINT64_MAX + +/* 7.18.3 Limits of other integer types */ +#define PTRDIFF_MIN INT32_MIN +#define PTRDIFF_MAX INT32_MAX + +#define SIG_ATOMIC_MIN INT32_MIN +#define SIG_ATOMIC_MAX INT32_MAX + +#define SIZE_MAX UINT32_MAX + +#ifndef WCHAR_MIN /* also in wchar.h */ +#define WCHAR_MIN 0 +#define WCHAR_MAX 0xffff /* UINT16_MAX */ +#endif + +/* + * wint_t is unsigned short for compatibility with MS runtime + */ +#define WINT_MIN 0 +#define WINT_MAX 0xffff /* UINT16_MAX */ + +#endif /* !defined ( __cplusplus) || defined __STDC_LIMIT_MACROS */ + + +/* 7.18.4 Macros for integer constants */ +#if !defined ( __cplusplus) || defined (__STDC_CONSTANT_MACROS) + +/* 7.18.4.1 Macros for minimum-width integer constants + + Accoding to Douglas Gwyn : + "This spec was changed in ISO/IEC 9899:1999 TC1; in ISO/IEC + 9899:1999 as initially published, the expansion was required + to be an integer constant of precisely matching type, which + is impossible to accomplish for the shorter types on most + platforms, because C99 provides no standard way to designate + an integer constant with width less than that of type int. + TC1 changed this to require just an integer constant + *expression* with *promoted* type." +*/ + +#define INT8_C(val) ((int8_t) + (val)) +#define UINT8_C(val) ((uint8_t) + (val##U)) +#define INT16_C(val) ((int16_t) + (val)) +#define UINT16_C(val) ((uint16_t) + (val##U)) + +#define INT32_C(val) val##L +#define UINT32_C(val) val##UL +#define INT64_C(val) val##LL +#define UINT64_C(val) val##ULL + +/* 7.18.4.2 Macros for greatest-width integer constants */ +#define INTMAX_C(val) INT64_C(val) +#define UINTMAX_C(val) UINT64_C(val) + +#endif /* !defined ( __cplusplus) || defined __STDC_CONSTANT_MACROS */ + +#endif diff --git a/common/version.h b/common/version.h old mode 100644 new mode 100755 index bf26015..668f705 --- a/common/version.h +++ b/common/version.h @@ -1,6 +1,6 @@ /* * KernelEx - * Copyright (C) 2009, Xeno86 + * Copyright (C) 2009-2010, Xeno86 * * This file is part of KernelEx source code. * @@ -22,9 +22,9 @@ #ifndef __VERSION_H #define __VERSION_H -#define VERSION_STR "4.0 Final 2" -#define VERSION_CODE 0x04000066 -#define RCVERSION 4, 0, 10, 2 -#define _RCVERSION_ "4, 0, 10, 2" +#define VERSION_STR "4.5 Beta 1" +#define VERSION_CODE 0x04050001 +#define RCVERSION 4, 5, 0, 1 +#define _RCVERSION_ "4, 5, 0, 1" #endif diff --git a/common/winheap_allocator.hpp b/common/winheap_allocator.hpp new file mode 100755 index 0000000..e539caa --- /dev/null +++ b/common/winheap_allocator.hpp @@ -0,0 +1,113 @@ +#include +#include "debug.h" + +template +class winheap_allocator +{ +public: + typedef T value_type; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + + template + struct rebind { typedef winheap_allocator other; }; + + winheap_allocator(HANDLE heap) + { + this->heap = heap; + } + +// winheap_allocator(const winheap_allocator& a) +// { +// heap = a.heap; +// } + + template + winheap_allocator(const winheap_allocator& a) + { + heap = a.heap; + } + + ~winheap_allocator() + { + } + + pointer address(reference x) const + { + return &x; + } + + const_pointer address(const_reference x) const + { + return x; + } + + pointer allocate(size_type n, const_pointer = 0) + { + void* p = HeapAlloc(heap, 0, n * sizeof(T)); +// if (!p) +// throw std::bad_alloc(); + return static_cast(p); + } + + char* _Charalloc(size_type n) + { + return rebind::other(*this).allocate(n, (char*) 0); + } + + void deallocate(void* p, size_type) + { + BOOL ret = HeapFree(heap, 0, p); + DBGASSERT(ret == TRUE); + } + + size_type max_size() const + { + return static_cast(-1) / sizeof(T); + } + + void construct(pointer p, const value_type& x) + { + new (p) value_type(x); + } + + void destroy(pointer p) + { + p->~value_type(); + } + + HANDLE heap; + +private: + void operator=(const winheap_allocator&); +}; + +template<> +class winheap_allocator +{ + typedef void value_type; + typedef void* pointer; + typedef const void* const_pointer; + + template + struct rebind { typedef winheap_allocator other; }; +}; + + +template +inline bool operator==(const winheap_allocator& a, + const winheap_allocator& b) +{ + return a.heap == b.heap; +} + +template +inline bool operator!=(const winheap_allocator& a, + const winheap_allocator& b) +{ + return a.heap != b.heap; +} diff --git a/core/Core.rc b/core/Core.rc old mode 100644 new mode 100755 index 2ed65fa..f8b686d --- a/core/Core.rc +++ b/core/Core.rc @@ -98,7 +98,7 @@ BEGIN VALUE "FileDescription", "KernelEx Core\0" VALUE "FileVersion", _RCVERSION_ "\0" VALUE "InternalName", "KernelEx\0" - VALUE "LegalCopyright", "Copyright © 2009, Xeno86\0" + VALUE "LegalCopyright", "Copyright © 2009-2010, Xeno86\0" VALUE "OriginalFilename", "KernelEx.dll\0" VALUE "ProductName", "KernelEx\0" VALUE "ProductVersion", VERSION_STR "\0" @@ -151,6 +151,8 @@ IDR_LOGMENU MENU DISCARDABLE BEGIN POPUP "" BEGIN + MENUITEM "Enabled", IDM_ENABLE, CHECKED + MENUITEM SEPARATOR MENUITEM "Save to file", IDM_TOFILE MENUITEM "Clear", IDM_CLEAR MENUITEM "Filter", IDM_FILTER diff --git a/core/DebugWindow.cpp b/core/DebugWindow.cpp old mode 100644 new mode 100755 index 301d8ef..fc9ae52 --- a/core/DebugWindow.cpp +++ b/core/DebugWindow.cpp @@ -27,6 +27,8 @@ #include "internals.h" #include "debug.h" +extern bool apilog_enabled; + const unsigned short WM_KEXSTOPDEBUG = 0x6eee; const unsigned short WM_KEXAPPENDLOG = 0x6eef; @@ -39,6 +41,8 @@ char* strtok_r(char* s, const char* delim, char** holder); DebugWindow::DebugWindow() { DWORD tid; + DBGPRINTF(("Creating DebugWindow\n")); + hwnd = (HWND) -1; //we're interested in everything @@ -50,12 +54,14 @@ DebugWindow::DebugWindow() excludes.push_back("Interlocked"); InitializeCriticalSection(&cs); - InitCommonControls(); + MakeCriticalSectionGlobal(&cs); + LoadLibrary("COMCTL32.DLL"); hThread = CreateThread(NULL, 0, thread, (void*) this, 0, &tid); } DebugWindow::~DebugWindow() { + DBGPRINTF(("Destroying DebugWindow\n")); DeleteCriticalSection(&cs); SendMessage(hwnd, WM_KEXSTOPDEBUG, 0, 0); } @@ -118,30 +124,25 @@ void DebugWindow::InitDialog(HWND hwnd) LV_COLUMN col; memset(&col, 0, sizeof(col)); - col.mask = LVCF_TEXT | LVCF_SUBITEM | LVCF_WIDTH; + col.mask = LVCF_TEXT | LVCF_SUBITEM | LVCF_WIDTH | LVCF_FMT; col.cx = 20; col.pszText = "Depth"; + col.fmt = LVCFMT_RIGHT; ListView_InsertColumn(hList, 0, &col); col.cx = 60; + col.fmt = LVCFMT_LEFT; col.pszText = "Thread"; ListView_InsertColumn(hList, 1, &col); - col.cx = 90; - col.pszText = "Source"; + col.cx = 310; + col.pszText = "Info"; ListView_InsertColumn(hList, 2, &col); - col.cx = 90; - col.pszText = "Dest"; - ListView_InsertColumn(hList, 3, &col); - col.cx = 130; - col.pszText = "Function"; - ListView_InsertColumn(hList, 4, &col); col.cx = 60; - col.mask |= LVCF_FMT; col.fmt = LVCFMT_RIGHT; col.pszText = "Return"; - ListView_InsertColumn(hList, 5, &col); + ListView_InsertColumn(hList, 3, &col); -#define NUM_COLS 6 +#define NUM_COLS 4 menu = LoadMenu(hInstance, MAKEINTRESOURCE(IDR_LOGMENU)); menu = GetSubMenu(menu, 0); @@ -156,6 +157,10 @@ void DebugWindow::HandleMenu() p.x, p.y, 0, hwnd, NULL); switch (res) { + case IDM_ENABLE: + apilog_enabled = !apilog_enabled; + CheckMenuItem(menu, IDM_ENABLE, apilog_enabled ? MF_CHECKED : MF_UNCHECKED); + break; case IDM_TOFILE: WriteToFile(); break; @@ -316,13 +321,15 @@ void DebugWindow::WriteToFile() HMODULE hComDlg32; BOOL (WINAPI* pGetSaveFileName)(OPENFILENAME*); - hComDlg32 = LoadLibrary("COMDLG32.DLL"); + hComDlg32 = GetModuleHandle("COMDLG32.DLL"); + if (!hComDlg32) + hComDlg32 = LoadLibrary("COMDLG32.DLL"); if (!hComDlg32) return; pGetSaveFileName = (BOOL (WINAPI*)(OPENFILENAME*)) GetProcAddress(hComDlg32, "GetSaveFileNameA"); if (!pGetSaveFileName) - goto __fini; + return; filename[0] = '\0'; memset(&ofn, 0, sizeof(ofn)); @@ -335,11 +342,11 @@ void DebugWindow::WriteToFile() ofn.nMaxFile = sizeof(filename); ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT; if (!pGetSaveFileName(&ofn)) - goto __fini; + return; hFile = CreateFile(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) - goto __fini; + return; //write column headers col.mask = LVCF_TEXT; @@ -351,7 +358,7 @@ void DebugWindow::WriteToFile() DWORD len; ListView_GetColumn(hList, j, &col); len = strlen(buf); - if (j) WriteFile(hFile, "|", 1, &wlen, NULL); + if (j) WriteFile(hFile, " ", 1, &wlen, NULL); WriteFile(hFile, buf, len, &wlen, NULL); } WriteFile(hFile, "\r\n", 2, &wlen, NULL); @@ -365,7 +372,8 @@ void DebugWindow::WriteToFile() DWORD len; DWORD wlen; ListView_GetItemText(hList, i, j, buf, sizeof(buf)); len = strlen(buf); - if (j) WriteFile(hFile, "|", 1, &wlen, NULL); + if (j == 1 || j == 2) WriteFile(hFile, " ", 1, &wlen, NULL); + else if (j == 3 && len) WriteFile(hFile, " = ", 3, &wlen, NULL); WriteFile(hFile, buf, len, &wlen, NULL); } WriteFile(hFile, "\r\n", 2, &wlen, NULL); @@ -374,9 +382,6 @@ void DebugWindow::WriteToFile() CloseHandle(hFile); MessageBox(hwnd, "File written successfully", "Information", MB_ICONINFORMATION | MB_OK); - -__fini: - FreeLibrary(hComDlg32); } DWORD WINAPI DebugWindow::thread(void* param) @@ -468,4 +473,5 @@ void DebugWindow::destroy() { if (instance) delete instance; + instance = NULL; } diff --git a/core/DebugWindow.h b/core/DebugWindow.h old mode 100644 new mode 100755 index c21000b..1d5f4dc --- a/core/DebugWindow.h +++ b/core/DebugWindow.h @@ -29,23 +29,23 @@ using namespace std; -class DebugWindow +class DebugWindow { public: - DebugWindow(); - ~DebugWindow(); - static bool create(); static void destroy(); static DebugWindow* get(); void append(const char* str); private: + DebugWindow(); + ~DebugWindow(); + + static DebugWindow* instance; + HWND hwnd; HWND hList; HANDLE hThread; - int max_entries; - static DebugWindow* instance; CRITICAL_SECTION cs; HMENU menu; list includes; diff --git a/core/ModInit.cpp b/core/ModInit.cpp new file mode 100755 index 0000000..2324e0d --- /dev/null +++ b/core/ModInit.cpp @@ -0,0 +1,103 @@ +/* + * KernelEx + * Copyright (C) 2009, Xeno86 + * + * This file is part of KernelEx source code. + * + * KernelEx is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. + * + * KernelEx is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include "ModInit.h" +#include "ProcessStorage.h" +#include "internals.h" +#include "resolver.h" +#include "debug.h" + +static int modinit_index; + +bool ModuleInitializer_init() +{ + modinit_index = ProcessStorage::allocate(); + return modinit_index != -1; +} + +ModuleInitializer::ModuleInitializer() +{ + size = 0; + init = 0; + memset(data, 0, sizeof(data)); +} + +void ModuleInitializer::add_module(MODREF* mr) +{ + data[size++] = mr; + DBGASSERT(size < countof(data)); +} + +DWORD ModuleInitializer::get_handle_for_index(WORD idx) +{ + IMTE** pmteModTable = *ppmteModTable; + + for (int i = 0 ; i < size ; i++) + { + IMTE_KEX* imte = (IMTE_KEX*) pmteModTable[data[i]->mteIndex]; + if (imte->mod_index == idx) + return imte->pNTHdr->OptionalHeader.ImageBase; + } + + return 0; +} + +bool ModuleInitializer::initialize_modules() +{ + while (init < size) + { + DBGPRINTF(("Post-Initializing %s [PID=%08x]\n", + (*ppmteModTable)[data[init]->mteIndex]->pszModName, + GetCurrentProcessId())); + + init++; + + if (FLoadTreeNotify(data[init-1], TRUE)) + return false; + } + return true; +} + +ModuleInitializer* ModuleInitializer::get_instance(bool alloc) +{ + ProcessStorage* store = ProcessStorage::get_instance(); + ModuleInitializer* mi = (ModuleInitializer*) store->get(modinit_index); + + if (!mi && alloc) + { + mi = (ModuleInitializer*) HeapAlloc(_GetProcessHeap(), 0, sizeof(ModuleInitializer)); + DBGASSERT(mi != NULL); + new (mi) ModuleInitializer; + store->set(modinit_index, mi); + } + + return mi; +} + +void ModuleInitializer::destroy() +{ + ProcessStorage* store = ProcessStorage::get_instance(); + HeapFree(_GetProcessHeap(), 0, this); + store->set(modinit_index, NULL); +} diff --git a/core/ModInit.h b/core/ModInit.h new file mode 100755 index 0000000..dd98bdf --- /dev/null +++ b/core/ModInit.h @@ -0,0 +1,54 @@ +/* + * KernelEx + * Copyright (C) 2009, Xeno86 + * + * This file is part of KernelEx source code. + * + * KernelEx is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. + * + * KernelEx is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __MODINIT_H +#define __MODINIT_H + +#include "structs.h" + +bool ModuleInitializer_init(); + +class ModuleInitializer +{ +public: + void add_module(MODREF* mr); + DWORD get_handle_for_index(WORD idx); + bool has_initialize(); + bool initialize_modules(); + void destroy(); + + static ModuleInitializer* get_instance(bool alloc); + +private: + int size; + int init; + MODREF* data[64]; + + ModuleInitializer(); + ~ModuleInitializer(); +}; + +inline bool ModuleInitializer::has_initialize() +{ + return init < size; +} + +#endif diff --git a/core/ProcessStorage.cpp b/core/ProcessStorage.cpp new file mode 100755 index 0000000..26afa44 --- /dev/null +++ b/core/ProcessStorage.cpp @@ -0,0 +1,95 @@ +/* + * KernelEx + * Copyright (C) 2009, Xeno86 + * + * This file is part of KernelEx source code. + * + * KernelEx is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. + * + * KernelEx is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include "ProcessStorage.h" +#include "internals.h" +#include "debug.h" + +long ProcessStorage::count; + +struct PDB_KEX : PDB98 +{ + void* kex_storage; +}; + +ProcessStorage::ProcessStorage() +{ + for (int i = 0 ; i < PS_MAX_INDEX ; i++) + data[i] = NULL; +} + +ProcessStorage* ProcessStorage::get_instance() +{ + PDB_KEX* pdb = (PDB_KEX*) *pppdbCur; + if (!pdb->kex_storage) + return create_instance(); + return (ProcessStorage*) pdb->kex_storage; +} + +void* ProcessStorage::get(int index) +{ + if (index >= 0 && index < PS_MAX_INDEX) + return data[index]; + else + return NULL; +} + +bool ProcessStorage::set(int index, void* value) +{ + if (index >= 0 && index < PS_MAX_INDEX) + data[index] = value; + else + return false; + return true; +} + +int ProcessStorage::allocate() +{ + if (count >= PS_MAX_INDEX - 1) + return -1; + return InterlockedIncrement(&count); +} + + +ProcessStorage* ProcessStorage::create_instance() +{ + ProcessStorage* ret; + PDB_KEX* pdb = (PDB_KEX*) *pppdbCur; + + _EnterSysLevel(krnl32lock); + //double check - we might have been waiting on krnl32lock for create_instance + if (pdb->kex_storage) + { + _LeaveSysLevel(krnl32lock); + return (ProcessStorage*) pdb->kex_storage; + } + + pdb->kex_storage = HeapAlloc(_GetProcessHeap(), 0, sizeof(ProcessStorage)); + + ret = new (pdb->kex_storage) ProcessStorage(); + _LeaveSysLevel(krnl32lock); + + DBGASSERT(pdb->kex_storage != NULL && ret != NULL); + + return ret; +} diff --git a/core/ProcessStorage.h b/core/ProcessStorage.h new file mode 100755 index 0000000..8df3f92 --- /dev/null +++ b/core/ProcessStorage.h @@ -0,0 +1,44 @@ +/* + * KernelEx + * Copyright (C) 2009, Xeno86 + * + * This file is part of KernelEx source code. + * + * KernelEx is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. + * + * KernelEx is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __PROCESSSTORAGE_H +#define __PROCESSSTORAGE_H + +#define PS_MAX_INDEX 64 + +class ProcessStorage +{ +public: + static ProcessStorage* get_instance(); + void* get(int index); + bool set(int index, void* value); + static int allocate(); + +private: + static long count; + void* data[PS_MAX_INDEX]; + + static ProcessStorage* create_instance(); + ProcessStorage(); + ~ProcessStorage(); +}; + +#endif diff --git a/core/SettingsDB.cpp b/core/SettingsDB.cpp old mode 100644 new mode 100755 index 1194b7f..c7a277f --- a/core/SettingsDB.cpp +++ b/core/SettingsDB.cpp @@ -66,6 +66,7 @@ void SettingsDB::parse_configs() HKEY key; DWORD index = 0; char path[MAX_PATH]; + char epath[MAX_PATH]; DWORD path_len; char name[256]; DWORD name_len; @@ -98,13 +99,17 @@ void SettingsDB::parse_configs() if (!as.conf) continue; - strupr(path); - if (strchr(path, '*') || strchr(path, '?')) + int ret = ExpandEnvironmentStrings(path, epath, MAX_PATH); + if (ret > MAX_PATH || ret == 0) + continue; + + strupr(epath); + if (strchr(epath, '*') || strchr(epath, '?')) pdb = &db_wild; else pdb = &db; - pdb->insert(pair(path, as)); + pdb->insert(pair(epath, as)); } RegCloseKey(key); } diff --git a/core/SettingsDB.h b/core/SettingsDB.h old mode 100644 new mode 100755 index be8bc3f..a748ed1 --- a/core/SettingsDB.h +++ b/core/SettingsDB.h @@ -22,23 +22,13 @@ #ifndef __SETTINGSDB_H #define __SETTINGSDB_H -#ifdef _MSC_VER -#pragma warning(disable:4786) -#endif - #include "sstring.hpp" #include +#include "resolver.h" #include "apiconf.h" using namespace std; -struct appsetting -{ - appsetting() : conf(NULL), flags(0) {} - ApiConfiguration* conf; - unsigned long flags; -}; - class SettingsDB { public: diff --git a/core/apiconf.cpp b/core/apiconf.cpp old mode 100644 new mode 100755 diff --git a/core/apiconf.h b/core/apiconf.h old mode 100644 new mode 100755 diff --git a/core/apiconfmgr.cpp b/core/apiconfmgr.cpp old mode 100644 new mode 100755 diff --git a/core/apiconfmgr.h b/core/apiconfmgr.h old mode 100644 new mode 100755 diff --git a/core/apilib.cpp b/core/apilib.cpp old mode 100644 new mode 100755 index 7c724a5..9067415 --- a/core/apilib.cpp +++ b/core/apilib.cpp @@ -186,8 +186,7 @@ bool ApiLibraryManager::load_apilib(const char* apilib_name) // DBGPRINTF((" * %s\n", p->target_library)); if (!add_overridden_module(p->target_library)) { - DBGPRINTF(("Failed to add overridden module %s\n", p->target_library)); - goto __error; + DBGPRINTF(("Failed to add overridden module %s. Skipping\n", p->target_library)); } } @@ -375,6 +374,13 @@ bool ApiLibraryManager::add_overridden_module(const char* mod) return true; } + apilib_api_table table; + if (!parse_system_dll(mod, &table)) + { + DBGPRINTF(("Failed to parse system DLL: %s\n", mod)); + return false; + } + //allocate space for new overridden modules if (overridden_module_count % ALLOC_CAPACITY == 0) { @@ -396,11 +402,7 @@ bool ApiLibraryManager::add_overridden_module(const char* mod) std_api_table = (apilib_api_table*) new_block; } - if (!parse_system_dll(mod, &std_api_table[overridden_module_count])) - { - DBGPRINTF(("Failed to parse system DLL: %s\n", mod)); - return false; - } + std_api_table[overridden_module_count] = table; //add to table of overridden modules overridden_module_names[overridden_module_count] @@ -529,7 +531,10 @@ bool ApiLibraryManager::parse_system_dll(const char* dll_name, apilib_api_table* char* new_mod = (char*) malloc(strlen(dll_name) + 1); if (!new_mod) + { + free(mem); return false; + } strcpy(new_mod, dll_name); strupr(new_mod); diff --git a/core/apilib.h b/core/apilib.h old mode 100644 new mode 100755 diff --git a/core/apilog.cpp b/core/apilog.cpp old mode 100644 new mode 100755 index a95ed99..0d56965 --- a/core/apilog.cpp +++ b/core/apilog.cpp @@ -21,48 +21,16 @@ #include #include -#include #include "apilog.h" #include "debug.h" #include "internals.h" #include "DebugWindow.h" +#include "ProcessStorage.h" #define APILOG_TLS_INDEX 78 -void* get_process_env_data(const char* env, void* (*creator)()) -{ - //environment variable: ENV=ProcessID:DATA - char buf[20]; - DWORD ret; - DWORD ProcID; - void* data = NULL; - - ret = GetEnvironmentVariable(env, buf, sizeof(buf)); - if (ret == 0 || ret > sizeof(buf) - || sscanf(buf, "%x:%x", &ProcID, &data) != 2 - || ProcID != GetCurrentProcessId()) - { - //invalid/missing value - create new data - data = creator(); - if (data) - { - sprintf(buf, "%x:%x", GetCurrentProcessId(), data); - SetEnvironmentVariable(env, buf); - } - } - - return data; -} - -void* heap_creator() -{ - return HeapCreate(0, 0, 0); -} - -HANDLE get_process_debug_heap() -{ - return get_process_env_data("KEXDBGH", heap_creator); -} +static int apilog_ps_index = -1; +bool apilog_enabled = true; void* tls_creator() { @@ -73,43 +41,20 @@ void* tls_creator() return (void*) APILOG_TLS_INDEX; } -DWORD get_process_debug_tls() +void get_process_debug_tls() { - return (DWORD) get_process_env_data("KEXDBGT", tls_creator); + ProcessStorage* ps = ProcessStorage::get_instance(); + if (apilog_ps_index == -1) + apilog_ps_index = ps->allocate(); + if (APILOG_TLS_INDEX != (DWORD) ps->get(apilog_ps_index)) + { + ps->set(apilog_ps_index, tls_creator()); + } } extern "C" int snprintf(char *buffer, size_t n, const char* format, ...); -DWORD __stdcall log_api(const char* source, const char* target, const char* api_name, DWORD depth, DWORD ret) -{ - DebugWindow* dw = DebugWindow::get(); - if (!dw) - return 0; - - char msg[DEBUGMSG_MAXLEN]; - - //fancy call stack depth indicator - if (depth < DEBUGMSG_MAXLEN / 2) - { - for (int i = 0 ; i < depth ; i++) - msg[i] = 'l'; - } - else - { - msg[0] = 'E'; - msg[1] = 'E'; - depth = 2; - } - - snprintf(msg + depth, sizeof(msg) - depth, "|%x|%s|%s|%s|%x", - GetCurrentThreadId(), source, target, api_name, ret); - - dw->append(msg); - - return ret; -} - ThreadAddrStack::ThreadAddrStack() { pos = 0; @@ -117,49 +62,121 @@ ThreadAddrStack::ThreadAddrStack() void __stdcall ThreadAddrStack::push_ret_addr(DWORD addr) { - //TlsGetValue clears last error value so remember & restore it - DWORD lasterr = GetLastError(); ThreadAddrStack* tas = (ThreadAddrStack*) TlsGetValue(APILOG_TLS_INDEX); - SetLastError(lasterr); if (!tas) { - void* mem = HeapAlloc(get_process_debug_heap(), 0, sizeof(ThreadAddrStack)); + void* mem = HeapAlloc(_GetProcessHeap(), 0, sizeof(ThreadAddrStack)); tas = new (mem) ThreadAddrStack; TlsSetValue(APILOG_TLS_INDEX, mem); } tas->stack[tas->pos++] = addr; - DBGASSERT(tas->pos < sizeof(tas->stack) / sizeof(tas->stack[0])); + DBGASSERT(tas->pos < countof(tas->stack)); } DWORD __stdcall ThreadAddrStack::pop_ret_addr() { - //TlsGetValue clears last error value so remember & restore it - DWORD lasterr = GetLastError(); ThreadAddrStack* tas = (ThreadAddrStack*) TlsGetValue(APILOG_TLS_INDEX); - SetLastError(lasterr); DBGASSERT(tas->pos > 0); return tas->stack[--tas->pos]; } DWORD __stdcall ThreadAddrStack::get_level() { - //TlsGetValue clears last error value so remember & restore it - DWORD lasterr = GetLastError(); ThreadAddrStack* tas = (ThreadAddrStack*) TlsGetValue(APILOG_TLS_INDEX); - SetLastError(lasterr); return tas->pos; } + +log_stub::log_stub(const char* source, const char* target, const char* name, + unsigned long proc) + : call_prelog(DWORD(pre_log)), call_postlog(DWORD(post_log)), + call_orig(proc) +{ + c_pushad1 = c_pushad2 = 0x60; + c_popad1 = c_popad2 = 0x61; + c_ret = 0xc3; + c_push1 = c_push2 = 0x68; + v_lgd1 = &lgd; + v_lgd2 = &lgd; + c_push_eax = 0x50; + c_add_esp = 0xc483; + c_sub_esp = 0xec83; + c_byte_4 = c_byte_4_1 = 4; + lgd.source = source; + lgd.target = target; + lgd.api_name = name; +} + +void __stdcall log_stub::pre_log(log_data* lgd) +{ + DWORD last_err; + DWORD caller_addr; + + caller_addr = *((DWORD*) &lgd + 9); + last_err = GetLastError(); + + ThreadAddrStack::push_ret_addr(caller_addr); + + DebugWindow* dw = DebugWindow::get(); + if (dw && apilog_enabled) + { + DWORD level; + char msg[DEBUGMSG_MAXLEN]; + + level = ThreadAddrStack::get_level(); + + snprintf(msg, sizeof(msg), "%-2d|%x|%*s[%s]%08x:<%s>%s", + level, + GetCurrentThreadId(), + (level-1) * 2, "", + lgd->source, caller_addr, + lgd->target, lgd->api_name); + + dw->append(msg); + } + + SetLastError(last_err); +} + +void __stdcall log_stub::post_log(log_data* lgd, DWORD retval) +{ + DWORD last_err; + DWORD& caller_addr = *((DWORD*) &retval + 9); + + last_err = GetLastError(); + + caller_addr = ThreadAddrStack::pop_ret_addr(); + + DebugWindow* dw = DebugWindow::get(); + if (dw && apilog_enabled) + { + DWORD level; + char msg[DEBUGMSG_MAXLEN]; + + level = ThreadAddrStack::get_level(); + + snprintf(msg, sizeof(msg), "%-2d|%x|%*s[%s]%08x:<%s>%s|%x", + level, + GetCurrentThreadId(), + (level-1) * 2, "", + lgd->source, caller_addr, + lgd->target, lgd->api_name, + retval); + + dw->append(msg); + } + + SetLastError(last_err); +} + PROC create_log_stub(const char* caller, const char* target, const char* api, PROC orig) { - HANDLE heap = get_process_debug_heap(); - char* new_api = (char*) HeapAlloc(heap, 0, strlen(api) + 1); + char* new_api = (char*) HeapAlloc(_GetProcessHeap(), 0, strlen(api) + 1); strcpy(new_api, api); get_process_debug_tls(); - void* mem = HeapAlloc(heap, 0, sizeof(log_stub)); + void* mem = HeapAlloc(_GetProcessHeap(), 0, sizeof(log_stub)); return (PROC) new (mem) log_stub(caller, - target, new_api, (unsigned long) orig, - (unsigned long) log_api); + target, new_api, (unsigned long) orig); } PROC create_log_stub(const char* caller, const char* target, WORD ord, PROC orig) diff --git a/core/apilog.h b/core/apilog.h old mode 100644 new mode 100755 index 24a746b..2db2a8c --- a/core/apilog.h +++ b/core/apilog.h @@ -45,41 +45,58 @@ class log_stub { public: log_stub(const char* source, const char* target, const char* name, - unsigned long proc, unsigned long log_fun) - : call_orig(proc, true), jmp_logfun(log_fun), - tas_store((unsigned long) ThreadAddrStack::push_ret_addr, true), - tas_restore((unsigned long) ThreadAddrStack::pop_ret_addr, true), - tas_depth((unsigned long) ThreadAddrStack::get_level, true) - { - c_push2 = c_push3 = c_push4 = 0x68; - v_source = source; - v_target = target; - v_name = name; - c_pusheax1 = c_pusheax2 = c_pusheax3 = c_pusheax4 = 0x50; - c_popeax4 = 0x58; - c_pushecx = 0x51; - c_popecx = 0x59; - } + unsigned long proc); private: - unsigned char c_popeax4; //caller ret - unsigned char c_pushecx; - unsigned char c_pusheax4; //caller ret - redir_stub tas_store; - unsigned char c_popecx; + struct log_data + { + const char* source; + const char* target; + const char* api_name; + }; + + static void __stdcall pre_log(log_data* lgd); + static void __stdcall post_log(log_data* lgd, DWORD retval); + +/* + pushad + push lgd + call pre_log@4 + popad + + add esp, 4 + call orig + sub esp, 4 + + pushad + push eax + push lgd + call post_log@8 + popad + ret +*/ + + BYTE c_pushad1; + BYTE c_push1; + log_data* v_lgd1; + redir_stub call_prelog; + BYTE c_popad1; + + WORD c_add_esp; + BYTE c_byte_4; redir_stub call_orig; - unsigned char c_pusheax1; //orig ret - redir_stub tas_depth; - unsigned char c_pusheax3; //call stack depth - unsigned char c_push2; //api name - const char* v_name; - unsigned char c_push3; //target module - const char* v_target; - unsigned char c_push4; //calling module - const char* v_source; - redir_stub tas_restore; - unsigned char c_pusheax2; //caller return address - redir_stub jmp_logfun; //jump to log_fun + WORD c_sub_esp; + BYTE c_byte_4_1; + + BYTE c_pushad2; + BYTE c_push_eax; + BYTE c_push2; + log_data* v_lgd2; + redir_stub call_postlog; + BYTE c_popad2; + BYTE c_ret; + + log_data lgd; }; #pragma pack(pop) diff --git a/core/core.def b/core/core.def old mode 100644 new mode 100755 diff --git a/core/core.dsp b/core/core.dsp old mode 100644 new mode 100755 index 107b2d7..e9ccf33 --- a/core/core.dsp +++ b/core/core.dsp @@ -43,7 +43,7 @@ RSC=rc.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "KERNELEX_EXPORTS" /YX /FD /c -# ADD CPP /nologo /W3 /O2 /I "." /I "../common" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "KEXCORE_EXPORTS" /YX /FD /GF /c +# ADD CPP /nologo /W3 /O2 /I "." /I "../common" /FI"msvc_quirks.h" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "KEXCORE_EXPORTS" /YX /FD /GF /c # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x415 /d "NDEBUG" @@ -70,7 +70,7 @@ LINK32=link.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "KERNELEX_EXPORTS" /YX /FD /GZ /c -# ADD CPP /nologo /ML /W3 /Gm /Zi /Od /I "." /I "../common" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "KEXCORE_EXPORTS" /YX /FD /GZ /GF /c +# ADD CPP /nologo /ML /W3 /Gm /Zi /Od /I "." /I "../common" /FI"msvc_quirks.h" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "KEXCORE_EXPORTS" /YX /FD /GZ /GF /c # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x415 /d "_DEBUG" @@ -209,10 +209,18 @@ SOURCE=.\main.cpp # End Source File # Begin Source File +SOURCE=.\ModInit.cpp +# End Source File +# Begin Source File + SOURCE=..\common\pemanip.cpp # End Source File # Begin Source File +SOURCE=.\ProcessStorage.cpp +# End Source File +# Begin Source File + SOURCE=.\resolver.cpp # End Source File # Begin Source File @@ -225,10 +233,6 @@ SOURCE=.\sharedmem.cpp # End Source File # Begin Source File -SOURCE=.\storage.cpp -# End Source File -# Begin Source File - SOURCE=.\thunks.cpp # End Source File # Begin Source File @@ -290,10 +294,18 @@ SOURCE=..\common\kexcoresdk.h # End Source File # Begin Source File +SOURCE=.\ModInit.h +# End Source File +# Begin Source File + SOURCE=..\common\pemanip.h # End Source File # Begin Source File +SOURCE=.\ProcessStorage.h +# End Source File +# Begin Source File + SOURCE=.\resolver.h # End Source File # Begin Source File @@ -310,10 +322,6 @@ SOURCE=..\common\sstring.hpp # End Source File # Begin Source File -SOURCE=.\storage.h -# End Source File -# Begin Source File - SOURCE=.\structs.h # End Source File # Begin Source File diff --git a/core/core.ini b/core/core.ini old mode 100644 new mode 100755 diff --git a/core/debug.cpp b/core/debug.cpp old mode 100644 new mode 100755 diff --git a/core/debug.h b/core/debug.h old mode 100644 new mode 100755 index 3789d34..f00fd17 --- a/core/debug.h +++ b/core/debug.h @@ -47,6 +47,4 @@ void dbgvprintf(const char* format, void* _argp); void dbgprintf(const char* format, ...); -#include "apilog.h" - #endif diff --git a/core/debugproto.cpp b/core/debugproto.cpp old mode 100644 new mode 100755 diff --git a/core/debugproto.h b/core/debugproto.h old mode 100644 new mode 100755 diff --git a/core/internals.cpp b/core/internals.cpp old mode 100644 new mode 100755 index abd782f..62ef105 --- a/core/internals.cpp +++ b/core/internals.cpp @@ -25,6 +25,13 @@ #include "resolver.h" #include "debug.h" #include "pemanip.h" +#include "ModInit.h" + +#ifdef _DEBUG +#define _D(x) x +#else +#define _D(x) NULL +#endif static bool is_winme; HINSTANCE hInstance; @@ -39,7 +46,6 @@ MRFromHLib_t MRFromHLib = NULL; TIDtoTDB_t TIDtoTDB = NULL; MRLoadTree_t MRLoadTree = NULL; FreeLibTree_t FreeLibTree = NULL; -FLoadTreeNotify_t FLoadTreeNotify = NULL; FreeLibRemove_t FreeLibRemove = NULL; AllocHandle_t AllocHandle = NULL; @@ -59,7 +65,7 @@ void ShowError(UINT id, ...) va_start(vargs, id); if (!LoadString(hInstance, id, format, sizeof(format))) - sprintf(out, "ERROR: Missing string resource %d", id); + sprintf(out, "ERROR: %d [Missing error description]", id); else _vsnprintf(out, sizeof(out), format, vargs); va_end(vargs); @@ -181,14 +187,32 @@ HANDLE _OpenThread(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId) return ret; } +HANDLE _GetProcessHeap() +{ + HANDLE hp = GetProcessHeap(); + + if (!hp) + { + PDB98* pdb = *pppdbCur; + IMAGE_NT_HEADERS* nth = (*ppmteModTable)[pdb->pExeMODREF->mteIndex]->pNTHdr; + //create new default heap + hp = pdb->DefaultHeap = HeapCreate(0, nth->OptionalHeader.SizeOfHeapCommit, 0); + //this will prevent the system from creating another default heap + nth->OptionalHeader.SizeOfHeapReserve = 0; + } + + DBGASSERT(hp != NULL); + return hp; +} + /* find win32 mutex */ static CRITICAL_SECTION* find_krnl32lock() { - CRITICAL_SECTION* ret; + static const char* pat_name = _D("Win32 lock"); + static const short pat[] = {0x55,0xA1,-2,-2,-2,-2,0x8B,0xEC,0x56,0x57,0x33,0xF6,0x50,0xE8}; + static const int pat_len = sizeof(pat) / sizeof(short); - const char* pat_name = "Win32 lock"; - short pat[] = {0x55,0xA1,-2,-2,-2,-2,0x8B,0xEC,0x56,0x57,0x33,0xF6,0x50,0xE8}; - int pat_len = sizeof(pat) / sizeof(short); + CRITICAL_SECTION* ret; DWORD* res = find_unique_pattern((void*) iGetProcAddress(h_kernel32, "VirtualQueryEx"), pat_len, pat, pat_len, pat_name); if (!res) @@ -202,11 +226,11 @@ static CRITICAL_SECTION* find_krnl32lock() /* find current process PDB */ static PDB98** find_curPDB() { - PDB98** ret; + static const char* pat_name = _D("pppdbCur"); + static const short pat[] = {0xA1,-2,-2,-2,-2,0xFF,0x30,0xE8,-1,-1,-1,-1,0xC3}; + static const int pat_len = sizeof(pat) / sizeof(short); - const char* pat_name = "pppdbCur"; - short pat[] = {0xA1,-2,-2,-2,-2,0xFF,0x30,0xE8,-1,-1,-1,-1,0xC3}; - int pat_len = sizeof(pat) / sizeof(short); + PDB98** ret; DWORD* res = find_unique_pattern((void*) iGetProcAddress(h_kernel32, "GetCurrentProcessId"), pat_len, pat, pat_len, pat_name); if (!res) @@ -220,12 +244,12 @@ static PDB98** find_curPDB() /* find global module tables */ static IMTE*** find_mod_table() { + static const char* pat_name = _D("Module table"); + static const short pat[] = {0x8B,0x0D,-2,-2,-2,-2}; + static const int pat_len = sizeof(pat) / sizeof(short); + IMTE*** ret; - const char* pat_name = "Module table"; - short pat[] = {0x8B,0x0D,-2,-2,-2,-2}; - int pat_len = sizeof(pat) / sizeof(short); - DWORD* res = find_unique_pattern((void*) iGetProcAddress(h_kernel32, (LPSTR)23), 0x20, pat, pat_len, pat_name); ret = (IMTE***)*res; @@ -235,11 +259,11 @@ static IMTE*** find_mod_table() static MRFromHLib_t find_MRFromHLib() { - MRFromHLib_t ret; + static const char* pat_name = _D("MRFromHLib"); + static const short pat[] = {0xE8,-2,-2,-2,-2}; + static const int pat_len = sizeof(pat) / sizeof(short); - const char* pat_name = "MRFromHLib"; - short pat[] = {0xE8,-2,-2,-2,-2}; - int pat_len = sizeof(pat) / sizeof(short); + MRFromHLib_t ret; DWORD* res = find_unique_pattern((void*) iGetProcAddress(h_kernel32, (LPSTR)23), 0x20, pat, pat_len, pat_name); if (!res) @@ -252,16 +276,16 @@ static MRFromHLib_t find_MRFromHLib() static WORD* find_pimteMax() { + static const char* pat_name = _D("pimteMax"); + static const short pat[] = {0x66,0x8B,0x44,0x24,0x04,0x66,-1,0x05,-2,-2,-2,-2,-1,0x17,0x8B,0x0D,-1,-1,-1,-1,0x0F,0xBF,0xC0,0x8B,0x04,0x81,0x85,0xC0,0x74,0x07,0x8B,0x40,0x04,0x85,0xC0,0x75,0x09}; + static const int pat_len = sizeof(pat) / sizeof(short); + static const char* sec_name = ".text"; + WORD* ret; PEmanip pe(h_kernel32); if (!pe.HasTarget()) return NULL; - const char* pat_name = "pimteMax"; - short pat[] = {0x66,0x8B,0x44,0x24,0x04,0x66,-1,0x05,-2,-2,-2,-2,-1,0x17,0x8B,0x0D,-1,-1,-1,-1,0x0F,0xBF,0xC0,0x8B,0x04,0x81,0x85,0xC0,0x74,0x07,0x8B,0x40,0x04,0x85,0xC0,0x75,0x09}; - int pat_len = sizeof(pat) / sizeof(short); - const char* sec_name = ".text"; - DWORD* res = find_unique_pattern(pe.GetSectionByName(sec_name), pe.GetSectionSize(sec_name), pat, pat_len, pat_name); if (!res) return NULL; @@ -273,16 +297,16 @@ static WORD* find_pimteMax() static TIDtoTDB_t find_TIDtoTDB() { + static const char* pat_name = _D("TIDtoTDB"); + static const short pat[] = {0x89,-1,0xFF,0x75,0xFC,0xFF,0x77,0x14,0xE8,-2,-2,-2,-2,0x50}; + static const int pat_len = sizeof(pat) / sizeof(short); + static const char* sec_name = ".text"; + TIDtoTDB_t ret; PEmanip pe(h_kernel32); if (!pe.HasTarget()) return NULL; - const char* pat_name = "TIDtoTDB"; - short pat[] = {0x89,-1,0xFF,0x75,0xFC,0xFF,0x77,0x14,0xE8,-2,-2,-2,-2,0x50}; - int pat_len = sizeof(pat) / sizeof(short); - const char* sec_name = ".text"; - DWORD* res = find_unique_pattern(pe.GetSectionByName(sec_name), pe.GetSectionSize(sec_name), pat, pat_len, pat_name); if (!res) return NULL; @@ -294,16 +318,16 @@ static TIDtoTDB_t find_TIDtoTDB() static MRLoadTree_t find_MRLoadTree() { + static const char* pat_name = _D("MRLoadTree"); + static const short pat[] = {0x33,0xF6,0xE8,-1,-1,-1,-1,0x39,0x35,-1,-1,-1,-1,0x74,0x11,0xA1,-1,-1,-1,-1,0x50,0xE8,-1,-1,-1,-1,0x89,0x35,-1,-1,-1,-1,0xFF,0x74,0x24,0x14,0xE8,-2,-2,-2,-2,0x8B,0xF0,0x85,0xF6}; + static const int pat_len = sizeof(pat) / sizeof(short); + static const char* sec_name = ".text"; + MRLoadTree_t ret; PEmanip pe(h_kernel32); if (!pe.HasTarget()) return NULL; - const char* pat_name = "MRLoadTree"; - short pat[] = {0x33,0xF6,0xE8,-1,-1,-1,-1,0x39,0x35,-1,-1,-1,-1,0x74,0x11,0xA1,-1,-1,-1,-1,0x50,0xE8,-1,-1,-1,-1,0x89,0x35,-1,-1,-1,-1,0xFF,0x74,0x24,0x14,0xE8,-2,-2,-2,-2,0x8B,0xF0,0x85,0xF6}; - int pat_len = sizeof(pat) / sizeof(short); - const char* sec_name = ".text"; - DWORD* res = find_unique_pattern(pe.GetSectionByName(sec_name), pe.GetSectionSize(sec_name), pat, pat_len, pat_name); if (!res) return NULL; @@ -315,11 +339,11 @@ static MRLoadTree_t find_MRLoadTree() static FreeLibTree_t find_FreeLibTree() { - FreeLibTree_t ret; + static const char* pat_name = _D("FreeLibTree"); + static const short pat[] = {0x75,0x09,0x6A,0x06,0xE8,-1,-1,-1,-1,0xEB,0x08,0x50,0xE8,-2,-2,-2,-2,0x8B,0xF0}; + static const int pat_len = sizeof(pat) / sizeof(short); - const char* pat_name = "FreeLibTree"; - short pat[] = {0x75,0x09,0x6A,0x06,0xE8,-1,-1,-1,-1,0xEB,0x08,0x50,0xE8,-2,-2,-2,-2,0x8B,0xF0}; - int pat_len = sizeof(pat) / sizeof(short); + FreeLibTree_t ret; DWORD* res = find_unique_pattern((void*) iGetProcAddress(h_kernel32, "FreeLibrary"), 0x80, pat, pat_len, pat_name); if (!res) @@ -330,39 +354,18 @@ static FreeLibTree_t find_FreeLibTree() return ret; } -static FLoadTreeNotify_t find_FLoadTreeNotify() -{ - FLoadTreeNotify_t ret; - PEmanip pe(h_kernel32); - if (!pe.HasTarget()) - return NULL; - - const char* pat_name = "FLoadTreeNotify"; - short pat[] = {0x56,0xA1,-1,-1,-1,-1,0x6A,0x01,0x8B,0x08,0xFF,0xB1,0x98,0x00,0x00,0x00,0xE8,-2,-2,-2,-2,0x83,0xF8,0x01,0x1B,0xF6,0xF7,0xDE,0x85,0xF6}; - int pat_len = sizeof(pat) / sizeof(short); - const char* sec_name = ".text"; - - DWORD* res = find_unique_pattern(pe.GetSectionByName(sec_name), pe.GetSectionSize(sec_name), pat, pat_len, pat_name); - if (!res) - return NULL; - - ret = (FLoadTreeNotify_t)decode_calljmp(res); - DBGPRINTF(("%s @ 0x%08x\n", pat_name, ret)); - return ret; -} - static FreeLibRemove_t find_FreeLibRemove() { + static const char* pat_name = _D("FreeLibRemove"); + static const short pat[] = {0x8B,0xF0,0x85,0xF6,0x75,0x05,0xE8,-2,-2,-2,-2,0xA1,-1,-1,-1,-1,0x50}; + static const int pat_len = sizeof(pat) / sizeof(short); + static const char* sec_name = ".text"; + FreeLibRemove_t ret; PEmanip pe(h_kernel32); if (!pe.HasTarget()) return NULL; - const char* pat_name = "FreeLibRemove"; - short pat[] = {0x8B,0xF0,0x85,0xF6,0x75,0x05,0xE8,-2,-2,-2,-2,0xA1,-1,-1,-1,-1,0x50}; - int pat_len = sizeof(pat) / sizeof(short); - const char* sec_name = ".text"; - DWORD* res = find_unique_pattern(pe.GetSectionByName(sec_name), pe.GetSectionSize(sec_name), pat, pat_len, pat_name); if (!res) return NULL; @@ -374,11 +377,11 @@ static FreeLibRemove_t find_FreeLibRemove() static AllocHandle_t find_AllocHandle() { - AllocHandle_t ret; + static const char* pat_name = _D("AllocHandle"); + static const short pat[] = {0x83,0xD1,0xFF,0x81,0xE2,0xFF,0x0F,0x1F,0x00,0x81,0xE1,0x00,0x00,0x00,0x80,0x0B,0xCA,0x8B,0x15,-1,-1,-1,-1,0x51,0x50,0xFF,0x32,0xE8,-2,-2,-2,-2}; + static const int pat_len = sizeof(pat) / sizeof(short); - const char* pat_name = "AllocHandle"; - short pat[] = {0x83,0xD1,0xFF,0x81,0xE2,0xFF,0x0F,0x1F,0x00,0x81,0xE1,0x00,0x00,0x00,0x80,0x0B,0xCA,0x8B,0x15,-1,-1,-1,-1,0x51,0x50,0xFF,0x32,0xE8,-2,-2,-2,-2}; - int pat_len = sizeof(pat) / sizeof(short); + AllocHandle_t ret; DWORD* res = find_unique_pattern((void*) iGetProcAddress(h_kernel32, "OpenProcess"), 0x80, pat, pat_len, pat_name); if (!res) @@ -445,15 +448,16 @@ int internals_init() TIDtoTDB = find_TIDtoTDB(); MRLoadTree = find_MRLoadTree(); FreeLibTree = find_FreeLibTree(); - FLoadTreeNotify = find_FLoadTreeNotify(); FreeLibRemove = find_FreeLibRemove(); AllocHandle = find_AllocHandle(); bool instdir_rslt = find_kernelex_install_dir(); is_winme = (GetVersion() == 0xc0005a04); + bool modinit_rslt = ModuleInitializer_init(); if (!h_kernel32 || !ppmteModTable || !krnl32lock || !pppdbCur || !MRFromHLib || !pimteMax || !TIDtoTDB || !MRLoadTree || !FreeLibTree - || !FLoadTreeNotify || !FreeLibRemove || !AllocHandle || !instdir_rslt) + || !FreeLibRemove || !AllocHandle || !instdir_rslt + || !modinit_rslt) return 0; return 1; } diff --git a/core/internals.h b/core/internals.h old mode 100644 new mode 100755 index 3734533..b1914ac --- a/core/internals.h +++ b/core/internals.h @@ -28,12 +28,7 @@ #include "resource.h" #include "k32ord.h" -/** MSVC 6.0 for-loop workaround. */ -#ifdef _MSC_VER -#if _MSC_VER < 1201 -#define for if (0); else for -#endif -#endif +#define countof(x) (sizeof(x)/sizeof(x[0])) #define IS_SHARED(x) (((DWORD)x) >= 0x80000000) @@ -75,5 +70,6 @@ extern AllocHandle_t AllocHandle; MODREF* MRfromCallerAddr(DWORD addr); HANDLE _OpenThread(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId); +HANDLE _GetProcessHeap(); #endif diff --git a/core/kexcoresdk.cpp b/core/kexcoresdk.cpp old mode 100644 new mode 100755 index eb562ee..cf0b988 --- a/core/kexcoresdk.cpp +++ b/core/kexcoresdk.cpp @@ -27,6 +27,8 @@ #include "internals.h" #include "SettingsDB.h" #include "debug.h" +#undef MAKE_PS_TAG +#include "ProcessStorage.h" unsigned long kexGetKEXVersion() { @@ -73,24 +75,60 @@ BOOL kexAreExtensionsEnabled() } void kexGetModuleSettings(const char* module, - char* conf_name, BYTE* ldr_flags) + char* conf_name, DWORD* mod_flags) { appsetting as = SettingsDB::instance.get_appsetting(module); if (!as.conf) + { conf_name[0] = '\0'; + } else + { strncpy(conf_name, as.conf->get_name(), 256); - *ldr_flags = as.flags; - conf_name[255] = '\0'; + conf_name[255] = '\0'; + } + + DWORD flags = 0; + if (as.flags & LDR_KEX_DISABLE) flags |= KRF_KEX_DISABLE; + if (as.flags & LDR_OVERRIDE_PROC_MOD) flags |= KRF_OVERRIDE_PROC_MOD; + if (as.flags & LDR_LOG_APIS) flags |= KRF_LOG_APIS; + if (as.flags & LDR_NO_INHERIT) flags |= KRF_NO_INHERIT; + if (as.flags & LDR_VALID_FLAG) flags |= KRF_VALID_FLAG; + *mod_flags = flags; } void kexSetModuleSettings(const char* module, - const char* conf_name, BYTE ldr_flags) + const char* conf_name, DWORD mod_flags) { - SettingsDB::instance.write_single(module, conf_name, ldr_flags); + BYTE flags = 0; + if (mod_flags & KRF_KEX_DISABLE) flags |= LDR_KEX_DISABLE; + if (mod_flags & KRF_OVERRIDE_PROC_MOD) flags |= LDR_OVERRIDE_PROC_MOD; + if (mod_flags & KRF_LOG_APIS) flags |= LDR_LOG_APIS; + if (mod_flags & KRF_NO_INHERIT) flags |= LDR_NO_INHERIT; + SettingsDB::instance.write_single(module, conf_name, flags); } void kexFlushAppSettings(void) { SettingsDB::instance.flush_all(); } + +int kexPsAllocIndex(void) +{ + return ProcessStorage::allocate(); +} + +void* kexPsGetValue(int index) +{ + return ProcessStorage::get_instance()->get(index); +} + +int kexPsSetValue(int index, void* value) +{ + return ProcessStorage::get_instance()->set(index, value); +} + +void* kexGetK32Lock() +{ + return krnl32lock; +} diff --git a/core/main.cpp b/core/main.cpp old mode 100644 new mode 100755 diff --git a/core/resolver.cpp b/core/resolver.cpp old mode 100644 new mode 100755 index 4e3b452..0654e44 --- a/core/resolver.cpp +++ b/core/resolver.cpp @@ -29,7 +29,10 @@ #include "../setup/loadstub.h" #include "thunks.h" #include "SettingsDB.h" -#include "storage.h" +#include "ModInit.h" +#ifdef _DEBUG +#include "apilog.h" +#endif using namespace std; @@ -40,6 +43,8 @@ static PLONG jtab; static LONG old_jtab[JTAB_SIZE]; static HKEY known_dlls_key; +FLoadTreeNotify_t FLoadTreeNotify; + /** Get API configuration for selected module. * @param module Target module. @@ -50,86 +55,102 @@ static bool get_config(MODREF* moduleMR, config_params& cp) { IMTE** pmteModTable = *ppmteModTable; PDB98* ppdbCur = *pppdbCur; - IMTE_KEX* module = (IMTE_KEX*) pmteModTable[moduleMR->mteIndex]; - IMTE_KEX* process = (IMTE_KEX*) pmteModTable[ppdbCur->pExeMODREF->mteIndex]; - ApiConfiguration* conf; - BYTE flags; + volatile MODREF_KEX module(moduleMR); + MODREF_KEX process(ppdbCur->pExeMODREF); //shared modules should use standard api - if (IS_SHARED(module->baseAddress)) + if (IS_SHARED(pmteModTable[module.mr.mteIndex]->baseAddress)) return false; - //unless override flag is set try to get module configuration first - if (!(process->flags & LDR_OVERRIDE_PROC_MOD)) - { - if (!(module->flags & LDR_VALID_FLAG)) - { - appsetting as = SettingsDB::instance.get_appsetting(module->pszFileName); - module->config = as.conf; - module->flags = as.flags; - } - conf = module->config; - flags = module->flags; + //if settings are already known, exit immediatelly + if (module.as.flags & LDR_VALID_FLAG) + goto __end; - if (flags & LDR_KEX_DISABLE) - return false; + //we need process settings to know if process.LDR_OVERRIDE_PROC_MOD is set + if (!(process.as.flags & LDR_VALID_FLAG)) + { + //try to take settings from database... + pmteModTable = *ppmteModTable; + process.as = SettingsDB::instance + .get_appsetting(pmteModTable[process.mr.mteIndex]->pszFileName); + + //...if settings are not there, take them from parent process... + if (!(process.as.flags & LDR_VALID_FLAG)) + { + PDB98* ppdbParent = ppdbCur->ParentPDB; + + //...IF there is parent process and... + if (ppdbParent && !(ppdbParent->Flags & (fTerminated | fTerminating | + fNearlyTerminating | fDosProcess | fWin16Process))) + { + MODREF_KEX parent(ppdbParent->pExeMODREF); + + //...unless parent disallows us to inherit them + if ((parent.as.flags & LDR_VALID_FLAG) && !(parent.as.flags & LDR_NO_INHERIT)) + { + process.as = parent.as; +#ifdef _DEBUG //don't inherit log flag + process.as.flags &= ~LDR_LOG_APIS; +#endif + } + } + } } + + //at this point we know whether override is enabled or not + if ((process.as.flags & LDR_VALID_FLAG)) + { + //if it is then take process settings + if (process.as.flags & LDR_OVERRIDE_PROC_MOD) + { + module.as = process.as; + goto __end; + } + } + //if process still doesn't have settings, set some reasonable defaults else - conf = NULL; - - //if above failed or override flag was set try to get process configuration - if (!conf) - { - if (!(process->flags & LDR_VALID_FLAG)) - { - appsetting as = SettingsDB::instance.get_appsetting(process->pszFileName); - process->config = as.conf; - process->flags = as.flags; - } - conf = process->config; - flags = process->flags; - - if (flags & LDR_KEX_DISABLE) - return false; - } - - //if no process configuration then get parent configuration - if (!conf) - { - PDB98* ppdbParent = ppdbCur->ParentPDB; - - if (ppdbParent && !(ppdbParent->Flags & (fTerminated | fTerminating | - fNearlyTerminating | fDosProcess | fWin16Process))) - { - pmteModTable = *ppmteModTable; - IMTE_KEX* parent = (IMTE_KEX*) pmteModTable[ppdbParent->pExeMODREF->mteIndex]; - conf = parent->config; - flags = parent->flags; - flags &= ~LDR_LOG_APIS; //don't inherit LOG flag - - if (flags & LDR_KEX_DISABLE) - return false; - } - } - - if (flags & LDR_FILTER_APIS) - { - //TODO: not implemented yet - DBGPRINTF(("Resolver flag LDR_FILTER_APIS not implemented\n")); - } - - //finally if everything else fails take default configuration - if (!conf) { if (apiconfmgr.are_extensions_disabled()) - return false; - conf = apiconfmgr.get_default_configuration(); + { + process.as.flags = LDR_VALID_FLAG | LDR_KEX_DISABLE; + } + else + { + process.as.conf = apiconfmgr.get_default_configuration(); + process.as.flags = LDR_VALID_FLAG; + } } - DBGASSERT(conf != NULL); - cp.apiconf = conf; + //if module == process then we've already got everything we need + if (&module.as == &process.as) + goto __end; + + //lookup module settings in database + pmteModTable = *ppmteModTable; + module.as = SettingsDB::instance + .get_appsetting(pmteModTable[module.mr.mteIndex]->pszFileName); + + if (module.as.flags & LDR_VALID_FLAG) + { +#ifdef _DEBUG //copy log flag from process to module + if (process.as.flags & LDR_LOG_APIS) + module.as.flags |= LDR_LOG_APIS; +#endif + goto __end; + } + + //if module has no settings, take them from process + module.as = process.as; + +__end: + DBGASSERT(module.as.flags & LDR_VALID_FLAG); + if (module.as.flags & LDR_KEX_DISABLE) + return false; + + DBGASSERT(module.as.conf != NULL); + cp.apiconf = module.as.conf; #ifdef _DEBUG - cp.log_apis = (process->flags & LDR_LOG_APIS) != 0; + cp.log_apis = (module.as.flags & LDR_LOG_APIS) != 0; #endif return true; } @@ -163,10 +184,10 @@ static WORD resolve_mod_index(IMTE_KEX* target) * (static resolve). * @param addr Encoded api library ID + offset in this api library * @param caller Module that requests api from api library. - * @param refmod + * @param is_static True if implicit (static), false if explicit (GetProcAddress) resolve * @return Valid address to function for calling process. */ -static PROC resolve_nonshared_addr(DWORD addr, MODREF* caller, PMODREF** refmod) +static PROC resolve_nonshared_addr(DWORD addr, MODREF* caller, BOOL is_static) { MODREF* mr; WORD idx; @@ -175,9 +196,8 @@ static PROC resolve_nonshared_addr(DWORD addr, MODREF* caller, PMODREF** refmod) char dllpath[MAX_PATH]; ApiLibrary* apilib; IMTE** pmteModTable = *ppmteModTable; - static MODREF* buffer[1024]; + ModuleInitializer* mi = ModuleInitializer::get_instance(true); - DBGASSERT(addr >= 0xc0000000); api_lib_num = (addr >> 24) - 0xc0; DBGASSERT(api_lib_num > 0); //ensure apilib ID isn't STD's apilib = apilibmgr.get_apilib_by_index(api_lib_num); @@ -186,19 +206,9 @@ static PROC resolve_nonshared_addr(DWORD addr, MODREF* caller, PMODREF** refmod) idx = 0xff00 + api_lib_num; //first check if api library has already been loaded - mr = (*pppdbCur)->MODREFList; - do - { - IMTE_KEX* imte = (IMTE_KEX*) pmteModTable[mr->mteIndex]; - if (imte->mod_index == idx) - { - IMAGE_NT_HEADERS* nthdr = imte->pNTHdr; - img_base = nthdr->OptionalHeader.ImageBase; - return (PROC)(img_base + (addr & 0x00ffffff)); - } - mr = mr->pNextModRef; - } - while (mr); + img_base = mi->get_handle_for_index(idx); + if (img_base != 0) + return (PROC)(img_base + (addr & 0x00ffffff)); //if not - load it @@ -216,46 +226,15 @@ static PROC resolve_nonshared_addr(DWORD addr, MODREF* caller, PMODREF** refmod) _LeaveSysLevel(krnl32lock); return 0; } + mi->add_module(mr); _LeaveSysLevel(krnl32lock); - if (refmod) //static resolve (implicit) - { - //FIXME: this will cause problems if apilib references another non-shared apilib!! - //it is okay to use global buffer because static resolve code is protected by k32 lock - - //not buffered yet? - if (!(*refmod >= buffer && *refmod < buffer + sizeof(buffer))) - { - //make a copy - for (int i = 0 ; i < caller->cImportedModules ; i++) - buffer[i] = caller->ImplicitImports[i].pMR; - - //set reference to copy - copy will be seen by continuing resolve process - *refmod += buffer - &caller->ImplicitImports[0].pMR; - } - - DBGPRINTF(("Implicit load: replacing tree %s => %s [PID=%08x]\n", - (*ppmteModTable)[caller->ImplicitImports[*refmod - buffer].pMR->mteIndex] - ->pszModName, apilib->apilib_name, - GetCurrentProcessId())); - - //remember tree which we overwrite - we will initialize it ourselves - //in resolver_process_attach as a result of initializing our tree - //requirement: Core is in IAT of the apilib !!! - storage* s = storage::get_storage(true); - DBGASSERT(s != NULL); - s->data[s->size++] = (void*) caller->ImplicitImports[*refmod - buffer].pMR; - - //modify original - modifications will be seen by dll initializer - //which will initialize our mr tree - caller->ImplicitImports[*refmod - buffer].pMR = mr; - } - else //dynamic resolve (GetProcAddress) + if (!is_static) { DBGPRINTF(("Explicit load: initializing tree %s [PID=%08x]\n", apilib->apilib_name, GetCurrentProcessId())); - if (FLoadTreeNotify(mr, 0)) + if (FLoadTreeNotify(mr, FALSE)) { FreeLibTree(mr); return 0; @@ -280,27 +259,6 @@ static PROC resolve_nonshared_addr(DWORD addr, MODREF* caller, PMODREF** refmod) */ BOOL resolver_process_attach() { - //initialize all modules replaced by api libraries - bool loaded = false; - storage* s = storage::get_storage(false); - if (!s) - return TRUE; - - for (int i = 0 ; i < s->size ; i++) - { - DBGPRINTF(("Post-Initializing %s [PID=%08x]\n", - (*ppmteModTable)[((MODREF*) s->data[i])->mteIndex]->pszModName, - GetCurrentProcessId())); - - if (FLoadTreeNotify((MODREF*) s->data[i], 1)) - return FALSE; - loaded = true; - } - storage::return_storage(); - - if (!loaded) - return TRUE; - //reference all shared api libraries ApiLibrary* lib; int i = 1; @@ -310,13 +268,15 @@ BOOL resolver_process_attach() { char dllpath[MAX_PATH]; lib->get_dll_path(dllpath); - LoadLibrary(dllpath); + if (!LoadLibrary(dllpath)) + return FALSE; } } return TRUE; } +/** Original ExportFromOrdinal function. @see ExportFromOrdinal */ static PROC WINAPI OriExportFromOrdinal(IMAGE_NT_HEADERS* PEh, WORD ordinal) { DWORD img_base; @@ -381,6 +341,7 @@ static PROC WINAPI OriExportFromOrdinal(IMAGE_NT_HEADERS* PEh, WORD ordinal) return (PROC) addr; } +/** Original ExportFromName function. @see ExportFromName */ static PROC WINAPI OriExportFromName(IMAGE_NT_HEADERS* PEh, WORD hint, LPCSTR name) { DWORD img_base; @@ -453,6 +414,12 @@ static PROC WINAPI OriExportFromName(IMAGE_NT_HEADERS* PEh, WORD hint, LPCSTR na return 0; } +/** Encode function pointer + API library information into single dword. + * @see decode_address + * @param addr Absolute address. + * @param apilib Pointer to API library. + * @return Encoded pointer. + */ DWORD encode_address(DWORD addr, const ApiLibrary* apilib) { //note: rules have to be the same as in decode_address @@ -472,7 +439,7 @@ DWORD encode_address(DWORD addr, const ApiLibrary* apilib) //extremely rare scenario: driver hijacked apis so the address is now //above 0xc0000000 and we use these for encoded apilib addresses //so we have to create a stub in shared arena with proper address - return (DWORD) new redir_stub(addr); + return (DWORD) new redir_stub(addr, false); } //non-shared apilib @@ -487,7 +454,15 @@ DWORD encode_address(DWORD addr, const ApiLibrary* apilib) return addr; } -inline PROC decode_address(DWORD p, IMAGE_NT_HEADERS* target_NThdr, MODREF* caller, PMODREF** refmod) +/** Decodes pointers created with encode_address. + * @see encode_address + * @param p Encoded pointer. + * @param target_NThdr Target module NT header. + * @param caller Calling module ref. + * @param is_static True if implicit resolve, false if explicit. + * @return Decoded function pointer. + */ +inline PROC decode_address(DWORD p, IMAGE_NT_HEADERS* target_NThdr, MODREF* caller, BOOL is_static) { //note: rules have to be the same as in encode_address //zero address @@ -501,12 +476,19 @@ inline PROC decode_address(DWORD p, IMAGE_NT_HEADERS* target_NThdr, MODREF* call return (PROC)(p + target_NThdr->OptionalHeader.ImageBase); //non-shared api library if (p >= 0xc0000000) - return resolve_nonshared_addr(p, caller, refmod); + return resolve_nonshared_addr(p, caller, is_static); //shared system or api library return (PROC) p; } -PROC WINAPI ExportFromOrdinal(IMTE_KEX* target, MODREF* caller, PMODREF** refmod, WORD ordinal) +/** Performs function resolve by ordinal number. + * @param target Target module, module from which we want function. + * @param caller Calling module, module which wants function. + * @param is_static True if static resolve, false if dynamic. + * @param ordinal Function ordinal number. + * @return Function pointer. + */ +PROC WINAPI ExportFromOrdinal(IMTE_KEX* target, MODREF* caller, BOOL is_static, WORD ordinal) { PROC ret; @@ -527,13 +509,13 @@ PROC WINAPI ExportFromOrdinal(IMTE_KEX* target, MODREF* caller, PMODREF** refmod if (!cp.apiconf->is_table_empty(mod_index)) ret = decode_address(cp.apiconf->get(mod_index, ordinal), - target->pNTHdr, caller, refmod); + target->pNTHdr, caller, is_static); else ret = OriExportFromOrdinal(target->pNTHdr, ordinal); #ifdef _DEBUG if (ret && cp.log_apis) { - IMTE_KEX* icaller = (IMTE_KEX*)((*ppmteModTable)[caller->mteIndex]); + IMTE* icaller = (*ppmteModTable)[caller->mteIndex]; if (DWORD(ret) < target->pNTHdr->OptionalHeader.ImageBase + target->pNTHdr->OptionalHeader.BaseOfData) ret = create_log_stub(icaller->pszModName, target->pszModName, ordinal, ret); @@ -543,7 +525,7 @@ PROC WINAPI ExportFromOrdinal(IMTE_KEX* target, MODREF* caller, PMODREF** refmod else ret = OriExportFromOrdinal(target->pNTHdr, ordinal); - if (!ret && refmod) + if (!ret && is_static) { DBGPRINTF(("%s: unresolved export %s:%d\n", ((*ppmteModTable)[caller->mteIndex])->pszModName, @@ -553,7 +535,15 @@ PROC WINAPI ExportFromOrdinal(IMTE_KEX* target, MODREF* caller, PMODREF** refmod return ret; } -PROC WINAPI ExportFromName(IMTE_KEX* target, MODREF* caller, PMODREF** refmod, WORD hint, LPCSTR name) +/** Performs function resolve by name. + * @param target Target module, module from which we want function. + * @param caller Calling module, module which wants function. + * @param is_static True if static resolve, false if dynamic. + * @param hint Hint number, tells resolver where to start search. + * @param name Function name. + * @return Function pointer. + */ +PROC WINAPI ExportFromName(IMTE_KEX* target, MODREF* caller, BOOL is_static, WORD hint, LPCSTR name) { PROC ret; @@ -574,13 +564,13 @@ PROC WINAPI ExportFromName(IMTE_KEX* target, MODREF* caller, PMODREF** refmod, W if (!cp.apiconf->is_table_empty(mod_index)) ret = decode_address(cp.apiconf->get(mod_index, hint, name), - target->pNTHdr, caller, refmod); + target->pNTHdr, caller, is_static); else ret = OriExportFromName(target->pNTHdr, hint, name); #ifdef _DEBUG if (ret && cp.log_apis) { - IMTE_KEX* icaller = (IMTE_KEX*)((*ppmteModTable)[caller->mteIndex]); + IMTE* icaller = (*ppmteModTable)[caller->mteIndex]; if (DWORD(ret) < target->pNTHdr->OptionalHeader.ImageBase + target->pNTHdr->OptionalHeader.BaseOfData) ret = create_log_stub(icaller->pszModName, target->pszModName, name, ret); @@ -590,7 +580,7 @@ PROC WINAPI ExportFromName(IMTE_KEX* target, MODREF* caller, PMODREF** refmod, W else ret = OriExportFromName(target->pNTHdr, hint, name); - if (!ret && refmod) + if (!ret && is_static) { DBGPRINTF(("%s: unresolved export %s:%s\n", ((*ppmteModTable)[caller->mteIndex])->pszModName, @@ -600,10 +590,12 @@ PROC WINAPI ExportFromName(IMTE_KEX* target, MODREF* caller, PMODREF** refmod, W return ret; } +/** Determines whether process has API extensions enabled. */ bool are_extensions_enabled() { config_params cp; MODREF* exe = (*pppdbCur)->pExeMODREF; + DBGASSERT(exe != NULL); return get_config(exe, cp); } @@ -619,6 +611,9 @@ static BOOL WINAPI IsKnownKexDLL(char* name, const char* ext) if (ext && strcmp(ext, "DLL") != 0) return FALSE; + if ((*pppdbCur)->pExeMODREF == NULL) + return FALSE; + if (are_extensions_enabled()) { //workaround windows bug @@ -644,6 +639,15 @@ static BOOL WINAPI IsKnownKexDLL(char* name, const char* ext) } } +static BOOL WINAPI KexLoadTreeNotify(MODREF* mr, BOOL is_static) +{ + ModuleInitializer* mi = ModuleInitializer::get_instance(false); + if (mi && mi->has_initialize() && !mi->initialize_modules()) + return TRUE; + + return FLoadTreeNotify(mr, is_static); +} + PROC WINAPI iGetProcAddress(HMODULE hModule, LPCSTR lpProcName) { IMAGE_DOS_HEADER* dos_hdr; @@ -688,9 +692,13 @@ static void reset_imtes() IMTE_KEX* imte = (IMTE_KEX*) pmteModTable[i]; if (imte) { - imte->config = NULL; - imte->flags = 0; imte->mod_index = 0; + for (MODREF* mr = imte->pMR ; mr != NULL ; mr = mr->pNextMteMR) + { + MODREF_KEX kmr(mr); + kmr.as.conf = NULL; + kmr.as.flags = 0; + } } } @@ -706,17 +714,22 @@ void dump_imtes(void) int total = 0; dbgprintf("Dumping IMTEs...\n"); - dbgprintf("%-4s %-12s %-7s %s %s\n", "No.", "Process", "Config", "Fl", "Module"); for (WORD i = 0 ; i < imteMax ; i++) { IMTE_KEX* imte = (IMTE_KEX*) pmteModTable[i]; if (imte) { - dbgprintf("#%-3d %-12s %-7s %02x %s\n", i, - pmteModTable[imte->pMR->ppdb->pExeMODREF->mteIndex]->pszSModName, - imte->config ? imte->config->get_name() : "unknown", - imte->flags, - imte->pszFileName); + dbgprintf("%s\n", imte->pszFileName); + + for (MODREF* mr = imte->pMR ; mr != NULL ; mr = mr->pNextMteMR) + { + MODREF_KEX kmr(mr); + dbgprintf("\t%02x %-7s %-12s\n", + kmr.as.flags, + kmr.as.conf ? kmr.as.conf->get_name() : "none", + pmteModTable[mr->ppdb->pExeMODREF->mteIndex]->pszModName); + } + total++; } } @@ -765,6 +778,7 @@ int resolver_init() } jtab = (PLONG) dseg->jtab; + FLoadTreeNotify = (FLoadTreeNotify_t) jtab[JTAB_FLD_TRN]; system_path_len = GetSystemDirectory(system_path, sizeof(system_path)); RegOpenKey(HKEY_LOCAL_MACHINE, "Software\\KernelEx\\KnownDLLs", &known_dlls_key); @@ -790,6 +804,7 @@ void resolver_hook() old_jtab[JTAB_EFN_DYN] = InterlockedExchange(jtab + JTAB_EFN_DYN, (LONG) ExportFromNameDynamic_thunk); old_jtab[JTAB_EFN_STA] = InterlockedExchange(jtab + JTAB_EFN_STA, (LONG) ExportFromNameStatic_thunk); old_jtab[JTAB_KNO_DLL] = InterlockedExchange(jtab + JTAB_KNO_DLL, (LONG) IsKnownKexDLL); + old_jtab[JTAB_FLD_TRN] = InterlockedExchange(jtab + JTAB_FLD_TRN, (LONG) KexLoadTreeNotify); } void resolver_unhook() diff --git a/core/resolver.h b/core/resolver.h old mode 100644 new mode 100755 index cf6a6b6..0b97f75 --- a/core/resolver.h +++ b/core/resolver.h @@ -30,6 +30,7 @@ #define LDR_OVERRIDE_PROC_MOD 2 /* use same configuration and flags for all modules in a process */ #define LDR_LOG_APIS 4 /* enable API tracing */ #define LDR_FILTER_APIS 8 /* allow to control single APIs - enable, disable, switch */ +#define LDR_NO_INHERIT 16 /* don't inherit configuration and flags to child processes */ #define LDR_VALID_FLAG 128 /* denotes that flags field is valid */ #pragma pack(push,1) @@ -38,26 +39,40 @@ class ApiConfiguration; struct IMTE_KEX : public IMTE { - ApiConfiguration* config; /* pointer to API configuration required by the module - * 0 - not checked */ - BYTE flags; /* loader flags */ - BYTE unused; /* unused */ WORD mod_index; /* this value minus 1 is index into MODAPI table in API configurations * 0xff00-0xfffe - api libraries * 0 - not checked, 0xffff - not an overridden module */ }; +struct appsetting +{ + appsetting() : conf(NULL), flags(0) {} + ApiConfiguration* conf; /* pointer to API configuration used by the module */ + unsigned long flags; /* resolver flags */ +}; + + +struct MODREF_KEX +{ + MODREF_KEX(PMODREF pmr) : mr(*pmr), + as(*(appsetting*)(mr.ImplicitImports + mr.cImportedModules)) {} + MODREF& mr; + appsetting& as; +}; + /* Creates a stub that calls address specified in the constructor. */ class redir_stub { public: - redir_stub(unsigned long target, bool make_call = false) : c_eax(0xb8), - v_eax(target), c_jmp(make_call ? 0xd0ff : 0xe0ff) {} + redir_stub(unsigned long target, bool make_call = true) + { + op = make_call ? 0xe8 : 0xe9; + addr = target - (unsigned long(this) + 5); + } private: - unsigned char c_eax; - unsigned long v_eax; - unsigned short c_jmp; + unsigned char op; + unsigned long addr; }; struct config_params @@ -73,8 +88,8 @@ struct config_params bool are_extensions_enabled(); DWORD encode_address(DWORD addr, const ApiLibrary* apilib); PROC WINAPI iGetProcAddress(HMODULE hModule, LPCSTR lpProcName); -PROC WINAPI ExportFromOrdinal(IMTE_KEX* target, MODREF* caller, PMODREF** refmod, WORD ordinal); -PROC WINAPI ExportFromName(IMTE_KEX* target, MODREF* caller, PMODREF** refmod, WORD hint, LPCSTR name); +PROC WINAPI ExportFromOrdinal(IMTE_KEX* target, MODREF* caller, BOOL is_static, WORD ordinal); +PROC WINAPI ExportFromName(IMTE_KEX* target, MODREF* caller, BOOL is_static, WORD hint, LPCSTR name); #ifdef _DEBUG void dump_imtes(void); diff --git a/core/resource.h b/core/resource.h old mode 100644 new mode 100755 index 3110b14..d007f18 --- a/core/resource.h +++ b/core/resource.h @@ -14,13 +14,14 @@ #define IDM_TOFILE 40001 #define IDM_CLEAR 40002 #define IDM_FILTER 40003 +#define IDM_ENABLE 40004 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 104 -#define _APS_NEXT_COMMAND_VALUE 40004 +#define _APS_NEXT_COMMAND_VALUE 40005 #define _APS_NEXT_CONTROL_VALUE 1006 #define _APS_NEXT_SYMED_VALUE 101 #endif diff --git a/core/sharedmem.cpp b/core/sharedmem.cpp old mode 100644 new mode 100755 diff --git a/core/sharedmem.h b/core/sharedmem.h old mode 100644 new mode 100755 diff --git a/core/storage.cpp b/core/storage.cpp deleted file mode 100644 index 041d8b8..0000000 --- a/core/storage.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - * KernelEx - * Copyright (C) 2009, Xeno86 - * - * This file is part of KernelEx source code. - * - * KernelEx is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; version 2 of the License. - * - * KernelEx is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include -#include "storage.h" -#include "internals.h" -#include "debug.h" - -struct PDB_KEX : PDB98 -{ - void* kex_data_storage; -}; - -const int storage::storage_size = 0x1000; - -storage* storage::get_storage(bool alloc) -{ - PDB_KEX* pdb = (PDB_KEX*) *pppdbCur; - storage* s = (storage*) pdb->kex_data_storage; - - if (!s && alloc) - { - pdb->kex_data_storage = VirtualAlloc(NULL, storage_size, - MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); - DBGASSERT(pdb->kex_data_storage != NULL); - memset(pdb->kex_data_storage, 0, storage_size); - s = (storage*) pdb->kex_data_storage; - s->size = 0; - } - - return s; -} - -void storage::return_storage() -{ - PDB_KEX* pdb = (PDB_KEX*) *pppdbCur; - if (pdb->kex_data_storage) - { - BOOL ret = VirtualFree(pdb->kex_data_storage, 0, MEM_RELEASE); - DBGASSERT(ret != FALSE); - pdb->kex_data_storage = NULL; - } -} diff --git a/core/structs.h b/core/structs.h old mode 100644 new mode 100755 index 4b9265a..eea8e6b --- a/core/structs.h +++ b/core/structs.h @@ -58,6 +58,21 @@ typedef struct _HANDLE_TABLE { HANDLE_TABLE_ENTRY array[1]; // An array (number is given by cEntries) } HANDLE_TABLE, *PHANDLE_TABLE; +// List node +typedef struct _NODE +{ + struct _NODE* next; + struct _NODE* prev; + PVOID data; +} NODE, *PNODE; + +// List +typedef struct _LIST { + PNODE firstNode; + PNODE lastNode; + PNODE currentNode; +} LIST, *PLIST; + struct _PDB98; // MODREF @@ -145,16 +160,15 @@ typedef struct _PDB98 { // Size = 0xC4 (from Kernel32) PHANDLE_TABLE pHandleTable; // 44 Pointer to Handle Table struct _PDB98* ParentPDB; // 48 Pointer to parent process (PDB) PMODREF MODREFList; // 4C Pointer to list of modules - DWORD ThreadList; // 50 Pointer to list of threads + PLIST ThreadList; // 50 Pointer to list of threads DWORD DebuggeeCB; // 54 Debuggee context block DWORD LocalHeapFreeHead; // 58 Free list for process default heap DWORD InitialRing0ID; // 5C Meaning unknown CRITICAL_SECTION CriticalSection; // 60 For synchronizing threads - DWORD Unknown4[3]; // 78 - DWORD pConsole; // 84 Output console - DWORD tlsInUseBits1; // 88 Status of TLS indexes 0 - 31 - DWORD tlsInUseBits2; // 8C Status of TLS indexes 32 - 63 - DWORD ProcessDWORD; // 90 Undocumented API GetProcessDword, meaning unknown + DWORD Unknown4[2]; // 78 + DWORD pConsole; // 80 Output console + DWORD tlsInUseBits[3]; // 84 Status of TLS indexes + DWORD ProcessDWORD; // 90 Undocumented API GetProcessDword - user data struct _PDB98* ProcessGroup; // 94 Master process PDB (in debugging) PMODREF pExeMODREF; // 98 Points to exe's module structure DWORD TopExcFilter; // 9C SetUnhandledExceptionFilter @@ -171,60 +185,6 @@ typedef struct _PDB98 { // Size = 0xC4 (from Kernel32) DWORD Unknown6; // C0 } PDB98, *PPDB98; -// Process Database -typedef struct _PDBME { // Size = 0xC4 (from Kernel32) - BYTE Type; // 00 Kernel object type = K32OBJ_PROCESS (6) - BYTE Unknown_A; // 01 (align ?) - WORD cReference; // 02 Number of references to process - DWORD Unknown_B; // 04 Pointer to ??? - DWORD Unknown1; // 08 (zero) - DWORD pEvent; // 0C Event for process waiting - DWORD TerminationStatus; // 10 GetExitCodeProcess - DWORD Unknown2; // 14 May be used for private purposes - DWORD DefaultHeap; // 18 GetProcessHeap - DWORD MemoryContext; // 1C Pointer to process context - DWORD Flags; // 20 Flags - DWORD pPSP; // 24 Linear address of DOS PSP - WORD PSPSelector; // 28 Selector to DOS PSP - WORD MTEIndex; // 2A Index into global module table - WORD cThreads; // 2C Threads.ItemCount - WORD cNotTermThreads; // 2E Threads.ItemCount - WORD Unknown3; // 30 (zero) - WORD cRing0Threads; // 32 Normally Threads.ItemCount (except kernel32) - HANDLE HeapHandle; // 34 Kernel32 shared heap - DWORD w16TDB; // 38 Win16 task database selector - DWORD MemMappedFiles; // 3C List of memory mapped files - PEDB pEDB; // 40 Pointer to Environment Database - PHANDLE_TABLE pHandleTable; // 44 Pointer to Handle Table - struct _PDBME* ParentPDB; // 48 Pointer to parent process (PDB) - PMODREF MODREFList; // 4C Pointer to list of modules - DWORD ThreadList; // 50 Pointer to list of threads - DWORD DebuggeeCB; // 54 Debuggee context block - DWORD LocalHeapFreeHead; // 58 Free list for process default heap - DWORD InitialRing0ID; // 5C Meaning unknown - CRITICAL_SECTION CriticalSection; // 60 For synchronizing threads - DWORD Unknown4[2]; // 78 - DWORD pConsole; // 80 Output console - DWORD tlsInUseBits1; // 84 Status of TLS indexes 0 - 31 - DWORD tlsInUseBits2; // 88 Status of TLS indexes 32 - 63 - DWORD ProcessDWORD; // 8C Undocumented API GetProcessDword, meaning unknown - DWORD Unknown_C; // 90 Unknown - struct _PDBME* ProcessGroup; // 94 Master process PDB (in debugging) - PMODREF pExeMODREF; // 98 Points to exe's module structure - DWORD TopExcFilter; // 9C SetUnhandledExceptionFilter - DWORD PriorityClass; // A0 PriorityClass (8 = NORMAL) - DWORD HeapList; // A4 List of heaps - DWORD HeapHandleList; // A8 List of moveable memory blocks - DWORD HeapPointer; // AC Pointer to one moveable memory block, meaning unknown - DWORD pConsoleProvider; // B0 Console for DOS apps - WORD EnvironSelector; // B4 Environment database selector - WORD ErrorMode; // B6 SetErrorMode - DWORD pEventLoadFinished; // B8 Signaled when the process has finished loading - WORD UTState; // BC Universal thunking, meaning unknown - WORD Unknown5; // BE (zero) - DWORD Unknown6; // C0 -} PDBME, *PPDBME; - // Thread Information Block (FS:[0x18]) typedef struct _TIB98 { // Size = 0x38 PSEH pvExcept; // 00 Head of exception record list @@ -240,8 +200,8 @@ typedef struct _TIB98 { // Size = 0x38 DWORD DebugContext; // 20 Pointer to debug context structure DWORD pCurrentPriority; // 24 Pointer to DWORD containing current priority level DWORD pvQueue; // 28 Message Queue selector - PVOID *pvTLSArray; // 2C Thread Local Storage (TLS) array - PVOID *pProcess; // 30 Pointer to owning process database (PDB) + DWORD *pvTLSArray; // 2C Pointer to TDB.TlsSlots + PDB98 *pProcess; // 30 Pointer to owning process database (PDB) DWORD Unknown; // 34 Pointer to ??? } TIB98, *PTIB98; @@ -262,8 +222,13 @@ typedef struct _TDB98 { // Size = 0x228 (from Kernel32) DWORD cHandles; // 50 Handle count DWORD Ring0Thread; // 54 R0 thread control block (TCB) TDBX98 *pTDBX; // 58 R0 thread database extension (TDBX) - DWORD un1[109]; // 5C + DWORD un1[3]; // 5C + DWORD LastError; // 68 GetLastError code value + DWORD un2[9]; // 6C + LPVOID TlsSlots[80]; // 90 Thread Local Storage + DWORD un3[16]; // 1D0 DWORD APISuspendCount; // 210 Count of SuspendThread's minus ResumeThread's + DWORD un4[5]; // 214 } TDB98, *PTDB98; typedef struct _TDBME { // Size = 0x228 (from Kernel32) @@ -280,10 +245,15 @@ typedef struct _TDBME { // Size = 0x228 (from Kernel32) DWORD cHandles; // 50 Handle count DWORD Ring0Thread; // 54 R0 thread control block (TCB) DWORD Unknown3; // 58 Selector for ??? - DWORD un1[11]; // 5C - TDBX98 *pTDBX; // 88 - DWORD un2[97]; // 8C + DWORD un1[8]; // 5C + DWORD LastError; // 7C GetLastError code value + DWORD un2[2]; // 80 + TDBX98 *pTDBX; // 88 R0 thread database extension (TDBX) + DWORD Unknown4; // 8C + DWORD TlsSlots[80]; // 90 Thread Local Storage + DWORD un3[16]; // 1D0 DWORD APISuspendCount; // 210 Count of SuspendThread's minus ResumeThread's + DWORD un4[5]; // 214 } TDBME, *PTDBME; // Thread database extension diff --git a/core/thunks.cpp b/core/thunks.cpp old mode 100644 new mode 100755 index 2d7057b..820a62f --- a/core/thunks.cpp +++ b/core/thunks.cpp @@ -39,8 +39,7 @@ __asm { push dword ptr [esp+4] //return address mov eax, [ebp+8] mov [esp+8], eax //caller MODREF - lea eax, [ebp-4Ch] - mov dword ptr [esp+12], eax + mov dword ptr [esp+12], 1 jmp ExportFromOrdinal } } @@ -60,8 +59,7 @@ __asm { push dword ptr [esp+4] //return address mov eax, [ebp+8] mov [esp+8], eax //caller MODREF - lea eax, [ebp-4Ch] - mov dword ptr [esp+12], eax + mov dword ptr [esp+12], 1 jmp ExportFromName } } diff --git a/core/thunks.h b/core/thunks.h old mode 100644 new mode 100755 diff --git a/core/wildcmp.cpp b/core/wildcmp.cpp old mode 100644 new mode 100755 diff --git a/core/wildcmp.h b/core/wildcmp.h old mode 100644 new mode 100755 diff --git a/kexCOM/factory.cpp b/kexCOM/factory.cpp new file mode 100755 index 0000000..6509993 --- /dev/null +++ b/kexCOM/factory.cpp @@ -0,0 +1,97 @@ +/* + * KernelEx + * Copyright (C) 2009, Xeno86 + * + * This file is part of KernelEx source code. + * + * KernelEx is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. + * + * KernelEx is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "factory.h" +#include "server.h" +#include "shelllink.h" + +CFactory::CFactory(IClassFactory* prevCF) +{ + m_cRef = 1; + m_prevCF = prevCF; + InterlockedIncrement(&g_LockCount); +} + +CFactory::~CFactory() +{ + m_prevCF->Release(); + InterlockedDecrement(&g_LockCount); +} + +STDMETHODIMP CFactory::QueryInterface(const IID& iid, void** ppv) +{ + if (iid == IID_IUnknown) + *ppv = static_cast(this); + else if (iid == IID_IClassFactory) + *ppv = static_cast(this); + else + { + *ppv = NULL; + return E_NOINTERFACE; + } + AddRef(); + return S_OK; +} + +STDMETHODIMP_(ULONG) CFactory::AddRef() +{ + return InterlockedIncrement(&m_cRef); +} + +STDMETHODIMP_(ULONG) CFactory::Release() +{ + if (InterlockedDecrement(&m_cRef) == 0) + { + delete this; + return 0; + } + return m_cRef; +} + +STDMETHODIMP CFactory::CreateInstance(IUnknown* pUnkOuter, const IID& iid, void** ppv) +{ + HRESULT hr; + + if (pUnkOuter != NULL) + return CLASS_E_NOAGGREGATION; + + IUnknown* pUnk; + hr = m_prevCF->CreateInstance(NULL, IID_IUnknown, (void**) &pUnk); + if (FAILED(hr)) + return hr; + + CShellLink* pObject = new CShellLink(pUnk); + if (pObject == NULL) + return E_OUTOFMEMORY; + + hr = pObject->QueryInterface(iid, ppv); + pObject->Release(); + return hr; +} + +STDMETHODIMP CFactory::LockServer(BOOL bLock) +{ + if (bLock) + InterlockedIncrement(&g_LockCount); + else + InterlockedDecrement(&g_LockCount); + return S_OK; +} diff --git a/kexCOM/factory.h b/kexCOM/factory.h new file mode 100755 index 0000000..0a01219 --- /dev/null +++ b/kexCOM/factory.h @@ -0,0 +1,49 @@ +/* + * KernelEx + * Copyright (C) 2009, Xeno86 + * + * This file is part of KernelEx source code. + * + * KernelEx is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. + * + * KernelEx is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __FACTORY_H +#define __FACTORY_H + +#include + +class CFactory : public IClassFactory +{ +public: + // Constructor + CFactory(IClassFactory* prevCF); + // Destructor + ~CFactory(); + + // IUnknown + STDMETHODIMP QueryInterface(const IID& iid, void** ppv); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + // Interface IClassFactory + STDMETHODIMP CreateInstance(IUnknown* pUnknownOuter, const IID& iid, void** ppv); + STDMETHODIMP LockServer(BOOL bLock); + +private: + long m_cRef; + IClassFactory* m_prevCF; +}; + +#endif diff --git a/kexCOM/kexCOM.dsp b/kexCOM/kexCOM.dsp new file mode 100755 index 0000000..e7ce2b4 --- /dev/null +++ b/kexCOM/kexCOM.dsp @@ -0,0 +1,133 @@ +# Microsoft Developer Studio Project File - Name="kexCOM" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=kexCOM - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "kexCOM.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "kexCOM.mak" CFG="kexCOM - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "kexCOM - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "kexCOM - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "kexCOM - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "KEXCOM_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "KEXCOM_EXPORTS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x415 /d "NDEBUG" +# ADD RSC /l 0x415 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ../kexcrt/kexcrt.lib libc.lib /nologo /entry:"DllMain@12" /dll /map /machine:I386 /nodefaultlib /OPT:NOWIN98 +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "kexCOM - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "KEXCOM_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "KEXCOM_EXPORTS" /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x415 /d "_DEBUG" +# ADD RSC /l 0x415 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ../kexcrt/kexcrt.lib libc.lib /nologo /entry:"DllMain@12" /dll /debug /machine:I386 /nodefaultlib /OPT:NOWIN98 +# SUBTRACT LINK32 /pdb:none + +!ENDIF + +# Begin Target + +# Name "kexCOM - Win32 Release" +# Name "kexCOM - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\factory.cpp +# End Source File +# Begin Source File + +SOURCE=.\server.cpp +# End Source File +# Begin Source File + +SOURCE=.\server.def +# End Source File +# Begin Source File + +SOURCE=.\shelllink.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\factory.h +# End Source File +# Begin Source File + +SOURCE=.\server.h +# End Source File +# Begin Source File + +SOURCE=.\shelllink.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/kexCOM/server.cpp b/kexCOM/server.cpp new file mode 100755 index 0000000..62a7178 --- /dev/null +++ b/kexCOM/server.cpp @@ -0,0 +1,168 @@ +/* + * KernelEx + * Copyright (C) 2009, Xeno86 + * + * This file is part of KernelEx source code. + * + * KernelEx is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. + * + * KernelEx is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include "server.h" +#include "factory.h" + +long g_LockCount; +HMODULE g_hModule; +static HMODULE hShell32; +static LPFNGETCLASSOBJECT SHGetClassObject; + + +/* Hall of shame */ +static const char* blacklist[] = { + "COOLTYPE.DLL", /* Adobe Acrobat Reader 5.0.5, Adobe Photoshop 7.0 */ + NULL, +}; + + +static bool is_blacklisted() +{ + for (int i = 0 ; blacklist[i] ; i++) + { + if (GetModuleHandle(blacklist[i])) + return true; + } + return false; +} + + +static bool is_shell32_v5() +{ + DLLGETVERSIONPROC DllGetVersion; + DLLVERSIONINFO dvi; + HRESULT hr; + + dvi.cbSize = sizeof(dvi); + + DllGetVersion = (DLLGETVERSIONPROC) GetProcAddress(hShell32, "DllGetVersion"); + if (!DllGetVersion) + return false; + + hr = DllGetVersion(&dvi); + if (SUCCEEDED(hr) && dvi.dwMajorVersion >= 5) + return true; + + return false; +} + + +static bool is_failsafe_mode() +{ + static int s = -1; + if (s == -1) + s = GetSystemMetrics(SM_CLEANBOOT); + return s != 0; +} + + +STDAPI DllCanUnloadNow() +{ + return (g_LockCount > 0) ? S_FALSE : S_OK; +} + + +STDAPI DllRegisterServer() +{ + LONG result; + char filename[MAX_PATH]; + + // SHELL32 v5.0 and above has ShellLinkW - kexCOM is not needed + if (is_shell32_v5()) + return S_OK; + + GetModuleFileName(g_hModule, filename, sizeof(filename)); + result = RegSetValue(HKEY_CLASSES_ROOT, + "CLSID\\{00021401-0000-0000-C000-000000000046}\\InProcServer32", + REG_SZ, filename, strlen(filename)); + + return (result == ERROR_SUCCESS) ? S_OK : E_FAIL; +} + + +STDAPI DllUnregisterServer() +{ + LONG result; + const char szShell32[] = { "shell32.dll" }; + + result = RegSetValue(HKEY_CLASSES_ROOT, + "CLSID\\{00021401-0000-0000-C000-000000000046}\\InProcServer32", + REG_SZ, szShell32, strlen(szShell32)); + + return (result == ERROR_SUCCESS) ? S_OK : E_FAIL; +} + + +STDAPI DllGetClassObject(const CLSID& clsid, const IID& iid, void** ppv) +{ + HRESULT hr; + + if (is_failsafe_mode()) + return SHGetClassObject(clsid, iid, ppv); + + if (clsid == CLSID_ShellLink) + { + IClassFactory* pcf; + + hr = SHGetClassObject(CLSID_ShellLink, IID_IClassFactory, (void**) &pcf); + if (FAILED(hr)) + return hr; + + CFactory* factory = new CFactory(pcf); + if (!factory) + return E_OUTOFMEMORY; + + hr = factory->QueryInterface(iid, ppv); + factory->Release(); + return hr; + } + else + { + *ppv = NULL; + return CLASS_E_CLASSNOTAVAILABLE; + } +} + + +BOOL APIENTRY DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpReserved) +{ + if (dwReason == DLL_PROCESS_ATTACH) + { + if (is_blacklisted()) + return FALSE; + + g_hModule = hModule; + DisableThreadLibraryCalls(hModule); + + hShell32 = LoadLibrary("SHELL32"); + SHGetClassObject = (LPFNGETCLASSOBJECT) GetProcAddress(hShell32, "DllGetClassObject"); + } + else if (dwReason == DLL_PROCESS_DETACH) + { + FreeLibrary(hShell32); + } + + return TRUE; +} diff --git a/kexCOM/server.def b/kexCOM/server.def new file mode 100755 index 0000000..7795ee5 --- /dev/null +++ b/kexCOM/server.def @@ -0,0 +1,6 @@ + +EXPORTS +DllRegisterServer PRIVATE +DllUnregisterServer PRIVATE +DllGetClassObject PRIVATE +DllCanUnloadNow PRIVATE \ No newline at end of file diff --git a/kexCOM/server.h b/kexCOM/server.h new file mode 100755 index 0000000..b0402d9 --- /dev/null +++ b/kexCOM/server.h @@ -0,0 +1,28 @@ +/* + * KernelEx + * Copyright (C) 2009, Xeno86 + * + * This file is part of KernelEx source code. + * + * KernelEx is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. + * + * KernelEx is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _SERVER_H +#define _SERVER_H + +extern long g_LockCount; +extern HMODULE g_hModule; + +#endif // _SERVER_H diff --git a/kexCOM/shelllink.cpp b/kexCOM/shelllink.cpp new file mode 100755 index 0000000..735cd90 --- /dev/null +++ b/kexCOM/shelllink.cpp @@ -0,0 +1,703 @@ +/* + * KernelEx + * Copyright (C) 2009, Xeno86 + * + * This file is part of KernelEx source code. + * + * KernelEx is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. + * + * KernelEx is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include "shelllink.h" +#include "server.h" + + +// Constructor +CShellLink::CShellLink(IUnknown *prevUnk) +{ + InterlockedIncrement(&g_LockCount); + m_cRef = 1; + m_Unknown = prevUnk; + m_ShellLinkA = NULL; + m_PersistFile = NULL; + m_PersistStream = NULL; + m_ShellExtInit = NULL; + m_ContextMenu = NULL; + m_ContextMenu2 = NULL; + m_DropTarget = NULL; + m_ExtractIconA = NULL; +} + + +// Destructor +CShellLink::~CShellLink() +{ + InterlockedDecrement(&g_LockCount); + if (m_ShellLinkA) + m_ShellLinkA->Release(); + if (m_PersistFile) + m_PersistFile->Release(); + if (m_PersistStream) + m_PersistStream->Release(); + if (m_ShellExtInit) + m_ShellExtInit->Release(); + if (m_ContextMenu) + m_ContextMenu->Release(); + if (m_ContextMenu2) + m_ContextMenu2->Release(); + if (m_DropTarget) + m_DropTarget->Release(); + if (m_ExtractIconA) + m_ExtractIconA->Release(); + m_Unknown->Release(); +} + + +// IUnknown +HRESULT STDMETHODCALLTYPE CShellLink::QueryInterface( + /* [in] */ REFIID riid, + /* [iid_is][out] */ void **ppvObject) +{ + HRESULT hr; + + if (riid == IID_IUnknown) + { + hr = S_OK; + *ppvObject = static_cast(static_cast(this)); + } + else if (riid == IID_IShellLinkA) + { + if (m_ShellLinkA) + m_ShellLinkA->Release(); + hr = m_Unknown->QueryInterface(IID_IShellLinkA, (void**) &m_ShellLinkA); + *ppvObject = static_cast(this); + } + else if (riid == IID_IShellLinkW) + { + if (m_ShellLinkA) + m_ShellLinkA->Release(); + hr = m_Unknown->QueryInterface(IID_IShellLinkA, (void**) &m_ShellLinkA); + *ppvObject = static_cast(this); + } + else if (riid == IID_IPersistFile) + { + if (m_PersistFile) + m_PersistFile->Release(); + hr = m_Unknown->QueryInterface(IID_IPersistFile, (void**) &m_PersistFile); + *ppvObject = static_cast(this); + } + else if (riid == IID_IPersistStream) + { + if (m_PersistStream) + m_PersistStream->Release(); + hr = m_Unknown->QueryInterface(IID_IPersistStream, (void**) &m_PersistStream); + *ppvObject = static_cast(this); + } + else if (riid == IID_IShellExtInit) + { + if (m_ShellExtInit) + m_ShellExtInit->Release(); + hr = m_Unknown->QueryInterface(IID_IShellExtInit, (void**) &m_ShellExtInit); + *ppvObject = static_cast(this); + } + else if (riid == IID_IContextMenu) + { + if (m_ContextMenu) + m_ContextMenu->Release(); + hr = m_Unknown->QueryInterface(IID_IContextMenu, (void**) &m_ContextMenu); + *ppvObject = static_cast(this); + } + else if (riid == IID_IContextMenu2) + { + if (m_ContextMenu2) + m_ContextMenu2->Release(); + hr = m_Unknown->QueryInterface(IID_IContextMenu2, (void**) &m_ContextMenu2); + *ppvObject = static_cast(this); + } + else if (riid == IID_IDropTarget) + { + if (m_DropTarget) + m_DropTarget->Release(); + hr = m_Unknown->QueryInterface(IID_IDropTarget, (void**) &m_DropTarget); + *ppvObject = static_cast(this); + } + else if (riid == IID_IExtractIconA) + { + if (m_ExtractIconA) + m_ExtractIconA->Release(); + hr = m_Unknown->QueryInterface(IID_IExtractIconA, (void**) &m_ExtractIconA); + *ppvObject = static_cast(this); + } + else if (riid == IID_IExtractIconW) + { + if (m_ExtractIconA) + m_ExtractIconA->Release(); + hr = m_Unknown->QueryInterface(IID_IExtractIconA, (void**) &m_ExtractIconA); + *ppvObject = static_cast(this); + } + else + { + hr = E_NOINTERFACE; + } + + if (SUCCEEDED(hr)) + AddRef(); + else + *ppvObject = NULL; + + return hr; +} + +ULONG STDMETHODCALLTYPE CShellLink::AddRef( void) +{ + return InterlockedIncrement(&m_cRef); +} + +ULONG STDMETHODCALLTYPE CShellLink::Release( void) +{ + if (InterlockedDecrement(&m_cRef) == 0) + { + delete this; + return 0; + } + return m_cRef; +} + + +// IShellLinkA +HRESULT STDMETHODCALLTYPE CShellLink::GetPath( + /* [size_is][out] */ LPSTR pszFile, + /* [in] */ int cch, + /* [full][out][in] */ WIN32_FIND_DATAA *pfd, + /* [in] */ DWORD fFlags) +{ + return m_ShellLinkA->GetPath(pszFile, cch, pfd, fFlags); +} + +HRESULT STDMETHODCALLTYPE CShellLink::GetIDList( + /* [out] */ LPITEMIDLIST *ppidl) +{ + return m_ShellLinkA->GetIDList(ppidl); +} + +HRESULT STDMETHODCALLTYPE CShellLink::SetIDList( + /* [in] */ LPCITEMIDLIST pidl) +{ + return m_ShellLinkA->SetIDList(pidl); +} + +HRESULT STDMETHODCALLTYPE CShellLink::GetDescription( + /* [size_is][out] */ LPSTR pszName, + /* [in] */ int cch) +{ + return m_ShellLinkA->GetDescription(pszName, cch); +} + +HRESULT STDMETHODCALLTYPE CShellLink::SetDescription( + /* [in] */ LPCSTR pszName) +{ + return m_ShellLinkA->SetDescription(pszName); +} + +HRESULT STDMETHODCALLTYPE CShellLink::GetWorkingDirectory( + /* [size_is][out] */ LPSTR pszDir, + /* [in] */ int cch) +{ + return m_ShellLinkA->GetWorkingDirectory(pszDir, cch); +} + +HRESULT STDMETHODCALLTYPE CShellLink::SetWorkingDirectory( + /* [in] */ LPCSTR pszDir) +{ + return m_ShellLinkA->SetWorkingDirectory(pszDir); +} + +HRESULT STDMETHODCALLTYPE CShellLink::GetArguments( + /* [size_is][out] */ LPSTR pszArgs, + /* [in] */ int cch) +{ + return m_ShellLinkA->GetArguments(pszArgs, cch); +} + +HRESULT STDMETHODCALLTYPE CShellLink::SetArguments( + /* [in] */ LPCSTR pszArgs) +{ + return m_ShellLinkA->SetArguments(pszArgs); +} + +HRESULT STDMETHODCALLTYPE CShellLink::GetHotkey( + /* [out] */ WORD *pwHotkey) +{ + return m_ShellLinkA->GetHotkey(pwHotkey); +} + +HRESULT STDMETHODCALLTYPE CShellLink::SetHotkey( + /* [in] */ WORD wHotkey) +{ + return m_ShellLinkA->SetHotkey(wHotkey); +} + +HRESULT STDMETHODCALLTYPE CShellLink::GetShowCmd( + /* [out] */ int *piShowCmd) +{ + return m_ShellLinkA->GetShowCmd(piShowCmd); +} + +HRESULT STDMETHODCALLTYPE CShellLink::SetShowCmd( + /* [in] */ int iShowCmd) +{ + return m_ShellLinkA->SetShowCmd(iShowCmd); +} + +HRESULT STDMETHODCALLTYPE CShellLink::GetIconLocation( + /* [size_is][out] */ LPSTR pszIconPath, + /* [in] */ int cch, + /* [out] */ int *piIcon) +{ + return m_ShellLinkA->GetIconLocation(pszIconPath, cch, piIcon); +} + +HRESULT STDMETHODCALLTYPE CShellLink::SetIconLocation( + /* [in] */ LPCSTR pszIconPath, + /* [in] */ int iIcon) +{ + return m_ShellLinkA->SetIconLocation(pszIconPath, iIcon); +} + +HRESULT STDMETHODCALLTYPE CShellLink::SetRelativePath( + /* [in] */ LPCSTR pszPathRel, + /* [in] */ DWORD dwReserved) +{ + return m_ShellLinkA->SetRelativePath(pszPathRel, dwReserved); +} + +HRESULT STDMETHODCALLTYPE CShellLink::Resolve( + /* [in] */ HWND hwnd, + /* [in] */ DWORD fFlags) +{ + return m_ShellLinkA->Resolve(hwnd, fFlags); +} + +HRESULT STDMETHODCALLTYPE CShellLink::SetPath( + /* [in] */ LPCSTR pszFile) +{ + return m_ShellLinkA->SetPath(pszFile); +} + + +// IShellLinkW +HRESULT STDMETHODCALLTYPE CShellLink::GetPath( + /* [size_is][out] */ LPWSTR pszFile, + /* [in] */ int cch, + /* [full][out][in] */ WIN32_FIND_DATAW *pfd, + /* [in] */ DWORD fFlags) +{ + HRESULT hr; + LPSTR pszFileA; + WIN32_FIND_DATAA fdA; + + pszFileA = (LPSTR) alloca(cch); + hr = m_ShellLinkA->GetPath(pszFileA, cch, &fdA, fFlags); + if (FAILED(hr)) + return hr; + MultiByteToWideChar(CP_ACP, 0, pszFileA, -1, pszFile, cch); + + if (pfd) + { + pfd->dwFileAttributes = fdA.dwFileAttributes; + pfd->ftCreationTime = fdA.ftCreationTime; + pfd->ftLastAccessTime = fdA.ftLastAccessTime; + pfd->ftLastWriteTime = fdA.ftLastWriteTime; + pfd->nFileSizeHigh = fdA.nFileSizeHigh; + pfd->nFileSizeLow = fdA.nFileSizeLow; + pfd->dwReserved0 = fdA.dwReserved0; + pfd->dwReserved1 = fdA.dwReserved1; + MultiByteToWideChar(CP_ACP, 0, fdA.cFileName, -1, pfd->cFileName, sizeof(pfd->cFileName)); + MultiByteToWideChar(CP_ACP, 0, fdA.cAlternateFileName, -1, pfd->cAlternateFileName, sizeof(pfd->cAlternateFileName)); + } + + return hr; +} + +//HRESULT STDMETHODCALLTYPE CShellLink::GetIDList( +// /* [out] */ LPITEMIDLIST *ppidl) +//{ +//} +// +//HRESULT STDMETHODCALLTYPE CShellLink::SetIDList( +// /* [in] */ LPCITEMIDLIST pidl) +//{ +//} + +HRESULT STDMETHODCALLTYPE CShellLink::GetDescription( + /* [size_is][out] */ LPWSTR pszName, + int cch) +{ + HRESULT hr; + LPSTR pszNameA; + + pszNameA = (LPSTR) alloca(cch); + hr = m_ShellLinkA->GetDescription(pszNameA, cch); + if (SUCCEEDED(hr)) + MultiByteToWideChar(CP_ACP, 0, pszNameA, -1, pszName, cch); + return hr; +} + +HRESULT STDMETHODCALLTYPE CShellLink::SetDescription( + /* [in] */ LPCWSTR pszName) +{ + LPSTR pszNameA; + int lenA; + + lenA = (lstrlenW(pszName) + 1) * 2; + pszNameA = (LPSTR) alloca(lenA); + WideCharToMultiByte(CP_ACP, 0, pszName, -1, pszNameA, lenA, NULL, NULL); + return m_ShellLinkA->SetDescription(pszNameA); +} + +HRESULT STDMETHODCALLTYPE CShellLink::GetWorkingDirectory( + /* [size_is][out] */ LPWSTR pszDir, + int cch) +{ + HRESULT hr; + LPSTR pszDirA; + + pszDirA = (LPSTR) alloca(cch); + hr = m_ShellLinkA->GetWorkingDirectory(pszDirA, cch); + if (SUCCEEDED(hr)) + MultiByteToWideChar(CP_ACP, 0, pszDirA, -1, pszDir, cch); + return hr; +} + +HRESULT STDMETHODCALLTYPE CShellLink::SetWorkingDirectory( + /* [in] */ LPCWSTR pszDir) +{ + LPSTR pszDirA; + int lenA; + + lenA = (lstrlenW(pszDir) + 1) * 2; + pszDirA = (LPSTR) alloca(lenA); + WideCharToMultiByte(CP_ACP, 0, pszDir, -1, pszDirA, lenA, NULL, NULL); + return m_ShellLinkA->SetWorkingDirectory(pszDirA); +} + +HRESULT STDMETHODCALLTYPE CShellLink::GetArguments( + /* [size_is][out] */ LPWSTR pszArgs, + int cch) +{ + HRESULT hr; + LPSTR pszArgsA; + + pszArgsA = (LPSTR) alloca(cch); + hr = m_ShellLinkA->GetArguments(pszArgsA, cch); + if (SUCCEEDED(hr)) + MultiByteToWideChar(CP_ACP, 0, pszArgsA, -1, pszArgs, cch); + return hr; +} + +HRESULT STDMETHODCALLTYPE CShellLink::SetArguments( + /* [in] */ LPCWSTR pszArgs) +{ + LPSTR pszArgsA; + int lenA; + + lenA = (lstrlenW(pszArgs) + 1) * 2; + pszArgsA = (LPSTR) alloca(lenA); + WideCharToMultiByte(CP_ACP, 0, pszArgs, -1, pszArgsA, lenA, NULL, NULL); + return m_ShellLinkA->SetArguments(pszArgsA); +} + +//HRESULT STDMETHODCALLTYPE CShellLink::GetHotkey( +// /* [out] */ WORD *pwHotkey) +//{ +//} +// +//HRESULT STDMETHODCALLTYPE CShellLink::SetHotkey( +// /* [in] */ WORD wHotkey) +//{ +//} +// +//HRESULT STDMETHODCALLTYPE CShellLink::GetShowCmd( +// /* [out] */ int *piShowCmd) +//{ +//} +// +//HRESULT STDMETHODCALLTYPE CShellLink::SetShowCmd( +// /* [in] */ int iShowCmd) +//{ +//} + +HRESULT STDMETHODCALLTYPE CShellLink::GetIconLocation( + /* [size_is][out] */ LPWSTR pszIconPath, + /* [in] */ int cch, + /* [out] */ int *piIcon) +{ + HRESULT hr; + LPSTR pszIconPathA; + + pszIconPathA = (LPSTR) alloca(cch); + hr = m_ShellLinkA->GetIconLocation(pszIconPathA, cch, piIcon); + if (SUCCEEDED(hr)) + MultiByteToWideChar(CP_ACP, 0, pszIconPathA, -1, pszIconPath, cch); + return hr; +} + +HRESULT STDMETHODCALLTYPE CShellLink::SetIconLocation( + /* [in] */ LPCWSTR pszIconPath, + /* [in] */ int iIcon) +{ + LPSTR pszIconPathA; + int lenA; + + lenA = (lstrlenW(pszIconPath) + 1) * 2; + pszIconPathA = (LPSTR) alloca(lenA); + WideCharToMultiByte(CP_ACP, 0, pszIconPath, -1, pszIconPathA, lenA, NULL, NULL); + return m_ShellLinkA->SetIconLocation(pszIconPathA, iIcon); +} + +HRESULT STDMETHODCALLTYPE CShellLink::SetRelativePath( + /* [in] */ LPCWSTR pszPathRel, + /* [in] */ DWORD dwReserved) +{ + LPSTR pszPathRelA; + int lenA; + + lenA = (lstrlenW(pszPathRel) + 1) * 2; + pszPathRelA = (LPSTR) alloca(lenA); + WideCharToMultiByte(CP_ACP, 0, pszPathRel, -1, pszPathRelA, lenA, NULL, NULL); + return m_ShellLinkA->SetRelativePath(pszPathRelA, dwReserved); +} + +//HRESULT STDMETHODCALLTYPE CShellLink::Resolve( +// /* [in] */ HWND hwnd, +// /* [in] */ DWORD fFlags) +//{ +//} + +HRESULT STDMETHODCALLTYPE CShellLink::SetPath( + /* [in] */ LPCWSTR pszFile) +{ + LPSTR pszFileA; + int lenA; + + lenA = (lstrlenW(pszFile) + 1) * 2; + pszFileA = (LPSTR) alloca(lenA); + WideCharToMultiByte(CP_ACP, 0, pszFile, -1, pszFileA, lenA, NULL, NULL); + return m_ShellLinkA->SetPath(pszFileA); +} + + +// IPersist +HRESULT STDMETHODCALLTYPE CShellLink::GetClassID( +/* [out] */ CLSID *pClassID) +{ + return m_PersistFile->GetClassID(pClassID); +} + + +// IPersistFile +HRESULT STDMETHODCALLTYPE CShellLink::IsDirty( void) +{ + return m_PersistFile->IsDirty(); +} + +HRESULT STDMETHODCALLTYPE CShellLink::Load( + /* [in] */ LPCOLESTR pszFileName, + /* [in] */ DWORD dwMode) +{ + return m_PersistFile->Load(pszFileName, dwMode); +} + +HRESULT STDMETHODCALLTYPE CShellLink::Save( + /* [unique][in] */ LPCOLESTR pszFileName, + /* [in] */ BOOL fRemember) +{ + return m_PersistFile->Save(pszFileName, fRemember); +} + +HRESULT STDMETHODCALLTYPE CShellLink::SaveCompleted( + /* [unique][in] */ LPCOLESTR pszFileName) +{ + return m_PersistFile->SaveCompleted(pszFileName); +} + +HRESULT STDMETHODCALLTYPE CShellLink::GetCurFile( + /* [out] */ LPOLESTR *ppszFileName) +{ + return m_PersistFile->GetCurFile(ppszFileName); +} + + +// IPersistStream +//HRESULT STDMETHODCALLTYPE CShellLink::IsDirty( void) +//{ +//} + +HRESULT STDMETHODCALLTYPE CShellLink::Load( + /* [unique][in] */ IStream *pStm) +{ + return m_PersistStream->Load(pStm); +} + +HRESULT STDMETHODCALLTYPE CShellLink::Save( + /* [unique][in] */ IStream *pStm, + /* [in] */ BOOL fClearDirty) +{ + return m_PersistStream->Save(pStm, fClearDirty); +} + +HRESULT STDMETHODCALLTYPE CShellLink::GetSizeMax( + /* [out] */ ULARGE_INTEGER *pcbSize) +{ + return m_PersistStream->GetSizeMax(pcbSize); +} + + +// IShellExtInit +HRESULT STDMETHODCALLTYPE CShellLink::Initialize( + /* [in] */ LPCITEMIDLIST pidlFolder, + /* [in] */ IDataObject *pdtobj, + /* [in] */ HKEY hkeyProgID) +{ + return m_ShellExtInit->Initialize(pidlFolder, pdtobj, hkeyProgID); +} + + +// IContextMenu +HRESULT STDMETHODCALLTYPE CShellLink::QueryContextMenu( + HMENU hmenu, + UINT indexMenu, + UINT idCmdFirst, + UINT idCmdLast, + UINT uFlags) +{ + return m_ContextMenu->QueryContextMenu(hmenu, indexMenu, idCmdFirst, idCmdLast, uFlags); +} + +HRESULT STDMETHODCALLTYPE CShellLink::InvokeCommand( + LPCMINVOKECOMMANDINFO lpici) +{ + return m_ContextMenu->InvokeCommand(lpici); +} + +HRESULT STDMETHODCALLTYPE CShellLink::GetCommandString( + UINT_PTR idCmd, + UINT uType, + UINT *pwReserved, + LPSTR pszName, + UINT cchMax) +{ + return m_ContextMenu->GetCommandString(idCmd, uType, pwReserved, pszName, cchMax); +} + + +// IContextMenu2 +HRESULT STDMETHODCALLTYPE CShellLink::HandleMenuMsg( + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + return m_ContextMenu2->HandleMenuMsg(uMsg, wParam, lParam); +} + + +// IDropTarget +HRESULT STDMETHODCALLTYPE CShellLink::DragEnter( + /* [unique][in] */ IDataObject *pDataObj, + /* [in] */ DWORD grfKeyState, + /* [in] */ POINTL pt, + /* [out][in] */ DWORD *pdwEffect) +{ + return m_DropTarget->DragEnter(pDataObj, grfKeyState, pt, pdwEffect); +} + +HRESULT STDMETHODCALLTYPE CShellLink::DragOver( + /* [in] */ DWORD grfKeyState, + /* [in] */ POINTL pt, + /* [out][in] */ DWORD *pdwEffect) +{ + return m_DropTarget->DragOver(grfKeyState, pt, pdwEffect); +} + +HRESULT STDMETHODCALLTYPE CShellLink::DragLeave( void) +{ + return m_DropTarget->DragLeave(); +} + +HRESULT STDMETHODCALLTYPE CShellLink::Drop( + /* [unique][in] */ IDataObject *pDataObj, + /* [in] */ DWORD grfKeyState, + /* [in] */ POINTL pt, + /* [out][in] */ DWORD *pdwEffect) +{ + return m_DropTarget->Drop(pDataObj, grfKeyState, pt, pdwEffect); +} + + +// IExtractIconA +HRESULT STDMETHODCALLTYPE CShellLink::GetIconLocation( + UINT uFlags, + LPSTR szIconFile, + UINT cchMax, + int *piIndex, + UINT *pwFlags) +{ + return m_ExtractIconA->GetIconLocation(uFlags, szIconFile, cchMax, piIndex, pwFlags); +} + +HRESULT STDMETHODCALLTYPE CShellLink::Extract( + LPCSTR pszFile, + UINT nIconIndex, + HICON *phiconLarge, + HICON *phiconSmall, + UINT nIconSize) +{ + return m_ExtractIconA->Extract(pszFile, nIconIndex, phiconLarge, phiconSmall, nIconSize); +} + + +// IExtractIconW +HRESULT STDMETHODCALLTYPE CShellLink::GetIconLocation( + UINT uFlags, + LPWSTR szIconFile, + UINT cchMax, + int *piIndex, + UINT *pwFlags) +{ + HRESULT hr; + LPSTR szIconFileA; + + szIconFileA = (LPSTR) alloca(cchMax); + hr = m_ExtractIconA->GetIconLocation(uFlags, szIconFileA, cchMax, piIndex, pwFlags); + if (SUCCEEDED(hr)) + MultiByteToWideChar(CP_ACP, 0, szIconFileA, -1, szIconFile, cchMax); + return hr; +} + +HRESULT STDMETHODCALLTYPE CShellLink::Extract( + LPCWSTR pszFile, + UINT nIconIndex, + HICON *phiconLarge, + HICON *phiconSmall, + UINT nIconSize) +{ + LPSTR pszFileA; + int lenA; + + lenA = (lstrlenW(pszFile) + 1) * 2; + pszFileA = (LPSTR) alloca(lenA); + WideCharToMultiByte(CP_ACP, 0, pszFile, -1, pszFileA, lenA, NULL, NULL); + return m_ExtractIconA->Extract(pszFileA, nIconIndex, phiconLarge, phiconSmall, nIconSize); +} diff --git a/kexCOM/shelllink.h b/kexCOM/shelllink.h new file mode 100755 index 0000000..1bb3477 --- /dev/null +++ b/kexCOM/shelllink.h @@ -0,0 +1,329 @@ +/* + * KernelEx + * Copyright (C) 2009, Xeno86 + * + * This file is part of KernelEx source code. + * + * KernelEx is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. + * + * KernelEx is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __SHELLLINK_H +#define __SHELLLINK_H + +#include + +class CShellLink : public IShellLinkA, + public IShellLinkW, + public IPersistFile, + public IPersistStream, + public IShellExtInit, + public IContextMenu2, + public IDropTarget, + public IExtractIconA, + public IExtractIconW +{ +public: + + // Constructor + CShellLink(IUnknown *prevUnk); + + + // Destructor + ~CShellLink(); + + + // IUnknown + HRESULT STDMETHODCALLTYPE QueryInterface( + /* [in] */ REFIID riid, + /* [iid_is][out] */ void **ppvObject); + + ULONG STDMETHODCALLTYPE AddRef( void); + + ULONG STDMETHODCALLTYPE Release( void); + + + // IShellLinkA + HRESULT STDMETHODCALLTYPE GetPath( + /* [size_is][out] */ LPSTR pszFile, + /* [in] */ int cch, + /* [full][out][in] */ WIN32_FIND_DATAA *pfd, + /* [in] */ DWORD fFlags); + + HRESULT STDMETHODCALLTYPE GetIDList( + /* [out] */ LPITEMIDLIST *ppidl); + + HRESULT STDMETHODCALLTYPE SetIDList( + /* [in] */ LPCITEMIDLIST pidl); + + HRESULT STDMETHODCALLTYPE GetDescription( + /* [size_is][out] */ LPSTR pszName, + /* [in] */ int cch); + + HRESULT STDMETHODCALLTYPE SetDescription( + /* [in] */ LPCSTR pszName); + + HRESULT STDMETHODCALLTYPE GetWorkingDirectory( + /* [size_is][out] */ LPSTR pszDir, + /* [in] */ int cch); + + HRESULT STDMETHODCALLTYPE SetWorkingDirectory( + /* [in] */ LPCSTR pszDir); + + HRESULT STDMETHODCALLTYPE GetArguments( + /* [size_is][out] */ LPSTR pszArgs, + /* [in] */ int cch); + + HRESULT STDMETHODCALLTYPE SetArguments( + /* [in] */ LPCSTR pszArgs); + + HRESULT STDMETHODCALLTYPE GetHotkey( + /* [out] */ WORD *pwHotkey); + + HRESULT STDMETHODCALLTYPE SetHotkey( + /* [in] */ WORD wHotkey); + + HRESULT STDMETHODCALLTYPE GetShowCmd( + /* [out] */ int *piShowCmd); + + HRESULT STDMETHODCALLTYPE SetShowCmd( + /* [in] */ int iShowCmd); + + HRESULT STDMETHODCALLTYPE GetIconLocation( + /* [size_is][out] */ LPSTR pszIconPath, + /* [in] */ int cch, + /* [out] */ int *piIcon); + + HRESULT STDMETHODCALLTYPE SetIconLocation( + /* [in] */ LPCSTR pszIconPath, + /* [in] */ int iIcon); + + HRESULT STDMETHODCALLTYPE SetRelativePath( + /* [in] */ LPCSTR pszPathRel, + /* [in] */ DWORD dwReserved); + + HRESULT STDMETHODCALLTYPE Resolve( + /* [in] */ HWND hwnd, + /* [in] */ DWORD fFlags); + + HRESULT STDMETHODCALLTYPE SetPath( + /* [in] */ LPCSTR pszFile); + + + // IShellLinkW + HRESULT STDMETHODCALLTYPE GetPath( + /* [size_is][out] */ LPWSTR pszFile, + /* [in] */ int cch, + /* [full][out][in] */ WIN32_FIND_DATAW *pfd, + /* [in] */ DWORD fFlags); + +// HRESULT STDMETHODCALLTYPE GetIDList( +// /* [out] */ LPITEMIDLIST *ppidl); +// +// HRESULT STDMETHODCALLTYPE SetIDList( +// /* [in] */ LPCITEMIDLIST pidl); + + HRESULT STDMETHODCALLTYPE GetDescription( + /* [size_is][out] */ LPWSTR pszName, + int cch); + + HRESULT STDMETHODCALLTYPE SetDescription( + /* [in] */ LPCWSTR pszName); + + HRESULT STDMETHODCALLTYPE GetWorkingDirectory( + /* [size_is][out] */ LPWSTR pszDir, + int cch); + + HRESULT STDMETHODCALLTYPE SetWorkingDirectory( + /* [in] */ LPCWSTR pszDir); + + HRESULT STDMETHODCALLTYPE GetArguments( + /* [size_is][out] */ LPWSTR pszArgs, + int cch); + + HRESULT STDMETHODCALLTYPE SetArguments( + /* [in] */ LPCWSTR pszArgs); + +// HRESULT STDMETHODCALLTYPE GetHotkey( +// /* [out] */ WORD *pwHotkey); +// +// HRESULT STDMETHODCALLTYPE SetHotkey( +// /* [in] */ WORD wHotkey); +// +// HRESULT STDMETHODCALLTYPE GetShowCmd( +// /* [out] */ int *piShowCmd); +// +// HRESULT STDMETHODCALLTYPE SetShowCmd( +// /* [in] */ int iShowCmd); + + HRESULT STDMETHODCALLTYPE GetIconLocation( + /* [size_is][out] */ LPWSTR pszIconPath, + /* [in] */ int cch, + /* [out] */ int *piIcon); + + HRESULT STDMETHODCALLTYPE SetIconLocation( + /* [in] */ LPCWSTR pszIconPath, + /* [in] */ int iIcon); + + HRESULT STDMETHODCALLTYPE SetRelativePath( + /* [in] */ LPCWSTR pszPathRel, + /* [in] */ DWORD dwReserved); + +// HRESULT STDMETHODCALLTYPE Resolve( +// /* [in] */ HWND hwnd, +// /* [in] */ DWORD fFlags); + + HRESULT STDMETHODCALLTYPE SetPath( + /* [in] */ LPCWSTR pszFile); + + + // IPersist + HRESULT STDMETHODCALLTYPE GetClassID( + /* [out] */ CLSID *pClassID); + + + // IPersistFile + HRESULT STDMETHODCALLTYPE IsDirty( void); + + HRESULT STDMETHODCALLTYPE Load( + /* [in] */ LPCOLESTR pszFileName, + /* [in] */ DWORD dwMode); + + HRESULT STDMETHODCALLTYPE Save( + /* [unique][in] */ LPCOLESTR pszFileName, + /* [in] */ BOOL fRemember); + + HRESULT STDMETHODCALLTYPE SaveCompleted( + /* [unique][in] */ LPCOLESTR pszFileName); + + HRESULT STDMETHODCALLTYPE GetCurFile( + /* [out] */ LPOLESTR *ppszFileName); + + + // IPersistStream +// HRESULT STDMETHODCALLTYPE IsDirty( void); + + HRESULT STDMETHODCALLTYPE Load( + /* [unique][in] */ IStream *pStm); + + HRESULT STDMETHODCALLTYPE Save( + /* [unique][in] */ IStream *pStm, + /* [in] */ BOOL fClearDirty); + + HRESULT STDMETHODCALLTYPE GetSizeMax( + /* [out] */ ULARGE_INTEGER *pcbSize); + + + // IShellExtInit + HRESULT STDMETHODCALLTYPE Initialize( + /* [in] */ LPCITEMIDLIST pidlFolder, + /* [in] */ IDataObject *pdtobj, + /* [in] */ HKEY hkeyProgID); + + + // IContextMenu + HRESULT STDMETHODCALLTYPE QueryContextMenu( + HMENU hmenu, + UINT indexMenu, + UINT idCmdFirst, + UINT idCmdLast, + UINT uFlags); + + HRESULT STDMETHODCALLTYPE InvokeCommand( + LPCMINVOKECOMMANDINFO lpici); + + HRESULT STDMETHODCALLTYPE GetCommandString( + UINT_PTR idCmd, + UINT uType, + UINT *pwReserved, + LPSTR pszName, + UINT cchMax); + + + // IContextMenu2 + HRESULT STDMETHODCALLTYPE HandleMenuMsg( + UINT uMsg, + WPARAM wParam, + LPARAM lParam); + + + // IDropTarget + HRESULT STDMETHODCALLTYPE DragEnter( + /* [unique][in] */ IDataObject *pDataObj, + /* [in] */ DWORD grfKeyState, + /* [in] */ POINTL pt, + /* [out][in] */ DWORD *pdwEffect); + + HRESULT STDMETHODCALLTYPE DragOver( + /* [in] */ DWORD grfKeyState, + /* [in] */ POINTL pt, + /* [out][in] */ DWORD *pdwEffect); + + HRESULT STDMETHODCALLTYPE DragLeave( void); + + HRESULT STDMETHODCALLTYPE Drop( + /* [unique][in] */ IDataObject *pDataObj, + /* [in] */ DWORD grfKeyState, + /* [in] */ POINTL pt, + /* [out][in] */ DWORD *pdwEffect); + + + // IExtractIconA + HRESULT STDMETHODCALLTYPE GetIconLocation( + UINT uFlags, + LPSTR szIconFile, + UINT cchMax, + int *piIndex, + UINT *pwFlags); + + HRESULT STDMETHODCALLTYPE Extract( + LPCSTR pszFile, + UINT nIconIndex, + HICON *phiconLarge, + HICON *phiconSmall, + UINT nIconSize); + + + // IExtractIconW + HRESULT STDMETHODCALLTYPE GetIconLocation( + UINT uFlags, + LPWSTR szIconFile, + UINT cchMax, + int *piIndex, + UINT *pwFlags); + + HRESULT STDMETHODCALLTYPE Extract( + LPCWSTR pszFile, + UINT nIconIndex, + HICON *phiconLarge, + HICON *phiconSmall, + UINT nIconSize); + + +private: + long m_cRef; + IUnknown *m_Unknown; + IShellLinkA *m_ShellLinkA; +// IShellLinkW *m_ShellLinkW; + IPersistFile *m_PersistFile; + IPersistStream *m_PersistStream; + IShellExtInit *m_ShellExtInit; + IContextMenu *m_ContextMenu; + IContextMenu2 *m_ContextMenu2; + IDropTarget *m_DropTarget; + IExtractIconA *m_ExtractIconA; +// IExtractIconW *m_ExtractIconW; +}; + +#endif diff --git a/kexcontrol/kexcontrol.cpp b/kexcontrol/kexcontrol.cpp old mode 100644 new mode 100755 diff --git a/kexcontrol/kexcontrol.dsp b/kexcontrol/kexcontrol.dsp old mode 100644 new mode 100755 diff --git a/kexcrt/LICENSE b/kexcrt/LICENSE old mode 100644 new mode 100755 diff --git a/kexcrt/README b/kexcrt/README old mode 100644 new mode 100755 diff --git a/kexcrt/_vsnprintf.c b/kexcrt/_vsnprintf.c old mode 100644 new mode 100755 diff --git a/kexcrt/abort.c b/kexcrt/abort.c new file mode 100755 index 0000000..e3c43cc --- /dev/null +++ b/kexcrt/abort.c @@ -0,0 +1,6 @@ +#include + +void __cdecl abort(void) +{ + RaiseException(0xdeafcafe, EXCEPTION_NONCONTINUABLE, 0, NULL); +} diff --git a/kexcrt/assert.c b/kexcrt/assert.c new file mode 100755 index 0000000..30cc9d8 --- /dev/null +++ b/kexcrt/assert.c @@ -0,0 +1,13 @@ +/* + * assert.c + */ + +#include +#include +#include + +void _assert(const char *expr, const char *file, unsigned int line) +{ + printf("Assertion %s failed, file %s, line %u\n", expr, file, line); + abort(); +} diff --git a/kexcrt/atoi.c b/kexcrt/atoi.c old mode 100644 new mode 100755 diff --git a/kexcrt/atol.c b/kexcrt/atol.c old mode 100644 new mode 100755 diff --git a/kexcrt/atoll.c b/kexcrt/atoll.c old mode 100644 new mode 100755 diff --git a/kexcrt/atox.c b/kexcrt/atox.c old mode 100644 new mode 100755 diff --git a/kexcrt/ctype/ctypefunc.h b/kexcrt/ctype/ctypefunc.h old mode 100644 new mode 100755 diff --git a/kexcrt/ctype/isalnum.c b/kexcrt/ctype/isalnum.c old mode 100644 new mode 100755 diff --git a/kexcrt/ctype/isalpha.c b/kexcrt/ctype/isalpha.c old mode 100644 new mode 100755 diff --git a/kexcrt/ctype/isascii.c b/kexcrt/ctype/isascii.c old mode 100644 new mode 100755 diff --git a/kexcrt/ctype/isblank.c b/kexcrt/ctype/isblank.c old mode 100644 new mode 100755 diff --git a/kexcrt/ctype/iscntrl.c b/kexcrt/ctype/iscntrl.c old mode 100644 new mode 100755 diff --git a/kexcrt/ctype/isdigit.c b/kexcrt/ctype/isdigit.c old mode 100644 new mode 100755 diff --git a/kexcrt/ctype/isgraph.c b/kexcrt/ctype/isgraph.c old mode 100644 new mode 100755 diff --git a/kexcrt/ctype/islower.c b/kexcrt/ctype/islower.c old mode 100644 new mode 100755 diff --git a/kexcrt/ctype/isprint.c b/kexcrt/ctype/isprint.c old mode 100644 new mode 100755 diff --git a/kexcrt/ctype/ispunct.c b/kexcrt/ctype/ispunct.c old mode 100644 new mode 100755 diff --git a/kexcrt/ctype/isspace.c b/kexcrt/ctype/isspace.c old mode 100644 new mode 100755 diff --git a/kexcrt/ctype/isupper.c b/kexcrt/ctype/isupper.c old mode 100644 new mode 100755 diff --git a/kexcrt/ctype/isxdigit.c b/kexcrt/ctype/isxdigit.c old mode 100644 new mode 100755 diff --git a/kexcrt/ctype/tolower.c b/kexcrt/ctype/tolower.c old mode 100644 new mode 100755 diff --git a/kexcrt/ctype/toupper.c b/kexcrt/ctype/toupper.c old mode 100644 new mode 100755 diff --git a/kexcrt/ctypes.c b/kexcrt/ctypes.c old mode 100644 new mode 100755 diff --git a/kexcrt/ctypes.h b/kexcrt/ctypes.h old mode 100644 new mode 100755 diff --git a/kexcrt/exit.c b/kexcrt/exit.c old mode 100644 new mode 100755 index f54b1c4..4208242 --- a/kexcrt/exit.c +++ b/kexcrt/exit.c @@ -1,6 +1,8 @@ +#include + void __exit(void); -void exit(int v) +void __cdecl exit(int v) { __exit(); ExitProcess(v); diff --git a/kexcrt/gcc/dllcrt0.c b/kexcrt/gcc/dllcrt0.c old mode 100644 new mode 100755 diff --git a/kexcrt/gcc/init.c b/kexcrt/gcc/init.c old mode 100644 new mode 100755 diff --git a/kexcrt/gcc/init.h b/kexcrt/gcc/init.h old mode 100644 new mode 100755 diff --git a/kexcrt/gcc/pseudo-reloc-list.c b/kexcrt/gcc/pseudo-reloc-list.c old mode 100644 new mode 100755 diff --git a/kexcrt/gcc/pseudo-reloc.c b/kexcrt/gcc/pseudo-reloc.c old mode 100644 new mode 100755 diff --git a/kexcrt/gcc/purecall.c b/kexcrt/gcc/purecall.c new file mode 100755 index 0000000..9c41e0d --- /dev/null +++ b/kexcrt/gcc/purecall.c @@ -0,0 +1,4 @@ +void __cxa_pure_virtual() +{ + // print error message +} diff --git a/kexcrt/kexcrt.dsp b/kexcrt/kexcrt.dsp old mode 100644 new mode 100755 index 199ed17..3acf6cd --- a/kexcrt/kexcrt.dsp +++ b/kexcrt/kexcrt.dsp @@ -58,10 +58,18 @@ SOURCE=.\_vsnprintf.c # End Source File # Begin Source File +SOURCE=.\abort.c +# End Source File +# Begin Source File + SOURCE=.\msvc\argcargv.c # End Source File # Begin Source File +SOURCE=.\assert.c +# End Source File +# Begin Source File + SOURCE=.\atoi.c # End Source File # Begin Source File @@ -170,6 +178,14 @@ SOURCE=.\memmove.c # End Source File # Begin Source File +SOURCE=".\memory-cpp.cpp" +# End Source File +# Begin Source File + +SOURCE=.\memory.c +# End Source File +# Begin Source File + SOURCE=.\memrchr.c # End Source File # Begin Source File @@ -182,6 +198,14 @@ SOURCE=.\memswap.c # End Source File # Begin Source File +SOURCE=.\printf.c +# End Source File +# Begin Source File + +SOURCE=.\msvc\purecall.c +# End Source File +# Begin Source File + SOURCE=.\snprintf.c # End Source File # Begin Source File @@ -320,6 +344,10 @@ SOURCE=.\vsscanf.c SOURCE=.\msvc\wincrt0.c # End Source File +# Begin Source File + +SOURCE=.\write.c +# End Source File # End Group # Begin Group "Header Files" diff --git a/kexcrt/makefile b/kexcrt/makefile old mode 100644 new mode 100755 index 5dbab34..8c2dc82 --- a/kexcrt/makefile +++ b/kexcrt/makefile @@ -1,8 +1,9 @@ -OBJ = atoi.o atol.o atoll.o ctypes.o memccpy.o memchr.o memcmp.o memcpy.o memmem.o memmove.o memrchr.o memset.o memswap.o snprintf.o sprintf.o sscanf.o strcat.o strchr.o strcmp.o strcmpi.o strcpy.o strlen.o strncat.o strncmp.o strncpy.o strnicmp.o strnlen.o strntoimax.o strntoumax.o strpbrk.o strrchr.o strsep.o strstr.o strtok.o strtok_r.o strtol.o strtoll.o strtoul.o strtoull.o strtoumax.o strupr.o strxspn.o vsnprintf.o vsprintf.o vsscanf.o _vsnprintf.o exit.o \ +OBJ = abort.o assert.o atoi.o atol.o atoll.o ctypes.o memccpy.o memchr.o memcmp.o memcpy.o memmem.o memmove.o memory.o memory-cpp.o memrchr.o memset.o memswap.o printf.o snprintf.o sprintf.o sscanf.o strcat.o strchr.o strcmp.o strcmpi.o strcpy.o strlen.o strncat.o strncmp.o strncpy.o strnicmp.o strnlen.o strntoimax.o strntoumax.o strpbrk.o strrchr.o strsep.o strstr.o strtok.o strtok_r.o strtol.o strtoll.o strtoul.o strtoull.o strtoumax.o strupr.o strxspn.o vsnprintf.o vsprintf.o vsscanf.o _vsnprintf.o write.o exit.o \ ctype/isalnum.o ctype/isalpha.o ctype/isascii.o ctype/isblank.o ctype/iscntrl.o ctype/isdigit.o ctype/isgraph.o ctype/islower.o ctype/isprint.o ctype/ispunct.o ctype/isspace.o ctype/isupper.o ctype/isxdigit.o ctype/tolower.o ctype/toupper.o \ -gcc/init.o gcc/dllcrt0.o gcc/pseudo-reloc.o gcc/pseudo-reloc-list.o +gcc/init.o gcc/dllcrt0.o gcc/pseudo-reloc.o gcc/pseudo-reloc-list.o gcc/purecall.o CC = gcc +CXX = g++ CFLAGS = -O2 -s -I. -D__NO_CTYPE_INLINES -D__NO_ISOCEXT BIN = libkexcrt.a @@ -19,3 +20,6 @@ $(BIN) : $(OBJ) .c.o : $(CC) $(CFLAGS) -c -o $@ $< + +.cpp.o : + $(CXX) $(CFLAGS) -c -o $@ $< diff --git a/kexcrt/makefile.msv b/kexcrt/makefile.msv old mode 100644 new mode 100755 index 38df778..2fecdf4 --- a/kexcrt/makefile.msv +++ b/kexcrt/makefile.msv @@ -1,6 +1,6 @@ -OBJ = atoi.obj atol.obj atoll.obj ctypes.obj memccpy.obj memchr.obj memcmp.obj memcpy.obj memmem.obj memmove.obj memrchr.obj memset.obj memswap.obj snprintf.obj sprintf.obj sscanf.obj strcat.obj strchr.obj strcmp.obj strcmpi.obj strcpy.obj strlen.obj strncat.obj strncmp.obj strncpy.obj strnicmp.obj strnlen.obj strntoimax.obj strntoumax.obj strpbrk.obj strrchr.obj strsep.obj strstr.obj strtok.obj strtok_r.obj strtol.obj strtoll.obj strtoul.obj strtoull.obj strtoumax.obj strupr.obj strxspn.obj vsnprintf.obj vsprintf.obj vsscanf.obj _vsnprintf.obj exit.obj \ +OBJ = abort.obj assert.obj atoi.obj atol.obj atoll.obj ctypes.obj memccpy.obj memchr.obj memcmp.obj memcpy.obj memmem.obj memmove.obj memory.obj memory-cpp.obj memrchr.obj memset.obj memswap.obj printf.obj snprintf.obj sprintf.obj sscanf.obj strcat.obj strchr.obj strcmp.obj strcmpi.obj strcpy.obj strlen.obj strncat.obj strncmp.obj strncpy.obj strnicmp.obj strnlen.obj strntoimax.obj strntoumax.obj strpbrk.obj strrchr.obj strsep.obj strstr.obj strtok.obj strtok_r.obj strtol.obj strtoll.obj strtoul.obj strtoull.obj strtoumax.obj strupr.obj strxspn.obj vsnprintf.obj vsprintf.obj vsscanf.obj _vsnprintf.obj write.obj exit.obj \ ctype/isalnum.obj ctype/isalpha.obj ctype/isascii.obj ctype/isblank.obj ctype/iscntrl.obj ctype/isdigit.obj ctype/isgraph.obj ctype/islower.obj ctype/isprint.obj ctype/ispunct.obj ctype/isspace.obj ctype/isupper.obj ctype/isxdigit.obj ctype/tolower.obj ctype/toupper.obj \ -msvc/init.obj msvc/dllcrt0.obj msvc/argcargv.obj msvc/concrt0.obj msvc/wincrt0.obj +msvc/init.obj msvc/dllcrt0.obj msvc/argcargv.obj msvc/concrt0.obj msvc/wincrt0.obj msvc/purecall.obj CFLAGS = /O2 /Oi- /I. /nologo /D_CTYPE_DISABLE_MACROS @@ -19,3 +19,6 @@ $(BIN) : $(OBJ) .c.obj : $(CC) $(CFLAGS) /c /Fo$@ $< + +.cpp.obj : + $(CC) $(CFLAGS) /c /Fo$@ $< diff --git a/kexcrt/memccpy.c b/kexcrt/memccpy.c old mode 100644 new mode 100755 diff --git a/kexcrt/memchr.c b/kexcrt/memchr.c old mode 100644 new mode 100755 diff --git a/kexcrt/memcmp.c b/kexcrt/memcmp.c old mode 100644 new mode 100755 diff --git a/kexcrt/memcpy.c b/kexcrt/memcpy.c old mode 100644 new mode 100755 diff --git a/kexcrt/memmem.c b/kexcrt/memmem.c old mode 100644 new mode 100755 diff --git a/kexcrt/memmove.c b/kexcrt/memmove.c old mode 100644 new mode 100755 diff --git a/kexcrt/memory-cpp.cpp b/kexcrt/memory-cpp.cpp new file mode 100755 index 0000000..74e1457 --- /dev/null +++ b/kexcrt/memory-cpp.cpp @@ -0,0 +1,21 @@ +#include + +void* operator new(size_t size) +{ + return malloc(size); +} + +void operator delete(void* ptr) +{ + free(ptr); +} + +void* operator new[](size_t size) +{ + return malloc(size); +} + +void operator delete[](void* ptr) +{ + free(ptr); +} diff --git a/kexcrt/memory.c b/kexcrt/memory.c new file mode 100755 index 0000000..2c3ea84 --- /dev/null +++ b/kexcrt/memory.c @@ -0,0 +1,33 @@ +#include + +void* malloc(size_t size) +{ + return HeapAlloc(GetProcessHeap(), 0, size); +} + +void* calloc(size_t count, size_t size) +{ + return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, count * size); +} + +void free(void* ptr) +{ + if (ptr) + HeapFree(GetProcessHeap(), 0, ptr); +} + +void* realloc(void* ptr, size_t size) +{ + if (ptr) + return HeapReAlloc(GetProcessHeap(), 0, ptr, size); + else + return HeapAlloc(GetProcessHeap(), 0, size); +} + +void* recalloc(void* ptr, size_t size) +{ + if (ptr) + return HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ptr, size); + else + return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size); +} diff --git a/kexcrt/memrchr.c b/kexcrt/memrchr.c old mode 100644 new mode 100755 diff --git a/kexcrt/memset.c b/kexcrt/memset.c old mode 100644 new mode 100755 diff --git a/kexcrt/memswap.c b/kexcrt/memswap.c old mode 100644 new mode 100755 diff --git a/kexcrt/msvc/STDINT.H b/kexcrt/msvc/STDINT.H old mode 100644 new mode 100755 diff --git a/kexcrt/msvc/argcargv.c b/kexcrt/msvc/argcargv.c old mode 100644 new mode 100755 diff --git a/kexcrt/msvc/argcargv.h b/kexcrt/msvc/argcargv.h old mode 100644 new mode 100755 diff --git a/kexcrt/msvc/concrt0.c b/kexcrt/msvc/concrt0.c old mode 100644 new mode 100755 diff --git a/kexcrt/msvc/dllcrt0.c b/kexcrt/msvc/dllcrt0.c old mode 100644 new mode 100755 diff --git a/kexcrt/msvc/init.c b/kexcrt/msvc/init.c old mode 100644 new mode 100755 diff --git a/kexcrt/msvc/init.h b/kexcrt/msvc/init.h old mode 100644 new mode 100755 diff --git a/kexcrt/msvc/purecall.c b/kexcrt/msvc/purecall.c new file mode 100755 index 0000000..49d4bbc --- /dev/null +++ b/kexcrt/msvc/purecall.c @@ -0,0 +1,4 @@ +void __cdecl _purecall() +{ + // print error message +} diff --git a/kexcrt/msvc/wincrt0.c b/kexcrt/msvc/wincrt0.c old mode 100644 new mode 100755 diff --git a/kexcrt/printf.c b/kexcrt/printf.c new file mode 100755 index 0000000..007d048 --- /dev/null +++ b/kexcrt/printf.c @@ -0,0 +1,28 @@ +/* + * printf.c + */ + +#include +#include +#include + +#define BUFFER_SIZE 16384 + +int printf(const char *format, ...) +{ + va_list ap; + int rv; + char buffer[BUFFER_SIZE]; + + va_start(ap, format); + rv = vsnprintf(buffer, BUFFER_SIZE, format, ap); + va_end(ap); + + if (rv < 0) + return rv; + + if (rv > BUFFER_SIZE - 1) + rv = BUFFER_SIZE - 1; + + return write(1, buffer, rv); +} diff --git a/kexcrt/snprintf.c b/kexcrt/snprintf.c old mode 100644 new mode 100755 diff --git a/kexcrt/sprintf.c b/kexcrt/sprintf.c old mode 100644 new mode 100755 diff --git a/kexcrt/sscanf.c b/kexcrt/sscanf.c old mode 100644 new mode 100755 diff --git a/kexcrt/strcat.c b/kexcrt/strcat.c old mode 100644 new mode 100755 diff --git a/kexcrt/strchr.c b/kexcrt/strchr.c old mode 100644 new mode 100755 diff --git a/kexcrt/strcmp.c b/kexcrt/strcmp.c old mode 100644 new mode 100755 diff --git a/kexcrt/strcmpi.c b/kexcrt/strcmpi.c old mode 100644 new mode 100755 diff --git a/kexcrt/strcpy.c b/kexcrt/strcpy.c old mode 100644 new mode 100755 diff --git a/kexcrt/strlen.c b/kexcrt/strlen.c old mode 100644 new mode 100755 diff --git a/kexcrt/strncat.c b/kexcrt/strncat.c old mode 100644 new mode 100755 diff --git a/kexcrt/strncmp.c b/kexcrt/strncmp.c old mode 100644 new mode 100755 diff --git a/kexcrt/strncpy.c b/kexcrt/strncpy.c old mode 100644 new mode 100755 diff --git a/kexcrt/strnicmp.c b/kexcrt/strnicmp.c old mode 100644 new mode 100755 diff --git a/kexcrt/strnlen.c b/kexcrt/strnlen.c old mode 100644 new mode 100755 diff --git a/kexcrt/strntoimax.c b/kexcrt/strntoimax.c old mode 100644 new mode 100755 diff --git a/kexcrt/strntoumax.c b/kexcrt/strntoumax.c old mode 100644 new mode 100755 diff --git a/kexcrt/strpbrk.c b/kexcrt/strpbrk.c old mode 100644 new mode 100755 diff --git a/kexcrt/strrchr.c b/kexcrt/strrchr.c old mode 100644 new mode 100755 diff --git a/kexcrt/strsep.c b/kexcrt/strsep.c old mode 100644 new mode 100755 diff --git a/kexcrt/strstr.c b/kexcrt/strstr.c old mode 100644 new mode 100755 diff --git a/kexcrt/strtok.c b/kexcrt/strtok.c old mode 100644 new mode 100755 diff --git a/kexcrt/strtok_r.c b/kexcrt/strtok_r.c old mode 100644 new mode 100755 diff --git a/kexcrt/strtol.c b/kexcrt/strtol.c old mode 100644 new mode 100755 diff --git a/kexcrt/strtoll.c b/kexcrt/strtoll.c old mode 100644 new mode 100755 diff --git a/kexcrt/strtoul.c b/kexcrt/strtoul.c old mode 100644 new mode 100755 diff --git a/kexcrt/strtoull.c b/kexcrt/strtoull.c old mode 100644 new mode 100755 diff --git a/kexcrt/strtoumax.c b/kexcrt/strtoumax.c old mode 100644 new mode 100755 diff --git a/kexcrt/strtox.c b/kexcrt/strtox.c old mode 100644 new mode 100755 diff --git a/kexcrt/strupr.c b/kexcrt/strupr.c old mode 100644 new mode 100755 diff --git a/kexcrt/strxspn.c b/kexcrt/strxspn.c old mode 100644 new mode 100755 diff --git a/kexcrt/strxspn.h b/kexcrt/strxspn.h old mode 100644 new mode 100755 diff --git a/kexcrt/vsnprintf.c b/kexcrt/vsnprintf.c old mode 100644 new mode 100755 diff --git a/kexcrt/vsprintf.c b/kexcrt/vsprintf.c old mode 100644 new mode 100755 diff --git a/kexcrt/vsscanf.c b/kexcrt/vsscanf.c old mode 100644 new mode 100755 diff --git a/kexcrt/write.c b/kexcrt/write.c new file mode 100755 index 0000000..0e51ab0 --- /dev/null +++ b/kexcrt/write.c @@ -0,0 +1,36 @@ +#include + +#define STDIN_FILENO 0 +#define STDOUT_FILENO 1 +#define STDERR_FILENO 2 + +int __cdecl write(int fd, const void* buf, unsigned int size) +{ + DWORD written; + HANDLE hFile; + + switch (fd) + { + case STDIN_FILENO: + hFile = GetStdHandle(STD_INPUT_HANDLE); + break; + case STDOUT_FILENO: + hFile = GetStdHandle(STD_OUTPUT_HANDLE); + break; + case STDERR_FILENO: + hFile = GetStdHandle(STD_ERROR_HANDLE); + break; + default: + hFile = (HANDLE) fd; + } + + if (!WriteFile(hFile, buf, size, &written, NULL)) + return -1; + return written; + +} + +int __cdecl _write(int fd, const void* buf, unsigned int size) +{ + return write(fd, buf, size); +} diff --git a/setup/debug.h b/setup/debug.h old mode 100644 new mode 100755 diff --git a/setup/loadstub.h b/setup/loadstub.h old mode 100644 new mode 100755 index b5ddf18..9f8b736 --- a/setup/loadstub.h +++ b/setup/loadstub.h @@ -1,6 +1,6 @@ /* * KernelEx - * Copyright (C) 2008, Xeno86 + * Copyright (C) 2008-2010, Xeno86 * * This file is part of KernelEx source code. * @@ -23,14 +23,16 @@ #define __LOADSTUB_H #define KEX_SIGNATURE "KrnlEx" -#define KEX_STUB_VER 1 +/* Update this whenever patching functions are changed. */ +#define KEX_STUB_VER 6 -#define JTAB_SIZE 5 +#define JTAB_SIZE 6 #define JTAB_EFO_DYN 0 #define JTAB_EFO_STA 1 #define JTAB_EFN_DYN 2 #define JTAB_EFN_STA 3 #define JTAB_KNO_DLL 4 +#define JTAB_FLD_TRN 5 #include typedef struct diff --git a/setup/resource.h b/setup/resource.h old mode 100644 new mode 100755 index b74b4ab..861e6a9 --- a/setup/resource.h +++ b/setup/resource.h @@ -11,6 +11,7 @@ #define IDS_ERRCHECK 7 #define IDS_FAILOPENBACKUP 8 #define IDS_WINVER 9 +#define IDS_DOWNGRADE 10 // Next default values for new objects // diff --git a/setup/setup.cpp b/setup/setup.cpp old mode 100644 new mode 100755 index 952b265..f7d7911 --- a/setup/setup.cpp +++ b/setup/setup.cpp @@ -1,6 +1,6 @@ /* * KernelEx - * Copyright (C) 2008-2009, Xeno86 + * Copyright (C) 2008-2010, Xeno86 * * This file is part of KernelEx source code. * @@ -29,21 +29,20 @@ #include "loadstub.h" #include "setup.h" #include "wininit.h" +#include "version.h" #include "resource.h" #define CODE_SEG ".text" #define DATA_SEG ".data" +#define INIT_SEG "_INIT" -Setup::Setup(const char* backup_file) +Setup::Setup(char* _backup_file) : backup_file(strupr(_backup_file)) { - this->backup_file = backup_file; - for (string::iterator it = this->backup_file.begin() ; it != this->backup_file.end() ; it++) - *it = toupper(*it); - h_kernel32 = GetModuleHandle("KERNEL32"); detect_old_version(); + detect_downgrade(); pemem.OpenMemory(h_kernel32); if (!pemem.HasTarget()) @@ -90,6 +89,28 @@ bool Setup::detect_old_version() return true; } +void Setup::detect_downgrade() +{ + typedef unsigned long (*kexGetKEXVersion_t)(); + kexGetKEXVersion_t kexGetKEXVersion_pfn; + HMODULE h_kernelex; + unsigned long version; + + h_kernelex = LoadLibrary("KERNELEX.DLL"); + + //no KernelEx installed, continue + if (!h_kernelex) + return; + + kexGetKEXVersion_pfn = (kexGetKEXVersion_t) GetProcAddress(h_kernelex, "kexGetKEXVersion"); + version = kexGetKEXVersion_pfn(); + FreeLibrary(h_kernelex); + + //trying to downgrade - forbid + if (version > VERSION_CODE) + ShowError(IDS_DOWNGRADE); +} + int Setup::find_pattern(DWORD offset, int size, const short* pattern, int pat_len, DWORD* found_loc) { @@ -213,6 +234,62 @@ void Setup::disable_resource_check() set_pattern(found_loc, after, length); } +//no named/rcdata resource types mirroring +void Setup::disable_named_and_rcdata_resources_mirroring() +{ + static const short pattern[] = { + 0x66,0x8B,0x40,0x0E,0x66,0x89,0x45,0xDA,0x8B,0x45, -1,0x66,0x8B,0x48, + 0x0C,0x66,0x89,0x4D,0xD8,0x66,0x8B,0x45,0xE0,0x8B,0x4D,0xD4,0x66,0x89, + 0x01,0x83,0x45,0xD4,0x02,0x66,0x8B,0x45,0xDA,0x66,0x03,0x45,0xD8,0x66, + 0x89,0x45,0x8C,0x8B,0x4D,0xD4,0x66,0x89,0x01,0x83,0x45,0xD4,0x02 + }; + static const short after[] = { + 0x66,0x8B,0x48,0x0E,0x66,0x03,0x48,0x0C,0x66,0x89,0x4D,0x8C,0x8B,0x45, + 0xA4,0x83,0x38,0x0A,0x74,0x40,0x83,0x38,0x00,0x79,0x04,0x3B,0xC0,0xEB, + 0x37,0x66,0x8B,0x45,0xE0,0x8B,0x4D,0xD4,0x66,0x89,0x01,0x83,0xC1,0x02, + 0x66,0x8B,0x45,0x8C,0x66,0x89,0x01,0x83,0xC1,0x02,0x89,0x4D,0xD4 + }; + + DWORD offset = (DWORD) pefile.GetSectionByName(CODE_SEG); + int size = pefile.GetSectionSize(CODE_SEG); + int length = sizeof(pattern) / sizeof(short); + DWORD found_loc; + int found = find_pattern(offset, size, pattern, length, &found_loc); + if (found != 1) + { + if (!found) ShowError(IDS_NOPAT, "disable_named_and_rcdata_resources_mirroring"); + else ShowError(IDS_MULPAT, "disable_named_and_rcdata_resources_mirroring"); + } + DBGPRINTF(("%s: pattern found @ 0x%08x\n", "disable_named_and_rcdata_resources_mirroring", + pefile.PointerToRva((void*) found_loc) + pefile.GetImageBase())); + set_pattern(found_loc, after, length); +} + +//change obfuscator to non-negative IDs +void Setup::positive_pids_patch() +{ + static const short pattern[] = { + 0xB9,0x01,0x00,0xFF,0xFF,-1,0x23,0xD1,0x33,0xD1 + }; + static const short after[] = { + 0xB9,0x01,0x00,0xFF,0x4F,-1,0x23,0xD1,0x2B,0xD1 + }; + + DWORD offset = (DWORD) pefile.GetSectionByName(INIT_SEG); + int size = pefile.GetSectionSize(INIT_SEG); + int length = sizeof(pattern) / sizeof(short); + DWORD found_loc; + int found = find_pattern(offset, size, pattern, length, &found_loc); + if (found != 1) + { + if (!found) ShowError(IDS_NOPAT, "positive_pids_patch"); + else ShowError(IDS_MULPAT, "positive_pids_patch"); + } + DBGPRINTF(("%s: pattern found @ 0x%08x\n", "positive_pids_patch", + pefile.PointerToRva((void*) found_loc) + pefile.GetImageBase())); + set_pattern(found_loc, after, length); +} + void Setup::mod_imte_alloc() { //VA BFF8745C, RVA 1745C, file 15A5C, sec E45C @@ -220,7 +297,7 @@ void Setup::mod_imte_alloc() 0x66,0xff,0x05,-1,-1,-1,0xbf,0x6a,0x3c,0xe8, }; static const short after[] = { - 0x66,0xff,0x05,-1,-1,-1,0xbf,0x6a,0x44,0xe8, + 0x66,0xff,0x05,-1,-1,-1,0xbf,0x6a,0x40,0xe8, }; DWORD offset = (DWORD) pefile.GetSectionByName(CODE_SEG); @@ -238,6 +315,30 @@ void Setup::mod_imte_alloc() set_pattern(found_loc, after, length); } +void Setup::mod_mr_alloc() +{ + static const short pattern[] = { + 0x75,0xF6,0x8D,0x04,-1,0x1C,0x00,0x00,0x00,0x50 + }; + static const short after[] = { + 0x75,0xF6,0x8D,0x04,-1,0x24,0x00,0x00,0x00,0x50 + }; + + DWORD offset = (DWORD) pefile.GetSectionByName(CODE_SEG); + int size = pefile.GetSectionSize(CODE_SEG); + int length = sizeof(pattern) / sizeof(short); + DWORD found_loc; + int found = find_pattern(offset, size, pattern, length, &found_loc); + if (found != 1) + { + if (!found) ShowError(IDS_NOPAT, "mod_mr_alloc"); + else ShowError(IDS_MULPAT, "mod_mr_alloc"); + } + DBGPRINTF(("%s: pattern found @ 0x%08x\n", "mod_mr_alloc", + pefile.PointerToRva((void*) found_loc) + pefile.GetImageBase())); + set_pattern(found_loc, after, length); +} + void Setup::mod_pdb_alloc() { static const short pattern[] = { @@ -318,6 +419,52 @@ void Setup::find_IsKnownDLL() _IsKnownDLL = decode_call(IsKnownDLL_call, 5); } +void Setup::find_FLoadTreeNotify1() +{ + static const short pattern[] = { + 0x56,0xA1,-1,-1,-1,-1,0x6A,0x01,0x8B,0x08,0xFF,0xB1,0x98,0x00,0x00, + 0x00,0xE8,-2,-2,-2,-2,0x83,0xF8,0x01,0x1B,0xF6,0xF7,0xDE + }; + + DWORD offset = (DWORD) pefile.GetSectionByName(CODE_SEG); + int size = pefile.GetSectionSize(CODE_SEG); + int length = sizeof(pattern) / sizeof(short); + DWORD found_loc; + int found = find_pattern(offset, size,pattern, length, &found_loc); + if (found != 1) + { + if (!found) ShowError(IDS_NOPAT, "FLoadTreeNotify1"); + else ShowError(IDS_MULPAT, "FLoadTreeNotify1"); + } + DBGPRINTF(("%s: pattern found @ 0x%08x\n", "FLoadTreeNotify1", + pefile.PointerToRva((void*) found_loc) + pefile.GetImageBase())); + FLoadTreeNotify_call1 = found_loc + 16; + _FLoadTreeNotify = decode_call(FLoadTreeNotify_call1, 5); +} + +void Setup::find_FLoadTreeNotify2() +{ + static const short pattern[] = { + 0x6A,0x00,0x57,0xE8,-1,-1,-1,-1,0x6A,0x00,0x56,0xE8,-2,-2,-2,-2, + 0x85,0xC0,0x74,0x12,0x56,0xE8,-1,-1,-1,-1,0x68,0x5A,0x04,0x00,0x00, + 0x33,0xF6,0xE8,-1,-1,-1,-1 + }; + + DWORD offset = (DWORD) pefile.GetSectionByName(CODE_SEG); + int size = pefile.GetSectionSize(CODE_SEG); + int length = sizeof(pattern) / sizeof(short); + DWORD found_loc; + int found = find_pattern(offset, size,pattern, length, &found_loc); + if (found != 1) + { + if (!found) ShowError(IDS_NOPAT, "FLoadTreeNotify2"); + else ShowError(IDS_MULPAT, "FLoadTreeNotify2"); + } + DBGPRINTF(("%s: pattern found @ 0x%08x\n", "FLoadTreeNotify2", + pefile.PointerToRva((void*) found_loc) + pefile.GetImageBase())); + FLoadTreeNotify_call2 = found_loc + 11; +} + void Setup::kill_process(const char* name) { PROCESSENTRY32 pe32; @@ -394,7 +541,7 @@ bool Setup::is_fixupc(DWORD addr) return false; } -string Setup::get_temp_file_name() +sstring Setup::get_temp_file_name() { char tmpdir[MAX_PATH]; char target[MAX_PATH]; @@ -417,6 +564,7 @@ void Setup::ShowError(UINT id, ...) else _vsnprintf(out, sizeof(out), format, vargs); va_end(vargs); + DBGPRINTF(("%s\n", out)); MessageBox(NULL, out, "KernelEx Setup", MB_OK | MB_ICONERROR); exit(id); } @@ -428,28 +576,38 @@ void Setup::install() if (version >= 0) { if (version == KEX_STUB_VER) + { + DBGPRINTF(("No need to upgrade\n")); return; + } else + { upgrade = true; + } } char kernel32path[MAX_PATH]; GetModuleFileName(h_kernel32, kernel32path, sizeof(kernel32path)); - pefile.OpenFile(upgrade ? backup_file.c_str() : kernel32path, 0x10000); + pefile.OpenFile(upgrade ? backup_file : kernel32path, 0x10000); if (!pefile.HasTarget()) { if (upgrade) - ShowError(IDS_FAILOPENBACKUP, backup_file.c_str(), kernel32path); + ShowError(IDS_FAILOPENBACKUP, backup_file, kernel32path); else ShowError(IDS_FAILOPEN, kernel32path); } find_ExportFromX(); find_IsKnownDLL(); + find_FLoadTreeNotify1(); + find_FLoadTreeNotify2(); disable_platform_check(); disable_resource_check(); + disable_named_and_rcdata_resources_mirroring(); + positive_pids_patch(); mod_imte_alloc(); + mod_mr_alloc(); mod_pdb_alloc(); KernelEx_codeseg* cseg; @@ -478,6 +636,7 @@ void Setup::install() dseg->jtab[JTAB_EFN_DYN] = _ExportFromName + pefile.GetImageBase(); dseg->jtab[JTAB_EFN_STA] = _ExportFromName + pefile.GetImageBase(); dseg->jtab[JTAB_KNO_DLL] = _IsKnownDLL + pefile.GetImageBase(); + dseg->jtab[JTAB_FLD_TRN] = _FLoadTreeNotify + pefile.GetImageBase(); //exportfromx patch DWORD code = (DWORD) pefile.GetSectionByName(CODE_SEG); @@ -521,19 +680,27 @@ void Setup::install() //isknowndll patch set_call_ref(IsKnownDLL_call, (DWORD) &cseg->jmp_stub[JTAB_KNO_DLL]); - DBGPRINTF(("KNO_DLL: address %08x\n", pefile.PointerToRva((void*) a) + DBGPRINTF(("KNO_DLL: address %08x\n", pefile.PointerToRva((void*) IsKnownDLL_call) + + pefile.GetImageBase())); + + //FLoadTreeNotify patch + set_call_ref(FLoadTreeNotify_call1, (DWORD) &cseg->jmp_stub[JTAB_FLD_TRN]); + DBGPRINTF(("FLD_TRN: address %08x\n", pefile.PointerToRva((void*) FLoadTreeNotify_call1) + + pefile.GetImageBase())); + set_call_ref(FLoadTreeNotify_call2, (DWORD) &cseg->jmp_stub[JTAB_FLD_TRN]); + DBGPRINTF(("FLD_TRN: address %08x\n", pefile.PointerToRva((void*) FLoadTreeNotify_call2) + pefile.GetImageBase())); // backup original file if (!upgrade) { - if (!CopyFile(kernel32path, backup_file.c_str(), FALSE)) - ShowError(IDS_FAILBAK, backup_file.c_str()); + if (!CopyFile(kernel32path, backup_file, FALSE)) + ShowError(IDS_FAILBAK, backup_file); } // save patched file - string tmp_file = get_temp_file_name(); - pefile.SaveFile(tmp_file.c_str()); + sstring tmp_file = get_temp_file_name(); + pefile.SaveFile(tmp_file); if (is_winme) { @@ -561,10 +728,12 @@ void Setup::install() int main(int argc, char** argv) { + DBGPRINTF(("KernelEx setup program running\n")); if (argc != 2) return 1; Setup setup(argv[1]); setup.install(); + DBGPRINTF(("Setup finished\n")); return 0; } diff --git a/setup/setup.dsp b/setup/setup.dsp old mode 100644 new mode 100755 index 39c9dae..dd0719b --- a/setup/setup.dsp +++ b/setup/setup.dsp @@ -42,7 +42,7 @@ RSC=rc.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /GX /O2 /I "." /I "../common" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GF /c +# ADD CPP /nologo /W3 /O2 /I "." /I "../common" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GF /c # ADD BASE RSC /l 0x415 /d "NDEBUG" # ADD RSC /l 0x415 /d "NDEBUG" BSC32=bscmake.exe @@ -50,7 +50,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib comdlg32.lib advapi32.lib shell32.lib /nologo /subsystem:console /machine:I386 /out:"Release/setupkex.exe" /OPT:NOWIN98 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib comdlg32.lib advapi32.lib shell32.lib ..\kexcrt\kexcrt.lib libc.lib /nologo /entry:"mainCRTStartup" /subsystem:windows /machine:I386 /nodefaultlib /out:"Release/setupkex.exe" /OPT:NOWIN98 # SUBTRACT LINK32 /pdb:none !ELSEIF "$(CFG)" == "setup - Win32 Debug" @@ -67,7 +67,7 @@ LINK32=link.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "." /I "../common" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /GF /c +# ADD CPP /nologo /W3 /Gm /ZI /Od /I "." /I "../common" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /GF /c # ADD BASE RSC /l 0x415 /d "_DEBUG" # ADD RSC /l 0x415 /d "_DEBUG" BSC32=bscmake.exe @@ -75,7 +75,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib comdlg32.lib advapi32.lib shell32.lib /nologo /subsystem:console /debug /machine:I386 /out:"Debug/setupkex.exe" /pdbtype:sept /OPT:NOWIN98 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib comdlg32.lib advapi32.lib shell32.lib ..\kexcrt\kexcrt.lib libc.lib /nologo /subsystem:console /debug /machine:I386 /nodefaultlib /out:"Debug/setupkex.exe" /OPT:NOWIN98 # SUBTRACT LINK32 /pdb:none !ENDIF diff --git a/setup/setup.h b/setup/setup.h old mode 100644 new mode 100755 index 51777db..f017eb6 --- a/setup/setup.h +++ b/setup/setup.h @@ -1,6 +1,6 @@ /* * KernelEx - * Copyright (C) 2008-2009, Xeno86 + * Copyright (C) 2008-2010, Xeno86 * * This file is part of KernelEx source code. * @@ -22,23 +22,22 @@ #ifndef __SETUP_H #define __SETUP_H -#include - -using namespace std; +#include "sstring.hpp" class Setup { public: - Setup(const char* backup_file); + Setup(char* _backup_file); int get_signature_ver(); void install(); protected: private: - string backup_file; + sstring backup_file; DWORD _ExportFromOrdinal; DWORD _ExportFromName; DWORD _IsKnownDLL; + DWORD _FLoadTreeNotify; HMODULE h_kernel32; PEmanip pemem; PEmanip pefile; @@ -46,27 +45,33 @@ private: DWORD gpa_ExportFromName_call; DWORD EFN_EFO_call; DWORD IsKnownDLL_call; + DWORD FLoadTreeNotify_call1; + DWORD FLoadTreeNotify_call2; int version; bool is_winme; bool upgrade; bool detect_old_version(); + void detect_downgrade(); int find_pattern(DWORD offset, int size, const short* pattern, int pat_len, DWORD* found_loc); void set_pattern(DWORD loc, const short* new_pattern, int pat_len); void disable_platform_check(); void disable_resource_check(); + void disable_named_and_rcdata_resources_mirroring(); + void positive_pids_patch(); void mod_imte_alloc(); + void mod_mr_alloc(); void mod_pdb_alloc(); void find_ExportFromX(); void find_IsKnownDLL(); - DWORD find_ExportFromOrdinal(); - DWORD find_ExportFromName(); + void find_FLoadTreeNotify1(); + void find_FLoadTreeNotify2(); void kill_process(const char* name); DWORD decode_call(DWORD addr, int len); bool is_call_ref(DWORD loc, DWORD target); void set_call_ref(DWORD loc, DWORD target); bool is_fixupc(DWORD addr); - string get_temp_file_name(); + sstring get_temp_file_name(); void ShowError(UINT id, ...); }; diff --git a/setup/setup.rc b/setup/setup.rc old mode 100644 new mode 100755 index 96a76fc..f279be0 --- a/setup/setup.rc +++ b/setup/setup.rc @@ -37,6 +37,7 @@ BEGIN IDS_ERRCHECK "ERROR: Checksum error" IDS_FAILOPENBACKUP "ERROR: Failed to open backup file %s.\nPossible causes: previous version not uninstalled correctly or file has been deleted.\nRestore %s manually from install media." IDS_WINVER "Incompatible Windows version" + IDS_DOWNGRADE "Can't downgrade. Please uninstall currently installed version of KernelEx before continuing." END #endif // Neutral resources diff --git a/setup/wininit.h b/setup/wininit.h old mode 100644 new mode 100755 index 0684579..89cd2ab --- a/setup/wininit.h +++ b/setup/wininit.h @@ -26,7 +26,7 @@ #ifndef __WININIT_H #define __WININIT_H -#include +#include "sstring.hpp" #include using namespace std; @@ -41,8 +41,9 @@ class WININIT */ struct _2files { - string dest; - string src; + _2files(const sstring& d, const sstring& s) : dest(d), src(s) {} + sstring dest; + sstring src; }; /** Stack holding wininit.ini entries. */ @@ -72,8 +73,8 @@ public: if (!que.empty()) DBGPRINTF(("\nRemoving temporary files ...\n")); while (!que.empty()) { - DeleteFile(que.front().src.c_str()); - DBGPRINTF(("... %s\n", que.front().src.c_str())); + DeleteFile(que.front().src); + DBGPRINTF(("... %s\n", que.front().src)); que.pop(); } } @@ -90,11 +91,9 @@ public: * @param dest Destination file name (or 'NUL' for delete). * @param src Source file name. */ - void add(const string& dest, const string& src) + void add(const sstring& dest, const sstring& src) { - _2files t; - t.dest = dest; - t.src = src; + _2files t(dest, src); que.push(t); } @@ -118,12 +117,12 @@ public: char short_dest[MAX_PATH]; char short_src[MAX_PATH]; - if (!GetShortPathName(que.front().dest.c_str(), short_dest, sizeof(short_dest))) + if (!GetShortPathName(que.front().dest, short_dest, sizeof(short_dest))) //if fail, assume destination doesn't exit //fixme: may not be short path name or be invalid path name - strcpy(short_dest, que.front().dest.c_str()); - if (!GetShortPathName(que.front().src.c_str(), short_src, sizeof(short_src))) - strcpy(short_src, que.front().src.c_str()); + strcpy(short_dest, que.front().dest); + if (!GetShortPathName(que.front().src, short_src, sizeof(short_src))) + strcpy(short_src, que.front().src); strcpy(line, short_dest); strcat(line, "="); @@ -133,7 +132,8 @@ public: if (buf_len + line_len + 2 <= sizeof(buf)) { - DBGPRINTF(("... %s => %s\n", que.front().src.c_str(), que.front().dest.c_str())); + DBGPRINTF(("... %s => %s\n", (const char*) que.front().src, + (const char*) que.front().dest)); memcpy(&buf[buf_len], line, line_len); buf_len += line_len; } diff --git a/sheet/KexLinkage.cpp b/sheet/KexLinkage.cpp old mode 100644 new mode 100755 diff --git a/sheet/KexLinkage.h b/sheet/KexLinkage.h old mode 100644 new mode 100755 index 124d830..aebdcc9 --- a/sheet/KexLinkage.h +++ b/sheet/KexLinkage.h @@ -33,9 +33,9 @@ using namespace std; class KexLinkage { typedef void (*kexGetModuleSettings_t)(const char* module, - char* conf_name, BYTE* ldr_flags); + char* conf_name, DWORD* mod_flags); typedef void (*kexSetModuleSettings_t)(const char* module, - const char* conf_name, BYTE ldr_flags); + const char* conf_name, DWORD mod_flags); typedef unsigned long (*kexGetKEXVersion_t)(void); typedef int (*kexIsDebugCore_t)(void); diff --git a/sheet/factory.cpp b/sheet/factory.cpp old mode 100644 new mode 100755 index 5bce597..63830da --- a/sheet/factory.cpp +++ b/sheet/factory.cpp @@ -25,72 +25,71 @@ #include "sheet.h" #include "KexLinkage.h" -Factory::Factory() +CFactory::CFactory() { - m_RefCount = 0; + m_cRef = 1; + InterlockedIncrement(&g_LockCount); } - -STDMETHODIMP_(ULONG) Factory::AddRef() +CFactory::~CFactory() { - g_LockCount++; - return ++m_RefCount; + InterlockedDecrement(&g_LockCount); } - -STDMETHODIMP_(ULONG) Factory::Release() +STDMETHODIMP CFactory::QueryInterface(const IID& iid, void** ppv) { - g_LockCount--; - return --m_RefCount; -} - - -STDMETHODIMP Factory::QueryInterface(REFIID riid,LPVOID *ppv) -{ - if (riid==IID_IUnknown) + if (iid==IID_IUnknown) *ppv = static_cast(this); - else if (riid==IID_IClassFactory) + else if (iid==IID_IClassFactory) *ppv = static_cast(this); else { *ppv = NULL; return E_NOINTERFACE; } - AddRef(); return S_OK; } - -STDMETHODIMP Factory::LockServer(BOOL bLock) +STDMETHODIMP_(ULONG) CFactory::AddRef() { - if (bLock==TRUE) - g_LockCount++; - else - g_LockCount--; - return S_OK; + return InterlockedIncrement(&m_cRef); } - -STDMETHODIMP Factory::CreateInstance(IUnknown *pUnkOuter,REFIID riid, LPVOID *ppv) +STDMETHODIMP_(ULONG) CFactory::Release() { - *ppv = NULL; + if (InterlockedDecrement(&m_cRef) == 0) + { + delete this; + return 0; + } + return m_cRef; +} + +STDMETHODIMP CFactory::CreateInstance(IUnknown* pUnkOuter, const IID& iid, void** ppv) +{ + HRESULT hr; if (pUnkOuter != NULL) return CLASS_E_NOAGGREGATION; if (!KexLinkage::instance.IsReady()) - return E_ACCESSDENIED; + return E_NOINTERFACE; KexShlExt* pShlExt = new KexShlExt; if (pShlExt == NULL) return E_OUTOFMEMORY; - HRESULT hr = pShlExt->QueryInterface(riid,ppv); - if (FAILED(hr)) - { - delete pShlExt; - return E_NOINTERFACE; - } + hr = pShlExt->QueryInterface(iid, ppv); + pShlExt->Release(); + return hr; +} + +STDMETHODIMP CFactory::LockServer(BOOL bLock) +{ + if (bLock) + InterlockedIncrement(&g_LockCount); + else + InterlockedDecrement(&g_LockCount); return S_OK; } diff --git a/sheet/factory.h b/sheet/factory.h old mode 100644 new mode 100755 index 637db2e..b4a69ca --- a/sheet/factory.h +++ b/sheet/factory.h @@ -22,21 +22,26 @@ #ifndef _FACTORY_H #define _FACTORY_H -class Factory : public IClassFactory +class CFactory : public IClassFactory { - ULONG m_RefCount; - public: - Factory(); + // Constructor + CFactory(); - // IUnknown - STDMETHODIMP QueryInterface(REFIID riid,LPVOID *ppv); + // Destructor + ~CFactory(); + + // Interface IUnknown + STDMETHODIMP QueryInterface(const IID& iid, void** ppv); STDMETHODIMP_(ULONG) AddRef(); STDMETHODIMP_(ULONG) Release(); - // IClassFactory - STDMETHODIMP CreateInstance(IUnknown *pUnkOuter,REFIID riid, LPVOID *ppv); + // Interface IClassFactory + STDMETHODIMP CreateInstance(IUnknown* pUnkOuter, const IID& iid, void** ppv); STDMETHODIMP LockServer(BOOL bLock); + +private: + long m_cRef; }; #endif // _FACTORY_H diff --git a/sheet/fast_com_unload.reg b/sheet/fast_com_unload.reg old mode 100644 new mode 100755 diff --git a/sheet/resource.h b/sheet/resource.h old mode 100644 new mode 100755 index a5b5f76..9e28984 --- a/sheet/resource.h +++ b/sheet/resource.h @@ -2,6 +2,12 @@ // Microsoft Developer Studio generated include file. // Used by sheet.rc // +#define TIP_DISABLE 1 +#define TIP_COMPAT 2 +#define TIP_SYSTEM 3 +#define TIP_NOINHERIT 4 +#define TIP_OVERRIDE 5 +#define TIP_LOG 6 #define IDD_PROPPAGE 102 #define IDC_CHECK 1000 #define IDC_COMPAT 1000 @@ -12,6 +18,10 @@ #define IDC_GCOMPAT 1006 #define IDC_TCOMPAT 1007 #define IDC_LOG 1008 +#define IDC_NOINHERIT 1009 +#define IDC_GADVAN 1010 +#define IDC_CHECK1 1011 +#define IDC_OVERRIDE 1011 // Next default values for new objects // @@ -19,7 +29,7 @@ #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 102 #define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1009 +#define _APS_NEXT_CONTROL_VALUE 1012 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif diff --git a/sheet/server.cpp b/sheet/server.cpp old mode 100644 new mode 100755 index 990fb33..c5d10af --- a/sheet/server.cpp +++ b/sheet/server.cpp @@ -25,7 +25,7 @@ #include "factory.h" #include "sheet.h" -UINT g_LockCount; +long g_LockCount; HMODULE g_hModule; @@ -169,19 +169,29 @@ STDAPI DllUnregisterServer() } -STDAPI DllGetClassObject(REFCLSID rclsid,REFIID riid,LPVOID * ppv) +STDAPI DllGetClassObject(const CLSID& clsid, const IID& iid, void** ppv) { - static Factory factory; - *ppv = NULL; - - if (rclsid != CLSID_KexShlExt) - return CLASS_E_CLASSNOTAVAILABLE; + HRESULT hr; - return factory.QueryInterface(riid,ppv); + if (clsid == CLSID_KexShlExt) + { + CFactory* factory = new CFactory; + if (!factory) + return E_OUTOFMEMORY; + + hr = factory->QueryInterface(iid, ppv); + factory->Release(); + return hr; + } + else + { + *ppv = NULL; + return CLASS_E_CLASSNOTAVAILABLE; + } } -BOOL APIENTRY DllMain(HINSTANCE hModule,DWORD dwReason,LPVOID lpReserved) +BOOL APIENTRY DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpReserved) { if (dwReason == DLL_PROCESS_ATTACH) { diff --git a/sheet/server.def b/sheet/server.def old mode 100644 new mode 100755 diff --git a/sheet/server.h b/sheet/server.h old mode 100644 new mode 100755 index 24497fb..b0402d9 --- a/sheet/server.h +++ b/sheet/server.h @@ -22,7 +22,7 @@ #ifndef _SERVER_H #define _SERVER_H -extern UINT g_LockCount; +extern long g_LockCount; extern HMODULE g_hModule; #endif // _SERVER_H diff --git a/sheet/sheet.cpp b/sheet/sheet.cpp old mode 100644 new mode 100755 index d52db6a..43f6fd6 --- a/sheet/sheet.cpp +++ b/sheet/sheet.cpp @@ -27,16 +27,72 @@ #include "resource.h" #include "KexLinkage.h" +struct CTips +{ + char* _TIP_DISABLE; + char* _TIP_COMPAT; + char* _TIP_SYSTEM; + char* _TIP_NOINHERIT; + char* _TIP_OVERRIDE; + char* _TIP_LOG; + + CTips() + { + _TIP_DISABLE = _TIP_COMPAT = _TIP_SYSTEM = _TIP_NOINHERIT + = _TIP_OVERRIDE = _TIP_LOG = NULL; + loaded = false; + } + + ~CTips() + { + if (loaded) + { + free(_TIP_DISABLE); + free(_TIP_COMPAT); + free(_TIP_SYSTEM); + free(_TIP_NOINHERIT); + free(_TIP_OVERRIDE); + free(_TIP_LOG); + } + } + + void load_tips() + { + if (loaded) + return; + loaded = true; + _TIP_DISABLE = load_string(TIP_DISABLE); + _TIP_COMPAT = load_string(TIP_COMPAT); + _TIP_SYSTEM = load_string(TIP_SYSTEM); + _TIP_NOINHERIT = load_string(TIP_NOINHERIT); + _TIP_OVERRIDE = load_string(TIP_OVERRIDE); + _TIP_LOG = load_string(TIP_LOG); + } + +private: + bool loaded; + + char* load_string(int sID) + { + char buf[512]; + LoadString(g_hModule, sID, buf, sizeof(buf)); + buf[sizeof(buf) - 1] = '\0'; + return strdup(buf); + } +} tips; + + KexShlExt::KexShlExt() { - g_LockCount++; - m_RefCount = 0; + m_cRef = 1; + InterlockedIncrement(&g_LockCount); } + KexShlExt::~KexShlExt() { - g_LockCount--; + InterlockedDecrement(&g_LockCount); } @@ -61,18 +117,18 @@ STDMETHODIMP KexShlExt::QueryInterface(REFIID riid,LPVOID *ppv) STDMETHODIMP_(ULONG) KexShlExt::AddRef() { - return ++m_RefCount; + return InterlockedIncrement(&m_cRef); } STDMETHODIMP_(ULONG) KexShlExt::Release() { - if (!--m_RefCount) + if (InterlockedDecrement(&m_cRef) == 0) { delete this; return 0; } - return m_RefCount; + return m_cRef; } @@ -114,16 +170,16 @@ __end: bool KexShlExt::ResolveShortcut(const char* shortcutPath, char* filePath) { - HRESULT result; - IShellLink* shellLink; + HRESULT result; + IShellLink* shellLink; IPersistFile* persistFile; - char path[MAX_PATH]; - WCHAR tmp[MAX_PATH]; + char path[MAX_PATH]; + WCHAR tmp[MAX_PATH]; CoInitialize(NULL); - result = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, - IID_IShellLink, (void**) &shellLink); + result = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, + IID_IShellLink, (void**) &shellLink); if (FAILED(result)) { @@ -142,8 +198,7 @@ bool KexShlExt::ResolveShortcut(const char* shortcutPath, char* filePath) result = shellLink->Resolve(NULL, SLR_UPDATE); if (SUCCEEDED(result)) { - result = shellLink->GetPath(path, - MAX_PATH, NULL, SLGP_RAWPATH); + result = shellLink->GetPath(path, MAX_PATH, NULL, SLGP_RAWPATH); if (SUCCEEDED(result)) lstrcpyn(filePath, path, MAX_PATH); } @@ -156,7 +211,7 @@ bool KexShlExt::ResolveShortcut(const char* shortcutPath, char* filePath) CoUninitialize(); - return SUCCEEDED(result); + return SUCCEEDED(result); } STDMETHODIMP KexShlExt::Initialize(LPCITEMIDLIST pidlFolder, @@ -172,13 +227,13 @@ STDMETHODIMP KexShlExt::Initialize(LPCITEMIDLIST pidlFolder, InitCommonControls(); - if (FAILED(pDataObj->GetData(&etc, &stg))) - return E_INVALIDARG; + if (FAILED(pDataObj->GetData(&etc, &stg))) + return E_INVALIDARG; - // Get an HDROP handle. - hdrop = (HDROP) GlobalLock (stg.hGlobal); + // Get an HDROP handle. + hdrop = (HDROP) GlobalLock(stg.hGlobal); - if (!hdrop) + if (!hdrop) { ReleaseStgMedium(&stg); return E_INVALIDARG; @@ -186,10 +241,14 @@ STDMETHODIMP KexShlExt::Initialize(LPCITEMIDLIST pidlFolder, ms = new ModuleSetting; if (!ms) + { + GlobalUnlock(stg.hGlobal); + ReleaseStgMedium(&stg); return E_OUTOFMEMORY; + } // Determine how many files are involved in this operation. - UINT numFiles = DragQueryFile (hdrop, 0xFFFFFFFF, NULL, 0); + UINT numFiles = DragQueryFile(hdrop, 0xFFFFFFFF, NULL, 0); if (numFiles != 1) result = E_FAIL; @@ -235,7 +294,7 @@ STDMETHODIMP KexShlExt::AddPages(LPFNADDPROPSHEETPAGE lpfnAddPageProc, LPARAM lP psp.pfnDlgProc = DlgProc; psp.pfnCallback = CallbackProc; psp.lParam = (LPARAM) ms; - psp.pcRefParent = &g_LockCount; + psp.pcRefParent = (UINT*) &g_LockCount; hPage = CreatePropertySheetPage(&psp); if (hPage) @@ -272,13 +331,20 @@ BOOL CALLBACK KexShlExt::DlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lPa RECT r; POINT p; + + GetWindowRect(GetDlgItem(hwnd, IDC_GADVAN), &r); + p.x = r.left; + p.y = r.top; + ScreenToClient(hwnd, &p); + MoveWindow(GetDlgItem(hwnd, IDC_GADVAN), p.x, p.y, w - 2 * p.x, r.bottom - r.top, TRUE); + GetWindowRect(GetDlgItem(hwnd, IDC_GCOMPAT), &r); p.x = r.left; p.y = r.top; ScreenToClient(hwnd, &p); + MoveWindow(GetDlgItem(hwnd, IDC_GCOMPAT), p.x, p.y, w - 2 * p.x, r.bottom - r.top, TRUE); //reposition horizontal spacer and version text - MoveWindow(GetDlgItem(hwnd, IDC_GCOMPAT), p.x, p.y, w - 2 * p.x, r.bottom - r.top, TRUE); MoveWindow(GetDlgItem(hwnd, IDC_HORIZ1), p.x, h - 14 - p.x, w - 2 * p.x, 1, TRUE); MoveWindow(GetDlgItem(hwnd, IDC_KEXVER), p.x, h - 12 - p.x, w - 2 * p.x, 12, TRUE); GetWindowRect(GetDlgItem(hwnd, IDC_TCOMPAT), &r); @@ -304,6 +370,7 @@ BOOL CALLBACK KexShlExt::DlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lPa EnableWindow(GetDlgItem(hwnd, IDC_COMPAT), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_SYSTEM), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_LOG), FALSE); + EnableWindow(GetDlgItem(hwnd, IDC_NOINHERIT), FALSE); } else { @@ -311,6 +378,7 @@ BOOL CALLBACK KexShlExt::DlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lPa EnableWindow(GetDlgItem(hwnd, IDC_SYSTEM), IsDlgButtonChecked(hwnd, IDC_COMPAT)); EnableWindow(GetDlgItem(hwnd, IDC_LOG), TRUE); + EnableWindow(GetDlgItem(hwnd, IDC_NOINHERIT), TRUE); } PropSheet_Changed(GetParent(hwnd), hwnd); break; @@ -321,6 +389,7 @@ BOOL CALLBACK KexShlExt::DlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lPa break; case IDC_SYSTEM: case IDC_LOG: + case IDC_NOINHERIT: PropSheet_Changed(GetParent(hwnd), hwnd); break; } @@ -359,19 +428,22 @@ void KexShlExt::OnInitDialog(HWND hwnd, ModuleSetting* ms) SendMessage(GetDlgItem(hwnd, IDC_SYSTEM), CB_SETCURSEL, i, 0); break; } - if (!(ms->flags & 128) && (KexLinkage::instance.disable_extensions || !default_index_valid)) - ms->flags |= 1; - if (ms->flags & 1) + if (!(ms->flags & KRF_VALID_FLAG) && (KexLinkage::instance.disable_extensions || !default_index_valid)) + ms->flags |= KRF_KEX_DISABLE; + if (ms->flags & KRF_KEX_DISABLE) { CheckDlgButton(hwnd, IDC_DISABLE, BST_CHECKED); EnableWindow(GetDlgItem(hwnd, IDC_COMPAT), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_SYSTEM), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_LOG), FALSE); + EnableWindow(GetDlgItem(hwnd, IDC_NOINHERIT), FALSE); } - if (ms->flags & 4) - { + if (ms->flags & KRF_LOG_APIS) CheckDlgButton(hwnd, IDC_LOG, BST_CHECKED); - } + if (ms->flags & KRF_NO_INHERIT) + CheckDlgButton(hwnd, IDC_NOINHERIT, BST_CHECKED); + if (ms->flags & KRF_OVERRIDE_PROC_MOD) + CheckDlgButton(hwnd, IDC_OVERRIDE, BST_CHECKED); //set KernelEx version unsigned long ver = KexLinkage::instance.m_kexGetKEXVersion(); @@ -381,22 +453,45 @@ void KexShlExt::OnInitDialog(HWND hwnd, ModuleSetting* ms) ver>>24, (ver>>16) & 0xff, ver & 0xffff, debug ? "DEBUG" : ""); SendMessage(GetDlgItem(hwnd, IDC_KEXVER), WM_SETTEXT, 0, (LPARAM) ver_s); + ShowWindow(GetDlgItem(hwnd, IDC_OVERRIDE), debug ? SW_SHOW : SW_HIDE); ShowWindow(GetDlgItem(hwnd, IDC_LOG), debug ? SW_SHOW : SW_HIDE); + if (!debug) + { + RECT r; + HWND h = GetDlgItem(hwnd, IDC_GADVAN); + GetWindowRect(h, &r); + r.bottom -= 40; //height between IDC_LOG and element above + SetWindowPos(h, NULL, 0, 0, r.right - r.left, r.bottom - r.top, SWP_NOMOVE); + } + + tips.load_tips(); + + HWND hwndTip = CreateTooltipWindow(hwnd); + CreateTooltip(hwndTip, hwnd, IDC_DISABLE, tips._TIP_DISABLE); + CreateTooltip(hwndTip, hwnd, IDC_COMPAT, tips._TIP_COMPAT); + CreateTooltip(hwndTip, hwnd, IDC_SYSTEM, tips._TIP_SYSTEM); + CreateTooltip(hwndTip, hwnd, IDC_NOINHERIT, tips._TIP_NOINHERIT); + CreateTooltip(hwndTip, hwnd, IDC_OVERRIDE, tips._TIP_OVERRIDE); + CreateTooltip(hwndTip, hwnd, IDC_LOG, tips._TIP_LOG); } void KexShlExt::OnApply(HWND hwnd) { ModuleSetting* ms = (ModuleSetting*) GetWindowLong(hwnd, GWL_USERDATA); - BYTE flags = 0; + DWORD flags = 0; const char* conf = ""; if (IsDlgButtonChecked(hwnd, IDC_DISABLE)) - flags |= 1; + flags |= KRF_KEX_DISABLE; if (IsDlgButtonChecked(hwnd, IDC_COMPAT)) conf = KexLinkage::instance.confs[SendMessage( GetDlgItem(hwnd, IDC_SYSTEM), CB_GETCURSEL, 0, 0)].name; if (IsDlgButtonChecked(hwnd, IDC_LOG)) - flags |= 4; + flags |= KRF_LOG_APIS; + if (IsDlgButtonChecked(hwnd, IDC_NOINHERIT)) + flags |= KRF_NO_INHERIT; + if (IsDlgButtonChecked(hwnd, IDC_OVERRIDE)) + flags |= KRF_OVERRIDE_PROC_MOD; if (flags != ms->flags || strcmp(conf, ms->conf) != 0) KexLinkage::instance.m_kexSetModuleSettings(ms->file, conf, flags); @@ -405,8 +500,44 @@ void KexShlExt::OnApply(HWND hwnd) UINT CALLBACK KexShlExt::CallbackProc(HWND hwnd, UINT uMsg, LPPROPSHEETPAGE ppsp) { - if (uMsg == PSPCB_RELEASE) + if (uMsg == PSPCB_RELEASE) delete (ModuleSetting*) ppsp->lParam; - return 1; // used for PSPCB_CREATE - let the page be created + return 1; // used for PSPCB_CREATE - let the page be created +} + +HWND KexShlExt::CreateTooltipWindow(HWND parent) +{ + HWND hwndTip; + hwndTip = CreateWindow(TOOLTIPS_CLASS, NULL, + WS_POPUP | TTS_ALWAYSTIP | TTS_BALLOON, + CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, + parent, NULL, g_hModule, NULL); + SendMessage(hwndTip, TTM_SETMAXTIPWIDTH, 0, 300); + SendMessage(hwndTip, TTM_SETDELAYTIME, TTDT_AUTOPOP, MAKELONG(32767, 0)); + return hwndTip; +} + +bool KexShlExt::CreateTooltip(HWND hwndTip, HWND hDlg, int toolID, char* pText) +{ + if (!hwndTip || !toolID || !hDlg || !pText) + return false; + + // Get the window of the tool. + HWND hwndTool = GetDlgItem(hDlg, toolID); + if (!hwndTool) + return false; + + // Associate the tooltip with the tool. + TOOLINFO toolInfo; + toolInfo.cbSize = sizeof(toolInfo); + toolInfo.hwnd = hDlg; + toolInfo.uFlags = TTF_IDISHWND | TTF_SUBCLASS; + toolInfo.uId = (UINT_PTR) hwndTool; + toolInfo.lpszText = pText; + toolInfo.hinst = g_hModule; + SendMessage(hwndTip, TTM_ADDTOOL, 0, (LPARAM) &toolInfo); + + return true; } diff --git a/sheet/sheet.dsp b/sheet/sheet.dsp old mode 100644 new mode 100755 diff --git a/sheet/sheet.h b/sheet/sheet.h old mode 100644 new mode 100755 index 69d865b..6432944 --- a/sheet/sheet.h +++ b/sheet/sheet.h @@ -28,25 +28,17 @@ struct ModuleSetting { char file[MAX_PATH]; char conf[256]; - BYTE flags; + DWORD flags; }; class KexShlExt : public IShellExtInit, public IShellPropSheetExt { -protected: - ULONG m_RefCount; - ModuleSetting* ms; - - bool IsPEModule(const char* path); - bool ResolveShortcut(const char* shortcutPath, char* filePath); - static BOOL CALLBACK DlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); - static UINT CALLBACK CallbackProc(HWND hwnd, UINT uMsg, LPPROPSHEETPAGE ppsp); - static void OnInitDialog(HWND hwnd, ModuleSetting* ms); - static void OnApply(HWND hwnd); - public: + // Constructor KexShlExt(); + + // Destructor ~KexShlExt(); // IUnknown @@ -60,6 +52,21 @@ public: // IShellPropSheetExt STDMETHODIMP AddPages(LPFNADDPROPSHEETPAGE, LPARAM); STDMETHODIMP ReplacePage(UINT, LPFNADDPROPSHEETPAGE, LPARAM); + +protected: + ModuleSetting* ms; + + bool IsPEModule(const char* path); + bool ResolveShortcut(const char* shortcutPath, char* filePath); + static BOOL CALLBACK DlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + static UINT CALLBACK CallbackProc(HWND hwnd, UINT uMsg, LPPROPSHEETPAGE ppsp); + static void OnInitDialog(HWND hwnd, ModuleSetting* ms); + static void OnApply(HWND hwnd); + static HWND CreateTooltipWindow(HWND parent); + static bool CreateTooltip(HWND hwndTip, HWND hDlg, int toolID, char* pText); + +private: + long m_cRef; }; #endif // _SHEET_H diff --git a/sheet/sheet.rc b/sheet/sheet.rc old mode 100644 new mode 100755 index 97f1cc8..67ed434 --- a/sheet/sheet.rc +++ b/sheet/sheet.rc @@ -15,7 +15,7 @@ ///////////////////////////////////////////////////////////////////////////// // Polish resources -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_POL) +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_PLK) #ifdef _WIN32 LANGUAGE LANG_POLISH, SUBLANG_DEFAULT #pragma code_page(1250) @@ -54,8 +54,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,0,0,3 - PRODUCTVERSION 1,0,0,3 + FILEVERSION 1,0,0,4 + PRODUCTVERSION 1,0,0,4 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -73,14 +73,14 @@ BEGIN VALUE "Comments", "\0" VALUE "CompanyName", "Xeno86\0" VALUE "FileDescription", "sheet\0" - VALUE "FileVersion", "1, 0, 0, 3\0" + VALUE "FileVersion", "1, 0, 0, 4\0" VALUE "InternalName", "sheet\0" - VALUE "LegalCopyright", "Copyright © 2009, Xeno86\0" + VALUE "LegalCopyright", "Copyright © 2009-2010, Xeno86\0" VALUE "LegalTrademarks", "\0" VALUE "OriginalFilename", "sheet.dll\0" VALUE "PrivateBuild", "\0" VALUE "ProductName", "KernelEx\0" - VALUE "ProductVersion", "1, 0, 0, 3\0" + VALUE "ProductVersion", "1, 0, 0, 4\0" VALUE "SpecialBuild", "\0" END END @@ -110,26 +110,31 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US // Dialog // -IDD_PROPPAGE DIALOG DISCARDABLE 0, 0, 190, 127 +IDD_PROPPAGE DIALOG DISCARDABLE 0, 0, 190, 177 STYLE WS_CHILD | WS_DISABLED | WS_CAPTION CAPTION "Compatibility" FONT 8, "MS Sans Serif" BEGIN - GROUPBOX "Compatibility mode",IDC_GCOMPAT,7,30,176,64 - CONTROL "Run this program in compatibility mode for:",IDC_COMPAT, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,57,164,10 + GROUPBOX "Compatibility options",IDC_GCOMPAT,7,30,176,64 + CONTROL "Disable KernelEx extensions",IDC_DISABLE,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,15,43,165,10 + CONTROL "Use specific compatibility mode:",IDC_COMPAT,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,15,57,164,10 COMBOBOX IDC_SYSTEM,15,70,157,60,CBS_DROPDOWNLIST | WS_DISABLED | WS_VSCROLL | WS_TABSTOP - CONTROL "Disable KernelEx extensions for this program", - IDC_DISABLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,43, - 165,10 - LTEXT "kexver here",IDC_KEXVER,7,111,71,9,WS_DISABLED - LTEXT "If you have problems with this program, try selecting\na different compatibility mode.", + LTEXT "kexver here",IDC_KEXVER,7,161,71,9,WS_DISABLED + LTEXT "Try changing compatibility options if you have problems\nwith running this program.", IDC_TCOMPAT,7,7,175,22 - CONTROL "",IDC_HORIZ1,"Static",SS_BLACKFRAME | SS_SUNKEN,7,109, + CONTROL "",IDC_HORIZ1,"Static",SS_BLACKFRAME | SS_SUNKEN,7,160, 176,1 + GROUPBOX "Advanced options",IDC_GADVAN,7,100,176,57 + CONTROL "Don't use these settings in child processes", + IDC_NOINHERIT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,15, + 113,164,10 + CONTROL "Override settings of invidual modules",IDC_OVERRIDE, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,127,164,10 CONTROL "Enable api logging",IDC_LOG,"Button",BS_AUTOCHECKBOX | - NOT WS_VISIBLE | WS_TABSTOP,15,96,74,10 + NOT WS_VISIBLE | WS_TABSTOP,15,141,164,10 END @@ -146,11 +151,27 @@ BEGIN LEFTMARGIN, 7 RIGHTMARGIN, 183 TOPMARGIN, 7 - BOTTOMMARGIN, 120 + BOTTOMMARGIN, 170 END END #endif // APSTUDIO_INVOKED + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN + TIP_DISABLE "Use this option to run this program as if KernelEx wasn't installed." + TIP_COMPAT "Changes operating system identification and emulates different operating system behavior. Choose operating system which is required to run this program." + TIP_SYSTEM "Select operating system to emulate from the list." + TIP_NOINHERIT "Disables inheritance of these settings. Normally programs started by this application use settings from this tab as their default settings. Use this option to disable such behaviour." + TIP_OVERRIDE "Disables usage of per module settings. Use this option to use same settings for all modules in the application." + TIP_LOG "Use this option to enable api spying debugging feature." +END + #endif // English (U.S.) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/util/dumpconf.c b/util/dumpconf.c old mode 100644 new mode 100755 diff --git a/util/dumpimte.c b/util/dumpimte.c old mode 100644 new mode 100755 diff --git a/util/dumpsett.c b/util/dumpsett.c old mode 100644 new mode 100755 diff --git a/util/funique.cpp b/util/funique.cpp old mode 100644 new mode 100755 diff --git a/util/load.c b/util/load.c old mode 100644 new mode 100755 diff --git a/util/patterns.txt b/util/patterns.txt old mode 100644 new mode 100755 diff --git a/util/prep/prep.cpp b/util/prep/prep.cpp old mode 100644 new mode 100755 index a0a0622..49f21f9 --- a/util/prep/prep.cpp +++ b/util/prep/prep.cpp @@ -31,6 +31,7 @@ #include #include #include +#include using namespace std; #include "prep.h" @@ -463,41 +464,52 @@ void dump_all() write_ordinal_exports(cout); } -void replace_if_changed(const string& out, const string& in) +void replace(const string& out, const string& in) { - fstream f; - stringstream buf; - string in1; - string in2; + ifstream fin; + ofstream fout; - f.open(out.c_str(), fstream::in); - if (!f) + fin.open(in.c_str(), ios::in); + if (!fin) throw Exception("Failed to open file"); - buf << f.rdbuf(); - in1 = buf.str(); - f.close(); - f.open(in.c_str(), fstream::in); - if (!f) + fout.open(out.c_str(), ios::out | ios::trunc); + if (!fout) throw Exception("Failed to open file"); - buf.clear(); - buf.str(""); - buf << f.rdbuf(); - in2 = buf.str(); - f.close(); + fout << fin.rdbuf(); - if (in1.compare(in2)) - { - f.open(out.c_str(), ios::out | ios::trunc); - if (!f) - throw Exception("Failed to open file"); - f << in2; - f.close(); - } + fout.close(); + fin.close(); remove(in.c_str()); } +bool is_uptodate_dir(const string& path) +{ + string file; + FileFinder ff; + struct _stat st; + time_t mintime; + + ff.search_for(path + "_*_apilist.c"); + file = ff.get_next_file(); + if (file.empty()) + throw Exception("Couldn't find output def file"); + + _stat((path + file).c_str(), &st); + mintime = st.st_mtime; + + ff.search_for(path + "*.c"); + while (!(file = ff.get_next_file()).empty()) + { + _stat((path + file).c_str(), &st); + if (st.st_mtime > mintime) + return false; + } + + return true; +} + void work() { ifstream dirlist("dirlist"); @@ -527,6 +539,11 @@ void work() path += '\\'; cout << "Processing directory: '" << path << '\'' << endl; + if (is_uptodate_dir(path)) + { + cout << "Directory is up to date" << endl; + continue; + } ff.search_for(path + "*.c"); @@ -535,9 +552,6 @@ void work() { FileDeclParser* parser; - //if (file.find("_apilist.") != string::npos) - // continue; - file = path + file; cout << "Parsing file: '" << file << '\'' << endl; @@ -612,7 +626,7 @@ void work() } out_file.close(); - replace_if_changed(file, file + ".tmp"); + replace(file, file + ".tmp"); //write output decls ff.search_for(path + "_*_apilist.h"); @@ -665,7 +679,7 @@ void work() } out_file.close(); - replace_if_changed(file, file + ".tmp"); + replace(file, file + ".tmp"); } } diff --git a/util/prep/prep.dsp b/util/prep/prep.dsp old mode 100644 new mode 100755 index caf855e..6790182 --- a/util/prep/prep.dsp +++ b/util/prep/prep.dsp @@ -52,18 +52,6 @@ LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /OPT:NOWIN98 # SUBTRACT LINK32 /pdb:none -# Begin Custom Build -OutDir=.\Release -WkspDir=. -TargetName=prep -InputPath=.\Release\prep.exe -SOURCE="$(InputPath)" - -"nope" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - $(OutDir)\$(TargetName) "$(WkspDir)\apilibs\kexbases" - $(OutDir)\$(TargetName) "$(WkspDir)\apilibs\kexbasen" - -# End Custom Build !ELSEIF "$(CFG)" == "prep - Win32 Debug" @@ -89,18 +77,6 @@ LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /OPT:NOWIN98 # SUBTRACT LINK32 /pdb:none -# Begin Custom Build -OutDir=.\Debug -WkspDir=. -TargetName=prep -InputPath=.\Debug\prep.exe -SOURCE="$(InputPath)" - -"nope" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - $(OutDir)\$(TargetName) "$(WkspDir)\apilibs\kexbases" - $(OutDir)\$(TargetName) "$(WkspDir)\apilibs\kexbasen" - -# End Custom Build !ENDIF diff --git a/util/prep/prep.h b/util/prep/prep.h old mode 100644 new mode 100755 diff --git a/util/prep/test/_te_apilist.c b/util/prep/test/_te_apilist.c old mode 100644 new mode 100755 diff --git a/util/prep/test/dirlist b/util/prep/test/dirlist old mode 100644 new mode 100755 diff --git a/util/prep/test/junk.c b/util/prep/test/junk.c old mode 100644 new mode 100755 diff --git a/util/prep/test/test.c b/util/prep/test/test.c old mode 100644 new mode 100755 diff --git a/verify/main.cpp b/verify/main.cpp old mode 100644 new mode 100755 diff --git a/verify/resource.h b/verify/resource.h old mode 100644 new mode 100755 diff --git a/verify/verify.dsp b/verify/verify.dsp old mode 100644 new mode 100755 diff --git a/verify/verify.rc b/verify/verify.rc old mode 100644 new mode 100755