/* disp.c                      coded by isaku@pb4.so-net.ne.jp 2008
C言語/C++言語で OleLoadPicture を使って画像を表示する

●特徴
データは画像ファイルからと画像リソースからの両方に対応
形式は .jpg/.jpeg、.bmp、.gif に対応
内部では HBITMAP を経由して表示する
HBITMAP から画像の大きさを得る関数も用意してある

●関数の一覧
MakePict() : HGLOBAL から HBITMAP を作成する
ReadPict() : 画像ファイルから HBITMAP を作成する
LoadPict() : 画像リソースから HBITMAP を作成する
GetCx()    : HBITMAP の幅を取得する
GetCy()    : HBITMAP の高さを取得する
DispPict() : HBITMAP を指定位置に表示する
DispFile() : 画像ファイルを指定位置に表示する
DispRes()  : 画像リソースを指定位置に表示する

●関数の仕様
HBITMAP MakePict(HGLOBAL hGlbl,DWORD nSize)
HGLOBAL から HBITMAP を作成する( ReadPict(),LoadPict()の下請け )
hGlbl  : 移動可能なメモリ領域
nSize  : メモリ領域のバイト数
戻り値 : 失敗すると 0 になる。成功すると HBITMAP が返る


HBITMAP ReadPict(TCHAR*fname)
画像ファイルから HBITMAP を作成する
fname  : 画像のファイル名
戻り値 : 失敗すると 0 になる。成功すると HBITMAP が返る


HBITMAP LoadPict(TCHAR*res,TCHAR*type)
画像リソースから HBITMAP を作成する
res    : 画像リソースのID
type   : カスタムリソースのタイプ
戻り値 : 失敗すると 0 になる。成功すると HBITMAP が返る


int GetCx(HBITMAP hBit)
HBITMAP の幅を取得する
戻り値 : 幅


int GetCy(HBITMAP hBit)
HBITMAP の高さを取得する
戻り値 : 高さ


DWORD DispPict(HWND hwnd,HBITMAP hBit,int x,int y)
HBITMAP を指定位置に表示する
hwnd   : 表示先のウィンドウハンドル
hBit   : ビットマップハンドル
x,y    : 表示先での画像の左上の座標
戻り値 : 失敗すると 0 になる
         成功すると LOWORD が表示した幅を示し HIWORD が高さを示す


DWORD DispFile(HWND hwnd,TCHAR*fname,int x,int y)
画像ファイルを指定位置に表示する
hwnd   : 表示先のウィンドウハンドル
fname  : 画像のファイル名
x,y    : 表示先での画像の左上の座標
戻り値 : 失敗すると 0 になる
         成功すると LOWORD が表示した幅を示し HIWORD が高さを示す


DWORD DispRes(HWND hwnd,TCHAR*res,TCHAR*type,int x,int y)
画像リソースを指定位置に表示する
hwnd   : 表示先のウィンドウハンドル
res    : 画像リソースのID
type   : カスタムリソースのタイプ
x,y    : 表示先での画像の左上の座標
戻り値 : 失敗すると 0 になる
         成功すると LOWORD が表示した幅を示し HIWORD が高さを示す

●プログラムの例(超手抜きな画像ビューア)
#include <stdio.h>
#include "disp.c"
int main(void) {
    char fname[1028];
    for (;;) {
        printf("画像ファイル名を入力してください([ENTER]で終了) >");
        gets(fname); if (*fname==0) break;
        if (DispFile(GetForegroundWindow(),fname,0,0)==0)
             printf("ファイルを表示することができませんでした\n");
        else gets(fname);
    }
    return 0;
}

●コメント
DispFile() と DispRes() は使い方が簡単だが、毎回
OleLoadPicture() を呼び出すため非常に遅い。
同じ画像を何度も表示させるなら ReadPict() or LoadPict() で読み込んで
おいてから DispPict() で繰り返し表示させる方がずっと速い。
その際、使い終わったら DeleteObject() で開放するのを忘れずに。
*/

#include <olectl.h>

/*+------------------------------------------------------------+
 |HGLOBALからHBITMAPを作成する(ReadPict(),LoadPict()の下請け) |
 +------------------------------------------------------------+*/
