65.製品名の取得

 実行ファイルのプロパティ ダイアログボックスの[詳細]タブに表示される製品名を取得する。
 実行ファイルに製品名を付けるには、リソースに 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

66.OS バージョンの取得

-------------------------------- 変数の場合 --------------------------------

_winmajor
メジャー バージョン番号
_winminor
マイナー バージョン番号
_winver
上位バイトには _winmajor の値、下位バイトには _winminor の値
_osver
現在のビルド番号
WINVER
?
_WIN32
Win32bit, Win64bit OS の場合は TRUE、それ以外は FALSE
-------------------------------- 関数の場合 -------------------------------- #include <windows.h> #include <stdio.h> int WINAPI WinMain(HINSTANCE hInst,HINSTANCE hInstPrev,LPSTR lpCmdLine,int nCmdShow) { OSVERSIONINFO osvi; osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO); GetVersionEx (&osvi); char str[256],str2[256] = ""; switch (osvi.dwPlatformId) { case VER_PLATFORM_WIN32s: strcpy(str2, "Windows3.1"); break; case VER_PLATFORM_WIN32_WINDOWS: if(!osvi.dwMinorVersion) strcpy(str2, "Windows95"); else strcpy(str2, "Windows98 or Me"); break; case VER_PLATFORM_WIN32_NT: strcpy(str2, "WindowsNT series"); break; default: strcpy(str2, "?"); break; } sprintf(str, "%d %d %d %d %x %d %s %s", osvi.dwMajorVersion, osvi.dwMinorVersion, _winmajor, _winminor, WINVER, _WIN32, str2, osvi.szCSDVersion); MessageBox(0,str,"",0); return 0; } OSVERSIONINFO 構造体
DWORD dwMajorVersion
メジャー バージョン番号
DWORD dwMinorVersion
マイナー バージョン番号
DWORD dwBuildNumber
現在のビルド番号
DWORD dwPlatformId
VER_PLATFORM_WIN32s
Win32s on Windows 3.1
VER_PLATFORM_WIN32_WINDOWS
Win32 on Windows 95(dwMinorVersion == 0)
or Windows 98(dwMinorVersion > 0)
VER_PLATFORM_WIN32_NT
Win32 on Windows NT
TCHAR szCSDVersion[128]
Windows NT の場合はサービスパック名、Windows 9x の場合は補足情報

67.SHFILEOPSTRUCT 構造体

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 関数で管理された
グローバルカレントドライブやディレクトリー設定がとられる。

68.メニューにアイコン表示

 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

69.ファイルタイム

 ファイルの更新日時などのファイルタイムは、世界標準時(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);
}

70.リストビュー

リストビューのカラムをクリックすると並び替えのサンプル。
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

71.他のウィンドウへドラッグ&ドロップ

 他のウィンドウからのドラッグ&ドロップには対応していない。
 対応させるには、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);
}

72.IStream オブジェクト

// データをメモリから読み込む場合やメモリに保存する場合に使用する
// 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

73.ペイントソフトの作り方

 ドラッグで線を描画する場合は、点と点の間を線で結ぶ必要がある。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

74.PNG 形式のアイコン

 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;
}

75.ANI ファイルから CUR ファイルを抜き出す

 アニメーション カーソルからアイコンもしくはカーソルファイルを抜き出し保存する

// 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

76.CUR ファイルから ANI ファイルを作成

 

// 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

77.DestroyIcon と DestroyCursor

 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 アイコンの場合)


78.クライアント領域サイズを指定してウィンドウを作成

 

    // クライアント領域が 640x480 でメニューなしのウィンドウを作成する場合
    
    DWORD dwStyle   = WS_OVERLAPPED | WS_SYSMENU | WS_CAPTION;
    DWORD dwExStyle = 0;
    RECT rc = {0, 0, 640, 480};
    AdjustWindowRectEx(&rc, dwStyle, FALSE, dwExStyle);
    HWND hWnd = CreateWindowEx(dwExStyle, CLASS, TITLE,
                               dwStyle,
                               CW_USEDEFAULT, CW_USEDEFAULT, 
                               rc.right - rc.left, rc.bottom - rc.top,
                               NULL, NULL, hInst, NULL);

79.ページャー

 ページャーは、子ウィンドウが、親ウィンドウよりも大きい場合に、スクロールさせるコントロール。
 以下は、ツールバーが子ウィンドウの場合

#include <windows.h>
#include <commctrl.h>

#pragma comment(lib, "comctl32.lib")

#define MYWNDCLASS  "PAGER_CLASS"
#define MYWNDTITLE  "PAGER"
#define ID_PAGER    2000
#define ID_TOOLBAR  2001
#define IDM_COMMAND WM_USER + 500

HWND g_hPager = NULL;
HWND g_hToolBar = NULL;

LRESULT CALLBACK ProcWnd(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
void Create_Pager(HWND hParent);
void Create_ToolBar(HWND hParent);

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(0, 
                MYWNDCLASS,
                MYWNDTITLE,
                WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN,
                CW_USEDEFAULT, CW_USEDEFAULT, 300, 300,
                NULL,
                NULL,
                hInst,
                NULL);
    
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}// WinMain

