43.DLLの作成[__declspec(dllexport)を使う場合]

 [ファイル]-[新規作成]-[プロジェクト]-[Win32 Dynamic-Link Library]。

 test.h と test.cpp は同じディレクトリに置く。

 test.cpp をプロジェクトに追加して[ビルド]する。

 DLLファイルとLIBファイルが作成される。

 vc は、DEFファイルの方にも対応しているが、bcc は、こちらしか対応していない。
// test.h の内容

#include <windows.h>
#define DECLSPEC extern "C" __declspec( dllexport )

DECLSPEC void DisplayMessage( LPCTSTR lpszMessage );



// test.cpp の内容

#include "test.h"

extern "C" int APIENTRY DllMain( HINSTANCE hInst, DWORD dwReason, LPVOID lpRsv )
{
    return TRUE;
}

void DisplayMessage( LPCTSTR lpszMessage )
{
    MessageBox( NULL, lpszMessage, "DLLTEST", MB_OK );
}

44.DLLの作成[DEFファイルを使う場合]

 [ファイル]-[新規作成]-[プロジェクト]-[Win32 Dynamic-Link Library]。

 test.h と test.cpp と test.def は同じフォルダに置く。

 test.cpp と test.def をプロジェクトに追加して[ビルド]する。

 DLLファイルとLIBファイルが作成される。

 DEFファイルは、モジュール定義ファイルと呼ぶ。
// test.h の内容

#include <windows.h>

void DisplayMessage( LPCTSTR lpszMessage );



// test.cpp の内容

#include "test.h"

int APIENTRY DllMain( HINSTANCE hInst, DWORD dwReason, LPVOID lpRsv )
{
    return TRUE;
}

void DisplayMessage( LPCTSTR lpszMessage )
{
    MessageBox( NULL, lpszMessage, "DLLTEST", MB_OK );
}



// test.def の内容

LIBRARY test.dll
EXPORTS 
    DisplayMessage

45.DLLの読み込み[DLLの作成に__declspec(dllexport)を使った場合1]

 暗黙的リンク(LIBファイルとDLLファイルを使用する)の場合。

 [ファイル]-[新規作成]-[プロジェクト]-[Win32 Console Application]。

 43.DLLの作成[__declspec(dllexport)を使う場合]で作成した
 test.lib をソースファイルと同じフォルダに、
 test.dll を実行ファイルと同じフォルダにコピーする。

#include <windows.h>
#pragma comment( lib, "test.lib" ) 
#define DECLSPEC __declspec( dllimport )

DECLSPEC void DisplayMessage( LPCTSTR lpszMessage );

void main()
{
    DisplayMessage( "DLLEXE!!" );
}

46.DLLの読み込み[DLLの作成に__declspec(dllexport)を使った場合2]

 暗黙的リンク(HファイルとLIBファイルとDLLファイルを使用する)の場合。

 [ファイル]-[新規作成]-[プロジェクト]-[Win32 Console Application]。

 43.DLLの作成[__declspec(dllexport)を使う場合]で作成した
 test.h と test.lib をソースファイルと同じフォルダに、
 test.dll を実行ファイルと同じフォルダにコピーする。
 コピーした test.h の #define DECLSPEC extern "C" __declspec(dllexport) は、
 DECLSPEC extern "C" __declspec(dllimport) に書き換えておく。
// test.h の内容

#include <windows.h>
#define DECLSPEC extern "C" __declspec( dllimport )

DECLSPEC void DisplayMessage( LPCTSTR lpszMessage );



// test.cpp の内容

#include "test.h"
#pragma comment( lib, "test.lib" )

void main()
{
    DisplayMessage( "DLLEXE!!" );
}

47.DLLの読み込み[共通]

 明示的リンク(DLLファイルのみを使用する)の場合。

 読み込むDLLファイル名をプログラム内で変更できる。

 [ファイル]-[新規作成]-[プロジェクト]-[Win32 Console Application]。

 43.DLLの作成[__declspec(dllexport)を使う場合]、または、
 44.DLLの作成[DEFファイルを使う場合]で作成した
 test.dll を実行ファイルと同じフォルダにコピーする。

#include <windows.h>

typedef void ( *DISPLAYMESSAGE )( LPCTSTR );

void main()
{
    HINSTANCE hDll;
    DISPLAYMESSAGE MyDisplayMessage;

    hDll = LoadLibrary( "test.dll" );

    if( hDll != NULL ){
        MyDisplayMessage = (DISPLAYMESSAGE)GetProcAddress( hDll, "DisplayMessage" );
        if( MyDisplayMessage )
            MyDisplayMessage( "DLLEXE!!" );
        FreeLibrary( hDll );
    }
}

48.DLLの作成と読み込み[クラスの場合]

 クラスの場合は、__declspec( dllexport ) を記述する位置が異なる。
 また、extern "C" は不要である。
 読み込み時は、dll_class.h と dll_class.lib をソースファイルと同じフォルダに、
 dll_class.dll を実行ファイルと同じフォルダにコピーする。
 コピーした dll_class.h の #define DECLSPEC __declspec(dllexport) は、
 DECLSPEC __declspec(dllimport) に書き換えておく。
// dll_class.h (作成用)の内容

#define DECLSPEC __declspec( dllexport )

class DECLSPEC CMes
{
public:
    CMes( char *lpszMessage );
    void DisplayMessage();
    ~CMes();
private:
    char *m_str;
};



// dll_class.cpp (作成用)の内容

#include <windows.h>
#include "dll_class.h"

extern "C" int APIENTRY DllMain( HINSTANCE hInst, DWORD dwReason, LPVOID lpRsv )
{
    return TRUE;
}

CMes::CMes( char *lpszMessage )
{
    m_str = lpszMessage;
}

void CMes::DisplayMessage()
{
    MessageBox( NULL, m_str, "DLLTEST", MB_OK );
}

CMes::~CMes()
{
    m_str = NULL;
}



// dll_class_read.h (読み込み用)の内容

#define DECLSPEC __declspec( dllimport )

class DECLSPEC CMes
{
public:
    CMes( char *lpszMessage );
    void DisplayMessage();
    ~CMes();
private:
    char *m_str;
};



// dll_class_read.cpp (読み込み用)の内容

#include "dll_class_read.h"
#pragma comment( lib, "dll_class.lib" )

void main()
{
    CMes cmes( "DLLEXE!!" );
    cmes.DisplayMessage();
}

49.HBITMAP から BITMAPINFO を取得

 HBITMAP には、DDB と DIB の 2 種類があり、両者では内部構造が異なるために、使える関数も異なる場合がある。
 クリップボードでは、DDB は、CF_BITMAP を、DIB は、CF_DIB を使う。
 DIB から DDB への変換は、CreateDIBitmap() を使う。
 以下の例では、LoadImage() を使って、DIB の HBITMAP から BITMAPINFO を取得する。
 DDB の HBITMAP から BITMAPINFO を作る場合は、別の方法を使う。

 OleLoadPicture(), GDI+ などで取得した HBITMAP からも BITMAPINFO を取得できる。

 OleLoadPicture() の場合
  LPPICTURE pPic->get_Handle((OLE_HANDLE FAR *) &hBmp);
 GDI+ の場合
  Bitmap Bmp.GetHBITMAP(0, &hBmp);
 で DIB の HBITMAP を取得する。

