Link : http://blog.naver.com/ratmsma?Redirect=Log&logNo=40024001544
윈도우에는 자체적으로 시스템을 구성하기위해, 특수 폴더가 존재합니다. 예를 들어, 프린터관련 폴더, 쓰레기통관련 폴더 등을 들 수 있겠죠. 가끔가다 이것들을 접근해야 할 필요가 있습니다. 물론, 임의적으로 경로를 이용해서 접근할 수도 있지만, 이 경우에는 변경이 가능하기 때문에, 그렇게 좋은 방법은 아닙니다. 여기서 폴더를 접근하는 함수를 소개하겠습니다.
먼저 구조체와 함수를 소개하면다음과 같습니다.
LPITEMIDLIST pItemIDList;
SHGetSpecialFolderLocation(GetDesktopWindow() ->m_hWnd, 아래 아이디, &pItemIDList);
SHGetPathFromIDList(pItemIDList, szDir);
CSIDL_CONTROLS
컨트롤 패널
CSIDL_PRINTERS
프린터
CSIDL_PERSONAL
My Document
CSIDL_BITBUCKET
쓰레기통
CSIDL_DESKTOPDIRECTORY
DeskTop
CSIDL_DRIVES
내 컴퓨터
CSIDL_NETWORK
네트워크 컴퓨터
CSIDL_NETHOOD
네트워크 접속된 컴퓨터
CSIDL_TEMPLATES
문서 템플릿
CSIDL_APPDATA
어플리케이션 데이터
CSIDL_PRINTHOOD
사용 가능한 프린터
CSIDL_DESKTOP
데스크탑
CSIDL_FAVORITES
패이버릿 디렉토리
CSIDL_FONTS
폰트
CSIDL_PROGRAMS
스타트 메뉴의 프로그램디렉토리
CSIDL_RECENT
최근 사용한 파일
CSIDL_SENDTO
보내는 폴더
CSIDL_STARTMENU
스타트 메뉴
CSIDL_STARTUP
스타트 업
인클루드
위의 함수는 아래의 헤더파일을 포함시켜야 합니다.
#include "winnetwk.h"
#include "shlobj.h"
===========================================================
(활용)
//폴더의 ITEMIDLIST값을 가지고 올 때 쓰임
LPITEMIDLIST pidlExceptFolder;
//폴더의 ISHELLFOLDER의 값을 가지고 올 때 쓰임
LPSHELLFOLDER pExceptFolder;
// 바탕화면의 IShellFolder
SHGetDesktopFolder(&pExceptFolder);
//특정 스패셜 폴더(CSIDL_WINDOWS 등등)의 ITEMIDLIST의 값을 가지고 옮
SHGetSpecialFolderLocation(NULL, CSIDL_WINDOWS, &pidlExceptFolder);
//스패셜 폴더의 Display Name을 ISTRRET값으로 저장시킴
HRESULT hr = pExceptFolder->GetDisplayNameOf(pidlExceptFolder, 0, &str);
TCHAR szFolderName[1024];
//ISTRRET의 uType의 값을 비교하여 해당 표시되는 이름을 얻어냄
switch(str.uType)
{
case STRRET_WSTR:
WideCharToMultiByte
(CP_ACP, 0, str.pOleStr, -1, szFolderName, MAX_PATH,NULL, NULL);
break;
case STRRET_OFFSET:
lstrcpy(szFolderName, reinterpret_cast<LPSTR>(pidl) + str.uOffset);
break;
case STRRET_CSTR:
lstrcpy(szFolderName, str.cStr);
break;
}
============================================================
(참고자료)
쉘 프로그래밍을 하실 때는
폴더나 파일등의 경로를 쉘이 어떻게 관리하는지 부터 이해 하여야 합니다.
예전의 도스에서는 우리가 보고 사용하는 파일명은
그대로 디스크에 저장되어 사용되어 집니다.
그러나 윈도우 쉘(탐색기)에서는 우리가 보게되는 파일이나 폴더들의 이름과
실제 하드디스크에서의 위치나 혹은 내부적으로 관리되는 이름은 서로 다를 수 있습니다.
따라서,
우리가 윈도우에서 폴더 또는 파일관련 쉘 프로그래밍을 할 때는
사용자에게 보여주어야 하는 이름과
프로그램 내부적으로 다루어야할 파일관련 함수에 넘겨주어야할
이름이 다를 수 있기 때문에
이 두가지를 모두 관리하여 주어야만 합니다.
윈도우 탐색기와 같은 것을 보면
각 폴더나 파일을 단순한 text로 된 이름으로 관리하는 것이 아니라
ITEMIDLIST라는 메모리 블록을 만들고 이 데이터로 각 폴더나 파일의 실제경로
및 사용자에게 보여주어야할 이름 및 기타 정보를 찾아 나갑니다.
예를 들어 c:\a\b.txt 라는 경로를 ITEMIDLIST로 만들어 본다면
[c:] [a] [b.txt]라는 3개의 정보블럭이 있고 이 3개의 정보블럭은 하나의
메모리 블럭에 할당되져 관리됩니다.
실제 그 구조체는 ShTypes.h에 다음과 같이 정의되어 있습니다.
typedef struct _SHITEMID
{
USHORT cb; <---- 한 항목의 메모리 블럭의 크기를 저장하는 곳
BYTE abID[ 1 ]; <---- 한 항목의 정보를 저장하는 영역
} SHITEMID;
typedef struct _ITEMIDLIST
{
SHITEMID mkid;
} ITEMIDLIST;
typedef ITEMIDLIST *LPITEMIDLIST;
즉 위의 c:\a\b.txt 라는 경로를 저장하고 있는
LPITEMIDLIST 메모리의 내부 구조를 본다면
[c:] [a] [b.txt] 각각의 정보를 저정하는 ITEMIDLIST
즉 SHITEMID 구조체 3개가 차례로 연결되어
한개의 메모리 블럭을 구성하고 있는 것입니다.
그렇다면 이렇게 여러개의 SHITEMID가 연결되어있는
LPITEMIDLIST를 관리하는 함수
즉, 여러개중 몇개를 떼어내거나 붙이거나 몇개인지 세거나
전체크기를 세거나 하는 함수가 필요 하겠지요 ?
문의하신 함수들이 바로 그러한 일을 하는 함수입니다.
SH로 시작하는 윈도우 쉘함수들이 경로(Path)대신에 LPITEMIDLIST값을
요구하기 때문에 LPITEMIDLIST를 관리하는 함수는 꼭 필요하겠지요 !
// 이 함수는 여러개의 SHITEMID 블럭을 포함하는 LPCITEMIDLIST메모리 주소를
// 입력받아서 두번째(앞쪽에서부터) 즉 다음번 SHITEMID 블럭의 주소를 찾아줍니다.
LPITEMIDLIST CShellProc::Next(LPCITEMIDLIST pidl)
{
LPSTR lpMem=(LPSTR)pidl;
lpMem+=pidl->mkid.cb; // 첫번째 블럭의 크기만큼 더하므로 다음 주소가 만들어집니다.
return (LPITEMIDLIST)lpMem;
}
// 포함된 전체 SHITEMID 블럭들의 각 크기를 모두 더해서
// LPCITEMIDLIST메모리 블럭 전체의 메모리 크기를 구하는 함수입니다.
UINT CShellProc::GetSize(LPCITEMIDLIST pidl)
{
UINT cbTotal = 0;
if (pidl)
{
cbTotal += sizeof(pidl->mkid.cb); // Null terminator
while (pidl->mkid.cb)
{
cbTotal += pidl->mkid.cb;
pidl = Next(pidl);
}
}
return cbTotal;
}
// 지정된 크기의 LPITEMIDLIST 메모리 블럭을 할당합니다.
// 다만 쉘이 공통으로 사용할 수 있는 메모리는 malloc() 등의 함수로
// 할당되는 메모리가 아니며 반드시 메모리 SHGetMalloc()로 얻은 함수를
// 사용해야만 한다는 특징이 있습니다.
LPITEMIDLIST CShellProc::CreatePidl(UINT cbSize)
{
LPMALLOC lpMalloc;
HRESULT hr;
LPITEMIDLIST pidl=NULL;
hr=SHGetMalloc(&lpMalloc); <--------- 할당함수의 주소얻기
if (FAILED(hr)) return 0;
pidl=(LPITEMIDLIST)lpMalloc->Alloc(cbSize);
if (pidl) memset(pidl, 0, cbSize); // zero-init for external task alloc
if (lpMalloc) lpMalloc->Release(); <--------- 할당함수 반환
return pidl;
}
// 2개의 LPCITEMIDLIST 메모리 블럭을 1개로 합쳐줍니다.
LPITEMIDLIST CShellProc::ConcatPidls(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
{
LPITEMIDLIST pidlNew;
UINT cb1;
UINT cb2;
if (pidl1) cb1 = GetSize(pidl1) - sizeof(pidl1->mkid.cb);
else cb1 = 0;
cb2 = GetSize(pidl2);
pidlNew = CreatePidl(cb1 + cb2);
if (pidlNew)
{
if (pidl1)
memcpy(pidlNew, pidl1, cb1);
memcpy(((LPSTR)pidlNew) + cb1, pidl2, cb2);
}
return pidlNew;
}
// LPITEMIDLIST의 첫번째 SHITEMID 블럭과 동일한 크기의 새로운 쉘메모리를 할당하고
// 첫번째 SHITEMID 블럭의 내용을 복사해 돌려줍니다.
// lpMalloc는 미리 SHGetMalloc()로 얻은 쉘메모리 할당함수의 주소입니다.
LPITEMIDLIST CShellProc::CopyITEMID(LPMALLOC lpMalloc, LPITEMIDLIST lpi)
{
LPITEMIDLIST lpiTemp;
lpiTemp=(LPITEMIDLIST)lpMalloc->Alloc(lpi->mkid.cb+sizeof(lpi->mkid.cb));
CopyMemory((PVOID)lpiTemp, (CONST VOID *)lpi, lpi->mkid.cb+sizeof(lpi->mkid.cb));
return lpiTemp;
}
// 이 함수는 LPSHELLFOLDER를 이용하여 LPITEMIDLIST 메모리 블럭에 있는 항목의 이름을
// 찾아 줍니다.
// SHELLFOLDER라는 것은 한 폴더의 관리자라 생각하면 됩니다.
// dwFlags에는 다음을 사용할 수 있습니다.
// SHGDN_NORMAL = 0, // default (display purpose)
// SHGDN_INFOLDER = 1, // displayed under a folder (relative)
// SHGDN_INCLUDE_NONFILESYS = 0x2000, // if not set, display names for shell name space items that are not in the file system will fail.
// SHGDN_FORADDRESSBAR = 0x4000, // for displaying in the address (drives dropdown) bar
// SHGDN_FORPARSING = 0x8000, // for ParseDisplayName or path
BOOL CShellProc::GetName(LPSHELLFOLDER lpsf,LPITEMIDLIST lpi,DWORD dwFlags,
LPSTR lpFriendlyName)
{
BOOL bSuccess=TRUE;
STRRET str;
if (NOERROR==lpsf->GetDisplayNameOf(lpi,dwFlags, &str))
{
switch (str.uType)
{
case STRRET_WSTR:
WideCharToMultiByte(CP_ACP, // CodePage
0, // dwFlags
str.pOleStr, // lpWideCharStr
-1, // cchWideChar
lpFriendlyName, // lpMultiByteStr
MAX_PATH,
//sizeof(lpFriendlyName), // cchMultiByte, wrong. sizeof on a pointer, psk, psk
NULL, // lpDefaultChar,
NULL); // lpUsedDefaultChar
break;
case STRRET_OFFSET:
lstrcpy(lpFriendlyName, (LPSTR)lpi+str.uOffset);
break;
case STRRET_CSTR:
lstrcpy(lpFriendlyName, (LPSTR)str.cStr);
break;
default:
bSuccess = FALSE;
break;
}
}
else
bSuccess = FALSE;
return bSuccess;
}
// 윈도우에서 ROOT는 바탕화면 즉 Desktop입니다.
LPITEMIDLIST CShellProc::GetFullyQualPidl(LPSHELLFOLDER lpsf, LPITEMIDLIST lpi)
{
char szBuff[MAX_PATH];
OLECHAR szOleChar[MAX_PATH];
LPSHELLFOLDER lpsfDeskTop;
LPITEMIDLIST lpifq;
ULONG ulEaten, ulAttribs;
HRESULT hr;
if (!GetName(lpsf, lpi, SHGDN_FORPARSING, szBuff))
return NULL;
hr=SHGetDesktopFolder(&lpsfDeskTop); <-------
if (FAILED(hr))
return NULL;
MultiByteToWideChar(CP_ACP,
MB_PRECOMPOSED,
szBuff,
-1,
(USHORT *)szOleChar,
sizeof(szOleChar));
hr=lpsfDeskTop->ParseDisplayName(NULL,
NULL,
szOleChar,
&ulEaten,
&lpifq,
&ulAttribs);
lpsfDeskTop->Release();
if (FAILED(hr))
return NULL;
return lpifq;
}
// 쉘에서 오른쪽 마우스 버튼을 클릭했을 때 띄워줄 PopupMenu를 처리하는 함수입니다.
BOOL CShellProc::DoTheMenuThing(HWND hwnd, LPSHELLFOLDER lpsfParent,
LPITEMIDLIST lpi, LPPOINT lppt)
{
LPCONTEXTMENU lpcm;
HRESULT hr;
char szTemp[64];
CMINVOKECOMMANDINFO cmi;
DWORD dwAttribs=0;
int idCmd;
HMENU hMenu;
BOOL bSuccess=TRUE;
hr=lpsfParent->GetUIObjectOf(hwnd,
1, //Number of objects to get attributes of
(const struct _ITEMIDLIST **)&lpi,
IID_IContextMenu,
0,
(LPVOID *)&lpcm);
if (SUCCEEDED(hr))
{
hMenu = CreatePopupMenu();
if (hMenu)
{
hr=lpcm->QueryContextMenu(hMenu, 0, 1, 0x7fff, CMF_EXPLORE);
if (SUCCEEDED(hr))
{
idCmd=TrackPopupMenu(hMenu,
TPM_LEFTALIGN | TPM_RETURNCMD | TPM_RIGHTBUTTON,
lppt->x, lppt->y, 0, hwnd, NULL);
if (idCmd)
{
cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
cmi.fMask = 0;
cmi.hwnd = hwnd;
cmi.lpVerb = MAKEINTRESOURCE(idCmd-1);
cmi.lpParameters = NULL;
cmi.lpDirectory = NULL;
cmi.nShow = SW_SHOWNORMAL;
cmi.dwHotKey = 0;
cmi.hIcon = NULL;
hr=lpcm->InvokeCommand(&cmi);
if (!SUCCEEDED(hr))
{
wsprintf(szTemp, "InvokeCommand failed. hr=%lx", hr);
AfxMessageBox(szTemp);
}
}
}
else
bSuccess = FALSE;
DestroyMenu(hMenu);
}
else
bSuccess = FALSE;
lpcm->Release();
}
else
{
wsprintf(szTemp, "GetUIObjectOf failed! hr=%lx", hr);
AfxMessageBox(szTemp );
bSuccess = FALSE;
}
return bSuccess;
}
// LPITEMIDLIST로 주어진 어떠한 폴더나 파일의 아이콘 번호를 알려 줍니다.
// 탐색기에서 볼 수 있는 아이콘들을 의미합니다.
// 다만 윈도우에는 시스템이미지리스트라는 이미지 리스트를 사용하며
// 이 이미지 리스트에서의 아이콘 순번을 돌려줍니다.
// 시스템 이미지 리스트를 구하는 함수는 아래에 첨부합니다.
// 참고하세요 !
int CShellProc::GetItemIcon(LPITEMIDLIST lpi, UINT uFlags)
{
SHFILEINFO sfi;
SHGetFileInfo((LPCSTR)lpi,
0,
&sfi,
sizeof(SHFILEINFO),
uFlags);
return sfi.iIcon;
}
// 시스템이미지 리스트를 구하는 함수입니다.
// 참고하세요 !
// 이미지리스트는 큰 아이콘, 작은아이콘 등을 별도로 구할 수 있습니다.
HIMAGELIST GetSystemImageList(int type)
{
UINT flag;
PSHIDL pidl;
SHFILEINFO sfi;
HIMAGELIST hSysImageList;
flag=SHGFI_PIDL | SHGFI_SYSICONINDEX;
if(type==0) flag|=SHGFI_SMALLICON;
if(type==1) flag|=SHGFI_LARGEICON;
if(type==2) flag|=SHGFI_OPENICON;
pidl=GetDesktopPIDL();
ZeroMemory(&sfi, sizeof(SHFILEINFO));
hSysImageList = (HIMAGELIST) SHGetFileInfo((LPCTSTR)pidl, 0, &sfi, sizeof(SHFILEINFO),flag);
Free((void *)pidl);
return hSysImageList;
}
윈도우에는 자체적으로 시스템을 구성하기위해, 특수 폴더가 존재합니다. 예를 들어, 프린터관련 폴더, 쓰레기통관련 폴더 등을 들 수 있겠죠. 가끔가다 이것들을 접근해야 할 필요가 있습니다. 물론, 임의적으로 경로를 이용해서 접근할 수도 있지만, 이 경우에는 변경이 가능하기 때문에, 그렇게 좋은 방법은 아닙니다. 여기서 폴더를 접근하는 함수를 소개하겠습니다.
먼저 구조체와 함수를 소개하면다음과 같습니다.
LPITEMIDLIST pItemIDList;
SHGetSpecialFolderLocation(GetDesktopWindow() ->m_hWnd, 아래 아이디, &pItemIDList);
SHGetPathFromIDList(pItemIDList, szDir);
CSIDL_CONTROLS
컨트롤 패널
CSIDL_PRINTERS
프린터
CSIDL_PERSONAL
My Document
CSIDL_BITBUCKET
쓰레기통
CSIDL_DESKTOPDIRECTORY
DeskTop
CSIDL_DRIVES
내 컴퓨터
CSIDL_NETWORK
네트워크 컴퓨터
CSIDL_NETHOOD
네트워크 접속된 컴퓨터
CSIDL_TEMPLATES
문서 템플릿
CSIDL_APPDATA
어플리케이션 데이터
CSIDL_PRINTHOOD
사용 가능한 프린터
CSIDL_DESKTOP
데스크탑
CSIDL_FAVORITES
패이버릿 디렉토리
CSIDL_FONTS
폰트
CSIDL_PROGRAMS
스타트 메뉴의 프로그램디렉토리
CSIDL_RECENT
최근 사용한 파일
CSIDL_SENDTO
보내는 폴더
CSIDL_STARTMENU
스타트 메뉴
CSIDL_STARTUP
스타트 업
인클루드
위의 함수는 아래의 헤더파일을 포함시켜야 합니다.
#include "winnetwk.h"
#include "shlobj.h"
===========================================================
(활용)
//폴더의 ITEMIDLIST값을 가지고 올 때 쓰임
LPITEMIDLIST pidlExceptFolder;
//폴더의 ISHELLFOLDER의 값을 가지고 올 때 쓰임
LPSHELLFOLDER pExceptFolder;
// 바탕화면의 IShellFolder
SHGetDesktopFolder(&pExceptFolder);
//특정 스패셜 폴더(CSIDL_WINDOWS 등등)의 ITEMIDLIST의 값을 가지고 옮
SHGetSpecialFolderLocation(NULL, CSIDL_WINDOWS, &pidlExceptFolder);
//스패셜 폴더의 Display Name을 ISTRRET값으로 저장시킴
HRESULT hr = pExceptFolder->GetDisplayNameOf(pidlExceptFolder, 0, &str);
TCHAR szFolderName[1024];
//ISTRRET의 uType의 값을 비교하여 해당 표시되는 이름을 얻어냄
switch(str.uType)
{
case STRRET_WSTR:
WideCharToMultiByte
(CP_ACP, 0, str.pOleStr, -1, szFolderName, MAX_PATH,NULL, NULL);
break;
case STRRET_OFFSET:
lstrcpy(szFolderName, reinterpret_cast<LPSTR>(pidl) + str.uOffset);
break;
case STRRET_CSTR:
lstrcpy(szFolderName, str.cStr);
break;
}
============================================================
(참고자료)
쉘 프로그래밍을 하실 때는
폴더나 파일등의 경로를 쉘이 어떻게 관리하는지 부터 이해 하여야 합니다.
예전의 도스에서는 우리가 보고 사용하는 파일명은
그대로 디스크에 저장되어 사용되어 집니다.
그러나 윈도우 쉘(탐색기)에서는 우리가 보게되는 파일이나 폴더들의 이름과
실제 하드디스크에서의 위치나 혹은 내부적으로 관리되는 이름은 서로 다를 수 있습니다.
따라서,
우리가 윈도우에서 폴더 또는 파일관련 쉘 프로그래밍을 할 때는
사용자에게 보여주어야 하는 이름과
프로그램 내부적으로 다루어야할 파일관련 함수에 넘겨주어야할
이름이 다를 수 있기 때문에
이 두가지를 모두 관리하여 주어야만 합니다.
윈도우 탐색기와 같은 것을 보면
각 폴더나 파일을 단순한 text로 된 이름으로 관리하는 것이 아니라
ITEMIDLIST라는 메모리 블록을 만들고 이 데이터로 각 폴더나 파일의 실제경로
및 사용자에게 보여주어야할 이름 및 기타 정보를 찾아 나갑니다.
예를 들어 c:\a\b.txt 라는 경로를 ITEMIDLIST로 만들어 본다면
[c:] [a] [b.txt]라는 3개의 정보블럭이 있고 이 3개의 정보블럭은 하나의
메모리 블럭에 할당되져 관리됩니다.
실제 그 구조체는 ShTypes.h에 다음과 같이 정의되어 있습니다.
typedef struct _SHITEMID
{
USHORT cb; <---- 한 항목의 메모리 블럭의 크기를 저장하는 곳
BYTE abID[ 1 ]; <---- 한 항목의 정보를 저장하는 영역
} SHITEMID;
typedef struct _ITEMIDLIST
{
SHITEMID mkid;
} ITEMIDLIST;
typedef ITEMIDLIST *LPITEMIDLIST;
즉 위의 c:\a\b.txt 라는 경로를 저장하고 있는
LPITEMIDLIST 메모리의 내부 구조를 본다면
[c:] [a] [b.txt] 각각의 정보를 저정하는 ITEMIDLIST
즉 SHITEMID 구조체 3개가 차례로 연결되어
한개의 메모리 블럭을 구성하고 있는 것입니다.
그렇다면 이렇게 여러개의 SHITEMID가 연결되어있는
LPITEMIDLIST를 관리하는 함수
즉, 여러개중 몇개를 떼어내거나 붙이거나 몇개인지 세거나
전체크기를 세거나 하는 함수가 필요 하겠지요 ?
문의하신 함수들이 바로 그러한 일을 하는 함수입니다.
SH로 시작하는 윈도우 쉘함수들이 경로(Path)대신에 LPITEMIDLIST값을
요구하기 때문에 LPITEMIDLIST를 관리하는 함수는 꼭 필요하겠지요 !
// 이 함수는 여러개의 SHITEMID 블럭을 포함하는 LPCITEMIDLIST메모리 주소를
// 입력받아서 두번째(앞쪽에서부터) 즉 다음번 SHITEMID 블럭의 주소를 찾아줍니다.
LPITEMIDLIST CShellProc::Next(LPCITEMIDLIST pidl)
{
LPSTR lpMem=(LPSTR)pidl;
lpMem+=pidl->mkid.cb; // 첫번째 블럭의 크기만큼 더하므로 다음 주소가 만들어집니다.
return (LPITEMIDLIST)lpMem;
}
// 포함된 전체 SHITEMID 블럭들의 각 크기를 모두 더해서
// LPCITEMIDLIST메모리 블럭 전체의 메모리 크기를 구하는 함수입니다.
UINT CShellProc::GetSize(LPCITEMIDLIST pidl)
{
UINT cbTotal = 0;
if (pidl)
{
cbTotal += sizeof(pidl->mkid.cb); // Null terminator
while (pidl->mkid.cb)
{
cbTotal += pidl->mkid.cb;
pidl = Next(pidl);
}
}
return cbTotal;
}
// 지정된 크기의 LPITEMIDLIST 메모리 블럭을 할당합니다.
// 다만 쉘이 공통으로 사용할 수 있는 메모리는 malloc() 등의 함수로
// 할당되는 메모리가 아니며 반드시 메모리 SHGetMalloc()로 얻은 함수를
// 사용해야만 한다는 특징이 있습니다.
LPITEMIDLIST CShellProc::CreatePidl(UINT cbSize)
{
LPMALLOC lpMalloc;
HRESULT hr;
LPITEMIDLIST pidl=NULL;
hr=SHGetMalloc(&lpMalloc); <--------- 할당함수의 주소얻기
if (FAILED(hr)) return 0;
pidl=(LPITEMIDLIST)lpMalloc->Alloc(cbSize);
if (pidl) memset(pidl, 0, cbSize); // zero-init for external task alloc
if (lpMalloc) lpMalloc->Release(); <--------- 할당함수 반환
return pidl;
}
// 2개의 LPCITEMIDLIST 메모리 블럭을 1개로 합쳐줍니다.
LPITEMIDLIST CShellProc::ConcatPidls(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
{
LPITEMIDLIST pidlNew;
UINT cb1;
UINT cb2;
if (pidl1) cb1 = GetSize(pidl1) - sizeof(pidl1->mkid.cb);
else cb1 = 0;
cb2 = GetSize(pidl2);
pidlNew = CreatePidl(cb1 + cb2);
if (pidlNew)
{
if (pidl1)
memcpy(pidlNew, pidl1, cb1);
memcpy(((LPSTR)pidlNew) + cb1, pidl2, cb2);
}
return pidlNew;
}
// LPITEMIDLIST의 첫번째 SHITEMID 블럭과 동일한 크기의 새로운 쉘메모리를 할당하고
// 첫번째 SHITEMID 블럭의 내용을 복사해 돌려줍니다.
// lpMalloc는 미리 SHGetMalloc()로 얻은 쉘메모리 할당함수의 주소입니다.
LPITEMIDLIST CShellProc::CopyITEMID(LPMALLOC lpMalloc, LPITEMIDLIST lpi)
{
LPITEMIDLIST lpiTemp;
lpiTemp=(LPITEMIDLIST)lpMalloc->Alloc(lpi->mkid.cb+sizeof(lpi->mkid.cb));
CopyMemory((PVOID)lpiTemp, (CONST VOID *)lpi, lpi->mkid.cb+sizeof(lpi->mkid.cb));
return lpiTemp;
}
// 이 함수는 LPSHELLFOLDER를 이용하여 LPITEMIDLIST 메모리 블럭에 있는 항목의 이름을
// 찾아 줍니다.
// SHELLFOLDER라는 것은 한 폴더의 관리자라 생각하면 됩니다.
// dwFlags에는 다음을 사용할 수 있습니다.
// SHGDN_NORMAL = 0, // default (display purpose)
// SHGDN_INFOLDER = 1, // displayed under a folder (relative)
// SHGDN_INCLUDE_NONFILESYS = 0x2000, // if not set, display names for shell name space items that are not in the file system will fail.
// SHGDN_FORADDRESSBAR = 0x4000, // for displaying in the address (drives dropdown) bar
// SHGDN_FORPARSING = 0x8000, // for ParseDisplayName or path
BOOL CShellProc::GetName(LPSHELLFOLDER lpsf,LPITEMIDLIST lpi,DWORD dwFlags,
LPSTR lpFriendlyName)
{
BOOL bSuccess=TRUE;
STRRET str;
if (NOERROR==lpsf->GetDisplayNameOf(lpi,dwFlags, &str))
{
switch (str.uType)
{
case STRRET_WSTR:
WideCharToMultiByte(CP_ACP, // CodePage
0, // dwFlags
str.pOleStr, // lpWideCharStr
-1, // cchWideChar
lpFriendlyName, // lpMultiByteStr
MAX_PATH,
//sizeof(lpFriendlyName), // cchMultiByte, wrong. sizeof on a pointer, psk, psk
NULL, // lpDefaultChar,
NULL); // lpUsedDefaultChar
break;
case STRRET_OFFSET:
lstrcpy(lpFriendlyName, (LPSTR)lpi+str.uOffset);
break;
case STRRET_CSTR:
lstrcpy(lpFriendlyName, (LPSTR)str.cStr);
break;
default:
bSuccess = FALSE;
break;
}
}
else
bSuccess = FALSE;
return bSuccess;
}
// 윈도우에서 ROOT는 바탕화면 즉 Desktop입니다.
LPITEMIDLIST CShellProc::GetFullyQualPidl(LPSHELLFOLDER lpsf, LPITEMIDLIST lpi)
{
char szBuff[MAX_PATH];
OLECHAR szOleChar[MAX_PATH];
LPSHELLFOLDER lpsfDeskTop;
LPITEMIDLIST lpifq;
ULONG ulEaten, ulAttribs;
HRESULT hr;
if (!GetName(lpsf, lpi, SHGDN_FORPARSING, szBuff))
return NULL;
hr=SHGetDesktopFolder(&lpsfDeskTop); <-------
if (FAILED(hr))
return NULL;
MultiByteToWideChar(CP_ACP,
MB_PRECOMPOSED,
szBuff,
-1,
(USHORT *)szOleChar,
sizeof(szOleChar));
hr=lpsfDeskTop->ParseDisplayName(NULL,
NULL,
szOleChar,
&ulEaten,
&lpifq,
&ulAttribs);
lpsfDeskTop->Release();
if (FAILED(hr))
return NULL;
return lpifq;
}
// 쉘에서 오른쪽 마우스 버튼을 클릭했을 때 띄워줄 PopupMenu를 처리하는 함수입니다.
BOOL CShellProc::DoTheMenuThing(HWND hwnd, LPSHELLFOLDER lpsfParent,
LPITEMIDLIST lpi, LPPOINT lppt)
{
LPCONTEXTMENU lpcm;
HRESULT hr;
char szTemp[64];
CMINVOKECOMMANDINFO cmi;
DWORD dwAttribs=0;
int idCmd;
HMENU hMenu;
BOOL bSuccess=TRUE;
hr=lpsfParent->GetUIObjectOf(hwnd,
1, //Number of objects to get attributes of
(const struct _ITEMIDLIST **)&lpi,
IID_IContextMenu,
0,
(LPVOID *)&lpcm);
if (SUCCEEDED(hr))
{
hMenu = CreatePopupMenu();
if (hMenu)
{
hr=lpcm->QueryContextMenu(hMenu, 0, 1, 0x7fff, CMF_EXPLORE);
if (SUCCEEDED(hr))
{
idCmd=TrackPopupMenu(hMenu,
TPM_LEFTALIGN | TPM_RETURNCMD | TPM_RIGHTBUTTON,
lppt->x, lppt->y, 0, hwnd, NULL);
if (idCmd)
{
cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
cmi.fMask = 0;
cmi.hwnd = hwnd;
cmi.lpVerb = MAKEINTRESOURCE(idCmd-1);
cmi.lpParameters = NULL;
cmi.lpDirectory = NULL;
cmi.nShow = SW_SHOWNORMAL;
cmi.dwHotKey = 0;
cmi.hIcon = NULL;
hr=lpcm->InvokeCommand(&cmi);
if (!SUCCEEDED(hr))
{
wsprintf(szTemp, "InvokeCommand failed. hr=%lx", hr);
AfxMessageBox(szTemp);
}
}
}
else
bSuccess = FALSE;
DestroyMenu(hMenu);
}
else
bSuccess = FALSE;
lpcm->Release();
}
else
{
wsprintf(szTemp, "GetUIObjectOf failed! hr=%lx", hr);
AfxMessageBox(szTemp );
bSuccess = FALSE;
}
return bSuccess;
}
// LPITEMIDLIST로 주어진 어떠한 폴더나 파일의 아이콘 번호를 알려 줍니다.
// 탐색기에서 볼 수 있는 아이콘들을 의미합니다.
// 다만 윈도우에는 시스템이미지리스트라는 이미지 리스트를 사용하며
// 이 이미지 리스트에서의 아이콘 순번을 돌려줍니다.
// 시스템 이미지 리스트를 구하는 함수는 아래에 첨부합니다.
// 참고하세요 !
int CShellProc::GetItemIcon(LPITEMIDLIST lpi, UINT uFlags)
{
SHFILEINFO sfi;
SHGetFileInfo((LPCSTR)lpi,
0,
&sfi,
sizeof(SHFILEINFO),
uFlags);
return sfi.iIcon;
}
// 시스템이미지 리스트를 구하는 함수입니다.
// 참고하세요 !
// 이미지리스트는 큰 아이콘, 작은아이콘 등을 별도로 구할 수 있습니다.
HIMAGELIST GetSystemImageList(int type)
{
UINT flag;
PSHIDL pidl;
SHFILEINFO sfi;
HIMAGELIST hSysImageList;
flag=SHGFI_PIDL | SHGFI_SYSICONINDEX;
if(type==0) flag|=SHGFI_SMALLICON;
if(type==1) flag|=SHGFI_LARGEICON;
if(type==2) flag|=SHGFI_OPENICON;
pidl=GetDesktopPIDL();
ZeroMemory(&sfi, sizeof(SHFILEINFO));
hSysImageList = (HIMAGELIST) SHGetFileInfo((LPCTSTR)pidl, 0, &sfi, sizeof(SHFILEINFO),flag);
Free((void *)pidl);
return hSysImageList;
}
'Windows > MFC' 카테고리의 다른 글
fatal error C1189: #error : Please use the /MD switch for _AFXDLL builds (0) | 2013.10.02 |
---|---|
String convert macro (0) | 2013.10.02 |
object 위치 찾기 (0) | 2013.10.02 |
비트맵 배경 제거 (TransparentBitmap) (0) | 2013.10.02 |
Standard C pre-defined symbols (0) | 2013.10.02 |