LRESULT CALLBACK ProcWnd(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_CREATE:
        // ページャーとツールバーの初期化
        INITCOMMONCONTROLSEX    icex;
        icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
        icex.dwICC  = ICC_PAGESCROLLER_CLASS | ICC_BAR_CLASSES;
        InitCommonControlsEx(&icex);
        // ページャーの作成
        Create_Pager(hWnd);
        // ツールバーの作成
        Create_ToolBar(g_hPager);
        // ツールバーをページャーに関連付け
        Pager_SetChild(g_hPager, g_hToolBar);
        // ページャー ボタンの色の変更
        Pager_SetBkColor(g_hPager, RGB(0,255,0));
        return 0;
        
    case WM_SIZE:
        {
            int b_size = SendMessage(g_hToolBar, TB_GETBUTTONSIZE, 0, 0);
            MoveWindow(g_hPager, 0, 0, LOWORD(lParam), HIWORD(b_size) + 6, TRUE);
        }
        return 0;
        
    case WM_COMMAND:
        switch (wParam)
        {
        case WM_COMMAND:
            return 0;
        }
        break;
        
    case WM_NOTIFY:
        switch(((LPNMHDR)lParam)->code)
        {
        case PGN_CALCSIZE:
            {
                LPNMPGCALCSIZE  pCalcSize = (LPNMPGCALCSIZE) lParam;
                SIZE    size;
                SendMessage(g_hToolBar, TB_GETMAXSIZE, 0, (LPARAM) &size);
                switch(pCalcSize->dwFlag)
                {
                case PGF_CALCWIDTH:     // 横型の場合
                        pCalcSize->iWidth = size.cx;
                    break;
/*              case PGF_CALCHEIGHT:    // 縦型の場合
                        pCalcSize->iHeight = size.cy;
                    break;
*/              }
            }
            break;
/*      case PGN_SCROLL:
            {
                LPNMPGSCROLL    pScroll = (LPNMPGSCROLL) lParam;
                switch(pScroll->iDir)
                {
                case PGF_SCROLLLEFT:
                case PGF_SCROLLRIGHT:
                case PGF_SCROLLUP:
                case PGF_SCROLLDOWN:
                    pScroll->iScroll = 20;  // スクロール幅の設定
                    break;
                }
            }
            break;
*/      }
        return 0;
        
    case WM_CLOSE:
        DestroyWindow(hWnd);
        PostQuitMessage(0);
        return 0;
        
    default:
        break;
    }
    return DefWindowProc(hWnd, uMsg, wParam, lParam);
}// ProcWnd

void Create_Pager(HWND hParent)
{
    g_hPager =   CreateWindowEx(0,
                                WC_PAGESCROLLER,
                                NULL,
                                WS_CHILD |
                                WS_VISIBLE |
                                WS_CLIPCHILDREN |
                                PGS_HORZ,
                                0, 0, 0, 0,
                                hParent,
                                (HMENU) ID_PAGER,
                                GetModuleHandle(NULL),
                                NULL);
}// Create_Pager

