メモリ上に読み込まれたjpgファイルのイメージをGDI+でウィンドウに表示する標準的なソース(32/64bit)

icon 項目のみ表示/展開表示の切り替え

概要

EXEファイルと同一フォルダーにあるimage.jpgファイルをfreadでメモリ上に読み込んだJpegファイルのイメージをメモリストリームに変換しGDI+で描画するプログラムです。
使用例としては、WMAファイルなどJpegファイルのイメージがそのままファイルに取り込まれている場合、そのイメージをメモリに取り込めば表示が可能となります。

テスト環境

コンパイラ

Visual C++ 2008/2013 Express 32/64bit マルチバイト/UNICODE

実行環境

Windows XP Professional Service Pack 3 32bit(Virtual Box上の仮想マシーン)
Windows 7 Enterprise Service Pack 1 64bit

動作例

プログラムソースの概要

jpgviewmem.cpp

_tWinMain

GdiplusStartupによりGDI+の初期化をします。
その後Windowを作成します。
Windowが閉じられたら、GdiplusShutdownにより終了処理を実行します。

WndProc

ウィンドウの初期化時にWndProc関数にWM_CREATEメッセージが発生するので、image.jpgをfopenで開き、ファイルサイズを調べサイズをszに保存します。ファイルサイズ分のメモリをGlobalAlloc APIで確保しハンドルを取得します。その後メモリをロックし先頭のアドレスを取得します。そのアドレスにfread関数でファイルを読み込みます。メモリをストリームとして扱うため、CreateStreamOnHGlobal を実行しメモリストリームのハンドルを得ます。
画面の更新が必要な時にWM_PAINTメッセージが発生します。メッセージ発生時にストリームよりImageオブジェクトを作成し、それをDrawImageにより描画します。

ソースコード

jpgviewmem.cpp

//       メモリ上に読み込まれたjpgファイルのイメージををGDI+でウィンドウに表示する標準的なソース
//      Visual C++ 2008/2013 Express

#include <windows.h>
#include <gdiplus.h>
#include <tchar.h>
#include <iostream>

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


//      表示するファイル名指定

//TCHAR* szFile=TEXT("D:\\docu\\documents\\data\\program\\vc2013\\jpgviewmem\\Debug\\image.JPG");
TCHAR* szFile=TEXT("image.jpg");

using namespace Gdiplus;
GdiplusStartupInput     gdiSI;
ULONG_PTR       gdiToken;

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
BOOL InitApp(HINSTANCE, WNDPROC, TCHAR*);
BOOL InitInstance(HINSTANCE, TCHAR*, int);
HWND hWnd;

// 最初に呼び出される関数

int WINAPI _tWinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst,TCHAR* lpsCmdLine, int nCmdShow){
        MSG msg;
        BOOL b;
        TCHAR szClassName[] = TEXT("jpg_view");
        GdiplusStartup(&gdiToken, &gdiSI, NULL);
        if(!hPrevInst){
                if(!InitApp(hCurInst,WndProc, szClassName))     // ウィンドウクラスの登録
                        return FALSE;
        }
        if (!InitInstance(hCurInst, szClassName, nCmdShow))     { // ウィンドウの作成
                return FALSE;
        }

// 見慣れないメッセージループだがエラーの場合-1が返る場合があるのでこのように記述
// MSDNを見てください。

        while ((b=GetMessage(&msg, NULL, NULL, NULL))!=0 && b!=-1) {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
        }
        GdiplusShutdown(gdiToken);

        return (int)msg.wParam;
}

// ウィンドウを作成/閉じる/移動等のメッセージにより起動される関数


LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp){
        HDC hdc;
        PAINTSTRUCT ps;
        static BYTE* jpg_mem=0;
        FILE* fp;
        static unsigned long sz;
        static HGLOBAL hBuf;
        static IStream* pIStream;
        switch (msg) {
        case WM_CREATE:
                if(_tfopen_s(&fp,szFile,_TEXT("rb"))){
                        MessageBox(0,_TEXT("ファイルが開けません"),_TEXT("エラー"),MB_OK);
                        PostQuitMessage(0);
                }
                fseek(fp,0,SEEK_END);
                sz=ftell(fp);
                fseek(fp,0,SEEK_SET);
                hBuf=GlobalAlloc(GMEM_MOVEABLE,sz);
                if(hBuf==0){
                        MessageBox(0,_TEXT("GlobalAlloc APIでのメモリの確保に失敗しました"),_TEXT("エラー"),MB_OK);
                        fclose(fp);
                        PostQuitMessage(0);
                }
                jpg_mem=(BYTE*)GlobalLock(hBuf);
                if(jpg_mem==0){
                        MessageBox(0,_TEXT("GlobalLock APIでのメモリのロックに失敗しました"),_TEXT("エラー"),MB_OK);
                        fclose(fp);
                        PostQuitMessage(0);
                }
                fread(jpg_mem,sizeof(BYTE),sz,fp);
                fclose(fp);
                pIStream=0;
                if(CreateStreamOnHGlobal(hBuf,FALSE,&pIStream)!=S_OK){
                        MessageBox(0,_TEXT("CreateStreamOnHGlobal APIでのメモリストリームの作成に失敗しました"),_TEXT("エラー"),MB_OK);
                        GlobalFree(hBuf);
                        PostQuitMessage(0);
                }
                break;
        case WM_PAINT: {        // ウィンドウの描画が必要な場合に呼び出される。
                hdc = BeginPaint(hWnd, &ps);
                Graphics MyGraphics(hdc);
                Image myImage(pIStream);
                MyGraphics.DrawImage(&myImage, 0, 0);
                EndPaint(hWnd, &ps);
                break;
        }
        case WM_DESTROY:        // ウィンドウを閉じる場合に呼び出される。
                GlobalFree(hBuf);
                PostQuitMessage(0);
                break;
        default:
                return (DefWindowProc(hWnd, msg, wp, lp));
        }
        return 0L;
}

//      ウィンドウクラスの登録 1回しか呼ばれないのに関数化しているのは、ウィンドウを2回呼び出す場合に
//      この関数を再利用できるからです。

BOOL InitApp(HINSTANCE hInst,WNDPROC WndProc,TCHAR* szClassName){
        WNDCLASS wc;
        wc.style = CS_HREDRAW | CS_VREDRAW;
        wc.lpfnWndProc = WndProc;
        wc.cbClsExtra = 0;
        wc.cbWndExtra = 0;
        wc.hInstance = hInst;
        wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
        wc.hCursor = LoadCursor(NULL, IDC_ARROW);
        wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
        wc.lpszMenuName = NULL;
        wc.lpszClassName = (TCHAR*)szClassName;
        return (RegisterClass(&wc));
}

//      ウィンドウの作成 1回しか呼ばれないのに関数化しているのは、ウィンドウを2回呼び出す場合に
//      この関数を再利用できるからです。

BOOL InitInstance(HINSTANCE hInst, TCHAR* szClassName, int nCmdShow){
        hWnd = CreateWindow(szClassName,
                        TEXT("GDI+ Sample"),
                        WS_OVERLAPPEDWINDOW,
                        CW_USEDEFAULT,
                        CW_USEDEFAULT,
                        CW_USEDEFAULT,
                        CW_USEDEFAULT,
                        NULL,
                        NULL,
                        hInst,
                        NULL);
        if (!hWnd)
                return FALSE;
        ShowWindow(hWnd, nCmdShow);
        UpdateWindow(hWnd);
        return TRUE;
}

実行ファイルとソースファイルのダウンロード