Windows Explorer Benzeri Arayüz

► WinAPI Programları

Windows API ile bir adet Treeview ve bir adet Listview kontrolü kullanarak Windows Explorer benzeri bir arayüz oluşturabiliriz. Bu işlem için Windows Shell fonksiyonları bize yardımcı olacaktır.

"Bilgisayarım (My Computer)" altındaki sürücüler ve altında yer alan klasörler birer item olarak programın sol tarafında yer alan Treeview kontrolüne eklenecektir. Treeview üzerinde seçili olan klasör içinde yer alan dosyalar ise programın sağ tarafında bulunan Listview kontrolü içine eklenecektir.

1. Öncelikle Burada gösterildiği gibi bir Windows API projesi oluşturalım.

2. resource.h dosyası oluşturma

Aşağıda gösterildiği şekilde bir resource.h dosyası oluşturarak programa dahil edelim.

#include <windows.h>

#define IDC_TREEVIEW 101
#define IDC_LISTVIEW 201

3. resource.rc dosyası oluşturma

Aşağıda gösterildiği şekilde bir resource.rc dosyası oluşturarak programa dahil edelim.

#include "resource.h"

1 24 "manifest.xml"

4. manifest.xml dosyası oluşturma

Aşağıda gösterildiği şekilde bir manifest.xml dosyası oluşturarak program dosyalarının bulunduğu dizine kaydedelim.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
   <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
      <assemblyIdentity version="1.0.0.0" processorArchitecture="*" name="CompanyName.ProductName.YourApplication" type="win32" />
      <description>Your application description here.</description>
      <dependency>
         <dependentAssembly>
            <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*" />
         </dependentAssembly>
      </dependency>
   </assembly>

main.c dosyasını aşağıdaki şekilde düzenleyerek aşağıdaki hale getirelim.

main.c

#if defined(UNICODE) && !defined(_UNICODE)
    #define _UNICODE
#elif defined(_UNICODE) && !defined(UNICODE)
    #define UNICODE
#endif

#define _WIN32_WINNT 0x0601
#define _WIN32_IE 0x0501

#include <tchar.h>
#include <windows.h>
#include <commctrl.h>
#include <shlobj.h>
#include <shlwapi.h>
#include <objidl.h>
#include "resource.h"

HWND hwndMain;
HWND hwndTreeview, hwndListview;

/* Assign system icons to Treeview and Listview */
BOOL InitImageLists(void);
/* Treeview Procedure to prevent filling files into Listview during continuous key press in Treeview control */
LRESULT CALLBACK TreeviewProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData);
/* Calling InitCommonControlsEx() function */
BOOL Init_Common_Controls (void);
/* Calling MessageBox() function */
int MsgWrn (LPCTSTR lpCaption, LPCTSTR lpText);

/* Thanks to Damon Chandler for the functions below */
/* Fill Treeview content */
void FirstTree(void);
/* Insert drives items to Treeview */
void FillTree (LPSHELLFOLDER lpsf, LPITEMIDLIST lpidl, HTREEITEM ParentItem);
/* Insert child items to a folder while expanding */
void FillTreeEx(LPSHELLFOLDER lpsf, LPITEMIDLIST lpidl, HTREEITEM ParentItem);
/* Fill Listview content with files inside the folder selected in Treeview */
void FillFiles(void);
/* Fill Listview content with files */
void FillList (LPSHELLFOLDER lpsf, LPITEMIDLIST lpidl, HTREEITEM ParentItem);
/* Create a fully qualified itemidlist */
LPITEMIDLIST MergeIDLists(LPMALLOC lpMalloc, LPITEMIDLIST lpidl1, LPITEMIDLIST lpidl2);
unsigned short GetPIDLSize(LPITEMIDLIST lpidl);
LPITEMIDLIST GetNextItem(LPITEMIDLIST pidl);

/*  Declare Windows procedure  */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);

/*  Make the class name into a global variable  */
TCHAR szClassName[ ] = _T("ExplorerTypeApp");

