Page 1 of 1

Device Manager

Posted: Mon Mar 28, 2016 12:48 am
by Thunder93
I've made the fundamentals of Windows Device Manager. It's limited, but can be used as bases for creating an expert utility and meet various criteria. If your a PC technician, It may be useful project to work on.

Image

Main.pb

Code: Select all

; By Thunder93
;   Released to PureBasic Community on March 27th, 2016
;   
;   Requirements: setupapi_h.pbi, cfg_h.pbi files~
;     - available on ' SetupAPI, Cfg+ headers (for PureBasic Community) '
;        http://www.purebasic.fr/english/viewtopic.php?f=5&t=65230
;   Last Updated: March 28th, 2016 (#4)


Global hImageList
Global MergedIcons

IncludeFile "GetHardwareList_Func.pbi"

#ICON_DEV_PROBLEM  = 80
#ICON_DEV_DISABLED = 81
#ICON_DEV_INFO     = 82
#ICON_DEV_UNKNOWN  = 103


Structure GetFont
  Fontsize.b
  FontName.s
EndStructure : Global GetFont.GetFont

Global Dim Hd.HardwareInfo(200)

Declare.b SortALLTreeviewItemsbyNameAscending(GadgetID)
Declare.s GetComputerName()
Declare.b GetFontINFO()
Declare.b AddItem2Tree(ItemName.s, Pos.l)
Declare.b Main_Win()

If GetHardwareList(Hd(), 0, 1) = #True    
  Main_Win()  
EndIf
End


Procedure.b Main_Win()
  Protected i
  
  If OpenWindow(0, 0, 0, 700, 600, "Device Manager", #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_MinimizeGadget)
    If CreateStatusBar(0, WindowID(0))
      AddStatusBarField(420)
    EndIf
    
    GetFontINFO()
    If LoadFont(2, GetFont\FontName, GetFont\Fontsize)
      SetGadgetFont(#PB_Default, FontID(2))
    EndIf
    
    TreeGadget(1, 5, 5, WindowWidth(0)-10, WindowHeight(0)-StatusBarHeight(0)-10, #PB_Tree_NoLines)    
    
    AddGadgetItem(1, -1, GetComputerName(), ImageList_GetIcon_(hImageList, 34, #ILD_NORMAL), 1)    
    
    SortStructuredArray(Hd(), 0, OffsetOf(HardwareInfo\ClassDescription), TypeOf(HardwareInfo\ClassDescription))
    
    
    For i=0 To ArraySize(Hd())
      If Hd(i)\Class <> Class$
        Class$ = Hd(i)\Class
        AddGadgetItem(1, -1, Hd(i)\ClassDescription, ImageList_GetIcon_(hImageList, Hd(i)\ClassImgIndex, #ILD_NORMAL), 1)        
      EndIf
      
      AddItem2Tree(Hd(i)\Name, i)         
    Next
    
    SetGadgetItemState(1, 0, #PB_Tree_Expanded)
    
    StatusBarText(0, 0, Str(i)+" Items Found!")
    
    SortALLTreeviewItemsbyNameAscending(1)    
    
    Repeat
    Until WaitWindowEvent() = #PB_Event_CloseWindow
    
    If hImageList
      ImageList_Destroy_(hImageList)
    EndIf
    
    For i = 0 To ArraySize(Hd())
      DestroyIcon_(Hd(i)\hIcon)
    Next
  EndIf
EndProcedure


Structure ICONINFOEX Align #PB_Structure_AlignC
  cbSize.l
  fIcon.l
  xHotspot.l
  yHotspot.l
  hbmMask.i
  hbmColor.i
  wResID.w
  szModName.c[#MAX_PATH]
  szResName.c[#MAX_PATH]
EndStructure

#hBITMAP = 0
#hICON = 1

Procedure CreateFadedImage(hImage, Intensity.l = 100, TypeImg.l = #hICON)
  Protected ImageID = hImage, FadedImage, IB.BITMAP
  
  If TypeImg
    Protected Image_Bitmap.BITMAP, IconInfo.ICONINFOEX       
    IconInfo\cbSize = SizeOf(ICONINFOEX)
    GetIconInfoEx(hImage, @IconInfo)
    DestroyIcon_(hImage)
    ImageID = CopyImage_(IconInfo\hbmColor, #IMAGE_BITMAP, 0, 0, #LR_CREATEDIBSECTION)   
  EndIf
  
  
  If GetObject_(ImageID, SizeOf(BITMAP), @IB)    
    FadedImage = CreateImage(#PB_Any, IB\bmWidth, IB\bmHeight, 32, #PB_Image_Transparent)    
    
    StartDrawing(ImageOutput(FadedImage))
    DrawAlphaImage(ImageID, 0, 0, Intensity) 
    StopDrawing()
    
    DeleteObject_(ImageID)
    
    ProcedureReturn ImageID(FadedImage)
  EndIf
EndProcedure

Procedure MergeImages(hICON, Mode.b)
  Protected Image_Bitmap.BITMAP, IconInfo.ICONINFOEX
  Protected hICON2, MergedIcons, ImageID, ImageID1, ImageID2
  
  hICON2 = ImageList_GetIcon_(hImageList, Mode, #ILD_NORMAL)
  
  IconInfo\cbSize = SizeOf(ICONINFOEX)
  GetIconInfoEx(hICON2, @IconInfo)   
  DestroyIcon_(hICON2)
  
  ImageID1 = CopyImage_(IconInfo\hbmColor, #IMAGE_BITMAP, 0, 0, #LR_CREATEDIBSECTION)  
  
  GetIconInfoEx(hICON, @IconInfo)        
  ImageID2 = CopyImage_(IconInfo\hbmColor, #IMAGE_BITMAP, 0, 0, #LR_CREATEDIBSECTION)
  
  MergedIcons = CreateImage(#PB_Any, 16, 16, 32, #PB_Image_Transparent)
  If StartDrawing(ImageOutput(MergedIcons))
    DrawAlphaImage(ImageID2, 0, 0, 255)
    DrawAlphaImage(ImageID1, 0, 0, 255)
    StopDrawing()
  EndIf
  
  DeleteObject_(ImageID1)
  DeleteObject_(ImageID2)
  
  ProcedureReturn ImageID(MergedIcons)
EndProcedure      

Procedure.b AddItem2Tree(ItemName.s, Pos.l)
  Protected.l CM_Status, CM_Problem
  
  CM_Status = Hd(Pos)\CM_Status : CM_Problem = Hd(Pos)\CM_Problem
  
  If #DN_STARTED & (CM_Status + CM_Problem) Or (CM_Problem = 0 And CM_Status)
    AddGadgetItem(1, -1, ItemName, Hd(Pos)\hICON, 2)
    
    ElseIf CM_Problem = #CM_PROB_DISABLED
      AddGadgetItem(1, -1, ItemName, MergeImages(Hd(Pos)\hICON, #ICON_DEV_DISABLED), 2)
      
    ElseIf 0 = (CM_Status + CM_Problem)      
      AddGadgetItem(1, -1, ItemName, CreateFadedImage(Hd(Pos)\hICON), 2)
    Else
      AddGadgetItem(1, -1, ItemName, MergeImages(Hd(Pos)\hICON, #ICON_DEV_UNKNOWN), 2)      
  EndIf  
EndProcedure

Procedure.b SortALLTreeViewItemsbyNameAscending(GadgetID)
  Protected i.l
  
  For i=0 To CountGadgetItems(GadgetID)-1
    If SendMessage_(GadgetID(GadgetID), #TVM_GETNEXTITEM, #TVGN_CHILD, GadgetItemID(GadgetID, i))
      SendMessage_(GadgetID(GadgetID), #TVM_SORTCHILDREN, 0, GadgetItemID(GadgetID, i))
    EndIf
  Next
  SendMessage_(GadgetID(GadgetID), #TVM_SORTCHILDREN, 0, 0)
EndProcedure

Procedure.s GetComputerName()
  Protected buffer.s=Space(64), bufsize.l=64
  GetComputerName_(@buffer, @bufsize)
  
  ProcedureReturn buffer
EndProcedure

Procedure.b GetFontINFO()
  Protected hGDIOBJ = GetStockObject_(#DEFAULT_GUI_FONT)
  
  If hGDIOBJ
    Protected fINFO.LOGFONT
    
    GetObject_(hGDIOBJ,SizeOf(LOGFONT),@fINFO)
    GetFont\Fontsize-fINFO\lfHeight
    GetFont\FontName = PeekS(@fINFO\lfFaceName[0])
    DeleteObject_(hGDIOBJ)
  Else
    GetFont\FontName = "System"
    GetFont\Fontsize = 12
  EndIf
  
  ProcedureReturn GetFont\Fontsize
EndProcedure
GetHardwareList_Func.pbi - ( this file can be compiled with debugger directly, and testing, Skipping the Main.pb containing the GUI. )

Code: Select all

XIncludeFile "\[Headers]\setupapi_h.pbi"
XIncludeFile "\[Headers]\cfg_h.pbi"


;Constant from CFGMGR32_H
#MAX_CLASS_NAME_LEN = 32
;________________________
#MAX_IT             = #MAX_PATH+64
;________________________


Global hImageList

Structure HardwareInfo
  Name.s{#MAX_IT}
  Class.s{#MAX_CLASS_NAME_LEN}
  ClassDescription.s
  ClassGUID.s
  ClassImgIndex.l
  *hIcon
  CM_Status.l
  CM_Problem.l  
EndStructure

Prototype GetIconInfoEx(*hICON, PICONINFOEX)

Global GetIconInfoEx.GetIconInfoEx

Declare.b User32_Init()
Declare.b User32_End()

Declare.s GetGUID(guid)

Procedure.b GetHardwareList(Array Hd.HardwareInfo(1), Max.l = 200, GetImage.b = 0)
  If setupapi_Init() = #False : ProcedureReturn -1 : EndIf
  If User32_Init() = #False : setupapi_End() : ProcedureReturn -3 : EndIf  
  
  Protected hDevInfo
  hDevInfo = SetupDiGetClassDevs_(#Null, #Null, #Null, #DIGCF_ALLCLASSES)
  
  If hDevInfo = #INVALID_HANDLE_VALUE    
    ProcedureReturn 0
  EndIf  
  
  Protected ClassImageListData.SP_CLASSIMAGELIST_DATA
  
  Protected DeviceInfoData.SP_DEVINFO_DATA
  Protected.l Property, reqSize, iIdx, ArrayPos, ClassImgIndex
  Protected.l CM_Status, CM_Problem
  Protected ClassDescription.s
  
  
  DeviceInfoData\cbSize = SizeOf(SP_DEVINFO_DATA)
  ClassImageListData\cbSize = SizeOf(ClassImageListData)  
  If SetupDiGetClassImageList_(ClassImageListData) = #False
    GetImage = 0
  EndIf
  
  
  While SetupDiEnumDeviceInfo_(hDevInfo, iIdx, @DeviceInfoData)    
    If GetLastError_() = #ERROR_NO_MORE_ITEMS : Break : EndIf
    
    Property = #SPDRP_FRIENDLYNAME    
    If Not SetupDiGetDeviceRegistryProperty_(hDevInfo, @DeviceInfoData, #SPDRP_FRIENDLYNAME, #Null, #Null, 0, @reqSize)
      If GetLastError_() = #ERROR_INVALID_DATA        
        SetupDiGetDeviceRegistryProperty_(hDevInfo, @DeviceInfoData, #SPDRP_DEVICEDESC, #Null, #Null, 0, @reqSize)
        If GetLastError_() = #ERROR_INSUFFICIENT_BUFFER
          Property = #SPDRP_DEVICEDESC
        Else
          ArrayPos = iIdx
          Goto PhaseWrap:
        EndIf        
      EndIf      
    EndIf   
    
    Hd(ArrayPos)\ClassGUID = GetGuid(DeviceInfoData\ClassGuid)
    
    CM_Retr = CM_Get_DevNode_Status(@CM_Status, @CM_Problem, DeviceInfoData\DevInst, 0)
    
    Hd(ArrayPos)\CM_Status = CM_Status
    Hd(ArrayPos)\CM_Problem = CM_Problem    

    SetupDiGetDeviceRegistryProperty_(hDevInfo, @DeviceInfoData, Property, #Null, @Hd(ArrayPos)\Name, #MAX_IT, #Null)
    SetupDiGetDeviceRegistryProperty_(hDevInfo, @DeviceInfoData, #SPDRP_CLASS, #Null, @Hd(ArrayPos)\Class, #MAX_CLASS_NAME_LEN, #Null)  
    
    ClassDescription.s = Space(#MAX_PATH)    
    If SetupDiGetClassDescription(DeviceInfoData\ClassGuid, @ClassDescription, #MAX_PATH, 0)
      Hd(ArrayPos)\ClassDescription = ClassDescription
    EndIf
    
    If GetImage      
      SetupDiLoadDeviceIcon(hDevInfo, @DeviceInfoData, 16, 16, 0, @Hd(ArrayPos)\hIcon)
    EndIf
    
    If SetupDiGetClassImageIndex_(ClassImageListData, DeviceInfoData\ClassGuid, @ClassImgIndex) = #True
      Hd(ArrayPos)\ClassImgIndex = ClassImgIndex
    EndIf
    
    ArrayPos+1
    PhaseWrap:
    CM_Status = 0 : CM_Problem = 0
    iIdx+1
    If iIdx > Max : Max = iIdx+20 : ReDim Hd(Max) : EndIf
  Wend 
  
  If GetImage
    hImageList = ImageList_Duplicate_(ClassImageListData\ImageList)
  EndIf
  
  
  ReDim Hd.HardwareInfo(ArrayPos-1)
  
  SetupDiDestroyClassImageList_(ClassImageListData)
  SetupDiDestroyDeviceInfoList_(hDevInfo)
  
  User32_End() : setupapi_End()
  
  If *pBuf : FreeMemory(*pBuf) : EndIf
  
  ProcedureReturn 1
EndProcedure

Procedure.s GetGUID(Guid)
  Protected  lpsz.s{78}
  ProcedureReturn PeekS(@lpsz, StringFromGUID2_(Guid, @lpsz, 78), #PB_Unicode)
EndProcedure

CompilerIf #PB_Compiler_IsMainFile  
  MaxArray_Size.l = 200 : GetImage.b = 0
  Dim Hd.HardwareInfo(MaxArray_Size)
  GetHardwareList(Hd.HardwareInfo(), MaxArray_Size)
  
  Debug "(((( Array Size: "+ArraySize(Hd())+" ))))"+#LF$
  For i = 0 To ArraySize(Hd())
    Debug "Item: "+Str(i+1)
    Debug "  Device Name: "+Hd(i)\Name
    Debug "  Class: "+Hd(i)\Class
    Debug "  Class Description: "+Hd(i)\ClassDescription
    Debug "  Class GUID: "+Hd(i)\ClassGUID
    Debug "  Class Image Index: "+Hd(i)\ClassImgIndex 
    
    Debug "  CM_Status: "+Hd(i)\CM_Status
    Debug "  CM_Problem: "+Hd(i)\CM_Problem+#CRLF$
    
    If Hd(i)\CM_Status
      Debug "  Device Status flags...:"
      If Hd(i)\CM_Status & #DN_ROOT_ENUMERATED : Debug "    DN_ROOT_ENUMERATED" : EndIf
      If Hd(i)\CM_Status & #DN_DRIVER_LOADED : Debug "    DN_DRIVER_LOADED" : EndIf
      If Hd(i)\CM_Status & #DN_ENUM_LOADED : Debug "    DN_ENUM_LOADED" : EndIf
      If Hd(i)\CM_Status & #DN_STARTED : Debug "    DN_STARTED" : EndIf
      If Hd(i)\CM_Status & #DN_MANUAL : Debug "    DN_MANUAL" : EndIf
      If Hd(i)\CM_Status & #DN_NEED_TO_ENUM : Debug "    DN_NEED_TO_ENUM" : EndIf
      If Hd(i)\CM_Status & #DN_DRIVER_BLOCKED : Debug "    DN_DRIVER_BLOCKED" : EndIf
      If Hd(i)\CM_Status & #DN_HARDWARE_ENUM : Debug "    DN_HARDWARE_ENUM" : EndIf
      If Hd(i)\CM_Status & #DN_NEED_RESTART : Debug "    DN_NEED_RESTART" : EndIf
      If Hd(i)\CM_Status & #DN_CHILD_WITH_INVALID_ID : Debug "    DN_CHILD_WITH_INVALID_ID" : EndIf    
      If Hd(i)\CM_Status & #DN_HAS_PROBLEM : Debug "    DN_HAS_PROBLEM" : EndIf
      If Hd(i)\CM_Status & #DN_FILTERED : Debug "    DN_FILTERED" : EndIf
      If Hd(i)\CM_Status & #DN_LEGACY_DRIVER : Debug "    DN_LEGACY_DRIVER" : EndIf
      If Hd(i)\CM_Status & #DN_DISABLEABLE : Debug "    DN_DISABLEABLE" : EndIf
      If Hd(i)\CM_Status & #DN_REMOVABLE : Debug "    DN_REMOVABLE" : EndIf
      If Hd(i)\CM_Status & #DN_PRIVATE_PROBLEM : Debug "    DN_PRIVATE_PROBLEM" : EndIf
      If Hd(i)\CM_Status & #DN_MF_PARENT : Debug "    DN_MF_PARENT" : EndIf
      If Hd(i)\CM_Status & #DN_MF_CHILD : Debug "    DN_MF_CHILD" : EndIf
      If Hd(i)\CM_Status & #DN_WILL_BE_REMOVED : Debug "    DN_WILL_BE_REMOVED" : EndIf
      If Hd(i)\CM_Status & #DN_NOT_FIRST_TIMEE : Debug "    DN_NOT_FIRST_TIMEE" : EndIf
      If Hd(i)\CM_Status & #DN_STOP_FREE_RES : Debug "    DN_STOP_FREE_RES" : EndIf
      If Hd(i)\CM_Status & #DN_REBAL_CANDIDATE : Debug "    DN_REBAL_CANDIDATE" : EndIf
      If Hd(i)\CM_Status & #DN_BAD_PARTIAL : Debug "    DN_BAD_PARTIAL" : EndIf
      If Hd(i)\CM_Status & #DN_NT_ENUMERATOR : Debug "    DN_NT_ENUMERATOR" : EndIf
      If Hd(i)\CM_Status & #DN_NT_DRIVER : Debug "    DN_NT_DRIVER" : EndIf
      If Hd(i)\CM_Status & #DN_NEEDS_LOCKING : Debug "    DN_NEEDS_LOCKING" : EndIf
      If Hd(i)\CM_Status & #DN_ARM_WAKEUP : Debug "    DN_ARM_WAKEUP" : EndIf
      If Hd(i)\CM_Status & #DN_APM_ENUMERATOR : Debug "    DN_APM_ENUMERATOR" : EndIf
      If Hd(i)\CM_Status & #DN_APM_DRIVER : Debug "    DN_APM_DRIVER" : EndIf
      If Hd(i)\CM_Status & #DN_SILENT_INSTALL : Debug "    DN_SILENT_INSTALL" : EndIf
      If Hd(i)\CM_Status & #DN_NO_SHOW_IN_DM : Debug "    DN_NO_SHOW_IN_DM" : EndIf
      If Hd(i)\CM_Status & #DN_BOOT_LOG_PROB : Debug "    DN_BOOT_LOG_PROB" : EndIf
    EndIf    
    Debug "-"
  Next
  
  FreeArray(Hd())
  End
CompilerEndIf

Procedure.b User32_Init()
  Shared hUser32, cExt
  Protected Retr.b
  
  hUser32 = OpenLibrary(#PB_Any, "user32.dll")
  If hUser32 <> 0
    GetIconInfoEx = GetFunction(hUser32, "GetIconInfoEx"+cExt)
    Retr = 1
  EndIf
  
  ProcedureReturn Retr
EndProcedure

Procedure.b User32_End()
  Shared hUser32
  CloseLibrary(hUser32)
EndProcedure

Re: Device Manager

Posted: Mon Mar 28, 2016 7:22 am
by Joris
Thanks but, don't we need these XIncludeFile setupapi_h.pbi and cfg_h.pb too ?

Re: Device Manager

Posted: Mon Mar 28, 2016 7:24 am
by Thunder93
They are available via link also giving in the code section at the top.. of the Main.pb

Re: Device Manager

Posted: Mon Mar 28, 2016 7:25 am
by Thunder93
; Requirements: setupapi_h.pbi, cfg_h.pbi files~
; - available on ' SetupAPI, Cfg+ headers (for PureBasic Community) '
; http://www.purebasic.fr/english/viewtop ... =5&t=65230

Re: Device Manager

Posted: Mon Mar 28, 2016 8:03 am
by Bisonte
Good work !

Btw. this works with Win10 x64 compiled with PB5.42x64

Re: Device Manager

Posted: Mon Mar 28, 2016 11:31 am
by Thunder93
Thank you, you guys.

I believe it should work with Windows Vista+.

However the APIs used to get and handle the graphics can be switched out to allow it to fully work for Windows 2000 Professional and newer.

Basically here's the API OS requirements;

SetupDiLoadDeviceIcon, ImageList_Duplicate, ImageList_Destroy, GetIconInfoEx - Available in Windows Vista and later versions of Windows.

CopyImage, DestroyIcon, GetStockObject, DeleteObject - Available in Windows 2000 Professional and later versions of Windows.

Rest of the APIs ~ used - Available in Windows 2000 and later versions of Windows.


It has been tested under Windows 10 x64, x64 and x86 compiles. You can use either ASCII or Unicode mode, it shouldn't be affected.
I used PureBasic 5.42 (x64 and x86), and everything checks out good.

Re: Device Manager

Posted: Mon Mar 28, 2016 5:33 pm
by Thunder93
I've made some edits. I also made an adjustment in the setupap_h.pbi file to one of the prototypes.

I feel comfortable with this being good base-line example of Windows – Device Manager.

Enjoy. :wink:

Re: Device Manager

Posted: Sun Jul 31, 2016 9:03 am
by le_magn
PB 5.43LTS : Constant not found: #MAX_IT

Re: Device Manager

Posted: Sun Jul 31, 2016 11:28 am
by Thunder93
GetHardwareList_Func.pbi has been updated to include #MAX_IT constant. One of the updates I've made after it was posted, I managed to miss the constant. Thanks :)

Re: Device Manager

Posted: Sun Jul 31, 2016 11:59 am
by le_magn
Image
Change it to (CM_Status And CM_Problem)=0 ?

Re: Device Manager

Posted: Sun Jul 31, 2016 12:21 pm
by Thunder93
It was actually suppose to be ' + ' instead of ' AND ' , ... like a few lines above.

Code: Select all

0 = (CM_Status + CM_Problem)
Replace AND with +, sorry about that. :)

Thanks once again. :)

Re: Device Manager

Posted: Sun Jul 31, 2016 2:55 pm
by uweb
Thank you, but ...
[15:50:06] Warte auf den Start des Executable...
[15:50:05] Executable-Typ: Windows - x64 (64bit)
[15:50:06] Executable gestartet.
[15:50:06] [ERROR] Main.pb (Zeile: 146)
[15:50:06] [ERROR] DrawAlphaImage(): Das angegebene 'ImageID' ist null.
means : The given 'ImageID' is zero.

On Win7 with PB 5.42 x64 and also with x86.

Re: Device Manager

Posted: Sun Jul 31, 2016 3:55 pm
by le_magn
Thunder93 wrote:It was actually suppose to be ' + ' instead of ' AND ' , ... like a few lines above.

Code: Select all

0 = (CM_Status + CM_Problem)
Replace AND with +, sorry about that. :)

Thanks once again. :)
Yes work great thank you:)

Re: Device Manager

Posted: Sun Jul 31, 2016 5:19 pm
by Thunder93
@le_magn: You certainly welcome.


@uweb: This is strange, I'm not able to reproduce this issue.

Like you said, DrawAlphaImage() is failing because ImageID is not set.

This would imply that the culprit line at fault is 139. CopyImage API is failing for some reason? Would it be possible for you to do GetLastError on the following line, after;

Code: Select all

ImageID1 = CopyImage_(IconInfo\hbmColor, #IMAGE_BITMAP, 0, 0, #LR_CREATEDIBSECTION)

Re: Device Manager

Posted: Mon Aug 01, 2016 9:06 am
by uweb

Code: Select all

Procedure.s GetLastErrorAsText(LastError.l) ; Used to get Last Win32 API Error
   Protected *ErrorBuffer, message.s
   If LastError
    *ErrorBuffer = AllocateMemory(1024)
    FormatMessage_(#FORMAT_MESSAGE_FROM_SYSTEM, 0, LastError, 0, *ErrorBuffer, 1024, 0)
    message.s=PeekS(*ErrorBuffer)
    FreeMemory(*ErrorBuffer)
  EndIf
  ProcedureReturn message
EndProcedure

Procedure MergeImages(hICON, Mode.b)
  Protected Image_Bitmap.BITMAP, IconInfo.ICONINFOEX
  Protected hICON2, MergedIcons, ImageID, ImageID1, ImageID2
 
  hICON2 = ImageList_GetIcon_(hImageList, Mode, #ILD_NORMAL)
 
  IconInfo\cbSize = SizeOf(ICONINFOEX)
  GetIconInfoEx(hICON2, @IconInfo)   
  DestroyIcon_(hICON2)
 
  ImageID1 = CopyImage_(IconInfo\hbmColor, #IMAGE_BITMAP, 0, 0, #LR_CREATEDIBSECTION) : Debug ImageID1 
Debug GetLastError_() : Debug GetLastErrorAsText(GetLastError_())
  GetIconInfoEx(hICON, @IconInfo)       
  ImageID2 = CopyImage_(IconInfo\hbmColor, #IMAGE_BITMAP, 0, 0, #LR_CREATEDIBSECTION) : Debug ImageID2
 
  MergedIcons = CreateImage(#PB_Any, 16, 16, 32, #PB_Image_Transparent)
  If StartDrawing(ImageOutput(MergedIcons))
    DrawAlphaImage(ImageID2, 0, 0, 255)
    DrawAlphaImage(ImageID1, 0, 0, 255)
    StopDrawing()
  EndIf
 
  DeleteObject_(ImageID1)
  DeleteObject_(ImageID2)
 
  ProcedureReturn ImageID(MergedIcons)
EndProcedure 
produce :
0
6
Das Handle ist ungültig.

33890524
This means : The handle is infalid.
0 and 6 appear always.
I think the last one is falid because it changes.

edit - add GetLastErrorAsText() from http://www.purebasic.fr/english/viewtop ... 27&t=62899