October 28, 2025, 11:32:50 AM

News:

IWBasic runs in Windows 11!


Listview with system icons

Started by fasecero, September 26, 2010, 06:26:40 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

fasecero

Hi, I'm trying to show some system icons in a listview, but I get some Access Violations... any clue?



$INCLUDE "WindowsSDK.inc"
$INCLUDE "commoncontrols.inc"
$INCLUDE "CommCtrl.inc"

CONST LISTVIEW_1 = 1
DIALOG d1
CREATEDIALOG d1,0,0,690,422,0x80C80080,0,"Caption",&d1_handler
CONTROL d1,@LISTVIEW,"",13,11,662,393,0x50000001,LISTVIEW_1

DOMODAL d1

SUB d1_handler
SELECT @MESSAGE
CASE @IDINITDIALOG
CENTERWINDOW d1

/* Initialize any controls here */
INT himl = GetSystemImageList(1)
IF himl THEN
ListviewSetImageList( GETCONTROLHANDLE(d1, LISTVIEW_1) , himl)
ListviewAddItem( GETCONTROLHANDLE(d1, LISTVIEW_1), 1, "first", 1)
ENDIF
CASE @IDCLOSEWINDOW
CLOSEDIALOG d1,@IDOK
CASE @IDCONTROL
SELECT @CONTROLID
CASE LISTVIEW_1
/* respond to control notifications here */
ENDSELECT
ENDSELECT
RETURN
ENDSUB


SUB GetSystemImageList(int size), INT
HRESULT hr
INT sizeflag
pointer ppvObj
INT himl = 0

SELECT size
CASE 1
sizeflag = SHIL_SMALL
CASE 2
sizeflag = SHIL_LARGE
DEFAULT
sizeflag = SHIL_EXTRALARGE
ENDSELECT

hr = SHGetImageList(sizeflag, _IID_IImageList, &ppvObj)

IF hr = S_OK THEN himl = *<int> ppvObj

RETURN himl
ENDSUB

SUB ListviewSetImageList(int hwndlv, int himl), INT
RETURN SendMessage(hwndlv, LVM_SETIMAGELIST , LVSIL_NORMAL, himl)
ENDSUB

SUB ListviewAddItem(int hwndlv, int npos, string text, int nimage), INT
LVITEM lvit

lvit.mask= LVIF_IMAGE | LVIF_TEXT
lvit.iItem=npos-1
lvit.iSubItem=0
lvit.pszText=text
lvit.iImage=nimage-1

RETURN SendMessageA(hwndlv, LVM_INSERTITEM,  0, &lvit)
ENDSUB

LarryMc

This is an old program by Sapero that may help you.
WINDOW d1
STRING name
UINT himl_Big, himl_Small, lvView
TYPE LVITEM   /*saved space :) */
    UINT    mask
    INT     iItem[4]
    POINTER pszText[2]
    INT     iImage[6]
ENDTYPE
TYPE LVBKIMAGE   /*saved space :) */
    UINT    ulFlags[2]
    POINTER pszImage[4]
ENDTYPE
Const ID_TCOLOR = 44442
Const ID_BCOLOR = 44443
Const ID_PAPER  = 44444
Const ID_NEW    = 44445
Const ID_BIG    = 0x1000
Const ID_REPORT = 0x1001
Const ID_SMALL  = 0x1002
Const ID_LIST   = 0x1003
Const LVS_ICON      = 0
Const LVS_REPORT    = 1
Const LVS_SMALLICON = 2
Const LVS_LIST      = 3
Declare import, GetSystemDirectory alias GetSystemDirectoryA(lpBuffer:pointer, nSize:int),int
Declare import, ScreenToClient(hwnd:uint, POINT:pointer),int
Declare import, GetCursorPos(POINT:pointer),int
Declare import, GetWindowLong alias GetWindowLongA(hwnd:uint, nIndex:int),uint
Declare import, SetWindowLong alias SetWindowLongA(hWnd:uint, nIndex:int, dwNewLong:uint),uint
Declare import, ZeroMemory alias RtlZeroMemory(dat:uint, length:int),int
Declare import, InvalidateRect(hwnd:uint, opt WINRECT:pointer, opt bErase=TRUE:int),int
Declare import, DestroyIcon(hIcon:uint),int
'Declare import, ImageList_Create(cx:int, xy:int, flags:uint, cInitial:int, cGrow:int),uint
'Declare import, ImageList_ReplaceIcon(himl_Big:uint, position:int, hIcon:uint),int
'Declare import, ImageList_Destroy(himl_Big:uint),int
'Declare import, ImageList_Remove(himl_Big:uint,position:int),int
Declare import, ExtractIconEx alias ExtractIconExA(filename:pointer, index:int, _
      pArrayLarge:pointer, pArraySmall:pointer, nIcons:int),int