LRESULT CALLBACK ProcWnd(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    static BITMAPINFO       *pbmi = NULL;
    static BYTE             *pbits = NULL;
    
    switch (uMsg)
    {
    case WM_CREATE:
        if(__argc <= 1){
            MessageBox(hWnd, "Btimap ファイルの Drag & Drop 専用です", MYWNDTITLE, 0);
            SendMessage(hWnd, WM_CLOSE, 0, 0);
        }
        
        DIBSECTION  Dib;
        HBITMAP     hBmp;
        int         r,bpp,num_colors,size_pbits,size_pbmi,size_mask;
        
        hBmp = (HBITMAP) LoadImage(NULL, __argv[1], IMAGE_BITMAP, 0, 0, 
                                    LR_LOADFROMFILE | LR_CREATEDIBSECTION);
        if(!hBmp){
            MessageBox(hWnd, "Bitmap ファイルを読み込めません", MYWNDTITLE, 0);
            SendMessage(hWnd, WM_CLOSE, 0, 0);
        }
        // ビットマップの情報を取得
        r = GetObject(hBmp, sizeof(DIBSECTION), &Dib);
        if(r != sizeof(DIBSECTION)) return 0;
        // ビットマップのピクセル値を取得
        // Dib.dsBm.bmWidthBytes は、((((Dib.dsBmih.biWidth * bpp) + 31) & ~31) >> 3) で求められる
        size_pbits = Dib.dsBm.bmWidthBytes * Dib.dsBm.bmHeight;
        if(pbits)   LocalFree(pbits);
        pbits = (BYTE *) LocalAlloc(LPTR, size_pbits);
        memcpy(pbits, Dib.dsBm.bmBits, size_pbits);
        // パレットの色数を計算
        bpp = Dib.dsBmih.biBitCount * Dib.dsBmih.biPlanes; // 1ピクセルあたりのビット数
        if(Dib.dsBmih.biClrUsed != 0)
            num_colors = Dib.dsBmih.biClrUsed;
        else if(bpp <= 8)
            num_colors = 1 << bpp;
        else
            num_colors = 0;
        // ピクセルフォーマットマスクのサイズを取得
        if(Dib.dsBmih.biCompression == BI_BITFIELDS)
            size_mask = sizeof(DWORD) * 3;
        else
            size_mask = 0;
        // BITMAPINFO 構造体のメモリを確保
        size_pbmi = sizeof(BITMAPINFOHEADER) + size_mask + (num_colors * sizeof(RGBQUAD));
        if(pbmi)    LocalFree(pbmi);
        pbmi = (BITMAPINFO *) LocalAlloc(LPTR, size_pbmi);
        // BITMAPINFOHEADER 構造体をコピー
        pbmi->bmiHeader = Dib.dsBmih;
        // パレット または、ピクセルフォーマットマスクを取得
        if(bpp <= 8){
            HDC     hMemDC = CreateCompatibleDC(NULL);
            HBITMAP hBmp_pre = (HBITMAP) SelectObject(hMemDC, hBmp);
            GetDIBColorTable(hMemDC, 0, num_colors, pbmi->bmiColors);
            SelectObject(hMemDC, hBmp_pre);
            DeleteDC(hMemDC);
        }
        else if(Dib.dsBmih.biCompression == BI_BITFIELDS){
            memcpy(pbmi->bmiColors, Dib.dsBitfields, size_mask);
        }
        // ビットマップのハンドルを削除
        DeleteObject(hBmp);
        
        // 別名で保存する
        HANDLE  hFile;
        DWORD   dwWrite;
        char    *p;
        p = strrchr(__argv[1], '.');
        if(p){
            strcpy(p, "_new.bmp");
        }
        else{
            strcat(p, "_new.bmp");
        }
        hFile = CreateFile(__argv[1], GENERIC_WRITE, FILE_SHARE_WRITE,
                            NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
        if(hFile == INVALID_HANDLE_VALUE){
            SendMessage(hWnd, WM_CLOSE, 0, 0);
        }
        // BITMAPFILEHEADER 構造体を設定
        BITMAPFILEHEADER bmfh;
        ZeroMemory(&bmfh, sizeof(BITMAPFILEHEADER));
        bmfh.bfType = 0x4d42;
        bmfh.bfOffBits = sizeof(bmfh) + size_pbmi;
        bmfh.bfSize = bmfh.bfOffBits + size_pbits;
        WriteFile(hFile, &bmfh, sizeof(BITMAPFILEHEADER), &dwWrite, NULL);
        WriteFile(hFile, pbmi, size_pbmi, &dwWrite, NULL);
        WriteFile(hFile, pbits, size_pbits, &dwWrite, NULL);
        CloseHandle(hFile);
        return 0;
    case WM_PAINT:
        HDC         hDC;
        PAINTSTRUCT ps;
        hDC = BeginPaint(hWnd,&ps);
        // 描画
        if(pbmi){
            SetDIBitsToDevice(hDC,
                        0, 0, pbmi->bmiHeader.biWidth, pbmi->bmiHeader.biHeight,
                        0, 0, 0, pbmi->bmiHeader.biHeight,
                        pbits, pbmi, DIB_RGB_COLORS);
        }
        EndPaint(hWnd,&ps);
        return 0;
    case WM_CLOSE:
        // メモリを解放
        if(pbmi){
            LocalFree(pbmi);
            pbmi = NULL;
        }
        if(pbits){
            LocalFree(pbits);
            pbits = NULL;
        }
        DestroyWindow(hWnd);
        PostQuitMessage(0);
        return 0;
    default:
        break;
    }
    return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

50.ICON ファイルの読み込み

 ドラッグ&ドロップされたアイコンファイルを表示する。
 wType が 2 の場合は、カーソルファイルとなる。
 その場合は、wPlanes と wBitCount が、
 それぞれホットスポットの X 座標と Y 座標になる。
 アイコンの場合は、両方とも 0 が望ましいと MSDN のANIFILE.C に書いてある。
 PNG フォーマットには対応していない。
 PNG アイコンについては Wikipedia ICO 参照

// Source code from the MSDN Library (Icons in Win32, ICONS.C)

#include <windows.h>
#include <stdio.h>
#include "resource.h"

#define MYWNDCLASS  "MYWNDCLASS"
#define MYWNDTITLE  "icon"
#define NUM_MAX     32      // 取り出す画像の最大数
#define WIDTHBYTES(bits)    ((((bits) + 31)>>5)<<2)

typedef struct
{
    BYTE        bWidth;             // Width, in pixels, of the image
    BYTE        bHeight;            // Height, in pixels, of the image
    BYTE        bColorCount;        // Number of colors in image (0 if >=8bpp)
    BYTE        bReserved;          // Reserved ( must be 0)
    WORD        wPlanes;            // Color Planes
    WORD        wBitCount;          // Bits per pixel
    DWORD       dwBytesInRes;       // How many bytes in this resource?
    DWORD       dwImageOffset;      // Where in the file is this image?
} ICONDIRENTRY, *LPICONDIRENTRY;

typedef struct
{
    WORD            wReserved;          // Reserved (must be 0)
    WORD            wType;              // Resource Type (1 for icons)
    WORD            wCount;             // How many images?
    ICONDIRENTRY    idEntries[NUM_MAX]; // An entry for each image (wCount of 'em)
} ICONDIR, *LPICONDIR;

typedef struct
{
    LPBYTE          pData;          // ptr to DIB data
    LPBITMAPINFO    pbmi;           // DIB BITMAPINFO
    LPBYTE          pXOR;           // DIB bits for XOR mask
    LPBYTE          pAND;           // DIB bits for AND mask
} ICONIMAGE, *LPICONIMAGE;

ICONDIR     g_id;                   // アイコンのファイルヘッダ
ICONIMAGE   g_iImg[NUM_MAX];        // アイコンのインフォヘッダとピクセルデータ
char        g_file_name[MAX_PATH];  // 読み込み・保存ファイル名

LRESULT CALLBACK ProcWnd(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
bool    DrawANDMask(HDC hDC);
void    Load_Dialog(HWND hWnd);
bool    Load_Icon(HWND hWnd);
bool    AdjustIconImagePointers( LPICONIMAGE pIImg );
LPBYTE  FindDIBBits( LPBITMAPINFOHEADER lpbih );
WORD    PaletteSize( LPBITMAPINFOHEADER lpbih );
WORD    DIBNumColors( LPBITMAPINFOHEADER lpbih );
DWORD   BytesPerLine( LPBITMAPINFOHEADER lpBMIH );
void    Save_Dialog(HWND hWnd);
bool    Save_Icon(HWND hWnd);
DWORD   CalculateImageOffset( UINT nIndex );
void    Set_Title(HWND hWnd);
void    Cleanup();

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);
    
    HMENU   hMenu = LoadMenu(hInst,MAKEINTRESOURCE(IDR_MENU1));
    
    hWnd = CreateWindowEx(WS_EX_ACCEPTFILES, 
                MYWNDCLASS,
                MYWNDTITLE,
                WS_OVERLAPPEDWINDOW | WS_VISIBLE,
                CW_USEDEFAULT, CW_USEDEFAULT, 256, 256,
                NULL,
                hMenu,
                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:
        if(__argc > 1){
            strncpy(g_file_name, __argv[1], sizeof(g_file_name));
            Load_Icon(hWnd);
        }
        return 0;
    case WM_DROPFILES:
        HDROP   hDrop;
        hDrop = (HDROP) wParam;
        DragQueryFile(hDrop, 0, g_file_name, sizeof(g_file_name));
        Load_Icon(hWnd);
        DragFinish(hDrop);
        SetForegroundWindow(hWnd);
        return 0;
    case WM_COMMAND:
        switch( LOWORD(wParam) )
        {
        case IDM_OPEN:  // 開く
            Load_Dialog(hWnd);
            break;
        case IDM_SAVEAS:// 名前を付けて保存
            Save_Dialog(hWnd);
            break;
        case IDM_EXIT:  // 終了
            Cleanup();
            SendMessage(hWnd,WM_CLOSE,0,0);
            break;
        }
        return 0;
    case WM_PAINT:
        HDC         hDC;
        PAINTSTRUCT ps;
        hDC = BeginPaint(hWnd,&ps);
        DrawANDMask(hDC);
        EndPaint(hWnd,&ps);
        return 0;
    case WM_CLOSE:
        DestroyWindow(hWnd);
        PostQuitMessage(0);
        return 0;
    default:
        break;
    }
    return DefWindowProc(hWnd, uMsg, wParam, lParam);
}// ProcWnd

bool DrawANDMask( HDC hDC )
{
    int i,indent = 0;
    
    for(i=0;i<g_id.wCount;i++){
        if( g_iImg[i].pData == NULL ){
            continue;
        }
        if(g_iImg[i].pbmi->bmiHeader.biSize != sizeof(BITMAPINFOHEADER)){
            continue;
        }
        int height = g_iImg[i].pbmi->bmiHeader.biHeight / 2;
        SetDIBitsToDevice( hDC, indent, 0, g_iImg[i].pbmi->bmiHeader.biWidth, height,
                    0, 0, 0, height, g_iImg[i].pXOR, g_iImg[i].pbmi, DIB_RGB_COLORS );
        LPBITMAPINFO    lpbi;
        lpbi = (LPBITMAPINFO) malloc( sizeof(BITMAPINFO) + (2 * sizeof( RGBQUAD )) );
        lpbi->bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
        lpbi->bmiHeader.biWidth = g_iImg[i].pbmi->bmiHeader.biWidth;
        lpbi->bmiHeader.biHeight = height;
        lpbi->bmiHeader.biPlanes = 1;
        lpbi->bmiHeader.biBitCount = 1;
        lpbi->bmiHeader.biCompression = BI_RGB;
        lpbi->bmiHeader.biSizeImage = 0;
//      lpbi->bmiHeader.biSizeImage = WIDTHBYTES(lpbi->bmiHeader.biWidth * 
//                  lpbi->bmiHeader.biPlanes * lpbi->bmiHeader.biBitCount) * 
//                  lpbi->bmiHeader.biHeight;
        lpbi->bmiHeader.biXPelsPerMeter = 0;
        lpbi->bmiHeader.biYPelsPerMeter = 0;
        lpbi->bmiHeader.biClrUsed = 0;
        lpbi->bmiHeader.biClrImportant = 0;
        lpbi->bmiColors[0].rgbRed = 0;
        lpbi->bmiColors[0].rgbGreen = 0;
        lpbi->bmiColors[0].rgbBlue = 0;
        lpbi->bmiColors[0].rgbReserved = 0;
        lpbi->bmiColors[1].rgbRed = 255;
        lpbi->bmiColors[1].rgbGreen = 255;
        lpbi->bmiColors[1].rgbBlue = 255;
        lpbi->bmiColors[1].rgbReserved = 0;
        SetDIBitsToDevice( hDC, indent, lpbi->bmiHeader.biHeight, lpbi->bmiHeader.biWidth, lpbi->bmiHeader.biHeight,
                    0, 0, 0, lpbi->bmiHeader.biHeight, g_iImg[i].pAND, lpbi, DIB_RGB_COLORS );
        free( lpbi );
        indent += (g_iImg[i].pbmi->bmiHeader.biWidth + 1);
    }
    return TRUE;
}// DrawANDMask

// オープンダイアログ
void Load_Dialog(HWND hWnd)
{
    OPENFILENAME ofn;
    char fn[MAX_PATH];
    fn[0] = '\0';
    
    ZeroMemory(&ofn, sizeof(OPENFILENAME));
    ofn.lStructSize = sizeof(OPENFILENAME);
    ofn.hwndOwner = hWnd;
    ofn.Flags = OFN_HIDEREADONLY; 
    ofn.lpstrFile = fn;
    ofn.nMaxFile = sizeof(fn);
    ofn.lpstrFilter = "アイコン ファイル (*.ico)\0" "*.ico\0"
                      "すべてのファイル (*.*)\0" "*.*\0";
    ofn.nFilterIndex = 1;
    if (GetOpenFileName(&ofn)){
        strcpy(g_file_name,fn);
        if(ofn.nFilterIndex == 1){
            if(strrchr(g_file_name,'.') == NULL){
                strcat(g_file_name,".ico");
            }
        }
        Load_Icon(hWnd);
    }
}// Load_Dialog

// ファイルからデータを読み込む
bool Load_Icon(HWND hWnd)
{
    HANDLE hFile;
    DWORD   dwRead;
    
    Cleanup();
    Set_Title(hWnd);
    
    hFile = CreateFile(g_file_name,GENERIC_READ,FILE_SHARE_READ,
                        NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
    if(hFile == INVALID_HANDLE_VALUE){
        return 0;
    }
    // Read the Reserved word
    ReadFile( hFile, &(g_id.wReserved), sizeof( WORD ), &dwRead, NULL );
    // Read the Type word - make sure it is 1 for icons
    ReadFile( hFile, &(g_id.wType), sizeof( WORD ), &dwRead, NULL );
    if(g_id.wType != 1) return 0;
    // Read the count - how many images in this file?
    ReadFile( hFile, &(g_id.wCount), sizeof( WORD ), &dwRead, NULL );
    g_id.wCount = NUM_MAX > g_id.wCount ? g_id.wCount : NUM_MAX;
    // Read the ICONDIRENTRY elements
    ReadFile( hFile, g_id.idEntries, g_id.wCount * sizeof(ICONDIRENTRY), &dwRead, NULL );
    // Loop through and read in each image
    for(int i=0;i<g_id.wCount;i++)
    {
        if(i >= NUM_MAX)    break;
        // Allocate memory to hold the image
        g_iImg[i].pData = new BYTE [g_id.idEntries[i].dwBytesInRes];
        // Seek to the location in the file that has the image
        SetFilePointer( hFile, g_id.idEntries[i].dwImageOffset, NULL, FILE_BEGIN );
        // Read the image data
        ReadFile( hFile, g_iImg[i].pData, g_id.idEntries[i].dwBytesInRes, &dwRead, NULL );
        // Set the internal pointers appropriately
        AdjustIconImagePointers( &(g_iImg[i]) );
    }
    CloseHandle(hFile);
    InvalidateRect(hWnd,NULL,TRUE);
    return 1;
}// Load_Icon

bool AdjustIconImagePointers( LPICONIMAGE pIImg )
{
    // Sanity check
    if( pIImg == NULL )
        return false;
    // BITMAPINFO is at beginning of bits
    pIImg->pbmi = (LPBITMAPINFO) pIImg->pData;
    // XOR bits follow the header and color table
    pIImg->pXOR = FindDIBBits(&(pIImg->pbmi->bmiHeader));
    // AND bits follow the XOR bits
    pIImg->pAND = pIImg->pXOR + (pIImg->pbmi->bmiHeader.biHeight / 2
        * BytesPerLine((LPBITMAPINFOHEADER)&(pIImg->pbmi->bmiHeader)));
    return true;
}// AdjustIconImagePointers

LPBYTE FindDIBBits( LPBITMAPINFOHEADER lpbih )
{
    return (LPBYTE) lpbih + *(LPDWORD)lpbih + PaletteSize( lpbih );
}// FindDIBBits

WORD PaletteSize( LPBITMAPINFOHEADER lpbih )
{
    return ( DIBNumColors( lpbih ) * sizeof( RGBQUAD ) );
}// PaletteSize

WORD DIBNumColors( LPBITMAPINFOHEADER lpbih )
{
    int num;
    if(lpbih->biBitCount > 8)
        num = 0;
    else if(lpbih->biClrUsed == 0)
        num = 1 << lpbih->biBitCount;
    else
        num = lpbih->biClrUsed;
    return num;
}// DIBNumColors

DWORD BytesPerLine( LPBITMAPINFOHEADER lpBMIH )
{
    return WIDTHBYTES(lpBMIH->biWidth * lpBMIH->biPlanes * lpBMIH->biBitCount);
}// BytesPerLine

// セーブダイアログ
void Save_Dialog(HWND hWnd)
{
    OPENFILENAME ofn;
    char fn[MAX_PATH];
    fn[0] = '\0';
    
    ZeroMemory(&ofn, sizeof(OPENFILENAME));
    ofn.lStructSize = sizeof(OPENFILENAME);
    ofn.hwndOwner = hWnd;
    ofn.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_EXTENSIONDIFFERENT;
    ofn.lpstrFile = fn;
    ofn.nMaxFile = sizeof(fn);
    ofn.lpstrDefExt  = "ico";
    ofn.lpstrFilter = "アイコン ファイル (*.ico)\0" "*.ico\0"
                      "すべてのファイル (*.*)\0" "*.*\0";
    ofn.nFilterIndex = 1;
    if (GetSaveFileName(&ofn)){
        strcpy(g_file_name,fn);
        Save_Icon(hWnd);
    }
}// Save_Dialog

// ファイルにデータを書き込む
bool Save_Icon(HWND hWnd)
{
    HANDLE hFile;
    DWORD   dwWrite;
    int     i;
    
    Set_Title(hWnd);
    
    // open the file
    hFile = CreateFile(g_file_name,GENERIC_WRITE,FILE_SHARE_WRITE,
                        NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
    if(hFile == INVALID_HANDLE_VALUE){
        return 0;
    }
    // Write the Reserved word
    WriteFile( hFile, &(g_id.wReserved), sizeof( WORD ), &dwWrite, NULL );
    // Write the Type word - make sure it is 1 for icons
    WriteFile( hFile, &(g_id.wType), sizeof( WORD ), &dwWrite, NULL );
    // Write the count - how many images in this file?
    int num;
    NUM_MAX > g_id.wCount ? num = g_id.wCount : num = NUM_MAX;
    WriteFile( hFile, &num, sizeof( WORD ), &dwWrite, NULL );
    
    for(i=0;i<num;i++)
    {
        ICONDIRENTRY    ide;
        
        // Convert internal format to ICONDIRENTRY
        ide.bWidth    = (BYTE) g_iImg[i].pbmi->bmiHeader.biWidth;
        ide.bHeight   = (BYTE) g_iImg[i].pbmi->bmiHeader.biHeight / 2;
        ide.bReserved = 0;
        ide.wPlanes   = 0;
        ide.wBitCount = 0;
        UINT bpp = g_iImg[i].pbmi->bmiHeader.biPlanes * g_iImg[i].pbmi->bmiHeader.biBitCount;
        if( bpp >= 8 )
            ide.bColorCount = 0;
        else
            ide.bColorCount = 1 << bpp;
        ide.dwBytesInRes  = g_id.idEntries[i].dwBytesInRes;
        ide.dwImageOffset = CalculateImageOffset( i );
        // Write the ICONDIRENTRY out to disk
        WriteFile( hFile, &ide, sizeof( ICONDIRENTRY ), &dwWrite, NULL );
        // Did we write a full ICONDIRENTRY ?
        if( dwWrite != sizeof( ICONDIRENTRY ) )
            return 0;
    }
    for(i=0;i<num;i++)
    {
        DWORD dwTemp = g_iImg[i].pbmi->bmiHeader.biSizeImage;
        
        // Set the sizeimage member to zero
        g_iImg[i].pbmi->bmiHeader.biSizeImage = 0;
        // Write the image data to file
        WriteFile( hFile, g_iImg[i].pData, g_id.idEntries[i].dwBytesInRes, &dwWrite, NULL );
        if( dwWrite != g_id.idEntries[i].dwBytesInRes )
            return 0;
        // set it back
        g_iImg[i].pbmi->bmiHeader.biSizeImage = dwTemp;
    }
    CloseHandle(hFile);
    return 1;
}// Save_Icon

DWORD CalculateImageOffset( UINT nIndex )
{
    DWORD   dwSize;
    UINT    i;
    
    // Calculate the ICO header size
    dwSize = 3 * sizeof(WORD);
    // Add the ICONDIRENTRY's
    dwSize += g_id.wCount * sizeof(ICONDIRENTRY);
    // Add the sizes of the previous images
    for(i=0;i<nIndex;i++)
        dwSize += g_id.idEntries[i].dwBytesInRes;
    // we're there - return the number
    return dwSize;
}// CalculateImageOffset

// ウィンドウタイトルの変更
void Set_Title(HWND hWnd)
{
    char    *p,s[MAX_PATH];
    p = strrchr(g_file_name,'\\');
    sprintf(s,"%s  <%s>",MYWNDTITLE,p+1);
    SendMessage(hWnd, WM_SETTEXT, 0, (LPARAM)s);
}// Set_Title

// メモリの解放
void Cleanup()
{
    for(int i=0;i<NUM_MAX;i++){
        delete [] (g_iImg[i].pData);
        g_iImg[i].pData = NULL;
    }
}// Cleanup

51.ショートカットの作成

 ファイルのショートカットをデスクトップに作成する。

// Source code from the MSDN Library (Using Shell Links in Windows 95)

#include <windows.h>
#include <stdio.h>
#include <shlobj.h>

#define MYWNDTITLE      "shortcut"

HRESULT CreateShortCut(LPCSTR pszShortcutFile, LPSTR pszLink, LPSTR pszDesc)
{
    HRESULT     hres;
    IShellLink* psl;
    
    // Get a pointer to the IShellLink interface.
    hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void **) &psl);
    if (SUCCEEDED(hres))
    {
        IPersistFile* ppf;
        
        // Query IShellLink for the IPersistFile interface for 
        // saving the shell link in persistent storage.
        hres = psl->QueryInterface(IID_IPersistFile, (void **) &ppf);
        if (SUCCEEDED(hres))
        {   
            WORD wsz[MAX_PATH];
            
            // Set the path to the shell link target.
            hres = psl->SetPath(pszShortcutFile);
            
            if (!SUCCEEDED(hres))
                MessageBox(0, "SetPath failed!", MYWNDTITLE, 0);
            
            // Set the description of the shell link.
            hres = psl->SetDescription(pszDesc);
            
            if (!SUCCEEDED(hres))
                MessageBox(0, "SetDescription failed!", MYWNDTITLE, 0);
            
            // Ensure string is ANSI.
            MultiByteToWideChar(CP_ACP, 0, pszLink, -1, wsz, MAX_PATH);
            
            // Save the link via the IPersistFile::Save method.
            hres = ppf->Save(wsz, TRUE);
            
            // Release pointer to IPersistFile.
            ppf->Release();
        }
        // Release pointer to IShellLink.
        psl->Release();
    }
    return hres;
}// CreateShortCut

int WINAPI WinMain(HINSTANCE hInst,HINSTANCE hInstPrev,LPSTR lpCmdLine,int nCmdShow)
{
    if(__argc <= 1){
        MessageBox(0, "Drag & Drop 専用です", MYWNDTITLE, 0);
        return 0;
    }
    
    CoInitialize(NULL);
    char desktop_path[MAX_PATH];
    char file_name[MAX_PATH];
    char shortcut_name[MAX_PATH];
    char shortcut_desc[MAX_PATH];
    char *p;
    
    SHGetSpecialFolderPath(NULL, desktop_path, CSIDL_DESKTOPDIRECTORY, FALSE);
    strncpy(file_name, __argv[1], MAX_PATH);
    GetFileTitle(file_name, shortcut_desc, MAX_PATH);
    p = strrchr(shortcut_desc, '.');
    if(p)
        strcpy(p, "のショートカット");
    _snprintf(shortcut_name, MAX_PATH,"%s\\%s.lnk", desktop_path, shortcut_desc);
    strcat(shortcut_desc, "のコメント");
    if(GetFileAttributes(shortcut_name) == -1)
        CreateShortCut(file_name, shortcut_name, shortcut_desc);
    else
        MessageBox(0, "デスクトップに同名のショートッカットが存在しています", MYWNDTITLE, 0);
    CoUninitialize();
    return 0;
}// WinMain

52.拡張メタファイルの表示

GDI+ の場合は、ファイル名に WMF と EMF を指定できる。

GDI の場合は、EMF ファイルのみ指定できる。
WMF ファイルを表示したいときは、フォーマットを EMF に変換する必要がある。

////////////////// GDI の場合 //////////////////

HENHMETAFILE    hEmf = GetEnhMetaFile("sample.emf");
ENHMETAHEADER   emh;
HDC             hDC  = GetDC(hWnd);

GetEnhMetaFileHeader(hEmf, sizeof(emh), &emh);
PlayEnhMetaFile(hDC, hEmf, (RECT*)&emh.rclBounds);
DeleteEnhMetaFile(hEmf);
ReleaseDC(hWnd, hDC);



////////////////// GDI+ の場合 /////////////////

Metafile meta(L"sample.emf");
HDC hDC  = GetDC(hWnd);
Graphics g(hDC);
g.DrawImage(&meta, Rect(0, 0, meta.GetWidth(), meta.GetHeight()));
ReleaseDC(hWnd, hDC);

53.フルパスからファイル名を抜き出す

// フルパスからファイル名(Windows7 以前は拡張子なし。Windows7 は拡張子あり)を抜き出す

char path[MAX_PATH],title[MAX_PATH];
GetFileTitle(path, title, sizeof(title));


// カレントドライブの取得

char drive[MAX_PATH];
GetCurrentDirectory(sizeof(drive), drive);
char *p = strchr(drive, '\\');
if(p){
    strcpy(p+1, "");
}


// フルパスの分解

char full_path[_MAX_PATH]; // フルパス名
char drive[_MAX_DRIVE];    // ドライブ名
char dir[_MAX_DIR];        // ディレクトリー パス
char fname[_MAX_FNAME];    // ファイル名
char ext[_MAX_EXT];        // 拡張子

_splitpath(full_path, drive, dir, fname, ext);

54.ドラッグ&ドロップ後に最前面にする

    case WM_DROPFILES:
        // SetForegroundWindow関数を使う(hWnd はメインウィンドウのハンドル)
        SetForegroundWindow(hWnd);
        
        // または、mouse_event関数を使う
        mouse_event(MOUSEEVENTF_LEFTDOWN,0,0,0,0);
        mouse_event(MOUSEEVENTF_LEFTUP,  0,0,0,0);
        break;

55.ODBC 関数でデータベース読み込み

STDREG32.MDB を例えば、C ドライブ直下にコピーして、
[コントロールパネル]→[ODBC データソース]→[ユーザDSN]タブ→[追加]
→[Microsoft Access Driver(*.mdb)]→[完了]→[データソース名]に、
Student Registration と入力→[選択]で STDREG32.MDB を選択→[OK]
→ [詳細設定]でユーザ名、パスワードを設定→[OK]→[OK]
をあらかじめ実行する。
または、SQLConfigDataSource()を使用する。
データベース名は、データソース名のこと。
以下の例では、ユーザ名とパスワードは未設定。
STDREG32.MDB は、MSDN Library CD 内のサンプル ファイル。
Student Registration には、COURSE, STUDENT, INSTRUCTOR, SECTION, DYNABIND_SECTION, ENROLLMENT
の6つのテーブルが入っている。

Win98, Me, 2000, Xp 専用

#include <windows.h>
#include <sql.h>
#include <sqlext.h>

#define MYWNDCLASS  "ODBC_CLASS"
#define MYWNDTITLE  "ODBC"
#define MAXBUFLEN   256     // string buffer size
#define MAX_COL     15      // maximum column in result set
#define MAX_ROW     100     // maximum number of rows
#define MAXDATALEN  25      // maximum data length per column
#define NULLDATASTRING      "SQL_NULL_DATA" // NULLレコードの置き換え文字列

SQLHENV     g_hEnv = NULL;  // Environment Handle
SQLHDBC     g_hDbc = NULL;  // hdbc
int         g_nRows = 0;    // データの数
char        g_sDispBuffer[MAX_ROW][MAX_COL*(MAXDATALEN+1)]; // 読み込んだデータ(全部)

LRESULT CALLBACK ProcWnd(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
bool InitEnv();
bool ConnectDB(SQLCHAR *sDsn, SQLCHAR *sUser, SQLCHAR *sPass);
bool DriverConnectDB(HWND hWnd);
void ExecuteQuery(SQLCHAR *sSqlStatement);
void CloseDB();
void FreeEnv();

LRESULT CALLBACK ProcWnd(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_CREATE:
        {
            InitEnv();
            // ConnectDB か DriverConnectDB のどちらかを実行する
            bool flag = true;
            if(flag){
                ConnectDB((SQLCHAR*)"Student Registration", (SQLCHAR*)"", (SQLCHAR*)"");
            }
            else{
                DriverConnectDB(hWnd);
            }
            ExecuteQuery((SQLCHAR*)"SELECT * FROM STUDENT");
        }
        return 0;
    case WM_PAINT:
        HDC         hDC;
        PAINTSTRUCT ps;
        hDC = BeginPaint(hWnd,&ps);
        RECT    rc;
        int     i;
        for(i=0;i<g_nRows;i++){
            SetRect(&rc,0,i*20,1000,(i+1)*20);
            DrawText(hDC, g_sDispBuffer[i], strlen(g_sDispBuffer[i]), 
                        &rc, DT_EXPANDTABS | DT_TABSTOP | (18 << 8));
        }
        EndPaint(hWnd,&ps);
        return 0;
    case WM_CLOSE:
        FreeEnv();
        DestroyWindow(hWnd);
        PostQuitMessage(0);
        return 0;
    default:
        break;
    }
    return DefWindowProc(hWnd, uMsg, wParam, lParam);
}// ProcWnd

// 初期化
bool InitEnv()
{
    if(SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &g_hEnv) != SQL_SUCCESS)
        return false;
    if(SQLSetEnvAttr(g_hEnv, SQL_ATTR_ODBC_VERSION,
                    (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_INTEGER) != SQL_SUCCESS)
        return false;
    return true;
}// InitEnv

// データベース名、ユーザ名、パスワードを指定してデータベースに接続する
bool ConnectDB(SQLCHAR *sDsn, SQLCHAR *sUser, SQLCHAR *sPass)
{
    SQLRETURN nResult;  // Result code
    
    if(SQLAllocHandle(SQL_HANDLE_DBC, g_hEnv, (SQLHDBC FAR *)&g_hDbc) != SQL_SUCCESS){
        return false;
    }
    nResult = SQLConnect(g_hDbc, sDsn, SQL_NTS, sUser, SQL_NTS, sPass, SQL_NTS);
    if(nResult != SQL_SUCCESS && nResult != SQL_SUCCESS_WITH_INFO){
        SQLFreeHandle(SQL_HANDLE_DBC, g_hDbc);
        return false;
    }
    return true;
}// ConnectDB

// データベース選択ダイアログを使ってデータベースに接続する
bool DriverConnectDB(HWND hWnd)
{
    SQLCHAR     sBuffer[MAXBUFLEN+1];   //display successful connection info on hdbc(s) combo-box
    SWORD       swStrLen;               //String length
    SQLRETURN   nResult;                //result code
    
    if(SQLAllocHandle(SQL_HANDLE_DBC, g_hEnv, (SQLHDBC FAR *)&g_hDbc) != SQL_SUCCESS){
        return false;
    }
    nResult = SQLDriverConnect(g_hDbc, hWnd, (SQLCHAR*)"", 0, sBuffer, 
                                MAXBUFLEN, &swStrLen, SQL_DRIVER_COMPLETE_REQUIRED);
    if(nResult != SQL_SUCCESS && nResult != SQL_SUCCESS_WITH_INFO){
        SQLFreeHandle(SQL_HANDLE_DBC, g_hDbc);
        return false;
    }
    return true;
}// DriverConnectDB

// SQLステートメントを実行する
void ExecuteQuery(SQLCHAR *sSqlStatement)
{
    SQLHSTMT    hstmt;
    SQLSMALLINT nCols = 0;              // フィールドの数
    SQLSMALLINT iColType;               // フィールドの型(SQL_CHAR, SQL_INTEGER ...)
    SQLSMALLINT iColNull;               // このフィールドのレコードにNULLは入力可能か?
    SQLSMALLINT iColScale;              // フィールドのサイズ(決まってなかったら 0)
    SQLUINTEGER uiColDef;               // 正確な10進数
    SQLSMALLINT iColLen;                // フィールド名の実際の長さ
    SQLCHAR     sBuffer[MAXDATALEN+1];  // フィールド名
    int         i;
    SQLCHAR     sData[MAX_COL][MAXDATALEN]; // Results Data Array(1レコード分)
    SQLINTEGER  iDataLen[MAX_COL];          // Results Data Length Array(1レコード分)
    
    if(SQLAllocHandle(SQL_HANDLE_STMT,g_hDbc, &hstmt) != SQL_SUCCESS){
        return;
    }
    // SQLステートメントを実行
    SQLExecDirect(hstmt, sSqlStatement, SQL_NTS);
    // フィールド数を取得
    SQLNumResultCols(hstmt, &nCols);
    if(nCols >= MAX_COL)
        nCols = MAX_COL;
    if(!nCols)
        return;
    
    g_sDispBuffer[0][0] = '\0';
    // フィールド名を取得
    for(i=1; i<= nCols; i++){
        SQLDescribeCol(hstmt, i, sBuffer, MAXDATALEN, &iColLen, &iColType, &uiColDef, &iColScale, &iColNull);
        strcat(g_sDispBuffer[0], (char*)sBuffer);
        strcat(g_sDispBuffer[0], "\t");
    }
    g_sDispBuffer[0][strlen(g_sDispBuffer[0])-1] = '\0';
    // レコードを配列にバインド
    for(i=0; i<nCols; i++){
        SQLBindCol(hstmt, (UWORD)(i+1), SQL_C_CHAR, sData[i], MAXDATALEN, &iDataLen[i]);
    }
    // レコードを取得
    g_nRows = 1;
    while(SQLFetch(hstmt) == SQL_SUCCESS){
        for(i=0; i<nCols; i++){
            // check if the column is a null value?
            strcat(g_sDispBuffer[g_nRows], (iDataLen[i]==SQL_NULL_DATA)?NULLDATASTRING:(char*)sData[i]);
            strcat(g_sDispBuffer[g_nRows], "\t");
        }
        g_sDispBuffer[g_nRows][strlen(g_sDispBuffer[g_nRows])-1] = '\0';
        g_nRows ++;
        if(g_nRows >= MAX_ROW){
            g_nRows = MAX_ROW - 1;
            break;
        }
    }
    // カーソルを閉じる
    SQLCloseCursor(hstmt);
    // バインドを解除
    SQLFreeStmt(hstmt, SQL_UNBIND);
    // ハンドルを解放
    SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
}// ExecuteQuery

// データベースの接続を切る
void CloseDB()
{
    SQLDisconnect(g_hDbc);
    SQLFreeHandle(SQL_HANDLE_DBC, g_hDbc);
}// CloseDB

// 終了処理
void FreeEnv()
{
    CloseDB();
    SQLFreeHandle(SQL_HANDLE_ENV, g_hEnv);
}// FreeEnv

56.ODBC 関数でデータベース作成・レコード追加

 データベースとテーブルを作成して、レコードを追加する

 [コントロールパネル]→[ODBC データソース]→[ドライバ]タブで、Access odbc driver (odbcjt32.dll) がインストールされていることをあらかじめ確認すること

 Win98, Me, 2000, Xp 専用

 odbccp32.lib のリンク設定が必要
#include <windows.h>
#include <stdio.h>
#include <sql.h>
#include <sqlext.h>
#include <odbcinst.h>

#define MYWNDCLASS  "ODBC_Create_CLASS"
#define MYWNDTITLE  "ODBC_Create"
#define DSN         "新規データソース"
#define DESC        "ODBC データベース作成サンプル"
#define USERID      "user"
#define PASSWORD    "password"
#define FILENAME    "C:\\new.mdb"

SQLHENV     g_hEnv = NULL;  // Environment Handle
SQLHDBC     g_hDbc = NULL;  // hdbc

LRESULT CALLBACK ProcWnd(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
bool CreateMDB(HWND hWnd, char *sDsn, char *sDesc, char *sUser, char *sPass, char *sFile);
bool InitEnv();
bool ConnectDB(SQLCHAR *sDsn, SQLCHAR *sUser, SQLCHAR *sPass);
void ExecuteQuery(SQLCHAR *sSqlStatement);
void CloseDB();
void FreeEnv();

LRESULT CALLBACK ProcWnd(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_CREATE:
        CreateMDB(hWnd,DSN,DESC,USERID,PASSWORD,FILENAME);
        InitEnv();
        ConnectDB((SQLCHAR*)DSN, (SQLCHAR*)USERID, (SQLCHAR*)PASSWORD);
        // テーブル foo を作成
        ExecuteQuery((SQLCHAR*)"CREATE TABLE foo (a INTEGER, b VARCHAR(20))");
        // テーブル foo にレコードを追加
        ExecuteQuery((SQLCHAR*)"INSERT INTO foo VALUES(100, 'abc')");
        ExecuteQuery((SQLCHAR*)"INSERT INTO foo VALUES(222, 'fff')");
        ExecuteQuery((SQLCHAR*)"INSERT INTO foo VALUES(0, '')");
        MessageBox(hWnd, "処理終了", MYWNDTITLE, MB_OK);
        return 0;
    case WM_CLOSE:
        FreeEnv();
        DestroyWindow(hWnd);
        PostQuitMessage(0);
        return 0;
    default:
        break;
    }
    return DefWindowProc(hWnd, uMsg, wParam, lParam);
}// ProcWnd

// MDBファイルを新規作成して、ODBCデータソースに格納する
bool CreateMDB(HWND hWnd, char *sDsn, char *sDesc, char *sUser, char *sPass, char *sFile)
{
    WORD    fRequest = ODBC_ADD_DSN;
    char    sDriver[] = "Microsoft Access Driver (*.mdb)";
    char    sAttributes1[256],sAttributes2[256];
    
    _snprintf(sAttributes1, sizeof(sAttributes1), "CREATE_DB=%s General;", sFile);
    if(!SQLConfigDataSource(NULL, fRequest, sDriver, sAttributes1)){
        MessageBox(hWnd,"MDBファイルを作成できません",MYWNDTITLE,MB_OK);
        return false;
    }
    _snprintf(sAttributes2, sizeof(sAttributes2), 
        "DSN=%s;DESCRIPTION=%s;UID=%s;PWD=%s;DBQ=%s;",
        sDsn, sDesc, sUser, sPass, sFile);
    if(!SQLConfigDataSource(hWnd, fRequest, sDriver, sAttributes2)){
        MessageBox(hWnd,"データソースに格納できません",MYWNDTITLE,MB_OK);
        return false;
    }
    return true;
}// CreateMDB

// 初期化
bool InitEnv()
{
    if(SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &g_hEnv) != SQL_SUCCESS)
        return false;
    if(SQLSetEnvAttr(g_hEnv, SQL_ATTR_ODBC_VERSION,
                    (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_INTEGER) != SQL_SUCCESS)
        return false;
    return true;
}// InitEnv

// データベース名、ユーザ名、パスワードを指定してデータベースに接続する
bool ConnectDB(SQLCHAR *sDsn, SQLCHAR *sUser, SQLCHAR *sPass)
{
    SQLRETURN nResult;  // Result code
    
    if(SQLAllocHandle(SQL_HANDLE_DBC, g_hEnv, (SQLHDBC FAR *)&g_hDbc) != SQL_SUCCESS){
        return false;
    }
    nResult = SQLConnect(g_hDbc, sDsn, SQL_NTS, sUser, SQL_NTS, sPass, SQL_NTS);
    if(nResult != SQL_SUCCESS && nResult != SQL_SUCCESS_WITH_INFO){
        SQLFreeHandle(SQL_HANDLE_DBC, g_hDbc);
        return false;
    }
    return true;
}// ConnectDB

// SQLステートメントを実行する
void ExecuteQuery(SQLCHAR *sSqlStatement)
{
    SQLHSTMT    hstmt;
    
    if(SQLAllocHandle(SQL_HANDLE_STMT,g_hDbc, &hstmt) != SQL_SUCCESS){
        return;
    }
    // SQLステートメントを実行
    SQLExecDirect(hstmt, sSqlStatement, SQL_NTS);
    // ハンドルを解放
    SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
}// ExecuteQuery

// データベースの接続を切る
void CloseDB()
{
    SQLDisconnect(g_hDbc);
    SQLFreeHandle(SQL_HANDLE_DBC, g_hDbc);
}// CloseDB

// 終了処理
void FreeEnv()
{
    CloseDB();
    SQLFreeHandle(SQL_HANDLE_ENV, g_hEnv);
}// FreeEnv

57.ADO エクステンションでデータベース読み込み

ODBC 関数でデータベース読み込みと同じ設定を行う。
既に設定済みの場合は、必要なし。
ソースファイルは、cpp ファイルで、プロジェクトは、コンソールで作成する。
Win98, Me, 2000, Xp 専用。
SQL ステートメントには、GradYear も表示するように指示しているが、表示されないコードになっている。
#define INITGUID
#import "C:\Program Files\Common Files\System\ado\msado15.dll" \
        no_namespace rename("EOF", "EndOfFile") \
        exclude("RecordCreateOptionsEnum")
#include <stdio.h>
#include <icrsint.h>

void dump_com_error(_com_error &e)
{
    printf("Error\n");
    printf("\a\tCode = %08lx\n", e.Error());
    printf("\a\tCode meaning = %s", e.ErrorMessage());
    _bstr_t bstrSource(e.Source());
    _bstr_t bstrDescription(e.Description());
    printf("\a\tSource = %s\n", (LPCSTR) bstrSource);
    printf("\a\tDescription = %s\n", (LPCSTR) bstrDescription);
}

class CCustomRs : public CADORecordBinding
{
BEGIN_ADO_BINDING(CCustomRs)
    ADO_VARIABLE_LENGTH_ENTRY2(1, adVarChar, m_szau_lname, 
            sizeof(m_szau_lname), lau_lnameStatus, FALSE)
    ADO_VARIABLE_LENGTH_ENTRY2(2, adVarChar, m_szau_fname, 
            sizeof(m_szau_fname), lau_fnameStatus, TRUE)
END_ADO_BINDING()

public:
    CHAR    m_szau_lname[41];
    ULONG   lau_lnameStatus;
    CHAR    m_szau_fname[41];
    ULONG   lau_fnameStatus;
};

VOID main()
{
    HRESULT             hr;
    IADORecordBinding   *picRs = NULL;
    
    ::CoInitialize(NULL);
    try 
    {
        _RecordsetPtr   pRs;
        CCustomRs       rs;
        pRs.CreateInstance(__uuidof(Recordset));
        pRs->Open("select StudentID, Name, GradYear from STUDENT", 
            "dsn=Student Registration;uid=;pwd=;", 
            adOpenStatic, adLockOptimistic, adCmdUnknown);
        if (FAILED(hr = pRs->QueryInterface(__uuidof(IADORecordBinding), (LPVOID*)&picRs)))
            _com_issue_error(hr);
        if (FAILED(hr = picRs->BindToRecordset(&rs)))
            _com_issue_error(hr);
        while (VARIANT_FALSE == pRs->EndOfFile)
        {
            // Process data in the CCustomRs C++ instance variables.
            printf("\a\tName = %s \t%s\n", 
                (rs.lau_fnameStatus == adFldOK ? rs.m_szau_fname : "<NULL>"), 
                (rs.lau_lnameStatus == adFldOK ? rs.m_szau_lname : "<NULL>"));
            // Change the current row of the Recordset. 
            // Recordset data for the new current row will automatically be 
            // extracted and placed in the CCustomRs C++ instance variables.
            pRs->MoveNext();
        }
    }
    catch (_com_error &e)
    {
        dump_com_error(e);
    }
    if (picRs)
        picRs->Release();
    CoUninitialize();
};

58.デスクトップのサイズの取得

int width  = GetSystemMetrics(SM_CXSCREEN);
int height = GetSystemMetrics(SM_CYSCREEN);

// デスクトップのハンドルが欲しい場合は以下のような方法もある
HWND hDsktp = GetDesktopWindow();
RECT rcDsktp;
GetClientRect(hDsktp, &rcDsktp);

59.クリップボードを使ったファイルの Copy&Paste

 クリップボードにあるファイル名をテキストファイルに保存する。
 予め、ファイルやフォルダをコピーしてから、プログラムを実行する。

 クリップボードにファイル名を置く場合は、実行前にCドライブに
 1.txt と 2.txt を作成しておく。

#include <windows.h>
#include <stdio.h>
#include <shlobj.h>

// クリップボードからファイル名を取り出す
void Get_ClipBoard_HDROP()
{
    HANDLE      hMem = NULL;
    LPDROPFILES pDF = NULL;
    
    if(!OpenClipboard(NULL)){
        MessageBox(NULL,"クリップボードを開けません",MYWNDTITLE,MB_OK | MB_ICONWARNING);
        return;
    }
    hMem = (HANDLE) GetClipboardData (CF_HDROP);
    if(!hMem){
        MessageBox(NULL,"HDROP がありません",MYWNDTITLE,MB_OK | MB_ICONWARNING);
        return;
    }
    if(GlobalSize(hMem) <= sizeof(DROPFILES)){
        return;
    }
    pDF = (LPDROPFILES) GlobalLock (hMem);
    if(!pDF){
        MessageBox(NULL,"ロックできません",MYWNDTITLE,MB_OK | MB_ICONWARNING);
        return;
    }
    
    DWORD   offset          = pDF->pFiles;
    POINT   pt              = pDF->pt;
    BOOL    bNonClientArea  = pDF->fNC;
    BOOL    bUnicde         = pDF->fWide;
    DWORD   offset2 = 0;
    FILE    *file;
    
    if((file=fopen("DROPFILES.txt","w"))==NULL){
        MessageBox(NULL,"ファイルを開けません",MYWNDTITLE,MB_OK | MB_ICONWARNING);
        return;
    }
    fprintf(file,"offset:%d\nX:%d Y:%d\nbNonClientArea:%d\nbUnicde:%d\n"
                ,offset,pt.x,pt.y,bNonClientArea,bUnicde);
    char *pBuf = (char*) pDF + offset;
    if(!bUnicde){
        while(pBuf[offset2] != '\0'){
            fputs(pBuf + offset2,file);
            offset2 += (strlen(pBuf + offset2) + 1);
            fputc('\n',file);
        }
    }
    else{
        WCHAR *pBufW = (WCHAR*) pBuf;
        char filename[MAX_PATH];
        while(pBufW[offset2] != L'\0'){
            WideCharToMultiByte(CP_ACP, 0, pBufW + offset2, -1,
                                filename, sizeof(filename), NULL, NULL);
            fputs(filename ,file);
            offset2 += (wcslen(pBufW + offset2) + 1);
            fputc('\n',file);
        }
    }
    fclose(file);
    GlobalUnlock(pDF);
    CloseClipboard();
}// Get_ClipBoard_HDROP

// クリップボードにファイル名を置く
void Set_ClipBoard_HDROP()
{
    HANDLE      hMem = NULL;
    DROPFILES   df;
    LPBYTE      pBuf = NULL;
    char        filename[2][MAX_PATH] = {"C:\\1.txt","C:\\2.txt"};
    
    ZeroMemory(&df, sizeof(df));
    df.pFiles = sizeof(df);
    df.fWide = 0;
    if(GetFileAttributes(filename[0]) == -1){
        MessageBox(NULL,filename[0],"ファイルがありません",MB_OK | MB_ICONWARNING);
        return;
    }
    if(GetFileAttributes(filename[1]) == -1){
        MessageBox(NULL,filename[1],"ファイルがありません",MB_OK | MB_ICONWARNING);
        return;
    }
    if(OpenClipboard(NULL)){
        EmptyClipboard();
        int i,size;
        size = sizeof(df) + 1;
        for(i=0;i<2;i++){
            size += (strlen(filename[i]) + 1);
        }
        hMem = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, size);
        pBuf = (LPBYTE) GlobalLock(hMem);
        memcpy(pBuf, &df, sizeof(df));
        int offset = sizeof(df);
        for(i=0;i<2;i++){
            memcpy(pBuf + offset, filename[i], strlen(filename[i]) + 1);
            offset += (strlen(filename[i]) + 1);
        }
        memcpy(pBuf + offset, "", 1);
        SetClipboardData(CF_HDROP, hMem);
        GlobalUnlock(hMem);
        CloseClipboard();
    }
}// Set_ClipBoard_HDROP

