概要

ドラッグ&ドロップされたWMAファイルのアルバムアートの表示および保存を行います。
WMAファイルよりWM_PICTUREを取り出し、そのイメージをメモリストリーム化しGDI+で表示を行います。

テスト環境

コンパイラ

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+の初期化をします。
その後ダイアログを表示します。
ダイアログが閉じられたら、GdiplusShutdownにより終了処理を実行します。

DlgProc1

ダイアログボックスの初期化時にDlgProc1関数にWM_INITDIALOGメッセージが発生するので、ドラッグ&ドロップを許可します。
ドラッグ&ドロップ
WMAファイルがドラッグ&ドロップされるとDlgProc1関数にWM_DROPFILESメッセージが発生するので、ファイル名を取得します。
ファイル名よりWMAファイルよりWM/Pictureプロパティを取得しそのアドレスとサイズからJpegイメージをメモリに取得します。
ファイルサイズ分のメモリをGlobalAlloc APIで確保しハンドルを取得します。その後メモリをロックし先頭のアドレスを取得します。
そのアドレスに先ほど読み込んだJpegイメージをコピーします。
メモリをストリームとして扱うため、CreateStreamOnHGlobal を実行しメモリストリームのハンドルを得ます。
Imageオブジェクトを作成し、それをDrawImageにより描画します。
WMAファイルにアルバムアートがない場合は、スタティックウィンドウを消去します。
画像保存ボタン
ボタンがクリックされると、DlgProc1関数にWM_COMMANDメッセージが発生するので、画像保存ボタンのメッセージの場合、保存ファイル名を取得するコモンダイアログボックスを表示します。ファイル名が取得できたらファイルを開き、メモリ上に保存されたWM_PICTUREを保存します。
OKボタン
ボタンがクリックされると、DlgProc1関数にWM_COMMANDメッセージが発生するので、OKボタンのメッセージの場合、終了します。

ソースコード

gwmaimg2.cpp

// ドラッグ&ドロップされたWMAファイルの画像を表示および保存する。

#include <windows.h>
#include <gdiplus.h>
#include <tchar.h>
#include <wmsdk.h>
#include <iostream>
#include "resource.h"

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


// 保存ファイル名の取得
BOOL GetSaveFileName(TCHAR* fname,int sz);

// ダイアログボックスのプロシージャー
LRESULT CALLBACK DlgProc1(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);	// ダイアログボックスのプロシージャー

// WMAファイルのタイトル・画像を取得する
bool wma_title_get(IWMMetadataEditor* pEditor,TCHAR* fname,WM_PICTURE** pP,int* sz);

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


int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPreInst,TCHAR* lpszCmdLine, int nCmdShow){
	GdiplusStartup(&gdiToken, &gdiSI, NULL);
	DialogBox(hInstance, TEXT("DLG1"), 0, (DLGPROC)DlgProc1);
	GdiplusShutdown(gdiToken);
	return 0;
}

// ダイアログボックスのプロシージャー