HBITMAP MakePict(HGLOBAL hGlbl,DWORD nSize) {
    IPicture*iPict; IStream*iStrm; HBITMAP hBit=0; static GUID iid=
    {0x7BF80980,0xBF32,0x101A,{0x8B,0xBB,0,0xAA,0,0x30,0xC,0xAB}};
    CreateStreamOnHGlobal(hGlbl,TRUE,&iStrm);
#ifdef __cplusplus
    if (OleLoadPicture(iStrm,nSize,0,iid,(void**)&iPict)==S_OK) {
        iPict->get_Handle((OLE_HANDLE*)&hBit);
        hBit=(HBITMAP)CopyImage(hBit,IMAGE_BITMAP,0,0,0);
    }
    iStrm->Release(); iPict->Release();
#else
    if (OleLoadPicture(iStrm,nSize,0,&iid,(void**)&iPict)==S_OK) {
        iPict->lpVtbl->get_Handle(iPict,(OLE_HANDLE*)&hBit);
        hBit=CopyImage(hBit,IMAGE_BITMAP,0,0,0);
    }
    iStrm->lpVtbl->Release(iStrm); iPict->lpVtbl->Release(iPict);
#endif
    GlobalFree(hGlbl); return hBit;
}

/*+------------------------------------+
 |画像ファイルから HBITMAP を作成する |
 +------------------------------------+*/
HBITMAP ReadPict(TCHAR*fname) {
    HANDLE hFile; HGLOBAL hGlbl; DWORD nSize,nRead; int r;
    if (fname==0||*fname==0) return 0;
    hFile=CreateFile(fname,GENERIC_READ,0,0,OPEN_EXISTING,0,0);
    if (hFile==INVALID_HANDLE_VALUE) return 0;
    nSize=GetFileSize(hFile,0); hGlbl=GlobalAlloc(GHND,nSize);
    if (hGlbl==0) { CloseHandle(hFile); return 0; }
    r=ReadFile(hFile,GlobalLock(hGlbl),nSize,&nRead,0);
    CloseHandle(hFile);
    if (r==0) { GlobalFree(hGlbl); return 0; }
    GlobalUnlock(hGlbl); return MakePict(hGlbl,nSize);
}

/*+------------------------------------+
 |画像リソースから HBITMAP を作成する |
 +------------------------------------+*/
HBITMAP LoadPict(TCHAR*res,TCHAR*type) {
    HRSRC hFind; HGLOBAL hLoad,hGlbl; DWORD nSize;
    HMODULE hInst=GetModuleHandle(0);
    if ((hFind=FindResource(hInst,res,type))==0) return 0;
    if ((hLoad=LoadResource(hInst,hFind))==0) return 0;
    if ((nSize=SizeofResource(hInst,hFind))==0) return 0;
    if ((hGlbl=GlobalAlloc(GHND,nSize))==0) return 0;
    CopyMemory(GlobalLock(hGlbl),LockResource(hLoad),nSize);
    GlobalUnlock(hGlbl); return MakePict(hGlbl,nSize);
}

/*+----------------------+
 |HBITMAP の幅を取得する|
 +----------------------+*/
int GetCx(HBITMAP hBit)
{ BITMAP bi; GetObject(hBit,sizeof bi,&bi); return bi.bmWidth; }

/*+------------------------+
 |HBITMAP の高さを取得する|
 +------------------------+*/
int GetCy(HBITMAP hBit)
{ BITMAP bi; GetObject(hBit,sizeof bi,&bi); return bi.bmHeight; }

/*+----------------------------+
 |HBITMAP を指定位置に表示する|
 +----------------------------+*/
DWORD DispPict(HWND hwnd,HBITMAP hBit,int x,int y) {
    BITMAP bi; int cx,cy;
    HDC hdc=GetDC(hwnd),hdc2=CreateCompatibleDC(hdc);
    GetObject(hBit,sizeof bi,&bi); cx=bi.bmWidth; cy=bi.bmHeight;
    SelectObject(hdc2,hBit); BitBlt(hdc,x,y,cx,cy,hdc2,0,0,SRCCOPY);
    DeleteDC(hdc2); ReleaseDC(hwnd,hdc); return cx+(cy<<16);
}

/*+--------------------------------+
 |画像ファイルを指定位置に表示する|
 +--------------------------------+*/
DWORD DispFile(HWND hwnd,TCHAR*fname,int x,int y) {
    HBITMAP hBit=ReadPict(fname); DWORD r;
    if (hBit==0) return 0;
    r=DispPict(hwnd,hBit,x,y); DeleteObject(hBit); return r;
}

/*+--------------------------------+
 |画像リソースを指定位置に表示する|
 +--------------------------------+*/
DWORD DispRes(HWND hwnd,TCHAR*res,TCHAR*type,int x,int y) {
    HBITMAP hBit=LoadPict(res,type); DWORD r;
    if (hBit==0) return 0;
    r=DispPict(hwnd,hBit,x,y); DeleteObject(hBit); return r;
}