Jpeg画像ファイルプロパティの編集

解決


丸中太郎  2006-12-13 04:00:01  No: 63928

現在  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();


シャノン  2006-12-13 18:02:43  No: 63929

タイトルや作成者等であれば、DocSummaryInformationではなくSummaryInformationだと思います。


丸中太郎  2006-12-13 19:18:59  No: 63930

回答ありがとうございます。

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つに該当していないのを使っているようです。


シャノン  2006-12-13 22:29:36  No: 63931

試してみたところ、確かに失敗してしまいました。

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


シャノン  2006-12-13 22:32:53  No: 63932

ごめんなさい。一点訂正。

> int _tmain()

int main() です。


丸中太郎  2006-12-14 01:51:40  No: 63933

ありがとう  ございました。上記のコードで  コメントを表示させることができました。

これは、VC++6.0だから SetStgOpenStorageEx  が対応していないのでしょうか?  やはり  2005  を  購入しないと無理なのでしょうか?

それから、実際にマウスで右クリックして概要を編集する動作自体をVC++でコードを書くことはできるのでしょうか?(VBSなどを使って、概要を編集するフリーソフトもあるようなので)


シャノン  2006-12-14 05:04:11  No: 63934

できるでしょうね。
VBSでできるということは、そのためのインターフェイス(IDispatchの派生インターフェイス)が公開されているということです。
そいつをVC++から使ってやれば、同じことはできるはずです。
おそらく、VBSでは使えないがVC++からなら使える、IDispatchでないインターフェイスを使えば、もっと効率的にできると思いますが。


丸中太郎  2006-12-15 00:30:05  No: 63935

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

}


シャノン  2006-12-16 00:47:18  No: 63936

#乗りかかった手前、一応返信しておきます。

IPropertySetStorage を使った方法ではご不満でしたでしょうか?
何か、プロパティページから取得したい理由がおありでしょうか?
個人的には、プロパティページから取得する方法を探究する気にはなれません。


丸中太郎  2006-12-16 04:07:52  No: 63937

個人的には、CFile::GetStatus で  簡単に入手できるものだと考えて開発していました。しかし、コードの量が想像と違うものだったのでもっと簡単なのがないかなと考えてShellの方も試してみたしだいです。

今、作成中のものは、

ActiveXコントロールの PhotoEditCtrl  を  9つフォームビューに配置。
画像を開くフォルダをユーザーが決定  後、画像を見ながら  タイトルからコメント  まで  を編集。

というような  内容のものです。

これがまた、OFFice の Home Style  が  インストールされているPCでないと、PhotoEditCtrl.dllがなくて  画像が表示されないのですが。

Jpeg画像の表示も、ネット等で検索すると大変コードを書かないと、実現できません。でも、PhotoEditCtrl.dll  を使うと、メンバ変1つで
m_cMphoto1.Load(  "ファイルフルパス"  );
表示できるのでこちらを採用しました。

そのような経緯がありまして、今回のようなことになりました。

ご迷惑をおかけして、大変申し訳ございませんでした。


丸中太郎  URL  2007-01-06 22:28:32  No: 63938

シャノンさん  どうもありがとうございました。

また、時間ができれば  アプリケーションを  ブログで  発表したいと

思います。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加