LRESULT CALLBACK DlgProc1(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam){
	TCHAR buf[MAX_PATH];
	HDROP hDrop;
	UINT fmax;
	HRESULT hr;
	IWMMetadataEditor* pEditor=NULL;
	static HGLOBAL hBuf=0;
	static IStream* pIStream=0;
	static BYTE* jpg_mem=0;
	static WM_PICTURE* pP;
	static int sz;
	HDC hdc;
	FILE* fp;
	int	i;
	switch (msg) {
		case WM_INITDIALOG:
			::hDlg=hDlg;
			DragAcceptFiles(hDlg, TRUE);
			return TRUE;
		case WM_DROPFILES:
			if(jpg_mem){
				jpg_mem=0;
				pIStream->Release();
				GlobalFree(hBuf);
				hBuf=0;
				sz=0;
				pIStream=0;
				pP=0;
			}
			hDrop = (HDROP)wParam;
			fmax = DragQueryFile((HDROP)wParam, 0xFFFFFFFF, NULL, 0);
			i=fmax-1;
			DragQueryFile(hDrop, i, buf, sizeof(buf)/sizeof(TCHAR));
			SetWindowText(GetDlgItem(hDlg,IDC_EDIT1),buf);
			DragFinish(hDrop);
			hr=WMCreateEditor(&pEditor);	// オブジェクトを作成
			if(wma_title_get(pEditor,buf,&pP,&sz)==true){
				hBuf=GlobalAlloc(GMEM_MOVEABLE,pP->dwDataLen);
				if(hBuf==0){
					MessageBox(0,_TEXT("GlobalAlloc APIでのメモリの確保に失敗しました"),_TEXT("エラー"),MB_OK);
					break;
				}
				jpg_mem=(BYTE*)GlobalLock(hBuf);
				if(jpg_mem==0){
					MessageBox(0,_TEXT("GlobalLock APIでのメモリのロックに失敗しました"),_TEXT("エラー"),MB_OK);
				}
				pIStream=0;
				sz=pP->dwDataLen;
				CopyMemory(jpg_mem,pP->pbData,sz);
				delete [] pP;
				if(CreateStreamOnHGlobal(hBuf,FALSE,&pIStream)!=S_OK){
					MessageBox(0,_TEXT("CreateStreamOnHGlobal APIでのメモリストリームの作成に失敗しました"),_TEXT("エラー"),MB_OK);
				}
				if(jpg_mem){
					HWND hS=GetDlgItem(hDlg,IDC_STATIC100);
					RECT rect;
					GetWindowRect(hS,&rect);
					int sx=rect.right-rect.left;
					int sy=rect.bottom-rect.top;
					float sa=float(sx)/float(sy);
					hdc = GetDC(hS);
					Graphics MyGraphics(hdc);
					Image myImage(pIStream);

					_stprintf_s(buf,sizeof(buf)/sizeof(TCHAR),_TEXT("%i*%i"),myImage.GetWidth(),myImage.GetHeight());
					SetWindowText(GetDlgItem(hDlg,IDC_LABEL2),buf);

					_stprintf_s(buf,sizeof(buf)/sizeof(TCHAR),_TEXT("%iBytes"),sz);
					SetWindowText(GetDlgItem(hDlg,IDC_LABEL3),buf);

					float pas=float(myImage.GetWidth())/float(myImage.GetHeight());
					if(sa>pas){	//	ウィンドウのほうが横長の場合
						float ssx=sy*pas;
						MyGraphics.DrawImage(&myImage, int((sx-ssx)/2), 0,int(ssx),sy);
					}else{
						float ssy=sx/pas;
						MyGraphics.DrawImage(&myImage, 0, int((sy-ssy)/2),sx,int(ssy));
					}
					ReleaseDC(hS, hdc);
				}
			}else{	//	アルバムアートがない場合
				SetWindowText(GetDlgItem(hDlg,IDC_LABEL2),_TEXT(""));
				SetWindowText(GetDlgItem(hDlg,IDC_LABEL3),_TEXT(""));

				HWND hS=GetDlgItem(hDlg,IDC_STATIC100);
				RECT rect;
				GetWindowRect(hS,&rect);
				int sx=rect.right-rect.left;
				int sy=rect.bottom-rect.top;
				HPEN hPen, hOldPen;
				HBRUSH hBrush, hOldBrush;
				hdc = GetDC(hS);
				hPen = CreatePen(PS_SOLID, 1, RGB(255, 255, 255));
				hOldPen = (HPEN)SelectObject(hdc, hPen);
				hBrush = CreateHatchBrush(BS_SOLID, RGB(255, 255, 255));
				hOldBrush = (HBRUSH)SelectObject(hdc, hBrush);
				Rectangle(hdc, 0, 0, sx, sy);
				SelectObject(hdc, hOldPen);
				SelectObject(hdc, hOldBrush);
				DeleteObject(hPen);
				DeleteObject(hBrush);

				ReleaseDC(hS, hdc);
			}
		case WM_COMMAND:
			switch (LOWORD(wParam)) {
				case IDOK:
					EndDialog(hDlg,FALSE);
					return TRUE;
				case IDC_SAVE:
					if(jpg_mem){
						if(GetSaveFileName(buf,sizeof(buf)/sizeof(TCHAR)))
							if(_tfopen_s(&fp,buf,_TEXT("wb"))==0){
								fwrite(jpg_mem,sizeof(BYTE),sz,fp);
								fclose(fp);
							}
					}
					return TRUE;
				default:
					return FALSE;
			}
			default:
				return FALSE;
	}
	return TRUE;
}