openwindow d1,0,0,700,500,@caption|@sysmenu|@minbox|@maxbox|@size,0,"Right click on listview to select file",&winproc
CONTROL d1,@LISTVIEW,"",0,0,856,60,0x50000101,1
controlcmd d1,1,@lvinsertcolumn, 0, "all the icons"
controlcmd d1,1,@lvsetcolwidth,0,200
sizelv()
/* lets go! create image list */
himl_Big   = ImageList_Create(32, 32, 0x21/*ILC_COLOR32|ILC_MASK*/, 150, 150)
himl_Small = ImageList_Create(16, 16, 0x21, 150, 150)
sendmessage d1, 4099/*LVM_SETIMAGELIST*/, 0/*LVSIL_NORMAL*/, himl_Big, 1
sendmessage d1, 4099, 1/*LVSIL_SMALL*/, himl_Small, 1
SetView(LVS_ICON)
/* insert all icons from %systemdir%/shell32.dll */
GetSystemDirectory(name, 255-12)
name+="\\shell32.dll"
LoadIcons()
ChangeWallpaper("http://www.pyxia.com/images/pyxiabanner1.gif")
ChangeColor(1, 0xFFFFFF)
waituntil d1.hwnd=0
end
sub winproc
   select @message
      case @idcreate
         centerwindow d1
         CoInitialize(NULL)
      case @idclosewindow
         ImageList_Destroy(himl_Big)
         ImageList_Destroy(himl_Small)
         CoUninitialize()
         closewindow d1
      case @idsize
         sizelv()
      case @idcontrol
         select @controlid
            case 1
               if @notifycode = @NMRCLICK
                  doContextMenu()
               endif
         endselect
      case @idmenupick
         select @menunum
            case ID_BCOLOR : ChangeColor()
            case ID_TCOLOR : ChangeColor(1)
            case ID_PAPER  : ChangeWallpaper()
            case ID_NEW    : LoadIcons()
'            case ID_BIG    : SetView(LVS_ICON)
'            case ID_SMALL  : SetView(LVS_SMALLICON)
'            case ID_LIST   : SetView(LVS_LIST)
'            case ID_REPORT : SetView(LVS_REPORT)
            case ID_BIG
            case& ID_SMALL
            case& ID_LIST
            case& ID_REPORT : SetView(@menunum&3)
         endselect
   endselect
   return
endsub
sub sizelv
   INT l,t,w,h
   getclientsize d1,l,t,w,h
   setsize d1,0,0,w,h,1
   return
endsub
sub doContextMenu
   POINT pt
   GetCursorPos(pt)
   ScreenToClient(d1.hwnd, pt)
   ContextMenu d1, pt.x, pt.y
   Menuitem "Change background color", 0, ID_BCOLOR
   Menuitem "Change text color",       0, ID_TCOLOR
   Menuitem "Set Wallpaper", 0, ID_PAPER
   Separator
   Menuitem "Load new icon file", 0, ID_NEW
   Separator
   Menuitem "View: Icons",       (lvView=LVS_ICON)<<3,      ID_BIG
   Menuitem "View: Small Icons", (lvView=LVS_SMALLICON)<<3, ID_SMALL
   Menuitem "View: List",        (lvView=LVS_LIST)<<3,      ID_LIST
   Menuitem "View: Report",      (lvView=LVS_REPORT)<<3,    ID_REPORT
   Endmenu
   return
endsub
sub ChangeColor(opt bg:int, opt colorref=-1:int)
   INT colo, hwnd
   hwnd = getcontrolhandle(d1, 1)
   colo = sendmessage(d1, 4096/*LVM_GETBKCOLOR*/, 0,0, 1)
   if colorref = -1
      colo = colorrequest(d1, colo)
   else
      colo = colorref
   endif
   if bg = 0
      sendmessage d1, 4097/*LVM_SETBKCOLOR*/, 0, colo, 1
      sendmessage d1, 4134/*LVM_SETTEXTBKCOLOR*/, 0, colo, 1
   else
      sendmessage d1, 4132/*LVM_SETTEXTCOLOR*/, 0, colo, 1
   endif
   InvalidateRect(hwnd, NULL, TRUE)
   return
endsub
Sub LoadIcons
   LVITEM lvi
   ZeroMemory(&lvi, 52)
   UINT IconBig[512], IconSmall[512], count, a
   ISTRING itemtxt[64]
   if name[0]=0 then name = filerequest("", d1, 1, _
      "exe,dll,ocx,sys,ico|*.exe;*.dll;*.ocx;*.sys;*.ico||")
   if name[0]<>0
      count = ExtractIconEx(name, 0, IconBig, IconSmall, 512)
      ImageList_Remove(himl_Big, -1)   /* remove all icons */
      ImageList_Remove(himl_Small, -1)/* from imagelist */
      CONTROLCMD d1,1, @LVDELETEALL
      SetCaption d1, using("& total # icons", name, count)
      lvi.mask    = 3 /* LVIF_TEXT | LVIF_IMAGE*/
      lvi.pszText = itemtxt
      lvi.iImage  = -1
      lvi.iItem   = -1
      count--
      for a = 0 to count
         if a=0 then seticon d1, IconSmall[0]
         ImageList_ReplaceIcon(himl_Big,   -1, IconBig[a])   /* add icon */
         ImageList_ReplaceIcon(himl_Small, -1, IconSmall[a])
         itemtxt     = using("icon #", a)
         lvi.iImage++
         lvi.iItem++
         SendMessage d1, 4103/*LVM_INSERTITEM*/, 0, &lvi, 1
         DestroyIcon(IconBig[a])
         DestroyIcon(IconSmall[a])
      next a
   endif
   name[0] = 0
   return
