イメージビューア2

DLLをつかう

前回のイメージビューアはビットマップしか表示できませんでした。
今回はjpegなどの圧縮画像も表示できるようにします。
ABでjpegを扱うには、自分で1からプログラムを書くという方法もあります。
でも、そんなことをするより先人の作ったDLLを使ったほうが賢い選択でしょう。
ルーチェ氏作のimgctlを使います。bmp,jpeg,gif,pngを簡単に扱える優れたDLLです。 べクターダウンロードページ

ABでDLLを使うには、DLLに含まれている関数のプロトタイプが分からなければいけません。
imgctlの説明はC言語なのでABに適宜翻訳しなければなりません。
Cの関数は以下のようになっています。
戻り値の型 関数名(引数の型 変数.....)
ABだと
Sub/Function 関数名(変数 As 引数の型.....) As 戻り値の型
型もABと名前が異なります。
ABC(Win32API)
Bytechar
Longint
Singlefloat
Doubledouble
DWordUINT
DWordDWORD
*ByteLPCSTR
*ByteLPSTR
LongBOOL
LongLPARAM
LongWPARAM
LPがつけばポインタです。LPVOID = VoidPtr
Hがつけば何かのハンドルです。ABに無い型はDWordでたぶん動くと思います。

imgctlには沢山の関数があります。今回は、ToDIB、DIBtoDC、HeadDIB、DeleteDIBの4つの関数を使います。
それぞれ、以下のようになっています。
HDIB ToDIB(LPCSTR lpImageFile)
BOOL DIBtoDC(HDC hdc, int nXDest, int nYDest, int nWidth, int nHeight,
HDIBC hDIB, int nXSrc, int nYSrc, DWORD dwRop)
BOOL HeadDIB(HDIBC hDIB, LPBITMAPINFOHEADER pbmih)
BOOL DeleteDIB(HDIB hDIB)
HDIBはCでもなんでもない独自の形です。*Byteです。
Typedef HDIB = *Byte
でHDIB型を定義しておきます。
これをABに変換します。
Function ToDIB(lpImageFile As *Byte) As *Byte
Function DIBtoDC(hdc As HDC, nXDest As Long, nYDest As Long, nWidth As Long, nHeight As Long , _
hDIB As HDIB, nXSrc As Long, nYSrc As Long, dwRop As DWord) As Long
Function HeadDIB( hDIB As HDIB, pbmih As *BITMAPINFOHEADER) As Long
Function DeleteDIB(hDIB As HDIB) As Long
これでABで使える関数の形になりました。
今度はDLLの関数であることを明記しなければなりません。
Declare と Lib "DLLファイル名" を追加します。
Declare Function ToDIB Lib"imgctl" (lpImageFile As *Byte) As *Byte
Declare Function DIBtoDC Lib"imgctl" (hdc As HDC, nXDest As Long, nYDest As Long, nWidth As Long, nHeight As Long , _
hDIB As HDIB, nXSrc As Long, nYSrc As Long, dwRop As DWord) As Long
Declare Function HeadDIB Lib"imgctl" ( hDIB As HDIB, pbmih As *BITMAPINFOHEADER) As Long
Declare Function DeleteDIB Lib"imgctl" (hDIB As HDIB) As Long
これで完了です。DLLから関数を呼び出せるようになりました。

'-----------------------------------------------------------------------------
'  イベント プロシージャ
'-----------------------------------------------------------------------------
' このファイルには、ウィンドウ [MainWnd] に関するイベントをコーディングします。
' ウィンドウ ハンドル: hMainWnd

' TODO: この位置にグローバルな変数、構造体、定数、関数を定義します。
'imgctl.dllインポート
Typedef HDIB = *Byte
Declare Function ToDIB Lib"imgctl" (pImageFile As *Byte) As HDIB
Declare Function DIBtoDC Lib"imgctl" ( hdc As HDC , _
        nXDest As Long, nYDest As Long, nWidth As Long, nHeight As Long,_
        hDIB As HDIB, nXSrc As Long, nYSrc As Long, dwRop As DWord) As Long