int WINAPI WinMain (HINSTANCE hThisInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR lpszArgument,
                     int nCmdShow)
{
    HWND hwnd;
    MSG messages;            /* Here messages to the application are saved */
    WNDCLASSEX wincl;        /* Data structure for the windowclass */

    /* The Window structure */
    wincl.hInstance = hThisInstance;
    wincl.lpszClassName = szClassName;
    wincl.lpfnWndProc = WindowProcedure;      /* This function is called by windows */
    wincl.style = CS_DBLCLKS;                 /* Catch double-clicks */
    wincl.cbSize = sizeof (WNDCLASSEX);

    /* Use default icon and mouse-pointer */
    wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
    wincl.lpszMenuName = NULL;                 /* No menu */
    wincl.cbClsExtra = 0;                      /* No extra bytes after the window class */
    wincl.cbWndExtra = 0;                      /* structure or the window instance */
    /* Use Windows's default colour as the background of the window */
    wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;
    /* Register the window class, and if it fails quit the program */
    if (!RegisterClassEx (&wincl))
        return 0;

    /* The class is registered, let's create the program*/
    hwnd = CreateWindowEx (
           0,                      /* Extended possibilites for variation */
           szClassName,            /* Classname */
           _T("Windows Explorer type interface"),    /* Title Text */
           WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,    /* default window */
           CW_USEDEFAULT,          /* Windows decides the position */
           CW_USEDEFAULT,          /* where the wint MsgWrn (LPCTSTR lpCaption, LPCTSTR lpText) window ends up on the screen */
           800,                    /* The programs width */
           500,                    /* and height in pixels */
           HWND_DESKTOP,           /* The window is a child-window to desktop */
           NULL,                   /* No menu */
           hThisInstance,          /* Program Instance handler */
           NULL                    /* No Window Creation data */
           );

    hwndMain = hwnd;

    ShowWindow (hwnd, nCmdShow);

    /* Run the message loop. It will run until GetMessage() returns 0 */
    while (GetMessage (&messages, NULL, 0, 0))
    {
        /* Translate virtual-key messages into character messages */
        TranslateMessage(&messages);
        /* Send message to WindowProcedure */
        DispatchMessage(&messages);
    }

    /* The program return-value is 0 - The value that PostQuitMessage() gave */
    return messages.wParam;
}

/*  This function is called by the Windows function DispatchMessage()  */
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)                  /* handle the messages */
    {
        case WM_CREATE:
        {
             RECT rect;
             /* Ensures that the common control DLL (Comctl32.dll) is loaded, and registers specific common control classes from the DLL.
             An application must call this function before creating a common control. */
             Init_Common_Controls(); /* Requires -lComctl32 (Comctl32.lib) and #define _WIN32_WINNT 0x0601 */

             /* Get client rectangle to calculate Treeview and Listview sizes */
             GetClientRect(hwnd, &rect);
             /* Creating Treeview control for the directory part of Windows Explorer type interface */
             hwndTreeview = CreateWindowEx(0, WC_TREEVIEW, "", WS_VISIBLE | WS_CHILD | WS_BORDER | TVS_HASBUTTONS | TVS_HASLINES,
                                           5, 5, 350, (rect.bottom-rect.top)-10,
                                           hwnd, (HMENU)IDC_TREEVIEW, 0, NULL);

             /* Treeview Procedure to prevent filling files into Listview during continuous key press in Treeview control */
             SetWindowSubclass(hwndTreeview, TreeviewProc, 0, 0); /* Requires -lComctl32 (Comctl32.lib) and #define _WIN32_WINNT 0x0601 */

             /* Creating Listview control for the file part of Windows Explorer type interface */
             hwndListview = CreateWindowEx(WS_EX_CLIENTEDGE , WC_LISTVIEW, "", WS_CHILD | WS_VISIBLE | LVS_LIST | LVS_SINGLESEL | WS_VSCROLL,
                                           360, 5, (rect.right-rect.left)-(350+15), (rect.bottom-rect.top)-10, hwnd,
                                           (HMENU)IDC_LISTVIEW, 0, NULL);

             /* Assign system icons to Treeview and Listview */
             InitImageLists();

             /* Fill Treeview content */
             FirstTree();
             /* Fill Listview content with files inside the folder selected in Treeview */
             FillFiles();
        }
        break;

        case WM_NOTIFY:
        {
            if (((LPNMHDR)lParam)->hwndFrom == hwndTreeview){
                switch (((LPNMHDR)lParam)->code){
                    /* Filling Listview content with files when the selected folder changed in Treeview */
                    case TVN_SELCHANGED:
                    {
                         HTREEITEM hSelectedItem;

                         if((HTREEITEM)SendMessage(((LPNMHDR)lParam)->hwndFrom, TVM_GETNEXTITEM, TVGN_CARET, (LPARAM) hSelectedItem)!=NULL) {
                             LPNMTREEVIEW nmtv = (LPNMTREEVIEW)lParam;

                             if (nmtv->action==TVC_BYMOUSE) {
                                 FillFiles();
                             }
                         }
                    }
                    break;

                    /* Insert child items to a folder while expanding */
                    case TVN_ITEMEXPANDING:
                    {
                         LPNMTREEVIEW nmtv = (LPNMTREEVIEW)lParam;
                         TVITEM item = nmtv->itemNew;
                         LPSHELLFOLDER lpsf;

                         if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
                             LPITEMIDLIST lpidl = (LPITEMIDLIST) item.lParam;
                             char m1[MAX_PATH];

                             if (SHGetPathFromIDList(lpidl, m1)) {
                                 if (lpidl->mkid.cb) {
                                     LPSHELLFOLDER lpsfSub;
                                     if (SUCCEEDED(lpsf->lpVtbl->BindToObject(lpsf, lpidl, NULL, &IID_IShellFolder,(void **)&lpsfSub))) {
                                         FillTreeEx(lpsfSub, lpidl, item.hItem);
                                         lpsfSub->lpVtbl->Release(lpsfSub);
                                     }
                                 }
                             }
                             lpsf->lpVtbl->Release(lpsf);
                         }
                         break;
                    }
                }
            }
            break;
        }

        case WM_DESTROY:
            PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
            break;
        default:                       /* for messages that we don't deal with */
            return DefWindowProc (hwnd, message, wParam, lParam);
    }

    return 0;
}

