現在 Jpeg画像ファイルプロパティの概要のタイトルや作成者 等を 読み込んだり、書き込んだりするプログラムを作成中です。 IPropertySetStorage などを使用して作成しております。しかしながら
hr = pPropSetStg->Open( FMTID_DocSummaryInformation, STGM_READ, &pPropStg );
で、AfxMessageBox( "pPropSetStg->Open 失敗" ); になってしまい 困っています。
開発環境は winXP pro、Visual C++6.0 です。
HRESULT hr;
IPropertySetStorage * pPropSetStg;
IPropertyStorage * pPropStg;
pPropSetStg = NULL;
hr = StgOpenStorageEx( L"c:/p01.jpg",
STGM_READ|STGM_SHARE_DENY_WRITE,
STGFMT_ANY,
0, NULL, NULL,
IID_IPropertySetStorage,
reinterpret_cast<void**>(&pPropSetStg) );
if ( hr == S_OK )
{
AfxMessageBox( "StgOpenStorageEx S_OK" );
pPropStg = NULL;
hr = pPropSetStg->Open( FMTID_SummaryInformation, STGM_READ | STGM_SHARE_DENY_WRITE, &pPropStg );
// ☆ここで S_OKになってくれません。
if ( hr == S_OK )
{
AfxMessageBox( "pPropSetStg->Open S_OK" );
}
else
{
AfxMessageBox( "pPropSetStg->Open 失敗" );
}
} // if ( hr == S_OK )
pPropSetStg->Release();
タイトルや作成者等であれば、DocSummaryInformationではなくSummaryInformationだと思います。
回答ありがとうございます。
FMTID_DocSummaryInformation
FMTID_SummaryInformation
FMTID_UserDefinedProperties
の 3つとも、S_OK になってくれません。
http://msdn2.microsoft.com/en-us/library/aa380387.aspx
に 掲載されているのは
// From uuidgen.exe:
const FMTID fmtid = { /* d170df2e-1117-11d2-aa01-00805ffe11b8 */
0xd170df2e,
0x1117,
0x11d2,
{0xaa, 0x01, 0x00, 0x80, 0x5f, 0xfe, 0x11, 0xb8}
};
で、上記3つに該当していないのを使っているようです。
試してみたところ、確かに失敗してしまいました。
> http://msdn2.microsoft.com/en-us/library/aa380387.aspx
> に 掲載されているのは
> 上記3つに該当していないのを使っているようです。
それは関係ありません。
そのサンプルでは、独自のプロパティセットを作って、その値を読み書きしています。
そのため、FMTID も独自のものを使っているのです。
結論から言うと、FMTID は SummaryInformation で合っています。
以下のコードでうまくいくかどうか試してみてください。
StgOpenStorageEx ではなく、CoCreateInstance を使っているのは、Windows XP から新たに採用された、SystemFileAssociations という関連付けの仕組みに、StgOpenStorageEx が対応していないためです。
そのため、StgOpenStorageEx が内部でやっているようなことを、手動でやっています。
以下の {eb9b1153-3b57-4e68-959a-a3266bc3d7fe} という CLSID はどこから出てきたかというと…
レジストリエディタで、HKEY_CLASSES_ROOT\.jpg を探します。
ここに、PerceivedType = image という値があるので、
HKEY_CLASSES_ROOT\SystemFileAssociations\image を見ます。
このファイルのための IPropertySetStorage を実装している DLL を探すため、その下の shellex\PropertyHandler を見ると、CLSID がわかります。
なお、実際の DLL は、
HKEY_CLASSES_ROOT\CLSID\{eb9b1153-3b57-4e68-959a-a3266bc3d7fe}\InProcServer32
の下に書かれている、shimgvw.dll でした。
もし、上記の手順をやってみて、DLL が見つからなかったら、また相談してください。
#include <windows.h>
#include <stdio.h>
#include <locale.h>
int _tmain()
{
setlocale( LC_ALL, "japanese" );
static DWORD const stgm =
STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_DIRECT;
HRESULT hr = CoInitialize( NULL );
IPropertySetStorage * ppss = NULL;
CLSID clsid = CLSID_NULL;
hr = CLSIDFromString( L"{eb9b1153-3b57-4e68-959a-a3266bc3d7fe}", &clsid );
IPersistFile * ppf = NULL;
hr = CoCreateInstance( clsid, NULL, CLSCTX_INPROC_SERVER, IID_IPersistFile, reinterpret_cast< void ** >( &ppf ) );
if( SUCCEEDED( hr ) )
{
hr = ppf->Load( L"C:\\p01.jpg", stgm );
if( SUCCEEDED( hr ) )
{
hr = ppf->QueryInterface(
IID_IPropertySetStorage, reinterpret_cast< void ** >( &ppss ) );
if( SUCCEEDED( hr ) )
{
IPropertyStorage * pps = NULL;
hr = ppss->Open( FMTID_SummaryInformation, stgm, &pps );
if( SUCCEEDED( hr ) )
{
PROPSPEC ps;
ps.ulKind = PRSPEC_PROPID;
ps.propid = PIDSI_COMMENTS;
PROPVARIANT pv;
PropVariantInit( &pv );
hr = pps->ReadMultiple( 1, &ps, &pv );
if( SUCCEEDED( hr ) )
{
switch( pv.vt )
{
case VT_LPSTR:
printf( "%s\n", pv.pszVal );
break;
case VT_LPWSTR:
wprintf( L"%s\n", pv.pwszVal );
break;
default:
printf( "Other Type : %d\n", pv.vt );
break;
}
PropVariantClear( &pv );
}
pps->Release();
}
ppss->Release();
}
}
ppf->Release();
}
CoUninitialize();
return 0;
}
ごめんなさい。一点訂正。
> int _tmain()
int main() です。
ありがとう ございました。上記のコードで コメントを表示させることができました。
これは、VC++6.0だから SetStgOpenStorageEx が対応していないのでしょうか? やはり 2005 を 購入しないと無理なのでしょうか?
それから、実際にマウスで右クリックして概要を編集する動作自体をVC++でコードを書くことはできるのでしょうか?(VBSなどを使って、概要を編集するフリーソフトもあるようなので)
できるでしょうね。
VBSでできるということは、そのためのインターフェイス(IDispatchの派生インターフェイス)が公開されているということです。
そいつをVC++から使ってやれば、同じことはできるはずです。
おそらく、VBSでは使えないがVC++からなら使える、IDispatchでないインターフェイスを使えば、もっと効率的にできると思いますが。
IPropertyStorage の方は、Genericクラスで
UsGetProperty,UsSetProperty をそれぞれ作成することで
タイトル、表題、作成者、キーワード、コメント を 編集することができました。 ありがとうございます。
また、別の方法も 検討中です。
SHELLEXECUTEINFO 辺りで 実現できそうな気がします。
これで、プロパティが表示されます。しかし、戻り値が 33以上らしいが
1 が 返ってきます。それでも プロパティダイアログがでてきます。
後は、それぞれのエディットボックスを編集してやればできそうなのですが
なかなか 値が取れそうで、とれません。実現、不可能なのでしょうか。
void CTest11Dlg::OnButton1()
{
// TODO: この位置にコントロール通知ハンドラ用のコードを追加してください
SHELLEXECUTEINFO shellinfo;
CString sfn;
int iret;
sfn = "e:/p01.jpg";
ZeroMemory( &shellinfo, sizeof(shellinfo) );
shellinfo.cbSize = sizeof(shellinfo);
shellinfo.fMask = SEE_MASK_INVOKEIDLIST;
shellinfo.hwnd = m_hWnd;
shellinfo.lpVerb = "properties";
shellinfo.lpFile = sfn;
//shellinfo.lpParameters = NULL;
//shellinfo.lpDirectory = NULL;
//shellinfo.nShow = SW_SHOWNORMAL;
iret = ShellExecuteEx( &shellinfo );
CString swk;
swk.Format( "%d", iret );
AfxMessageBox( swk );
}
#乗りかかった手前、一応返信しておきます。
IPropertySetStorage を使った方法ではご不満でしたでしょうか?
何か、プロパティページから取得したい理由がおありでしょうか?
個人的には、プロパティページから取得する方法を探究する気にはなれません。
個人的には、CFile::GetStatus で 簡単に入手できるものだと考えて開発していました。しかし、コードの量が想像と違うものだったのでもっと簡単なのがないかなと考えてShellの方も試してみたしだいです。
今、作成中のものは、
ActiveXコントロールの PhotoEditCtrl を 9つフォームビューに配置。
画像を開くフォルダをユーザーが決定 後、画像を見ながら タイトルからコメント まで を編集。
というような 内容のものです。
これがまた、OFFice の Home Style が インストールされているPCでないと、PhotoEditCtrl.dllがなくて 画像が表示されないのですが。
Jpeg画像の表示も、ネット等で検索すると大変コードを書かないと、実現できません。でも、PhotoEditCtrl.dll を使うと、メンバ変1つで
m_cMphoto1.Load( "ファイルフルパス" );
表示できるのでこちらを採用しました。
そのような経緯がありまして、今回のようなことになりました。
ご迷惑をおかけして、大変申し訳ございませんでした。
シャノンさん どうもありがとうございました。
また、時間ができれば アプリケーションを ブログで 発表したいと
思います。
ツイート | ![]() |