実行ファイルのプロパティ ダイアログボックスの[詳細]タブに表示される製品名を取得する。
実行ファイルに製品名を付けるには、リソースに Version を追加する。 |
// 製品名の取得 // pSrc : [IN] 実行ファイルのフルパス名 // pDst : [OUT] 受け取る製品名 // nDstSize : [IN] pDst の配列サイズ void Get_ProductName(char *pSrc, char *pDst, int nDstSize) { DWORD dwSize,dwHandle; dwSize = GetFileVersionInfoSize(pSrc, &dwHandle); if(dwSize > 0){ char *pMem = NULL; HANDLE hMem; hMem = GlobalAlloc(GMEM_MOVEABLE, dwSize); pMem = (char *)GlobalLock(hMem); if(GetFileVersionInfo(pSrc, 0, dwSize, pMem)){ char *strName = NULL; char strFileInfo[64]; UINT nLen = 0; sprintf(strFileInfo,"\\StringFileInfo\\%04x04B0\\ProductName", MAKELANGID(LANG_JAPANESE, SUBLANG_ENGLISH_US)); if(VerQueryValue(pMem, strFileInfo, (void**)&strName, &nLen)){ strncpy(pDst, strName, nDstSize); } } GlobalUnlock(hMem); GlobalFree(hMem); } }// Get_ProductName |
-------------------------------- 変数の場合 --------------------------------
|
SHFILEOPSTRUCT 構造体は、SHFileOperation() で使用する typedef struct _SHFILEOPSTRUCT{ HWND hwnd; UINT wFunc; LPCSTR pFrom; LPCSTR pTo; FILEOP_FLAGS fFlags; BOOL fAnyOperationsAborted; LPVOID hNameMappings; LPCSTR lpszProgressTitle; } SHFILEOPSTRUCT, FAR *LPSHFILEOPSTRUCT; hwnd ファイル操作状況のダイアログを表示したいウィンドウのハンドル wFunc 操作内容。以下のどれか1つを選択できる。 FO_COPY ファイルのコピー。pFrom から pTo へ。 FO_DELET ファイルをゴミ箱へ。pFrom のみ。pTo は無視される。 FO_MOVE ファイルの移動。pFrom から pTo へ。 FO_RENAME ファイル名の変更。pFrom から pTo へ。 pFrom 操作の元となる1つ、もしくは複数のファイル名が入ったバッファのアドレス。 複数の場合は、各ファイル名を NULL 文字で区切り、リストの最後には NULL 文字を 2 つ入れる。 pTo 操作の結果となるファイル名が入ったバッファのアドレス。 fFlags に FOF_MULTIDESTFILES が含まれていれば、複数のファイルを指定できる。 複数の場合は、各ファイル名を NULL 文字で区切り、リストの最後には NULL 文字を 2 つ入れる。 fFlags ファイル操作のフラグ。以下のフラグの組み合わせ。 FOF_ALLOWUNDO [元に戻す]操作の許可。pFrom がフルパス名でない場合は無視される。 FOF_CONFIRMMOUSE このフラグは選択できない。 FOF_FILESONLY ワイルドカード (*.*) が指定されていなければ、ファイル操作が実行される。 FOF_MULTIDESTFILES 総ての操作元ファイルが1つのディレクトリーに入っていれば、 それぞれの pFrom に対応させて pTo に複数のファイル名を指定できる。 FOF_NOCONFIRMATION 確認ダイアログを表示しない。(総てのダイアログに Yes として応答する) FOF_NOCONFIRMMKDIR 新しいディレクトリーの作成時に、確認ダイアログを表示しない。 FOF_NOCOPYSECURITYATTRIBS Version 4.71 以上。NTFS のみ。ファイルのセキュリティ属性はコピーしない。 FOF_NOERRORUI エラーを表示しない。 FOF_RENAMEONCOLLISION 移動・コピー・名前変更の実行後、そのファイル名が既に存在していた場合、 確認ダイアログを表示しないで別名を与える。 FOF_SILENT 進捗ダイアログを表示しない。 FOF_SIMPLEPROGRESS 進捗ダイアログにファイル名を表示しない。 FOF_WANTMAPPINGHANDLE FOF_RENAMEONCOLLISION が指定されている場合、いくつかのファイルが 名前変更されていたら、hNameMappings に書き入れる。 fAnyOperationsAborted ユーザーがファイル操作が完了する前に中止したら TRUE、さもなければ FALSE。 hNameMappings SHNAMEMAPPING 構造体の配列に含まれるファイル名マッピングオブジェクトのハンドル。 それぞれの構造体は、移動・コピー・名前変更されたそれぞれのファイルの古いパス名と新しいパス名を含む。 この引数は、FOF_WANTMAPPINGHANDLE フラグが含まれている場合だけ使われる。 このハンドルは、SHFreeNameMappings 関数で解放されなくてはならない。 lpszProgressTitle 進捗ダイアログのタイトルになる文字列のアドレス。 この引数は、FOF_SIMPLEPROGRESS フラグが含まれていない場合だけ使われる。 もし、pFrom や pTo のファイル名が適さない場合は、カレントディレクトリーは、 GetCurrentDirectory 関数や SetCurrentDirectory 関数で管理された グローバルカレントドライブやディレクトリー設定がとられる。 |
OwnerDrawメニュー以外の方法を使う場合(Windows7用)
|
#include <windows.h> #include <shlobj.h> #define IDM_CMD (WM_USER + 300) #define ITEM_NUM 3 void Menu_Add_Item(HMENU hMenu, UINT ID, char *string, UINT index) { MENUITEMINFO mi; ZeroMemory (&mi, sizeof(mi)); mi.cbSize = sizeof(mi); mi.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE; mi.wID = ID; mi.fType = MFT_STRING; mi.fState = MFS_ENABLED; mi.dwTypeData = string; InsertMenuItem(hMenu, index, TRUE, &mi); }// Menu_Add_Item // ビットマップの黒のピクセルをメニュー色に変更する void Bmp_BlackToMenuColor(HBITMAP *hbmColor, HBITMAP *hbmMask) { if(*hbmColor && *hbmMask){ BITMAP bmp; GetObject(*hbmColor, sizeof(BITMAP), &bmp); HBITMAP hBmpPre1,hBmpPre2; HDC hDCcp1 = CreateCompatibleDC(NULL); HDC hDCcp2 = CreateCompatibleDC(NULL); hBmpPre1 = (HBITMAP) SelectObject(hDCcp1, *hbmColor); hBmpPre2 = (HBITMAP) SelectObject(hDCcp2, *hbmMask); int x,y; for(y=0;y<bmp.bmHeight;y++){ for(x=0;x<bmp.bmWidth;x++){ if( RGB(0,0,0) == GetPixel(hDCcp1, x, y) && RGB(0,0,0) != GetPixel(hDCcp2, x, y)) { SetPixel(hDCcp1, x, y, GetSysColor(COLOR_MENU)); } } } SelectObject(hDCcp1, hBmpPre1); SelectObject(hDCcp2, hBmpPre2); DeleteDC(hDCcp1); DeleteDC(hDCcp2); } }// Bmp_BlackToMenuColor LRESULT CALLBACK ProcWnd(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { static char path[ITEM_NUM][MAX_PATH]; switch (uMsg) { case WM_COMMAND: if(LOWORD(wParam) >= IDM_CMD){ int idx = LOWORD(wParam) - IDM_CMD; if(idx >= 0 && idx < ITEM_NUM){ ShellExecute(NULL, "explore", path[idx], NULL, NULL, SW_SHOW); } } return 0; case WM_PAINT: { HDC hDC; PAINTSTRUCT ps; hDC = BeginPaint(hWnd,&ps); char str[256] = "クライアント領域で右クリックしてください"; TextOut(hDC, 10, 10, str, strlen(str)); EndPaint(hWnd,&ps); } return 0; case WM_CONTEXTMENU: { int i; static int nFolder[ITEM_NUM] = {CSIDL_DESKTOP, CSIDL_FAVORITES, CSIDL_HISTORY}; static char strFolder[ITEM_NUM][24] = {"デスクトップ", "お気に入り", "履歴"}; HBITMAP *hBmp = new HBITMAP [ITEM_NUM]; HMENU hMenu = CreatePopupMenu(); if(hMenu){ for(i=0;i<ITEM_NUM;i++){ // 仮想フォルダーのパスを取得 SHGetSpecialFolderPath(hWnd, path[i], nFolder[i], FALSE); // メニューアイテムの追加 Menu_Add_Item(hMenu, IDM_CMD + i, strFolder[i], i); // アイコンの取得 SHFILEINFO sfi; SHGetFileInfo(path[i], 0, &sfi, sizeof(sfi), SHGFI_ICON | SHGFI_SMALLICON); // アイコンからビットマップを取得し、黒のピクセルをメニュー色に変更 ICONINFO ici; ZeroMemory(&ici, sizeof(ici)); if(GetIconInfo(sfi.hIcon, &ici)){ hBmp[i] = ici.hbmColor; Bmp_BlackToMenuColor(&(ici.hbmColor), &(ici.hbmMask)); DeleteObject(ici.hbmMask); // メニューアイテムにビットマップを設定 SetMenuItemBitmaps(hMenu, IDM_CMD + i, MF_BYCOMMAND, ici.hbmColor, NULL); } DestroyIcon(sfi.hIcon); } // ポップアップメニューの表示 POINT pt; GetCursorPos(&pt); TrackPopupMenu(hMenu, TPM_LEFTALIGN, pt.x, pt.y, 0, hWnd, NULL); if(hBmp){ for(i=0;i<ITEM_NUM;i++){ DeleteObject(hBmp[i]); } delete [] hBmp; hBmp = NULL; } DestroyMenu(hMenu); } } break; case WM_CLOSE: DestroyWindow(hWnd); PostQuitMessage(0); return 0; default: break; } return DefWindowProc(hWnd, uMsg, wParam, lParam); }// ProcWnd |
ファイルの更新日時などのファイルタイムは、世界標準時(UTC)で保存する必要がある。
逆にファイルタイムを読み込む場合は、ローカルタイムで表示する必要がある。 |
// ファイルタイムを設定する場合 void Set_FileTime(SYSTEMTIME st) { FILETIME ft1,ft2; // システムタイム形式のローカルタイムをファイルタイム形式に変換 SystemTimeToFileTime(&st, &ft1); // ローカルタイムを UTC に変換 LocalFileTimeToFileTime(&ft1, &ft2); } // ファイルタイムを読み込む場合 void Get_FileTime(FILETIME ft1) { SYSTEMTIME st; FILETIME ft2; // UTC をローカルタイムに変換 FileTimeToLocalFileTime(&ft1, &ft2); // ファイルタイム形式をシステムタイム形式に変換 FileTimeToSystemTime(&ft2, &st); } |
リストビューのカラムをクリックすると並び替えのサンプル。
LPARAM に構造体のアドレスを入れると、アイテムを追加・削除したときに、 元データの並び替えをしたり、番号を合わせたりしなくて済む。 LPARAM に構造体のアドレスを入れるときは、必ず、メモリの確保が必要。 しなかったら、データ数が多いときにエラーが発生する。 リストボックスやコンボボックスの場合も同様。 comctl32.lib のリンク設定が必要 (あるいは、#pragma comment(lib, "comctl32.lib") をソースに追加) |
#include <windows.h> #include <commctrl.h> #define MYWNDCLASS "ListViewCLASS" #define MYWNDTITLE "ListView" #define ID_LIST (WM_USER + 200) #define COL_NUM 3 // リストビューのカラム数 #define ANM_NUM 4 // 動物の種類の数 // 動物情報 typedef struct{ char name[32]; // 名称 char order[32]; // 目 char family[32]; // 科 }ANIMAL,*LPANIMAL; LRESULT CALLBACK ProcWnd(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); int CALLBACK ProcListViewCmp(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort); void Add_One_Item(HWND hList, ANIMAL am); LPANIMAL Get_Lparam(HWND hList, int iItem); LRESULT CALLBACK ProcWnd(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { static HWND hList = NULL; static char colText[COL_NUM][24] = {"名称","目","科"}; static int colWdh[COL_NUM] = {100,100,100}; static int colFmt[COL_NUM] = {0,0,0}; static char animals[ANM_NUM][COL_NUM][32] = {{"猫","ネコ","ネコ"}, {"犬","ネコ","イヌ"}, {"人","サル","ヒト"}, {"牛","ウシ","ウシ"}}; switch (uMsg) { case WM_CREATE: { // リストビューの初期化 InitCommonControls(); // リストビューの作成 hList = CreateWindowEx(WS_EX_CLIENTEDGE, WC_LISTVIEW, NULL, WS_CHILD | WS_TABSTOP | WS_VISIBLE | LVS_REPORT | LVS_SHOWSELALWAYS, 0, 0, 0, 0, hWnd, (HMENU) ID_LIST, GetModuleHandle(NULL), NULL); // カラムの追加 int i; LV_COLUMN lvC; ZeroMemory(&lvC,sizeof(lvC)); lvC.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; for(i=0;i<COL_NUM;i++){ lvC.iSubItem = i; lvC.fmt = colFmt[i]; lvC.cx = colWdh[i]; lvC.pszText = colText[i]; ListView_InsertColumn(hList, i, &lvC); } // アイテムの追加 ANIMAL am[ANM_NUM]; for(i=0;i<ANM_NUM;i++){ strncpy(am[i].name, animals[i][0], 32); strncpy(am[i].order, animals[i][1], 32); strncpy(am[i].family, animals[i][2], 32); Add_One_Item(hList, am[i]); } } return 0; case WM_SIZE: if(hList){ // リストビューのサイズ変更 MoveWindow(hList, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE); } return 0; case WM_NOTIFY: { NMHDR *phdr = (NMHDR*) lParam; switch(phdr->code) { case LVN_COLUMNCLICK: // カラムがクリックされた if(phdr->hwndFrom == hList){ LPNMLISTVIEW pnmlv = (LPNMLISTVIEW) lParam; // 並び替え ListView_SortItems(hList, ProcListViewCmp, (LPARAM)(pnmlv->iSubItem)); } break; } } return 0; case WM_CLOSE: { int i,num = ListView_GetItemCount(hList); for(i=0;i<num;i++){ LPANIMAL pam = Get_Lparam(hList, i); if(pam){ delete pam; } } } DestroyWindow(hWnd); PostQuitMessage(0); return 0; default: break; } return DefWindowProc(hWnd, uMsg, wParam, lParam); } // カラムのクリックでソートするときのソートのルール int CALLBACK ProcListViewCmp(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) { LPANIMAL pam1 = (LPANIMAL)lParam1; LPANIMAL pam2 = (LPANIMAL)lParam2; int iResult = 0; if (pam1 && pam2) { switch(lParamSort) { case 0: iResult = strcmp(pam1->name, pam2->name); break; case 1: iResult = strcmp(pam1->order, pam2->order); break; case 2: iResult = strcmp(pam1->family, pam2->family); break; } } return iResult; }// ProcListViewCmp // アイテムの追加 void Add_One_Item(HWND hList, ANIMAL am) { LVITEM lvI; ZeroMemory(&lvI,sizeof(lvI)); lvI.mask = LVIF_TEXT | LVIF_STATE | LVIF_PARAM; lvI.state = 0; lvI.stateMask = -1; // 全ての状態を設定 lvI.iItem = ListView_GetItemCount(hList); lvI.iSubItem = 0; lvI.pszText = am.name; LPANIMAL pam = (LPANIMAL) new ANIMAL; *pam = am; lvI.lParam = (LPARAM)pam; int index = ListView_InsertItem(hList, &lvI); if(index != -1){ ListView_SetItemText(hList,index,1,am.order); ListView_SetItemText(hList,index,2,am.family); } }// Add_One_Item // LPARAM の取得 LPANIMAL Get_Lparam(HWND hList, int iItem) { if(iItem != -1){ LVITEM lvI; ZeroMemory(&lvI, sizeof(lvI)); lvI.mask = LVIF_PARAM; lvI.iItem = iItem; if(ListView_GetItem(hList, &lvI)){ LPANIMAL pam = (LPANIMAL) (lvI.lParam); return pam; } } return NULL; }// Get_Lparam |
他のウィンドウからのドラッグ&ドロップには対応していない。
対応させるには、IDropTarget を実装する。 列挙するファイル名は、フォルダからの相対パスである。 つまり、以下のサンプルは対応していないが、子孫ファイルやフォルダもドラッグできる。 参考文献: VisualC++ 逆引き大全500の極意 窓プログラミング(http://hp.vector.co.jp/authors/VA016117/) |
#include <windows.h> #include <stdio.h> #include <shlobj.h> #define FILE_MAX 32 // 列挙するファイル名の最大数 #define SAFE_RELEASE(p) if (p){p->Release();p=NULL;} class CDropSrc : public IDropSource { ULONG m_nRefCount; public: STDMETHODIMP QueryInterface(REFIID riid, LPVOID* ppv) { if(IsEqualIID(riid, IID_IUnknown)){ *ppv = (LPUNKNOWN)(IDropSource*)this; } else if(IsEqualIID(riid, IID_IDropSource)){ *ppv = (IDropSource*)this; } else{ *ppv = NULL; return E_NOINTERFACE; } AddRef(); return NOERROR; } STDMETHODIMP_(DWORD) Release() { if(--m_nRefCount) return m_nRefCount; delete this; return 0; } STDMETHODIMP_(DWORD) AddRef() { return ++m_nRefCount; } HRESULT STDMETHODCALLTYPE QueryContinueDrag( BOOL fEscapePressed, DWORD grfKeyState) { if(fEscapePressed) return DRAGDROP_S_CANCEL; else if(!(grfKeyState & MK_LBUTTON)) return DRAGDROP_S_DROP; else return NOERROR; } HRESULT STDMETHODCALLTYPE GiveFeedback(DWORD dwEffect) { return DRAGDROP_S_USEDEFAULTCURSORS; } }; LRESULT CALLBACK ProcWnd(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { static char path[MAX_PATH]; static char filename[FILE_MAX][MAX_PATH]; static int file_num = 0; switch (uMsg) { case WM_CREATE: { OleInitialize(NULL); // 実行ファイルがあるフォルダ内のファイルをDrag&Dropする GetModuleFileName(NULL, path, sizeof(path)); char *p = strrchr(path, '\\'); if(p){ strcpy(p, ""); } // ファイル名の列挙 HANDLE hfind; WIN32_FIND_DATA w32fd; char filename_find[MAX_PATH]; file_num = 0; _snprintf(filename_find, sizeof(filename_find)-1, "%s\\*.*", path); hfind = FindFirstFile(filename_find, &w32fd); if(hfind != INVALID_HANDLE_VALUE){ do{ if(strcmp(w32fd.cFileName, ".") && strcmp(w32fd.cFileName, "..")){ strncpy(filename[file_num], w32fd.cFileName, sizeof(filename[file_num])); file_num ++; if(file_num >= FILE_MAX){ break; } } }while(FindNextFile(hfind, &w32fd)); } FindClose(hfind); } return 0; case WM_LBUTTONDOWN: // マウスの左ボタンが押されたとき if(file_num > 0){ LPMALLOC pMalloc = NULL; LPITEMIDLIST *pidlFile = NULL; LPSHELLFOLDER pSH = NULL; LPSHELLFOLDER pSH2 = NULL; LPDATAOBJECT pDO = NULL; SHGetMalloc(&pMalloc); pidlFile = (LPITEMIDLIST*) pMalloc->Alloc(file_num * sizeof(LPITEMIDLIST)); HRESULT hr = SHGetDesktopFolder(&pSH); if(pSH){ LPITEMIDLIST pidlRoot; WCHAR wPath[MAX_PATH],wFname[MAX_PATH]; ULONG chEaten; if(path[strlen(path)-1] == '\\'){ strcpy(&path[strlen(path)-1], ""); } MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, path, -1, wPath, MAX_PATH); // フォルダーのPIDLを取得 hr = pSH->ParseDisplayName(hWnd, NULL, wPath, &chEaten, &pidlRoot, NULL); // フォルダーのIShellFolderオブジェクトを取得 hr = pSH->BindToObject(pidlRoot, NULL, IID_IShellFolder, (LPVOID *)&pSH2); SAFE_RELEASE(pSH); if(pSH2){ int len = strlen(path); // ファイルのPIDLを取得 for(int i=0;i<file_num;i++){ MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, filename[i], -1, wFname, MAX_PATH); hr = pSH2->ParseDisplayName(hWnd, NULL, wFname, &chEaten, &pidlFile[i], NULL); } hr = pSH2->GetUIObjectOf(hWnd, file_num, (LPCITEMIDLIST*) pidlFile, IID_IDataObject, NULL, (LPVOID*)&pDO); SAFE_RELEASE(pSH2); } if(pDO){ CDropSrc *pDS = new CDropSrc(); DWORD dwEffect; DoDragDrop(pDO, (IDropSource*) pDS, DROPEFFECT_COPY, &dwEffect); SAFE_RELEASE(pDO); SAFE_RELEASE(pDS); } if(pidlFile) pMalloc->Free(pidlFile); SAFE_RELEASE(pMalloc); } } return 0; case WM_PAINT: { HDC hDC; PAINTSTRUCT ps; hDC = BeginPaint(hWnd,&ps); char str[] = "クライアント領域からデスクトップにドラッグ&ドロップしてください"; TextOut(hDC, 10, 10, str, strlen(str)); EndPaint(hWnd,&ps); } return 0; case WM_CLOSE: OleUninitialize(); DestroyWindow(hWnd); PostQuitMessage(0); return 0; default: break; } return DefWindowProc(hWnd, uMsg, wParam, lParam); } |
// データをメモリから読み込む場合やメモリに保存する場合に使用する // GDI+ を使用する場合 // CreateStreamOnHGlobal() は 2番目の引数を TRUE にすると pStrm // の解放時に hMem も(pData も)解放される。 void Load_Image(char *fname) { HANDLE hFile; DWORD dwRead; hFile = CreateFile(fname,GENERIC_READ,FILE_SHARE_READ, NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); if(hFile != INVALID_HANDLE_VALUE){ DWORD size = GetFileSize(hFile, NULL); LPSTREAM pStrm = NULL; HGLOBAL hMem = GlobalAlloc(GPTR, size); LPBYTE pData = (LPBYTE) GlobalLock(hMem); if(size > 0 && size != 0xFFFFFFFF){ ReadFile(hFile, pData, size, &dwRead, NULL); CreateStreamOnHGlobal(hMem, TRUE, &pStrm); GlobalUnlock(hMem); Bitmap Bmp(pStrm, TRUE); HWND hWnd = GetFocus(); HDC hDC = GetDC(hWnd); Graphics g(hDC); g.DrawImage(&Bmp, 0, 0, Bmp.GetWidth(), Bmp.GetHeight()); ReleaseDC(hWnd, hDC); } pStrm->Release(); CloseHandle(hFile); } }// Load_Image void Save_Image(CLSID Clsid, char *filename) { DWORD size = 0; HGLOBAL hMem = NULL; LPSTREAM pStrm = NULL; CreateStreamOnHGlobal(NULL, TRUE, &pStrm); Bitmap Bmp(filename, TRUE); if(Ok == Bmp.Save(pStrm, &Clsid)){ GetHGlobalFromStream(pStrm, &hMem); LPBYTE pBuf = (BYTE *)GlobalLock(hMem); size = GlobalSize(hMem); LPBYTE pData = new BYTE [size]; memcpy(pData, pBuf, size); delete [] pData; GlobalUnlock(hMem); } pStrm->Release(); }// Save_Image |
ドラッグで線を描画する場合は、点と点の間を線で結ぶ必要がある。MoveToEx 関数と LineTo 関数で線を結んでも良いのだが、Bresenham の線分アルゴリズムを用いた方がそれらしくなる。
グリッドを描画する場合は、画像を拡大表示しても線幅は変化しないようにしたい。そのためには、クライアント領域全体をビットマップにして、そのビットマップに画像を貼り付けて線を描画する。ビットマップに描画するには、GDI+ であれば、Bitmap オブジェクトを引数にした Graphics オブジェクトを作成する。GDI であれば、CreateCompatibleDC 関数でメモリデバイスコンテキストを作成し、それにビットマップを SelectObject 関数で関連付ける。どちらもクライアント領域からはみだした画像領域は描画しないようにする。 レイヤーを使用する場合は、GDI+ であれば、Bitmap オブジェクトを引数にした Graphics オブジェクトを、GDI であれば、CreateCompatibleDC 関数で作成し、SelectObject 関数でビットマップを関連付けたメモリデバイスコンテキストをもう1つ作成して入れ子にして使う。 ペイントソフトを作成するときに重要となるのは、描画速度だが、最も時間がかかるのはディスプレイに表示するときである。例えば、画像を描画して、その上に線を描画するとき、デバイスコンテキストに画像を描画して、その上に線を描画すると、表示を2回した事になる。しかし、メモリデバイスコンテキストに画像を描画して、その上に線を描画して、そのメモリデバイスコンテキストをデバイスコンテキストに描画するならば、表示は1度ですみ、描画速度が飛躍的に向上する。メモリデバイスコンテキストへの描画は、表示ではないからである。 変数や配列への値の代入は、速度低下要因となるから、代入回数は減らした方がいい。 一般に、乗除よりは加減やシフトの方が演算速度が向上すると言われている。符号なし整数型は、左にシフトするごとに*2、右にシフトするごとに/2の演算をしたのと同じ結果が得られる。 GDI 高速描画手法は、乗除の減らし方やテーブルを使用したアルファブレンディングなどがある DirectX Programmers Page(http://www.interq.or.jp/black/minami-m/)のGDIライブラリがお奨めである。 テーブル アルファブレンディングは、ハッシュテーブル探索と考え方は同じである。 |
// GDI のグリッド表示例 #include <windows.h> #define MYWNDCLASS "grid_class" #define MYWNDTITLE "grid" #define WIDTHBYTES(bits) ((((bits) + 31)>>5)<<2) #define COLOR_BIT 24 // 作業用DIBの色深度 HBITMAP ghBmp = NULL; DIBSECTION gDib; HBITMAP ghBmpWork = NULL; BYTE *gpBitsWork = NULL; int gWidthWork,gHeightWork; float gZoom = 1.0f; LRESULT CALLBACK ProcWnd(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); void Load_Dib(char *filename); void Create_Work_Dib(); void Draw_Grid(HDC hDC, int width, int height, float zoom); void M_Paint(HDC hDC); int WINAPI WinMain(HINSTANCE hInst,HINSTANCE hInstPrev,LPSTR lpCmdLine,int nCmdShow) { MSG msg; WNDCLASSEX wc; HWND hWnd; ZeroMemory(&wc, sizeof(wc)); wc.cbSize = sizeof(WNDCLASSEX); wc.lpfnWndProc = (WNDPROC)ProcWnd; wc.hInstance = hInst; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wc.lpszMenuName = NULL; wc.lpszClassName = MYWNDCLASS; RegisterClassEx(&wc); hWnd = CreateWindowEx(WS_EX_ACCEPTFILES, MYWNDCLASS, MYWNDTITLE, WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInst, NULL); while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } LRESULT CALLBACK ProcWnd(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_CREATE: if(__argc > 1){ Load_Dib(__argv[1]); } return 0; case WM_DROPFILES: { HDROP hDrop; char fname[MAX_PATH] = ""; hDrop = (HDROP) wParam; DragQueryFile(hDrop, 0, fname, sizeof(fname)); Load_Dib(fname); DragFinish(hDrop); InvalidateRect(hWnd, NULL, FALSE); SetForegroundWindow(hWnd); } return 0; case WM_SIZE: gWidthWork = LOWORD(lParam); gHeightWork = HIWORD(lParam); InvalidateRect(hWnd, NULL, FALSE); return 0; case WM_KEYDOWN: switch (wParam) { case VK_UP: // [↑]キー gZoom += 0.1f; if(gZoom > 10){ gZoom = 10; } InvalidateRect(hWnd, NULL, FALSE); return 0; case VK_DOWN: // [↓]キー gZoom -= 0.1f; if(gZoom < 0.1f){ gZoom = 0.1f; } InvalidateRect(hWnd, NULL, FALSE); return 0; } break; case WM_PAINT: { HDC hDC; PAINTSTRUCT ps; hDC = BeginPaint(hWnd,&ps); M_Paint(hDC); EndPaint(hWnd,&ps); } return 0; case WM_CLOSE: if(ghBmp){ DeleteObject(ghBmp); } DestroyWindow(hWnd); PostQuitMessage(0); return 0; default: break; } return DefWindowProc(hWnd, uMsg, wParam, lParam); } // ビットマップ ファイルの読み込み void Load_Dib(char *filename) { if(ghBmp){ DeleteObject(ghBmp); } ghBmp = (HBITMAP) LoadImage(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE|LR_CREATEDIBSECTION); // ビットマップの情報を取得 GetObject(ghBmp, sizeof(DIBSECTION), &gDib); // 拡大率を初期化 gZoom = 1.0f; }// Load_Dib // 作業用DIBの作成 void Create_Work_Dib() { BITMAPINFO bmi; ZeroMemory(&bmi, sizeof(bmi)); bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmi.bmiHeader.biWidth = gWidthWork; bmi.bmiHeader.biHeight = gHeightWork; bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biBitCount = COLOR_BIT; bmi.bmiHeader.biCompression = BI_RGB; ghBmpWork = (HBITMAP) CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, (VOID **)&gpBitsWork, NULL, 0); int workSize = WIDTHBYTES(gWidthWork * COLOR_BIT) * gHeightWork; // 作業用DIBのサイズを求める ZeroMemory(gpBitsWork, workSize); // 作業用DIBを黒で塗りつぶす }// Create_Work_Dib // グリッドの描画 void Draw_Grid(HDC hDC, int width, int height, float zoom) { int oldMode = SetROP2(hDC, R2_NOT); int interval = (int)(zoom * 16); int width2 = (int)(zoom * width); int height2 = (int)(zoom * height); for(int x=0;x<width2;x+=interval){ MoveToEx(hDC, x, 0, NULL); LineTo(hDC, x, height2); } for(int y=0;y<height2;y+=interval){ MoveToEx(hDC, 0, y, NULL); LineTo(hDC, width2, y); } SetROP2(hDC, oldMode); }// Draw_Grid // 描画 void M_Paint(HDC hDC) { HDC hDCcp1,hDCcp2; HBITMAP hBmpPre1,hBmpPre2; int width = gDib.dsBmih.biWidth; int height = gDib.dsBmih.biHeight; Create_Work_Dib(); if(ghBmpWork){ hDCcp1 = CreateCompatibleDC(hDC); hBmpPre1 = (HBITMAP) SelectObject(hDCcp1, ghBmpWork); HRGN hrgn = CreateRectRgn(0, 0, gWidthWork, gHeightWork); SelectClipRgn(hDCcp1, hrgn); DeleteObject(hrgn); if(ghBmp){ hDCcp2 = CreateCompatibleDC(hDCcp1); hBmpPre2 = (HBITMAP) SelectObject(hDCcp2, ghBmp); StretchBlt(hDCcp1, 0, 0, (int)(width * gZoom), (int)(height * gZoom), hDCcp2, 0, 0, width, height, SRCCOPY); SelectObject(hDCcp2, hBmpPre2); DeleteDC(hDCcp2); } else{ char str1[256] = "BMP ファイルをこのウィンドウに DRAG & DROP してください"; TextOut(hDCcp1, 10, 10, str1, strlen(str1)); char str2[256] = "画像は、[↑]キーで拡大表示、[↓]キーで縮小表示されます"; TextOut(hDCcp1, 10, 30, str2, strlen(str2)); } Draw_Grid(hDCcp1, width, height, gZoom); BitBlt(hDC, 0, 0, gWidthWork, gHeightWork, hDCcp1, 0, 0, SRCCOPY); SelectObject(hDCcp1, hBmpPre1); SelectClipRgn(hDCcp1, (HRGN) NULL); DeleteDC(hDCcp1); DeleteObject(ghBmpWork); } }// M_Paint |
PNG ファイルをアイコンに保存する。
PNG アイコンについては Wikipedia ICO 参照 PNG アイコンは、PNG ファイルをそのままアイコンファイルに入れたものである。 |
#include <windows.h> #include <gdiplus.h> #pragma comment( lib, "gdiplus.lib" ) #define TITLE "PngIcon" #define ICON_MAX 1 // 読み込む画像の最大数 using namespace Gdiplus; typedef struct { BYTE bWidth; // 画像の幅 BYTE bHeight; // 画像の高さ BYTE bColorCount; // 色数(色深度が 8bpp 以上の場合は 0) BYTE bReserved; // 未使用(必ず 0) WORD wPlanes; // カーソルの場合はホットスポットのX座標、アイコンの場合は 0 WORD wBitCount; // カーソルの場合はホットスポットのY座標、アイコンの場合は 0 DWORD dwBytesInRes; // データサイズ DWORD dwImageOffset; // ファイル内のデータの位置 } ICONDIRENTRY, *LPICONDIRENTRY; ICONDIRENTRY g_ide[ICON_MAX]; BYTE *g_pData[ICON_MAX]; DWORD CalculateImageOffset( UINT nIndex, WORD wCount ) { DWORD dwSize; UINT i; // Calculate the ICO header size dwSize = 3 * sizeof( WORD ); // Add the ICONDIRENTRY's dwSize += wCount * sizeof( ICONDIRENTRY ); // Add the sizes of the previous images for( i=0;i<nIndex;i++ ) dwSize += g_ide[i].dwBytesInRes; // we're there - return the number return dwSize; }// CalculateImageOffset bool Load_PngFile( UINT nIndex, WORD wCount, char *pngfilename ) { char *p = strrchr( pngfilename, '.' ); if( !p || stricmp( p, ".png" ) ){ return false; } DWORD size_data = 0; HANDLE hFileR; hFileR = CreateFile( pngfilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if( hFileR ) { DWORD dwRead; size_data = GetFileSize( hFileR, NULL ); if( size_data > 0 && size_data != 0xFFFFFFFF ) { delete [] g_pData[nIndex]; g_pData[nIndex] = NULL; g_pData[nIndex] = new BYTE [size_data]; ZeroMemory( g_pData[nIndex], size_data ); ReadFile( hFileR, g_pData[nIndex], size_data, &dwRead, NULL ); } CloseHandle( hFileR ); } WCHAR wfname[MAX_PATH]; MultiByteToWideChar( CP_ACP, 0, pngfilename, -1, wfname, sizeof( wfname ) ); Bitmap Bmp( wfname, TRUE ); g_ide[nIndex].bWidth = Bmp.GetWidth(); g_ide[nIndex].bHeight = Bmp.GetHeight(); g_ide[nIndex].bReserved = 0; g_ide[nIndex].wPlanes = 0; g_ide[nIndex].wBitCount = 0; UINT bpp = (BYTE)(Bmp.GetPixelFormat() >> 8); if(bpp >= 8) g_ide[nIndex].bColorCount = 0; else g_ide[nIndex].bColorCount = 1 << bpp; g_ide[nIndex].dwBytesInRes = size_data; g_ide[nIndex].dwImageOffset = CalculateImageOffset( nIndex, wCount ); return true; }// Load_PngFile bool Save_PngIcon(char *iconfilename ) { char *p = strrchr( iconfilename, '.' ); if( !p || stricmp( p, ".ico" ) ) { return false; } HANDLE hFileW; DWORD dwWrite; int i; // open the file hFileW = CreateFile( iconfilename, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); if( hFileW == INVALID_HANDLE_VALUE ) { return 0; } // Write the Reserved word WORD wReserved = 0; WriteFile( hFileW, &wReserved, sizeof( WORD ), &dwWrite, NULL ); // Write the Type word - make sure it is 1 for icons WORD wType = 1; WriteFile( hFileW, &wType, sizeof( WORD ), &dwWrite, NULL ); // Write the count - how many images in this file? WORD wCount = 1; wCount = ICON_MAX > wCount ? wCount : ICON_MAX; WriteFile( hFileW, &wCount, sizeof( WORD ), &dwWrite, NULL ); for( i=0;i<wCount;i++ ) { // Load the PNG file Load_PngFile( i, wCount, "32bit256x256.png" ); } for( i=0;i<wCount;i++ ) { // Write the ICONDIRENTRY out to disk WriteFile( hFileW, &g_ide[i], sizeof( ICONDIRENTRY ), &dwWrite, NULL ); // Did we write a full ICONDIRENTRY ? if( dwWrite != sizeof( ICONDIRENTRY ) ) return 0; } for( i=0;i<wCount;i++ ) { // Write the image data to file WriteFile( hFileW, g_pData[i], g_ide[i].dwBytesInRes, &dwWrite, NULL ); if( dwWrite != g_ide[i].dwBytesInRes ) return 0; } CloseHandle( hFileW ); return 1; }// Save_PngIcon int WINAPI WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow ) { GdiplusStartupInput gdiSI; ULONG_PTR gdiToken; // GDI+オブジェクト初期化 GdiplusStartup( &gdiToken, &gdiSI, NULL ); // アイコンの保存 Save_PngIcon( "pngicon.ico" ); // メモリの解放 for( int i=0;i<ICON_MAX;i++ ) { delete [] g_pData[i]; g_pData[i] = NULL; } // GDI+オブジェクト解放 GdiplusShutdown( gdiToken ); return 0; } |
アニメーション カーソルからアイコンもしくはカーソルファイルを抜き出し保存する
|
// Source code from the MSDN Library (AniEdit, ANIFILE.C, 21-Apr-1993 JonPa) #include <windows.h> #include <stdio.h> #define MYWNDCLASS "AniToIconCLASS" #define MYWNDTITLE "AniToIcon" #define CCH_TITLE 80 #define CCH_CREATOR 80 #define PADUP(cb) (((cb) + 1) & ~1) typedef struct _RTAG { FOURCC ckID; DWORD ckSize; } RTAG, *PRTAG; #define FOURCC_ACON mmioFOURCC('A', 'C', 'O', 'N') #define FOURCC_anih mmioFOURCC('a', 'n', 'i', 'h') #define FOURCC_rate mmioFOURCC('r', 'a', 't', 'e') #define FOURCC_seq mmioFOURCC('s', 'e', 'q', ' ') #define FOURCC_fram mmioFOURCC('f', 'r', 'a', 'm') #define FOURCC_icon mmioFOURCC('i', 'c', 'o', 'n') #define FOURCC_INFO mmioFOURCC('I', 'N', 'F', 'O') // INFO list #define FOURCC_IART mmioFOURCC('I', 'A', 'R', 'T') // Artist #define FOURCC_INAM mmioFOURCC('I', 'N', 'A', 'M') // Name/Title typedef DWORD JIF, *PJIF; typedef struct _ANIHEADER { DWORD cbSizeof; DWORD cFrames; DWORD cSteps; DWORD cx, cy; DWORD cBitCount, cPlanes; JIF jifRate; DWORD fl; } ANIHEADER, *PANIHEADER; #define AF_ICON 0x0001L // Windows format icon/cursor animation typedef struct _FRAME // コマ情報 { int iFrame; // 表示する順番(不要の場合もある) POINT hotspot; // カーソルのホットスポット(不要の場合もある) JIF jif; // 表示時間(1 jif = 1 / 60 秒)(不要の場合もある) } FRAME, *PFRAME; typedef struct _ANICUR { ANIHEADER anih; CHAR azTitle[CCH_TITLE]; // ANI ファイルの題名 CHAR azCreator[CCH_CREATOR]; // ANI ファイルの作者名 CHAR azFilename[MAX_PATH]; // ANI ファイルのフルパス名 CHAR azSavepath[MAX_PATH]; // ICO ファイルの保存フォルダーのパス名 } ANICUR; ANICUR ganiAcon; PFRAME gpfrmFrames; BOOL ReadTag(HANDLE hf, PRTAG ptag) { DWORD cbActual; ptag->ckID = ptag->ckSize = 0L; if(!ReadFile(hf, ptag, sizeof(RTAG), &cbActual, NULL) || (cbActual != sizeof(RTAG))) return FALSE; return TRUE; }// ReadTag BOOL ReadTagID(HANDLE hf, FOURCC *pckID) { DWORD cbActual; *pckID = 0L; if(!ReadFile(hf, pckID, sizeof(FOURCC), &cbActual, NULL) || (cbActual < sizeof(FOURCC))) return FALSE; return TRUE; }// ReadTagID BOOL ReadChunk(HANDLE hf, PRTAG ptag, PVOID pv) { DWORD cbActual; if(!ReadFile(hf, pv, ptag->ckSize, &cbActual, NULL) || (cbActual != ptag->ckSize)) return FALSE; // 2 バイト境界のファイルポインター if(ptag->ckSize & 1) SetFilePointer(hf, 1, NULL, FILE_CURRENT); return TRUE; }// ReadChunk BOOL ReadChunkN(HANDLE hf, PRTAG ptag, PVOID pv, DWORD cbMax) { DWORD cbActual; DWORD cbRead = min(cbMax, ptag->ckSize); if(!ReadFile(hf, pv, ptag->ckSize, &cbActual, NULL) || (cbActual != cbRead)) return FALSE; // 2 バイト境界のファイルポインター cbRead = ptag->ckSize - cbActual; if(ptag->ckSize & 1) cbRead++; return SetFilePointer(hf, cbRead, NULL, FILE_CURRENT) != 0xFFFFFFFF; }// ReadChunkN BOOL SkipChunk(HANDLE hf, PRTAG ptag) { // Round ptag->ckSize up to nearest word boundary to maintain alignment return SetFilePointer(hf, PADUP(ptag->ckSize), NULL, FILE_CURRENT) != 0xFFFFFFFFL; }// SkipChunk void ReadIconFromFile(HANDLE hf, DWORD ckSize, int iFrame){ LPBYTE pBuf = (LPBYTE) malloc(ckSize); DWORD cbRead; if(pBuf){ if(ReadFile(hf, pBuf, ckSize, &cbRead, NULL) && cbRead == ckSize){ WORD wType; // 1:icon, その他:cursor memcpy(&wType, (BYTE*)pBuf+sizeof(WORD), sizeof(WORD)); // ico, cur ファイルの作成 char filename[MAX_PATH]; strncpy(filename, ganiAcon.azSavepath, sizeof(filename)); char title[MAX_PATH]; GetFileTitle(ganiAcon.azFilename, title, sizeof(title)); _snprintf(filename, sizeof(filename)-5, "%s\\%s%02d", ganiAcon.azSavepath, title, iFrame+1); if(wType == 1){ strcat(filename, ".ico"); } else{ strcat(filename, ".cur"); } FILE *file; if(file = fopen(filename, "wb")){ fwrite(pBuf, sizeof(BYTE), ckSize, file); fclose(file); } } } if(pBuf != NULL) free(pBuf); }// ReadIconFromFile BOOL ReadAniFile() { HANDLE hf; RTAG tag; BOOL fSuccess = FALSE; JIF *pjifRate = NULL; DWORD *pseq = NULL; DWORD i,iFrame = 0; hf = CreateFile(ganiAcon.azFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if(hf == INVALID_HANDLE_VALUE) goto laiFileErr; if(!ReadTag(hf, &tag)) goto laiFileErr; if(tag.ckID != FOURCC_RIFF) goto laiFileErr; if(!ReadTagID(hf, &tag.ckID)) goto laiFileErr; if(tag.ckID != FOURCC_ACON) goto laiFileErr; // ico, cur ファイルを入れるフォルダーの作成 strncpy(ganiAcon.azSavepath, ganiAcon.azFilename, sizeof(ganiAcon.azSavepath)); char *p; p = strrchr(ganiAcon.azSavepath, '\\'); if(p+1){ strcpy(p+1, ""); char title[MAX_PATH]; GetFileTitle(ganiAcon.azFilename, title, sizeof(title)); strcat(ganiAcon.azSavepath, title); if(!CreateDirectory(ganiAcon.azSavepath, NULL)){ ZeroMemory(ganiAcon.azSavepath, sizeof(ganiAcon.azSavepath)); } } // look for 'anih', 'rate', 'seq ', and 'icon' chunks while(ReadTag(hf, &tag)){ switch(tag.ckID) { case FOURCC_anih: // ANIHEADER 構造体の読み込み if(!ReadChunk(hf, &tag, &ganiAcon.anih)) goto laiFileErr; if(!(ganiAcon.anih.fl & AF_ICON) || (ganiAcon.anih.cFrames == 0)) goto laiFileErr; // gpfrmFrames のメモリ確保 if(gpfrmFrames != NULL) free(gpfrmFrames); gpfrmFrames = (PFRAME) malloc(ganiAcon.anih.cSteps * sizeof(FRAME)); // pjifRate と pseq のメモリ確保 pjifRate = (PJIF) malloc(ganiAcon.anih.cSteps * (sizeof(JIF) + sizeof(DWORD))); if(pjifRate == NULL) goto laiFileErr; pseq = (DWORD *)(pjifRate + ganiAcon.anih.cSteps); // 配列の初期化 for(i=0;i<(int)ganiAcon.anih.cSteps;i++){ gpfrmFrames[i].jif = pjifRate[i] = ganiAcon.anih.jifRate; gpfrmFrames[i].iFrame = pseq[i] = i; } break; case FOURCC_rate: // コマごとの表示時間の読み込み if(!ReadChunk(hf, &tag, (PBYTE)pjifRate)) goto laiFileErr; for(i=0;i<ganiAcon.anih.cSteps;i++){ gpfrmFrames[i].jif = pjifRate[i]; } break; case FOURCC_seq: // コマの順番の読み込み if(!ReadChunk(hf, &tag, (PBYTE)pseq)) goto laiFileErr; for(i=0;i<ganiAcon.anih.cSteps;i++){ gpfrmFrames[i].iFrame = pseq[i]; } break; case FOURCC_LIST:{ DWORD cbChunk = PADUP(tag.ckSize); // チャンクのリストが fram の場合 if(!ReadTagID(hf, &tag.ckID)) goto laiFileErr; cbChunk -= sizeof(tag.ckID); if(tag.ckID == FOURCC_fram){ while(cbChunk >= sizeof(tag)){ if(!ReadTag(hf, &tag)) goto laiFileErr; cbChunk -= sizeof(tag); if(tag.ckID == FOURCC_icon){ // カーソル画像の読み込み ReadIconFromFile(hf, tag.ckSize, iFrame); iFrame ++; } else{ // 必要のないチャンクは読み飛ばし SkipChunk(hf, &tag); } cbChunk -= PADUP(tag.ckSize); } } else if(tag.ckID == FOURCC_INFO){ // INAM チャンクと IART チャンクを探す while(cbChunk >= sizeof(tag)){ if(!ReadTag(hf, &tag)) goto laiFileErr; cbChunk -= sizeof(tag); switch(tag.ckID) { case FOURCC_INAM: if(cbChunk < tag.ckSize || !ReadChunkN(hf, &tag, ganiAcon.azTitle, sizeof(ganiAcon.azTitle))) goto laiFileErr; cbChunk -= PADUP(tag.ckSize); break; case FOURCC_IART: if(cbChunk < tag.ckSize || !ReadChunkN(hf, &tag, ganiAcon.azCreator, sizeof(ganiAcon.azCreator))) goto laiFileErr; cbChunk -= PADUP(tag.ckSize); break; default: if(!SkipChunk(hf, &tag)) goto laiFileErr; cbChunk -= PADUP(tag.ckSize); break; } } } else{ // fram リストでも INFO リストでもないチャンクは読み飛ばす tag.ckSize = cbChunk; SkipChunk(hf, &tag); break; } break; } default: // このチャンクは関係ないから読み飛ばす if(!SkipChunk(hf, &tag)) goto laiFileErr; break; } } // フレームの総数を設定する ganiAcon.anih.cFrames = iFrame; fSuccess = TRUE; laiFileErr: if(pjifRate != NULL) free(pjifRate); CloseHandle(hf); return fSuccess; }// ReadAniFile LRESULT CALLBACK ProcWnd(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_CREATE: ZeroMemory(ganiAcon.azSavepath, sizeof(ganiAcon.azSavepath)); if(__argc > 1){ strcpy(ganiAcon.azFilename, __argv[1]); ReadAniFile(); } return 0; case WM_DROPFILES: char fname[MAX_PATH]; HDROP hDrop; hDrop = (HDROP) wParam; DragQueryFile(hDrop, 0, fname, sizeof(fname)); strcpy(ganiAcon.azFilename, fname); ReadAniFile(); DragFinish(hDrop); InvalidateRect(hWnd, NULL, TRUE); return 0; case WM_PAINT: { HDC hDC; PAINTSTRUCT ps; hDC = BeginPaint(hWnd, &ps); char str1[256]; sprintf(str1, "題名:%s",ganiAcon.azTitle); TextOut(hDC, 0, 0, str1, strlen(str1)); sprintf(str1, "著作者:%s",ganiAcon.azCreator); TextOut(hDC, 0, 25, str1, strlen(str1)); HCURSOR hcur = (HCURSOR) LoadImage(NULL, ganiAcon.azFilename, IMAGE_CURSOR, 0, 0, LR_LOADFROMFILE); for(UINT i=0; i<ganiAcon.anih.cFrames; i++){ DrawIconEx(hDC, i*50, 50, hcur, 0, 0, i, NULL, DI_NORMAL); char str2[256]; itoa(gpfrmFrames[i].jif, str2, 10); TextOut(hDC, i*50, 100, str2, strlen(str2)); } if(strcmp(ganiAcon.azSavepath, "")){ char str3[MAX_PATH + 26]; sprintf(str3, "%s フォルダーを作成しました", ganiAcon.azSavepath); TextOut(hDC, 0, 150, str3, strlen(str3)); } else{ char str3[] = "ani ファイルを Drag & Drop してください"; TextOut(hDC, 0, 150, str3, strlen(str3)); } EndPaint(hWnd, &ps); } return 0; case WM_CLOSE: if(gpfrmFrames != NULL) free(gpfrmFrames); DestroyWindow(hWnd); PostQuitMessage(0); return 0; default: break; } return DefWindowProc(hWnd, uMsg, wParam, lParam); }// ProcWnd |
|
// Source code from the MSDN Library (AniEdit, ANIFILE.C, 21-Apr-1993 JonPa) #include <windows.h> #include <stdio.h> #include "anicur.h" #define MYWNDTITLE "IconToAni" #define CCH_TITLE 80 #define CCH_CREATOR 80 #define PADUP(cb) (((cb) + 1) & ~1) typedef struct _ANICUR { ANIHEADER anih; CHAR azTitle[CCH_TITLE]; // ANI ファイルの題名 CHAR azCreator[CCH_CREATOR]; // ANI ファイルの作者名 } ANICUR; ANICUR ganiAcon; // 読み込むファイル名(.cur or .ico) // あらかじめ、実行ファイルのあるフォルダーに各ファイルを入れておく char gazCurFiles[][MAX_PATH] = {"aero_busy_xl\\aero_busy_xl01.cur", "aero_busy_xl\\aero_busy_xl02.cur", "aero_busy_xl\\aero_busy_xl03.cur", "aero_busy_xl\\aero_busy_xl04.cur", "aero_busy_xl\\aero_busy_xl05.cur", "aero_busy_xl\\aero_busy_xl06.cur", "aero_busy_xl\\aero_busy_xl07.cur", "aero_busy_xl\\aero_busy_xl08.cur", "aero_busy_xl\\aero_busy_xl09.cur", "aero_busy_xl\\aero_busy_xl10.cur", "aero_busy_xl\\aero_busy_xl11.cur", "aero_busy_xl\\aero_busy_xl12.cur", "aero_busy_xl\\aero_busy_xl13.cur", "aero_busy_xl\\aero_busy_xl14.cur", "aero_busy_xl\\aero_busy_xl15.cur", "aero_busy_xl\\aero_busy_xl16.cur", "aero_busy_xl\\aero_busy_xl17.cur", "aero_busy_xl\\aero_busy_xl18.cur" }; BOOL WriteTag(HANDLE hf, PRTAG prtag) { DWORD cbWritten; return (WriteFile(hf, prtag, sizeof(RTAG), &cbWritten, NULL) && cbWritten == sizeof(RTAG)); }// WriteTag BOOL WriteType(HANDLE hf, FOURCC ckID) { DWORD cbWritten; return (WriteFile(hf, &ckID, sizeof(FOURCC), &cbWritten, NULL) && cbWritten == sizeof(FOURCC)); }// WriteType BOOL WriteTagData(HANDLE hf, PRTAG prtag, VOID *pvData) { DWORD cbWritten; DWORD cbWrite = PADUP(prtag->ckSize); return WriteTag(hf, prtag) && WriteFile(hf, pvData, cbWrite, &cbWritten, NULL) && cbWritten == cbWrite; }// WriteTagData BOOL SaveFile(char *anifilename) { HANDLE hf1; RTAG rtag; BOOL fSuccess = FALSE; DWORD cbFile, cbFram, cbINFO, cbTitle, cbAuthor; DWORD i,numFiles,cFrames; BOOL fRate, fSeq; hf1 = CreateFile( anifilename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if(hf1 == INVALID_HANDLE_VALUE) goto laiFileErr; fRate = fSeq = FALSE; cbINFO = cbFram = cbFile = cbTitle = cbAuthor = 0; strncpy(ganiAcon.azTitle, "aero_busy_xl", sizeof(ganiAcon.azTitle)); strncpy(ganiAcon.azCreator, "Microsoft corp.", sizeof(ganiAcon.azCreator)); cbTitle = strlen(ganiAcon.azTitle); cbAuthor = strlen(ganiAcon.azCreator); numFiles = sizeof(gazCurFiles) / sizeof(gazCurFiles[0]); cFrames = 0; for(i=0;i<numFiles;i++){ HANDLE hf2; hf2 = CreateFile(gazCurFiles[i], GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if(hf2 != INVALID_HANDLE_VALUE){ DWORD cbSize = GetFileSize(hf2, NULL); if(cbSize > 0 && cbSize != 0xFFFFFFFF){ cbFram += sizeof(RTAG); cbFram += PADUP(cbSize); cFrames ++; } } CloseHandle(hf2); } cbFram += sizeof(FOURCC); //fram type cbFile = cbFram; cbFile += sizeof(FOURCC) //ACON type + sizeof(RTAG) //anih tag + PADUP(sizeof(ANIHEADER)) + sizeof(RTAG); //LIST tag (for fram list) if(cbTitle || cbAuthor){ // Remember, azCreator, and azTitle are ANSI strings! if(cbTitle){ cbTitle += 1; //add in ASCIIZ terminator cbINFO += sizeof(RTAG) + //INAM tag PADUP( cbTitle * sizeof(char)); } if(cbAuthor){ cbAuthor += 1; //add in ASCIIZ terminator cbINFO += sizeof(RTAG) + //IART tag PADUP(cbAuthor * sizeof(char)); } cbINFO += sizeof(FOURCC); //INFO type cbFile += sizeof(RTAG) + //LIST tag cbINFO; } if(fSeq){ cbFile += sizeof(RTAG) + //seq tag PADUP(cFrames * sizeof(DWORD)); } if(fRate){ cbFile += sizeof(RTAG) + //rate tag PADUP(cFrames * sizeof(JIF)); } rtag.ckID = FOURCC_RIFF; rtag.ckSize = cbFile; if(!WriteTag(hf1, &rtag)) goto laiFileErr; if(!WriteType(hf1, FOURCC_ACON)) goto laiFileErr; if(cbTitle || cbAuthor){ rtag.ckID = FOURCC_LIST; rtag.ckSize = cbINFO; if(!WriteTag(hf1, &rtag)) goto laiFileErr; if(!WriteType(hf1, FOURCC_INFO)) goto laiFileErr; if(cbTitle){ rtag.ckID = FOURCC_INAM; rtag.ckSize = cbTitle; if(!WriteTagData(hf1, &rtag, ganiAcon.azTitle)) goto laiFileErr; } if(cbAuthor){ rtag.ckID = FOURCC_IART; rtag.ckSize = cbAuthor; if(!WriteTagData(hf1, &rtag, ganiAcon.azCreator)) goto laiFileErr; } } ganiAcon.anih.cbSizeof = sizeof(ganiAcon.anih); ganiAcon.anih.cFrames = cFrames; ganiAcon.anih.cSteps = cFrames; ganiAcon.anih.cx = 0; ganiAcon.anih.cy = 0; ganiAcon.anih.cBitCount = 0; ganiAcon.anih.cPlanes = 0; ganiAcon.anih.jifRate = 3; ganiAcon.anih.fl = AF_ICON | (fSeq ? AF_SEQUENCE : 0); rtag.ckID = FOURCC_anih; rtag.ckSize = sizeof(ganiAcon.anih); if(!WriteTagData(hf1, &rtag, &(ganiAcon.anih))) goto laiFileErr; if(fRate){ rtag.ckID = FOURCC_rate; rtag.ckSize = cFrames * sizeof(JIF); PJIF pjif = (PJIF) malloc(rtag.ckSize); for(i=0;i<cFrames;i++){ pjif[i] = 0; } WriteTagData(hf1, &rtag, pjif); if(pjif) free(pjif); } if(fSeq){ rtag.ckID = FOURCC_seq; rtag.ckSize = cFrames * sizeof(DWORD); LPDWORD pseq = (LPDWORD) malloc(rtag.ckSize); for(i=0;i<cFrames;i++){ pseq[i] = i; } WriteTagData(hf1, &rtag, pseq); if(pseq) free(pseq); } rtag.ckID = FOURCC_LIST; rtag.ckSize = cbFram; if(!WriteTag(hf1, &rtag)) goto laiFileErr; if(!WriteType(hf1, FOURCC_fram)) goto laiFileErr; for(i=0;i<cFrames;i++){ HANDLE hf2; hf2 = CreateFile(gazCurFiles[i], GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if(hf2 != INVALID_HANDLE_VALUE){ DWORD cbIcon = GetFileSize(hf2, NULL); if(cbIcon > 0 && cbIcon != 0xFFFFFFFF){ LPBYTE pBuf = (LPBYTE) malloc(cbIcon); DWORD cbRead; if(ReadFile(hf2, pBuf, cbIcon, &cbRead, NULL) && cbRead == cbIcon){ rtag.ckID = FOURCC_icon; rtag.ckSize = cbIcon; WriteTagData(hf1, &rtag, pBuf); } if(pBuf) free(pBuf); } } CloseHandle(hf2); } fSuccess = TRUE; laiFileErr: CloseHandle(hf1); return fSuccess; }// SaveFile int WINAPI WinMain(HINSTANCE hInst,HINSTANCE hInstPrev,LPSTR lpCmdLine,int nCmdShow) { SaveFile("new.ani"); return 0; }// WinMain |
CreateIconIndirect(), ExtractIcon(), ExtractIconEx() で作成したアイコンは、使用後、DestroyIcon() で必ず破棄する。
以下の関数で作成されるアイコンは、shared アイコンであるため削除してはならない。 他はしてもしなくても良い。 LoadIcon LoadImage (LR_SHARED フラグがある場合) CopyImage (LR_COPYRETURNORG フラグがあって、コピー元のイメージが shared アイコンの場合) CreateCursor(), CopyCursor(), SetSystemCursor() は、必ず、DestroyCursor() でカーソルを破棄する。 以下の関数で作成されるカーソルは、shared カーソルであるため削除してはならない。 他はしてもしなくても良い。 LoadCursor LoadCursorFromFile LoadImage (LR_SHARED フラグがある場合) CopyImage (LR_COPYRETURNORG フラグがあって、コピー元のイメージが shared アイコンの場合) |
|