/* Assign system icons to Treeview and Listview */
BOOL InitImageLists(void)
{
  HIMAGELIST himl;
  SHFILEINFO IconInfo;

  himl = (HIMAGELIST) SHGetFileInfo("", 0, &IconInfo, sizeof(IconInfo), SHGFI_ICON | SHGFI_SMALLICON | SHGFI_SYSICONINDEX);
  SendMessage(hwndTreeview, TVM_SETIMAGELIST, TVSIL_NORMAL, (LPARAM)himl);
  SendMessage(hwndListview, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)himl);

  return TRUE;
}

/* Program açılışında Treeview içeriğini doldurma */
void FirstTree(void)
{
  LPMALLOC lpMalloc; /* The address of a pointer that receives the Shell's IMalloc interface pointer (Allocates, frees, and manages memory) */

  /* Retrieves a pointer to the Shell's IMalloc interface */
  if (SUCCEEDED(SHGetMalloc(&lpMalloc))) {
      LPSHELLFOLDER lpsf;   /* IShellFolder interface: Exposed by all Shell namespace folder objects, its methods are used to manage folders. */
      SHFILEINFO FileInfo;  /* Contains information about a file object. */
      unsigned int uSHFlags = SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME | SHGFI_PIDL; /* Defines the file informations to be obtained with SHGetFileInfo() function. */

      if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) { /* Retrieves the IShellFolder interface for the desktop folder, which is the root of the Shell's namespace. */
          LPITEMIDLIST lpidl; /* Contains a list of item identifiers. The address of an ITEMIDLIST structure (PIDL) that identifies the subfolder. */
          /* Retrieves the path of a folder as an ITEMIDLIST structure (CSIDL_DRIVES: The virtual folder that represents My Computer) */
          if (SUCCEEDED(SHGetFolderLocation(hwndMain, CSIDL_DRIVES, NULL, 0, &lpidl))) {
              LPSHELLFOLDER lpsfSub;
              /* Retrieves a handler, typically the Shell folder object that implements IShellFolder for a particular item. */
              if (SUCCEEDED(lpsf->lpVtbl->BindToObject(lpsf, lpidl, 0, &IID_IShellFolder,(LPVOID *)&lpsfSub))) {
                  TVINSERTSTRUCT tvins;
                  HTREEITEM hItem;
                  /* Retrieves object information from the file system, such as a file, folder, directory, or drive home directory. */
                  SHGetFileInfo((LPCSTR)lpidl, 0, &FileInfo, sizeof(SHFILEINFO), uSHFlags);

                  tvins.item.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM;
                  tvins.item.pszText = FileInfo.szDisplayName;
                  tvins.item.cchTextMax = sizeof(tvins.item.pszText)/sizeof(tvins.item.pszText[0]);
                  tvins.item.iImage = FileInfo.iIcon;
                  tvins.item.iSelectedImage = FileInfo.iIcon;
                  tvins.item.lParam = (LPARAM)lpidl;
                  tvins.hParent = TVI_ROOT;

                  /* Insert My Computer item to Treeview */
                  hItem = (HTREEITEM) SendMessage(hwndTreeview, TVM_INSERTITEM, (WPARAM)0, (LPARAM)(LPTVINSERTSTRUCT)&tvins);
                  /* Insert drives items to Treeview */
                  FillTree(lpsfSub, lpidl, hItem);
                  /* Expand My Computer Item in Treeview */
                  SendMessage(hwndTreeview, TVM_EXPAND, TVE_EXPAND, (LPARAM)hItem);

                  lpsfSub->lpVtbl->Release(lpsfSub); /* Shell Folder pointer release */
              }
          }
          lpMalloc->lpVtbl->Free(lpMalloc, lpidl); /* IMalloc interface pointer free */
          lpsf->lpVtbl->Release(lpsf); /* Shell Folder pointer release */
      }
      lpMalloc->lpVtbl->Release(lpMalloc); /* IMalloc interface pointer release */
  }
}