int WINAPI WinMain(HINSTANCE hInst,HINSTANCE hInstPrev,LPSTR lpCmdLine,int nCmdShow)
{
    Get_ClipBoard_HDROP();
    return 0;
}// WinMain

60.指定されたフォルダを開く・ファイルを検索する

// 指定されたフォルダを開く
ShellExecute(hWnd, NULL, "C:\\WINDOWS", NULL, NULL, SW_SHOWNORMAL);
または
ShellExecute(hWnd, "explore", "C:\\WINDOWS", NULL, NULL, SW_SHOWNORMAL);


// 指定されたファイルを検索する
SearchPath( LPCTSTR lpPath,        // [in]  検索したいフォルダのパス名へのポインタ、またはNULL
            LPCTSTR lpFileName,    // [in]  ファイル名へのポインタ
            LPCTSTR lpExtension,   // [in]  拡張子へのポインタ(lpFileNameに拡張子がある場合はNULL。先頭に.を付ける)
            DWORD   nBufferLength, // [in]  lpBufferのサイズ
            LPTSTR  lpBuffer,      // [out] バッファへのポインタ(パスとファイル名が格納されるバッファ)
            LPTSTR  *lpFilePart    // [out] lpBuffer内のファイル名へのポインタを格納する変数へのポインタ
          )

