初版 2015/04/22

概要

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

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