/* Insert drives items to Treeview */
void FillTree (LPSHELLFOLDER lpsf, LPITEMIDLIST lpidl, HTREEITEM ParentItem)
{
  /* The address of a pointer that receives the Shell's IMalloc interface pointer (Allocates, frees, and manages memory) */
  LPMALLOC lpMalloc;

  SetCursor(LoadCursor(NULL, IDC_WAIT));
  /* Retrieve a pointer for Shell IMalloc interface */
  if (SUCCEEDED(SHGetMalloc(&lpMalloc))) {
      /* IEnumIDList interface exposes a standard set of methods used to enumerate the pointers to item identifier lists (PIDLs)
      of the items in a Shell folder. When a folder's IShellFolder::EnumObjects method is called, it creates an enumeration object
      and passes a pointer to the object's IEnumIDList interface back to the calling application. */
      LPENUMIDLIST lpeidl;
      HRESULT HRes;

      /* EnumObjects() function enables a client to determine the contents of a folder by creating an item identifier enumeration
      object and returning its IEnumIDList interface. */
      HRes = lpsf->lpVtbl->EnumObjects(lpsf, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &lpeidl);

      if (HRes == S_OK) {
          /* Contains a list of item identifiers. The address of an ITEMIDLIST structure (PIDL) that identifies the subfolder. */
          LPITEMIDLIST lpidlCurrent;
          unsigned long ulFetched;

          /* Retrieves the specified number of item identifiers in the enumeration sequence and advances the current position
          by the number of items retrieved. */
          while (lpeidl->lpVtbl->Next(lpeidl, 1, &lpidlCurrent, &ulFetched) == S_OK) {
                 LPITEMIDLIST lpidlFQ = MergeIDLists (lpMalloc, lpidl, lpidlCurrent);
                 if (lpidlFQ) {
                     SHFILEINFO FileInfo;
                     DWORD FileAttrib;
                     unsigned int uSHFlags;
                     uSHFlags = SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME | SHGFI_PIDL;
                     UINT drvtype;
                     char DrvName[4];

                     SHGetFileInfo((LPCSTR)lpidlFQ, FileAttrib, &FileInfo, sizeof(SHFILEINFO), uSHFlags);

                     DrvName[0] = FileInfo.szDisplayName[strlen(FileInfo.szDisplayName)-3];
                     DrvName[1] = FileInfo.szDisplayName[strlen(FileInfo.szDisplayName)-2];
                     DrvName[2] = '\\';
                     DrvName[3] = '\0';

                     drvtype = GetDriveType(DrvName);
                     if (drvtype > 1) { /* Fixed and removable drives */
                         TVINSERTSTRUCT tvins;
                         HTREEITEM hItem;

                         /* Insert drive */
                         tvins.item.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM;
                         tvins.item.pszText = FileInfo.szDisplayName;
                         tvins.item.cchTextMax = sizeof(tvins.item.pszText)/sizeof(tvins.item.pszText[0]);
                         tvins.item.iImage = FileInfo.iIcon;
                         tvins.item.iSelectedImage = FileInfo.iIcon;
                         tvins.item.lParam = (LPARAM)lpidlFQ;
                         tvins.hParent = ParentItem;

                         hItem = (HTREEITEM) SendMessage(hwndTreeview, TVM_INSERTITEM, (WPARAM)0, (LPARAM)(LPTVINSERTSTRUCT)&tvins);

                         /* Insert fake item as child into inserted item for the drive (for + sign) */
                         tvins.item.pszText = "";
                         tvins.item.iImage = -1;
                         tvins.item.iSelectedImage = -1;
                         tvins.hParent = hItem;

                         SendMessage(hwndTreeview, TVM_INSERTITEM, 0, (LPARAM)(LPTVINSERTSTRUCT)&tvins);
                     }
                 }
                 lpMalloc->lpVtbl->Free(lpMalloc, lpidlCurrent); /* IMalloc interface pointer free */
          }
          lpeidl->lpVtbl->Release(lpeidl); /* Shell Folder pointer release */
      }
      else {
          MsgWrn ("Error", "EnumObjects() error");
      }
      lpMalloc->lpVtbl->Release(lpMalloc); /* IMalloc interface pointer release */
  }
  else {
    SetCursor( LoadCursor(NULL, IDC_ARROW));
    MsgWrn ("Error", "SHGetMalloc() error");
  }
  SetCursor( LoadCursor(NULL, IDC_ARROW));
}