61.ポップアップメニューのマウスキャプチャーの解除

ポップアップメニューのマウスキャプチャーを解除したい時は、
SetCapture() を先ず実行する

SetCapture(hWnd);
ReleaseCapture();



	

62.他のウィンドウに独自のメッセージを送る



#define PWM_1 WM_APP+1
HWND g_hChild = NULL;

int CALLBACK ProcWnd()
{
    switch (uMsg)
    {
    case WM_INITDIALOG:
        SendMessage(g_hChild,PWM_1,0,0);
        return 0;
    }
    return DefWindowProc();
}

int CALLBACK ProcChild()
{
    switch (uMsg)
    {
    case PWM_1:
        return 0;
    }
    return DefWindowProc();
}

63.WM_KEYDOWN でリピートを処理しない

キーが、押されっぱなしの状態のときは、処理したくない場合

LRESULT CALLBACK ProcWnd(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
  switch (uMsg)
  {
  case WM_KEYDOWN:
    if(!(lParam & 0x40000000)){  // リピートではない場合
      switch (wParam)
      {
      case VK_RETURN:  // Enterキー
        return 0;
      }
    }
    break;
  }
  return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

64.エラー表示

[ LINK : warning LNK4089: "???.dll" へのすべての参照は /OPT:REF によって廃棄されます ]

作っただけで呼び出されない関数がある場合に、表示されることがある。


[ Link Error LNK1104: Cannot Open File OLECLI32.LIB ]

MSDEV.EXE のリンクの設定を
OLECLI32.LIB → ole32.lib
OLESVR32.LIB → oleaut32.lib
に変更する。


[ Runtime Error! R6002 -floating point not loaded ]

scanf() や sscanf() で取得した浮動小数点数が、どこにも使われてない場合に発生するエラー

char  str1[] = "1.2 3.4 5.6 7.8";
float f1,f2,f3;
sscanf(str1, "%f %f %f", &f1, &f2, &f3);

これを以下のように変更する

float f1,f2,f3,f4,f5,f6;
sscanf(str1, "%f %f %f", &f4, &f5, &f6);
f1 = f4;
f2 = f5;
f3 = f6;