diff --git a/2.x/trunk/CHANGELOG.txt b/2.x/trunk/CHANGELOG.txt index a51e65fe3..eda632245 100644 --- a/2.x/trunk/CHANGELOG.txt +++ b/2.x/trunk/CHANGELOG.txt @@ -2,6 +2,7 @@ Process Hacker 2.7 * NEW/IMPROVED: + * Vastly improved startup time, and lower memory usage * FIXED: * ToolStatus layout problems diff --git a/2.x/trunk/ProcessHacker/include/phapp.h b/2.x/trunk/ProcessHacker/include/phapp.h index e3c4ca124..6c0fc7713 100644 --- a/2.x/trunk/ProcessHacker/include/phapp.h +++ b/2.x/trunk/ProcessHacker/include/phapp.h @@ -12,7 +12,7 @@ #include #include #include -#include "resource.h" +#include "../resource.h" #define KPH_ERROR_MESSAGE (L"KProcessHacker does not support your operating system " \ L"or could not be loaded. Make sure Process Hacker is running " \ @@ -267,8 +267,6 @@ VOID PhUpdateProcessNode( VOID PhTickProcessNodes(); -HICON PhGetStockAppIcon(); - PHAPPAPI PPH_PROCESS_ITEM PhGetSelectedProcessItem(); diff --git a/2.x/trunk/ProcessHacker/mainwnd.c b/2.x/trunk/ProcessHacker/mainwnd.c index 78700d6ad..45b9a24e9 100644 --- a/2.x/trunk/ProcessHacker/mainwnd.c +++ b/2.x/trunk/ProcessHacker/mainwnd.c @@ -33,10 +33,6 @@ #include #include -typedef BOOL (WINAPI *_FileIconInit)( - __in BOOL RestoreCache - ); - typedef HRESULT (WINAPI *_LoadIconMetric)( __in HINSTANCE hinst, __in PCWSTR pszName, @@ -272,22 +268,6 @@ BOOLEAN PhMainWndInitialization( { PH_RECTANGLE windowRectangle; - // Initialize the system image lists. - { - HMODULE shell32; - _FileIconInit fileIconInit; - - shell32 = LoadLibrary(L"shell32.dll"); - - if (shell32) - { - fileIconInit = (_FileIconInit)GetProcAddress(shell32, (PSTR)660); - - if (fileIconInit) - fileIconInit(FALSE); - } - } - if (PhGetIntegerSetting(L"FirstRun")) { PPH_STRING autoDbghelpPath; @@ -2495,9 +2475,23 @@ VOID PhpAddIconProcesses( // Menu icons only work properly on Vista and above. if (WindowsVersion >= WINDOWS_VISTA) - iconBitmap = PhIconToBitmap(processItem->SmallIcon ? processItem->SmallIcon : PhGetStockAppIcon(), 16, 16); + { + if (processItem->SmallIcon) + { + iconBitmap = PhIconToBitmap(processItem->SmallIcon, 16, 16); + } + else + { + HICON icon; + + PhGetStockApplicationIcon(&icon, NULL); + iconBitmap = PhIconToBitmap(icon, 16, 16); + } + } else + { iconBitmap = NULL; + } subMenu->Bitmap = iconBitmap; Bitmaps[i] = iconBitmap; @@ -4321,8 +4315,11 @@ VOID PhMainWndOnNetworkItemAdded( if (!NetworkImageListWrapper.Handle) { + HICON icon; + + PhGetStockApplicationIcon(&icon, NULL); PhInitializeImageListWrapper(&NetworkImageListWrapper, 16, 16, ILC_COLOR32 | ILC_MASK); - PhImageListWrapperAddIcon(&NetworkImageListWrapper, PhGetStockAppIcon()); + PhImageListWrapperAddIcon(&NetworkImageListWrapper, icon); ListView_SetImageList(NetworkListViewHandle, NetworkImageListWrapper.Handle, LVSIL_SMALL); } diff --git a/2.x/trunk/ProcessHacker/procprv.c b/2.x/trunk/ProcessHacker/procprv.c index 911cefc3b..f7b857362 100644 --- a/2.x/trunk/ProcessHacker/procprv.c +++ b/2.x/trunk/ProcessHacker/procprv.c @@ -582,26 +582,16 @@ VOID PhpProcessQueryStage1( if (processItem->FileName) { // Small icon, large icon. + if (ExtractIconEx( + processItem->FileName->Buffer, + 0, + &Data->LargeIcon, + &Data->SmallIcon, + 1 + ) == 0) { - SHFILEINFO fileInfo; - - if (SHGetFileInfo( - processItem->FileName->Buffer, - 0, - &fileInfo, - sizeof(SHFILEINFO), - SHGFI_ICON | SHGFI_SMALLICON - )) - Data->SmallIcon = fileInfo.hIcon; - - if (SHGetFileInfo( - processItem->FileName->Buffer, - 0, - &fileInfo, - sizeof(SHFILEINFO), - SHGFI_ICON | SHGFI_LARGEICON - )) - Data->LargeIcon = fileInfo.hIcon; + Data->LargeIcon = NULL; + Data->SmallIcon = NULL; } // Version info. @@ -610,30 +600,22 @@ VOID PhpProcessQueryStage1( // Use the default EXE icon if we didn't get the file's icon. { - SHFILEINFO fileInfo; - - if (!Data->SmallIcon) + if (!Data->SmallIcon || !Data->LargeIcon) { - if (SHGetFileInfo( - L".exe", - FILE_ATTRIBUTE_NORMAL, - &fileInfo, - sizeof(SHFILEINFO), - SHGFI_ICON | SHGFI_SMALLICON | SHGFI_USEFILEATTRIBUTES - )) - Data->SmallIcon = fileInfo.hIcon; - } + if (Data->SmallIcon) + { + DestroyIcon(Data->SmallIcon); + Data->SmallIcon = NULL; + } + else if (Data->LargeIcon) + { + DestroyIcon(Data->LargeIcon); + Data->LargeIcon = NULL; + } - if (!Data->LargeIcon) - { - if (SHGetFileInfo( - L".exe", - FILE_ATTRIBUTE_NORMAL, - &fileInfo, - sizeof(SHFILEINFO), - SHGFI_ICON | SHGFI_LARGEICON | SHGFI_USEFILEATTRIBUTES - )) - Data->LargeIcon = fileInfo.hIcon; + PhGetStockApplicationIcon(&Data->SmallIcon, &Data->LargeIcon); + Data->SmallIcon = DuplicateIcon(NULL, Data->SmallIcon); + Data->LargeIcon = DuplicateIcon(NULL, Data->LargeIcon); } } diff --git a/2.x/trunk/ProcessHacker/proctree.c b/2.x/trunk/ProcessHacker/proctree.c index f3375d66e..3276ed103 100644 --- a/2.x/trunk/ProcessHacker/proctree.c +++ b/2.x/trunk/ProcessHacker/proctree.c @@ -463,25 +463,6 @@ VOID PhTickProcessNodes() } } -HICON PhGetStockAppIcon() -{ - if (!StockAppIcon) - { - SHFILEINFO fileInfo = { 0 }; - - SHGetFileInfo( - L".exe", - FILE_ATTRIBUTE_NORMAL, - &fileInfo, - sizeof(SHFILEINFO), - SHGFI_USEFILEATTRIBUTES | SHGFI_ICON | SHGFI_SMALLICON - ); - StockAppIcon = fileInfo.hIcon; - } - - return StockAppIcon; -} - VOID PhpUpdateProcessNodeWsCounters( __inout PPH_PROCESS_NODE ProcessNode ) @@ -1480,7 +1461,7 @@ BOOLEAN NTAPI PhpProcessTreeListCallback( } else { - getNodeIcon->Icon = PhGetStockAppIcon(); + PhGetStockApplicationIcon(&getNodeIcon->Icon, NULL); } getNodeIcon->Flags = TLC_CACHE; diff --git a/2.x/trunk/phlib/guisup.c b/2.x/trunk/phlib/guisup.c index d40316165..80ee23f6d 100644 --- a/2.x/trunk/phlib/guisup.c +++ b/2.x/trunk/phlib/guisup.c @@ -774,6 +774,65 @@ VOID PhImageListWrapperRemove( PhAddItemList(Wrapper->FreeList, (PVOID)Index); } +VOID PhGetStockApplicationIcon( + __out_opt HICON *SmallIcon, + __out_opt HICON *LargeIcon + ) +{ + static PH_INITONCE initOnce = PH_INITONCE_INIT; + static HICON smallIcon = NULL; + static HICON largeIcon = NULL; + + // This no longer uses SHGetFileInfo because it is *very* slow and causes + // many other DLLs to be loaded, increasing memory usage. + + if (PhBeginInitOnce(&initOnce)) + { + PPH_STRING systemDirectory; + PPH_STRING dllFileName; + + // user32,0 (Vista and above) or shell32,2 (XP) contains the default application icon. + + if (systemDirectory = PhGetSystemDirectory()) + { + PH_STRINGREF dllBaseName; + ULONG index; + + // TODO: Find a better solution. + + if (WindowsVersion >= WINDOWS_VISTA) + { + PhInitializeStringRef(&dllBaseName, L"\\user32.dll"); + index = 0; + } + else + { + PhInitializeStringRef(&dllBaseName, L"\\shell32.dll"); + index = 2; + } + + dllFileName = PhConcatStringRef2(&systemDirectory->sr, &dllBaseName); + PhDereferenceObject(systemDirectory); + + ExtractIconEx(dllFileName->Buffer, index, &largeIcon, &smallIcon, 1); + PhDereferenceObject(dllFileName); + } + + // Fallback icons - this is bad, because the icon isn't scaled correctly. + if (!smallIcon) + smallIcon = LoadIcon(NULL, IDI_APPLICATION); + if (!largeIcon) + largeIcon = LoadIcon(NULL, IDI_APPLICATION); + + PhEndInitOnce(&initOnce); + } + + if (SmallIcon) + *SmallIcon = smallIcon; + if (LargeIcon) + *LargeIcon = largeIcon; +} + HICON PhGetFileShellIcon( __in_opt PWSTR FileName, __in_opt PWSTR DefaultExtension, @@ -784,6 +843,34 @@ HICON PhGetFileShellIcon( ULONG iconFlag; HICON icon; + if (DefaultExtension && PhEqualStringZ(DefaultExtension, L".exe", TRUE)) + { + // Special case for executable files (see above for reasoning). + + icon = NULL; + + if (FileName) + { + ExtractIconEx( + FileName, + 0, + LargeIcon ? &icon : NULL, + !LargeIcon ? &icon : NULL, + 1 + ); + } + + if (!icon) + { + PhGetStockApplicationIcon( + !LargeIcon ? &icon : NULL, + LargeIcon ? &icon : NULL + ); + } + + return icon; + } + iconFlag = LargeIcon ? SHGFI_LARGEICON : SHGFI_SMALLICON; icon = NULL; diff --git a/2.x/trunk/phlib/include/phgui.h b/2.x/trunk/phlib/include/phgui.h index d6c9275ed..7a9fbbbe5 100644 --- a/2.x/trunk/phlib/include/phgui.h +++ b/2.x/trunk/phlib/include/phgui.h @@ -443,6 +443,12 @@ VOID PhImageListWrapperRemove( __in INT Index ); +PHLIBAPI +VOID PhGetStockApplicationIcon( + __out_opt HICON *SmallIcon, + __out_opt HICON *LargeIcon + ); + PHLIBAPI HICON PhGetFileShellIcon( __in_opt PWSTR FileName, diff --git a/2.x/trunk/phlib/support.c b/2.x/trunk/phlib/support.c index 671eefdde..88ba8ccfb 100644 --- a/2.x/trunk/phlib/support.c +++ b/2.x/trunk/phlib/support.c @@ -1706,10 +1706,22 @@ PPH_STRING PhGetBaseName( PPH_STRING PhGetSystemDirectory() { + static PPH_STRING cachedSystemDirectory = NULL; + PPH_STRING systemDirectory; ULONG bufferSize; ULONG returnLength; + // Use the cached value if possible. + + systemDirectory = cachedSystemDirectory; + + if (systemDirectory) + { + PhReferenceObject(systemDirectory); + return systemDirectory; + } + bufferSize = 0x40; systemDirectory = PhCreateStringEx(NULL, bufferSize * 2); @@ -1732,6 +1744,17 @@ PPH_STRING PhGetSystemDirectory() PhTrimToNullTerminatorString(systemDirectory); + // Try to cache the value. + if (_InterlockedCompareExchangePointer( + &cachedSystemDirectory, + systemDirectory, + NULL + ) == NULL) + { + // Success, add one more reference for the cache. + PhReferenceObject(systemDirectory); + } + return systemDirectory; }