/* Insert child items to a folder while expanding */
void FillTreeEx(LPSHELLFOLDER lpsf, LPITEMIDLIST lpidl, HTREEITEM ParentItem)
{
  LPMALLOC lpMalloc;
  HTREEITEM hItem;

  SetCursor(LoadCursor(NULL, IDC_WAIT));

  /* To delete fake item inserted before */
  while ((hItem = (HTREEITEM) SendMessage(hwndTreeview, TVM_GETNEXTITEM, (WPARAM)TVGN_CHILD, (LPARAM)ParentItem))) {
     SendMessage(hwndTreeview, TVM_DELETEITEM, 0, (LPARAM)hItem);
  }

  if (SUCCEEDED(SHGetMalloc(&lpMalloc))) {
      LPENUMIDLIST lpeidl;
      HRESULT HRes;
      HRes = lpsf->lpVtbl->EnumObjects(lpsf, NULL, SHCONTF_FOLDERS, &lpeidl);
      if (HRes == NOERROR) {
          LPITEMIDLIST lpidlCurrent;
          unsigned long ulFetched;

          while (lpeidl->lpVtbl->Next(lpeidl, 1, &lpidlCurrent, &ulFetched) == S_OK) {
                 LPITEMIDLIST lpidlFQ = MergeIDLists (lpMalloc, lpidl, lpidlCurrent);
                 if (lpidlFQ) {
                     SHFILEINFO FileInfo;
                     unsigned int uSHFlags;
                     uSHFlags = SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME | SHGFI_PIDL | SHGFI_ATTRIBUTES;
                     SHGetFileInfo((LPCSTR)(lpidlFQ), 0, &FileInfo, sizeof(SHFILEINFO), uSHFlags);

                     if (((FileInfo.dwAttributes & SFGAO_FILESYSANCESTOR) || (FileInfo.dwAttributes & SFGAO_FILESYSTEM))) {
                         TVINSERTSTRUCT tvins;
                         HTREEITEM hItem01;

                         tvins.item.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM;
                         tvins.item.pszText = FileInfo.szDisplayName;
                         tvins.item.cchTextMax = sizeof(tvins.item.pszText)/sizeof(tvins.item.pszText[0]);
                         tvins.item.iImage = FileInfo.iIcon;
                         tvins.item.iSelectedImage = FileInfo.iIcon;
                         tvins.item.lParam = (LPARAM)lpidlFQ;
                         tvins.hParent = ParentItem;

                         hItem01 = (HTREEITEM) SendMessage(hwndTreeview, TVM_INSERTITEM, (WPARAM)0, (LPARAM)(LPTVINSERTSTRUCT)&tvins);

                         SHGetFileInfo ((LPCSTR)(lpidlFQ), 0, &FileInfo, sizeof(SHFILEINFO), SHGFI_SYSICONINDEX | SHGFI_PIDL | SHGFI_OPENICON | SHGFI_ATTRIBUTES);

                         if (FileInfo.dwAttributes & SFGAO_HASSUBFOLDER) {
                             tvins.item.pszText = "";
                             tvins.item.iImage = -1;
                             tvins.item.iSelectedImage = -1;
                             tvins.hParent = hItem01;

                             SendMessage(hwndTreeview, TVM_INSERTITEM, 0, (LPARAM)(LPTVINSERTSTRUCT)&tvins);
                         }
                     }
                 }
                 lpMalloc->lpVtbl->Free(lpMalloc, lpidlCurrent); /* IMalloc interface pointer free */
          }
          lpeidl->lpVtbl->Release(lpeidl); /* Shell Folder pointer release */
      }
      else {
          MsgWrn ("Error", "EnumObjects() error");
      }
      lpMalloc->lpVtbl->Release(lpMalloc); /* IMalloc interface pointer release */
  }
  else {
    SetCursor( LoadCursor(NULL, IDC_ARROW));
    MsgWrn ("Error", "SHGetMalloc() error");
  }
  SetCursor( LoadCursor(NULL, IDC_ARROW));
}