EndSub
sub SetView(view:int)
   UINT hwnd, style
   hwnd = getcontrolhandle(d1, 1)
   lvView = view
   style = GetWindowLong(hwnd, -16/*GWL_STYLE*/) & -4 | view
   SetWindowLong(hwnd, -16, style)
   return
EndSub
sub ChangeWallpaper(opt location:string)
   ISTRING path[260]
   POINTER p
   LVBKIMAGE lbgi
   ZeroMemory(&lbgi, 24)
   p = location
   IF p <> NULL
      path = location
   else
      path = filerequest("", d1, 1, "bitmaps|*.bmp||")
   endif
   if path[0] <> 0
      lbgi.pszImage = path
      lbgi.ulFlags = 0x12 /*LVBKIF_STYLE_TILE | LVBKIF_SOURCE_URL*/
      if sendmessage(d1, 4164/*LVM_SETBKIMAGE*/, 0, &lbgi, 1) = FALSE
         messagebox d1, "cannot set new image", ""
      endif
   endif
   return
EndSub


LarryMc
LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

fasecero

Hi Larry, I have to reformulate my question, because it is wrong. The only thing that interests me in my example is the GetSystemImageList(...) function, the rest is just to check it out this function :)
I need the handle of the system image list. I know that I can get the system Imagelist using SHGetFileInfo(...), but I am interested in extra big icons (SHIL_EXTRALARGE flag of SHGetImageList(...) ).
However, the example you've provided have some nice stuff, and it will serve to me as a future reference, thanks again Larry :)

WayneA

September 26, 2010, 11:12:54 PM #3 Last Edit: September 26, 2010, 11:23:28 PM by WayneA
Ha! I haven't solved anything complex in awhile so this was a fun one. Glad I have internet at home now, I surely needed it!

Left Click the window and itll show the image specified at the index.

Okay heres the working example:
$Include "windows.inc"
$Define SHIL_EXTRALARGE 2
$Define ILD_NORMAL 0
Declare Import,SHGetImageList(iImageList As Int,riid As GUID,ppv As Pointer),UInt
Dim wndMain As Window
Dim IID_IImageList As GUID
Define_GUID(IID_IImageList,0x46EB5926,0x582E,0x4017,0x9F,0xDF,0xE8,0x99,0x8D,0xAA,0x09,0x50)
OpenWindow wndMain,0,0,640,480,@MinBox,0,"SHGetImageList",&wndMainProc
WaitUntil IsWindowClosed wndMain
End

Sub wndMainProc
Dim List=0,hdc As UInt
Select @Message
Case @IDLButtonDN
If SHGetImageList(SHIL_EXTRALARGE,IID_IImageList,List)=S_OK Then
hdc=GetHDC(wndMain)
If List And hdc Then
SetCaption wndMain,"List count:"+Str$(ImageList_GetImageCount(List))
_ImageList_Draw(List,0,hdc,0,0,ILD_NORMAL)
_ImageList_Destroy(List)
ReleaseHDC(wndMain,hdc)
Else
MessageBox wndMain,"List:"+Hex$(List)+"\nhdc:"+Hex$(hdc),"Error"
EndIf
Else
MessageBox wndMain,"SHGetImageList failed.","Error"
EndIf
Case @IDCloseWindow
CloseWindow wndMain
EndSelect
EndSub


I didn't really try to debug your original code, because that can confuse me sometimes when working with new APIs. I'm not sure what you were doing wrong, however I purposely defined the GUID on my own since I saw here:
http://www.ms-news.net/f2749/shgetimagelist-iid_iimagelist-4101385.html

That the predefined GUID was wrong for someone else, also I couldn't find a data structure for HIMAGELIST so I dug a little and found theres a suite of function for using these lists. Basically I get the impression that you can't really cast the returned pointer as an HIMAGELIST, everything that will accept this type of variable is actually a COM wrapper. Trying to access this as readable data would conceivable cause access violations though I didn't test it.

Hope this helps :)
99 little bugs in the code,
99 bugs in the code,
Fix one bug,
Compile again,
104 little bugs in the code...

All code I post is in the public domain.

fasecero

September 27, 2010, 12:30:37 AM #4 Last Edit: September 27, 2010, 12:37:21 AM by fasecero
Nice, you really save me this time. I'll be out two weeks and I'm happy that I can finish this before.
The example works perfectly, I even tested it with:

$Define SHIL_JUMBO 4

on a pc with win7 and draw a 256 x 256 icon!

Respect to the cast, I was thinking too that I can not make the cast of the returned pointer as an HIMAGELIST, or at least I'm pretty sure the problem is in there.
But the most important thing is that you've found a solution.
Thanks, Wayne!