void Create_ToolBar(HWND hParent)
{
    g_hToolBar = CreateWindowEx(0,
                                TOOLBARCLASSNAME,
                                NULL,
                                WS_CHILD | 
                                WS_VISIBLE | 
                                WS_CLIPCHILDREN | 
                                CCS_NORESIZE | 
                                CCS_NODIVIDER,
                                0,0,0,0,
                                hParent,
                                (HMENU) ID_TOOLBAR,
                                GetModuleHandle(NULL),
                                NULL);
    SendMessage(g_hToolBar, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
    
    // ツール ボタンの追加
    TBBUTTON    tbb;
    const int   t_num = 64; // ボタンの数
    
    ZeroMemory(&tbb, sizeof(TBBUTTON));
    
    for(int i=0;i<t_num;i++){
        tbb.fsStyle = TBSTYLE_AUTOSIZE;
        tbb.fsState = TBSTATE_ENABLED;
        tbb.iString = -1;
        tbb.iBitmap = i % 8;
        tbb.idCommand = IDM_COMMAND;
        SendMessage(g_hToolBar, TB_INSERTBUTTON, i, (LPARAM) &tbb);
    }
    
    // ツールバー画像の追加
    TBADDBITMAP ab;
    ZeroMemory(&ab, sizeof(TBADDBITMAP));
    ab.hInst = HINST_COMMCTRL;
    ab.nID   = IDB_STD_SMALL_COLOR;
    SendMessage(g_hToolBar, TB_ADDBITMAP, 0, (LPARAM) &ab);
}// Create_ToolBar

80.GDI のアルファブレンド


重ねる画像は、32 ビットで背景が黒色で各画素の透明度が設定されたビットマップである必要がある。
32 ビット ビットマップの背景色を設定するには、黒の透明色で塗りつぶされた画像に透明度が設定された画像を貼り付ける。あるいは、GDI+ の Bitmap::GetHBITMAP() と Bitmap::FromHBITMAP() を使う。
#include <windows.h>

#pragma comment(lib, "msimg32.lib")

HBITMAP     ghBmp[2] = {NULL, NULL};
DIBSECTION  gDib[2];

LRESULT CALLBACK ProcWnd(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
void Load_Dib(char *filename, int index);
void M_Paint(HDC hDC);

LRESULT CALLBACK ProcWnd(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_CREATE:
        Load_Dib("back.bmp", 0);
        Load_Dib("32bpp.bmp", 1);
        return 0;
    case WM_PAINT:
        {
            HDC         hDC;
            PAINTSTRUCT ps;
            hDC = BeginPaint(hWnd,&ps);
            M_Paint(hDC);
            EndPaint(hWnd,&ps);
        }
        return 0;
    case WM_CLOSE:
        {
            int i;
            for(i=0;i<2;i++){
                if(ghBmp[i]){
                    DeleteObject(ghBmp[i]);
                    ghBmp[i] = NULL;
                }
            }
        }
        DestroyWindow(hWnd);
        PostQuitMessage(0);
        return 0;
    default:
        break;
    }
    return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

// ビットマップ ファイルの読み込み
void Load_Dib(char *filename, int index)
{
    if(ghBmp[index]){
        DeleteObject(ghBmp[index]);
    }
    ghBmp[index] = (HBITMAP) LoadImage(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE|LR_CREATEDIBSECTION);
    // ビットマップの情報を取得
    GetObject(ghBmp[index], sizeof(DIBSECTION), &gDib[index]);
}// Load_Dib

// 描画
void M_Paint(HDC hDC)
{
    HDC     hDCcp1,hDCcp2;
    HBITMAP hBmpPre1,hBmpPre2;
    if(ghBmp[0]){
        int width  = gDib[0].dsBmih.biWidth;
        int height = gDib[0].dsBmih.biHeight;
        hDCcp1 = CreateCompatibleDC(hDC);
        hBmpPre1 = (HBITMAP) SelectObject(hDCcp1, ghBmp[0]);
        StretchBlt(hDC, 0, 0, width, height, hDCcp1, 0, 0, width, height, SRCCOPY);
        SelectObject(hDCcp1, hBmpPre1);
        DeleteDC(hDCcp1);
        if(ghBmp[1]){
            int width2  = gDib[1].dsBmih.biWidth;
            int height2 = gDib[1].dsBmih.biHeight;
            hDCcp2 = CreateCompatibleDC(hDC);
            hBmpPre2 = (HBITMAP) SelectObject(hDCcp2, ghBmp[1]);
            BLENDFUNCTION bf;
            bf.BlendOp = AC_SRC_OVER;
            bf.BlendFlags = 0;
            bf.SourceConstantAlpha = 255;
            bf.AlphaFormat = AC_SRC_NO_PREMULT_ALPHA;
            AlphaBlend(hDC, 0, 0, width2, height2, hDCcp2, 0, 0, width2, height2, bf);
            SelectObject(hDCcp2, hBmpPre2);
            DeleteDC(hDCcp2);
        }
    }
}// M_Paint

81.シャットダウン

 

システムをログオフさせるか、シャットダウンさせるか、シャットダウンの後に再起動させるかします。 

ExitWindowsEx()


シャットダウン処理を開始します。再起動を指示することもできます。

InitiateSystemShutdown()

82.bsearch() の使い方

二分探索は、指定されたデータを配列内から検索するアルゴリズムである。最初から1つずつ逐次探索するより高速に検索できる。二分探索は、ソート済みのデータでしか使えないから、使用前にはクイックソートでソートしておく。また、データ値が配列内で重複している場合も同じデータ値の内、どれが選ばれるか分からない。

#include <search.h>
#include <string.h>
#include <stdio.h>

typedef int (* COMP)(const void *, const void *);   // 関数型名のエイリアス定義

int cmpInt( int *n1, int *n2 ); // 比較関数の宣言

void main()
{
    int *result;
    int key = 5;
    int numbers[10] = {5,8,2,10,1,4,3,9,6,7};
    int i;

    //  元データの出力
    for( i = 0; i < 10; i++ )
        printf( "%d ", numbers[i] );

    // 改行
    putchar('\n');

    // クイック ソートで配列をソート
    qsort( numbers, 10, sizeof( int ), (COMP)cmpInt );

    // ソート結果の出力
    for( i = 0; i < 10; i++ )
        printf( "%d ", numbers[i] );

    // 二分探索アルゴリズムによる数値 key の探索
    result = (int *)bsearch( (const void *) &key, (const void *)numbers, 10,
                                        sizeof( int ), (COMP)cmpInt );
    if( result )
        printf( "\n数値 %d は %d 個目で見つかりました。\n", *result, result - numbers + 1 );
    else
        printf( "\n数値 %d は見つかりませんでした。\n", key );
}

// 比較関数(昇順)
int cmpInt( int *n1, int *n2 )
{
    return ( (*n1) - (*n2) );
}


------------ 出力結果 ------------

5 8 2 10 1 4 3 9 6 7
1 2 3 4 5 6 7 8 9 10
数値 5 は 5 個目で見つかりました。

83.