/* Fill Listview content with files inside the folder selected in Treeview */
void FillFiles(void)
{
  HTREEITEM hSelectedItem = TreeView_GetSelection(hwndTreeview);

  if (hSelectedItem != NULL) {
      char buffer[256];
      TVITEM item;
      item.hItem = hSelectedItem;
      item.mask = TVIF_TEXT;
      item.cchTextMax = 256;
      item.pszText = buffer;
      TreeView_GetItem(hwndTreeview, &item);

      LPITEMIDLIST lpidl = (LPITEMIDLIST)(item.lParam);
      LPSHELLFOLDER lpsf;
      HTREEITEM hItem = item.hItem;

      if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
          if (lpidl->mkid.cb) {
              LPSHELLFOLDER lpsfSub;
              if (SUCCEEDED(lpsf->lpVtbl->BindToObject(lpsf, lpidl, NULL, &IID_IShellFolder,(void **)&lpsfSub))) {
                  FillList (lpsfSub, lpidl, hItem);
                  lpsfSub->lpVtbl->Release(lpsfSub);
              }
          }
          lpsf->lpVtbl->Release(lpsf);
      }
  }
}

/* Fill Listview content with files */
void FillList (LPSHELLFOLDER lpsf, LPITEMIDLIST lpidl, HTREEITEM ParentItem)
{
  LPMALLOC lpMalloc;
  LVITEM lvI;

  SetCursor(LoadCursor(NULL, IDC_WAIT));
  SendMessage(hwndListview, LVM_DELETEALLITEMS, 0, 0);

  if (SUCCEEDED(SHGetMalloc(&lpMalloc))) {
      LPENUMIDLIST lpeidl;

      if (SUCCEEDED(lpsf->lpVtbl->EnumObjects(lpsf, NULL, SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &lpeidl))) {
          LPITEMIDLIST lpidlCurrent;
          unsigned long ulFetched;

          while (lpeidl->lpVtbl->Next(lpeidl, 1, &lpidlCurrent, &ulFetched) == S_OK) {
                 LPITEMIDLIST lpidlFQ = MergeIDLists (lpMalloc, lpidl, lpidlCurrent);
                 if (lpidlFQ) {
                     SHFILEINFO FileInfo;
                     unsigned int uSHFlags = SHGFI_ICON | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME | SHGFI_PIDL | SHGFI_ATTRIBUTES | SHGFI_TYPENAME;

                     SHGetFileInfo((LPCSTR)lpidlFQ, 0, &FileInfo, sizeof(SHFILEINFO), uSHFlags);

                     lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE;
                     lvI.stateMask = 0;
                     lvI.iSubItem = 0;
                     lvI.state = 0;
                     lvI.iImage = FileInfo.iIcon;
                     lvI.pszText = FileInfo.szDisplayName;

                     ListView_InsertItem(hwndListview, &lvI);

                     lpMalloc->lpVtbl->Free(lpMalloc, lpidlFQ);
                 }
                 lpMalloc->lpVtbl->Free(lpMalloc, lpidlCurrent);

          }
          lpeidl->lpVtbl->Release(lpeidl);
      }
      else {
          MsgWrn ("Warning", "Content not found!");
      }
      lpMalloc->lpVtbl->Release(lpMalloc);
  }
  else {
     SetCursor( LoadCursor(NULL, IDC_ARROW));
     MsgWrn ("Error", "SHGetMalloc() error");
  }
  SetCursor( LoadCursor(NULL, IDC_ARROW));
}