Declare Function HeadDIB Lib"imgctl" (hDIB As HDIB,ByRef pbmih As BITMAPINFOHEADER) As Long
Declare Function DeleteDIB Lib"imgctl" (hDib As HDIB) As Long

#include<vcrt71.sbp>
Dim hDspDC As HDC
Dim hDib As HDIB
Dim bmh As Long
Dim bmw As Long
'-----------------------------------------------------------------------------
' ウィンドウメッセージを処理するためのコールバック関数

Function MainWndProc(hWnd As HWND, dwMsg As DWord, wParam As WPARAM, lParam As LPARAM) As DWord
    ' TODO: この位置にウィンドウメッセージを処理するためのコードを記述します。

    ' イベントプロシージャの呼び出しを行います。
    MainWndProc=EventCall_MainWnd(hWnd,dwMsg,wParam,lParam)
End Function

'-----------------------------------------------------------------------------
' ここから下は、イベントプロシージャを記述するための領域になります。

'WM_DESTROY
Sub MainWnd_Destroy()
    DeleteDIB(hDib)
    ReleaseDC(hMainWnd , hDspDC)
    ImgVip_DestroyObjects()
    PostQuitMessage(0)
End Sub

'WM_CREATE
Sub MainWnd_Create(ByRef CreateStruct As CREATESTRUCT)
    hDspDC =GetDC(hMainWnd)
End Sub

'WM_PAINT
Sub MainWnd_Paint(hDC As HDC)
    DIBtoDC(hDC , 0,0,bmw,bmh,hDib , 0,0,SRCCOPY)
End Sub


'画像ファイルを開いてhBmpに描く
Sub OpenImg(filenam As *Byte)
    Dim WR As RECT, CR As RECT
    Dim dx As Long,dy As Long
    Dim bih As BITMAPINFOHEADER

    If hDib <> 0 Then DeleteDIB(hDib)

    hDib = ToDIB(filenam)
    HeadDIB(hDib , bih)
    bmh=bih.biHeight 
    bmw=bih.biWidth 

    'ウィンドウサイズとクライアント領域サイズの差を計算
    GetWindowRect(hMainWnd, WR)
    GetClientRect(hMainWnd, CR)
    dx = (WR.right - WR.left) - (CR.right - CR.left)
    dy = (WR.bottom - WR.top) - (CR.bottom - CR.top)
    
    'ウィンドウサイズをビットマップのサイズにあわせる
    MoveWindow(hMainWnd, WR.left, WR.top, bmw+dx ,bmh+dy, 1)

    MainWnd_Paint(hDspDC)
End Sub

'メニュー開く
Sub MainWnd_IDM_OPEN_MenuClick()
    Dim ofn As OPENFILENAME
    Dim file[MAX_PATH] As Byte
    ofn.hwndOwner = hMainWnd
    ofn.lStructSize = sizeof(OPENFILENAME)'
    ofn.lpstrFilter = Ex"画像ファイル(*.bmp;*.jpg;*.gif;*.png)\0*.bmp;*.jpg;*.gif;*.png\0全てのファイル\0*.*\0\0"
    ofn.nMaxFile = MAX_PATH
    ofn.lpstrFile = file
    GetOpenFileName(ofn)
    If file = NULL Then Exit Sub
    OpenImg(file)
End Sub

'メニュー終了
Sub MainWnd_IDM_EXIT_MenuClick()
    SendMessage(hMainWnd , WM_CLOSE , 0,0)
End Sub

'メニューバージョン情報
Sub MainWnd_IDM_ABOUT_MenuClick()
MessageBox(hMainWnd , _ 
    Ex"画像ビューア\nバージョン1.1\n画像表示はルーチェ氏のimgctl.dllを使っています。" , _
    "バージョン" , MB_OK)
End Sub

今回の完成品はこれです。