// 保存ファイル名の取得

BOOL GetSaveFileName(TCHAR* fname,int sz){
	OPENFILENAME o;
	fname[0]=_T('\0');
	ZeroMemory(&o,sizeof(o));
	o.lStructSize=sizeof(o);
	o.Flags=0;
	o.lpstrFile=fname;
	o.nMaxFile=sz;
	o.lpstrFilter=_TEXT("JPEG(*.JPG)\0");
	o.nFilterIndex=1;
	return GetSaveFileName(&o);
}


// WMAファイルのタイトル・画像を取得する

bool wma_title_get(IWMMetadataEditor* pEditor,TCHAR* fname,WM_PICTURE** pP,int* sz){

	bool flag=false;
	HRESULT hr;
	IWMHeaderInfo3* pHeaderInfo=NULL;

	hr=pEditor->Open(fname);
	pEditor->QueryInterface(IID_IWMHeaderInfo3,(void**)&pHeaderInfo);

	WORD wStreamNum = 0;
	WMT_ATTR_DATATYPE Type;
	WORD cbLength=0;

	TCHAR* getname;
	TCHAR pwszTitle[1024];
	*pP=0;

	Type=WMT_TYPE_STRING;
	getname=_TEXT("Title");
	//	タイトルの文字数を取得
	hr=pHeaderInfo->GetAttributeByName(&wStreamNum,getname,&Type, NULL, &cbLength );
	hr = pHeaderInfo->GetAttributeByName( &wStreamNum, getname, &Type,(BYTE *) pwszTitle, &cbLength );

	SetWindowText(GetDlgItem(hDlg,IDC_LABEL1),pwszTitle);

	Type=WMT_TYPE_BINARY;
	getname=(TCHAR*)g_wszWMPicture;

	//	タイトルの文字数を取得
	hr=pHeaderInfo->GetAttributeByName(&wStreamNum,getname,&Type, NULL, &cbLength );
	*sz=cbLength;
	if( ! FAILED(hr)){
		if( cbLength){
		//	タイトルを取得
			*pP=(WM_PICTURE*) new BYTE[cbLength];
			hr = pHeaderInfo->GetAttributeByName( &wStreamNum, getname, &Type,(BYTE *) *pP, &cbLength );
			if(! FAILED(hr)){
				flag=true;
			}
		}
	}
	pEditor->Close();
	return flag;
}

resource.h

#define IDC_STATIC100 2001
#define IDC_EDIT1 2002
#define IDC_LABEL1 2003
#define IDC_LABEL2 2004
#define IDC_LABEL3 2005
#define IDC_SAVE 2006

resource.rc

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


DLG1 DIALOG DISCARDABLE  0, 0, 174, 198
STYLE DS_MODALFRAME | WS_POPUP
CAPTION "WMAファイル画像表示"
FONT 9, "MS Pゴシック"
BEGIN
	LTEXT			"ここへファイルをドラッグドロップしてください",-1,7,7,168,10
	CONTROL "", IDC_EDIT1, "EDIT", WS_CHILD | WS_DLGFRAME | WS_VISIBLE | ES_AUTOHSCROLL, 7, 26, 160, 16
	LTEXT	"",IDC_LABEL1,7,49,160,24

	CONTROL "", IDC_STATIC100, "STATIC", WS_CHILD | WS_VISIBLE | SS_SUNKEN | SS_NOTIFY, 7, 80, 90, 90
	LTEXT	"",IDC_LABEL2,110,82,57,10
	LTEXT	"",IDC_LABEL3,110,99,57,10

	DEFPUSHBUTTON	"OK(&O)",IDOK,4,177,50,14
	PUSHBUTTON	"画像保存(&S)",IDC_SAVE,62,177,50,14
END

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