/* Treeview Procedure to prevent filling files into Listview during continuous key press in Treeview control */
LRESULT CALLBACK TreeviewProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
  switch (message) {
     case WM_KEYUP:
     {
          switch(wParam) {
              case VK_UP:
              case VK_DOWN:
              case VK_PRIOR:
              case VK_NEXT:
              case VK_HOME:
              case VK_END:
              case VK_LEFT:
              case VK_RIGHT:
                   FillFiles();
                   break;
          }
     }
     break;
  }

  return DefSubclassProc(hwnd, message, wParam, lParam);
}

BOOL Init_Common_Controls (void)
{
  INITCOMMONCONTROLSEX icex;
  icex.dwICC = ICC_STANDARD_CLASSES | ICC_LISTVIEW_CLASSES | ICC_TREEVIEW_CLASSES;
  return (InitCommonControlsEx(&icex));
}

int MsgWrn (LPCTSTR lpCaption, LPCTSTR lpText)
{
  return MessageBox(NULL, lpText, lpCaption, MB_OK | MB_ICONWARNING | MB_TASKMODAL);
}

/* Create a fully qualified itemidlist */
LPITEMIDLIST MergeIDLists(LPMALLOC lpMalloc, LPITEMIDLIST lpidl1,   LPITEMIDLIST lpidl2)
{
  int cb1, cb2;
  LPITEMIDLIST lpidlNew;

  if (lpidl1) cb1 = GetPIDLSize(lpidl1);
  if (cb1) cb1 = cb1 - 2;

  if (lpidl2) cb2 = GetPIDLSize(lpidl2);
  if (cb2) cb2 = cb2 - 2;

  int total_size = cb1 + cb2 + 2;

  lpidlNew = (LPITEMIDLIST)(lpMalloc->lpVtbl->Alloc(lpMalloc, total_size));
  if (lpidlNew) {
      ZeroMemory(lpidlNew, total_size);
      CopyMemory(lpidlNew, lpidl1, cb1);
      CopyMemory(((LPBYTE)(lpidlNew)) + cb1, lpidl2, cb2);
      FillMemory(((LPBYTE)(lpidlNew)) + cb1 + cb2, 2, 0);
      return lpidlNew;
  }
  return NULL;
}

unsigned short GetPIDLSize(LPITEMIDLIST lpidl)
{
  unsigned short cb = 0;
  while (lpidl) {
         cb = (unsigned short)(cb + lpidl->mkid.cb);
         lpidl = GetNextItem(lpidl);
  }
  return (unsigned short)(cb + 2);
}

LPITEMIDLIST GetNextItem(LPITEMIDLIST pidl)
{
  unsigned short nLen = pidl->mkid.cb;
  if (nLen == 0) return NULL;
  return (LPITEMIDLIST)((LPBYTE)pidl + nLen);
}

Program derleyip çalıştırdığımızda aşağıdakine benzer bir ekran görüntüsü karşımıza gelecektir:

Programın kaynak kodları

Programın exe dosyası