none
USB接続したデジカメの写真データにアクセスする方法を教えてください。 RRS feed

  • 質問

  • 使用環境は次のとおりです。  OS=Windows 7、開発環境=Visual Studio 2005 C++。 素人なもので、いくら探しても良く分かりません。ぜひ教えてください。

    デジカメ(ニコン D90、ファームウェアVer=1.00)をパソコンにUSB接続すると、エクスプローラではコンピュータの下に”D90”が表示され、これを開くと”リムーバブル記憶域”のホルダーが出てきます。さらにこれを開くと”DCIM”、さらに「カメラで設定した記録ホルダー」が表示され、ファイルセクションに「画像データのファイル名」が表示されます。

    エクスプローラ風のソフトを作っていますが、エクスプローラのように”D90”、”リムーバブル記憶域”、「カメラで設定した記録ホルダー」や「画像データのファイル名」を取得するにはどうすればよいでしょうか。そもそもデジカメにはドライブ文字がありませんので、画像データにアクセスする方法が皆目分からず、大変困っています。

    素人な質問だとは思いますが、お分かりの方、宜しく教授お願いします。

    2010年12月31日 2:04

回答

  • <その後>>>せっかくAzuleanさんからよいヒントをいただきましたが、残念ながらわが家のVisualStudio2005ではWindows API Code Pack のいずれのバージョンも利用できませんでした(残念)。このパッケージはVS2008以降が対象のようです。VS2005で解決する方法を是非お願いします。

    Windows API Code Pack は必要ありません。(そもそも ネイティブ C++ では使えません)
    あくまで私が試行錯誤する際に利用したに過ぎません。
    また、その後、C++ で試した際には Windows API Code Pack を利用しないコードです。
    (Shobjidl.h をインクルードして、CComPtr<IShellItem> など)

    IShellItem などが Shobjidl.h に定義されていれば、実現可能なはずです。
    ( http://msdn.microsoft.com/en-us/library/bb761144(v=vs.85).aspx )

    ただ、私が以前提示した手順のうち、SHGetKnownFolderIDList は Windows Vista 以降の API であるため、お手持ちの SDK に定義がないかもしれません。
    この部分は、SHGetSpecialFolderLocation 代用することになるかもしれません。


    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    2011年1月22日 1:17
    モデレータ

すべての返信

  • 良く分からないのですが、ニコンのD90がPCから見た時にどういう認識になっているかだと思います。

    たとえば、USB接続の大容量ストレージ扱いなら普通にパス指定すればアクセスできそうな気がします。
    但し、この場合は接続環境によってドライブレターが変わってしまうのでその部分をどう考えるかになりますね。

    外付けのストレージ扱いではない場合は、既にアドバイスを受けているような接続用のライブラリを通して
    アクセスする事になります。これを使ってアクセスする為にはそのライブラリの使い方をまず勉強する必要があります。
    VC++でのプログラミングに関しては知識があってライブラリの使い方だけを勉強すれば良いのであれば
    何とかなりそうに感じますが、VC++の勉強からはじめているのであれば、いきなり他のライブラリが必要になるような
    アプリに挑戦するのではなくてVC++の標準のライブラリの範囲で作成できるようなもので一度勉強した方が
    良いと思います。文章の内容からするとVC++でアプリを組む事自体は出来る前提で良いようにも読めますが、
    はっきりを書かれていないので念の為。

    あと、MFCに含まれないような機能を使いたい場合は、外部のライブラリを使って解決する必要があります。
    これらのライブラリに関してはMicrosoftから提供されているケースとハードウエアのメーカーから提供される
    ケースが有りますが、基本的にはヘッダーファイルを追加でインクルードする、リンク対象のライブラリに
    そのライブラリを追加すると言った作業が必要になります。

    この辺は実際にやって見て覚えた方が良いと思うので解説本かWeb上の情報を参考にやってみて下さい。

     


    解決した時は、参考になったレスポンスの所にある[回答としてマーク]ボタンをクリックしてスレッドを締めましょう。
    2011年1月6日 5:21
  • PATIOさん、ご教示大変ありがとうございます。

    以前のデジカメ、例えばニコンのD70などでは、ストレージはディレクトリの形式で保存でき、ドライブレターも認識できていたのですが、D90ではドライブレターそのものが認識できません。VC++は素人ながら一応のところは探れるレベルです。MFCでは解決できないのではないかと思っていまして、出口が見えません。

    2011年1月8日 14:15
  • エクスプローラー風のアプリケーションを作っていると言うことは、IShellFolder インターフェースを使っているのでしょうか?
    コンピューター(マイ コンピュータ)に対応する IShellFolder からそのドライブレターのないフォルダは見えるのでしょうか?

    # 現物を持っている人で知識・経験のある人にしか回答できないと思います。
    # 私は現物を持っていませんが。


    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    2011年1月9日 1:18
    モデレータ
  • Azuleanさん、お気遣い、大変有難うございます。

    ご質問の件、特殊フォルダーの取得などにIShellFolderを使用しています。使い方が悪いせいかもしれませんが、IShellFolderではデジカメの画像ファイルは検出できませんでした。そもそもデジカメの記憶域はドライブレターを持っていないようですので、お手上げ状態です。ちなみにエクスプローラではドライブレター無しに"D90"など、(カメラが提供していると思える)デバイスの名前が表示されます。カメラのファームウェアから情報を取得しているのかも知れません。Exif情報から攻める手も考えたのですが、うまく画像ファイル名を取得できませんでした。

    2011年1月9日 14:45
  • よくよく考えると、iPhone もドライブレターのない仮想フォルダを表示していますね。

    IShellFolderではデジカメの画像ファイルは検出できませんでした。

    SHGetDesktopFolder から BindToObject で攻めた場合、確かにドライブしか列挙されず、iPhone などは引っかかりません。
    (楽をするために)Windows API Code Pack のサンプル(C#)などをつつき回した結果、以下の手順で列挙に含まれることがわかりました。
    因果関係はよくわかりません。

    1.SHGetKnownFolderIDList(FOLDERID_ComputerFolder, ...) で ITEMIDLIST 取得。
    2.SHCreateShellItem で IShellItem を取得。
    3.BindToHandler(NULL, BHID_SFObject, IID_IShellFolder, ...) でコンピューターの IShellFolder を取得。
    4.あとは EnumObjects(NULL, SHCONTF_FOLDERS | SHCONTFS_NONFOLDERS, ...) あたりで列挙。

    2~3を SHGetDesktopFolder, BindToObject にしていると、なぜか列挙されません。
    その違いまでは未調査です。


    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    2011年1月9日 16:28
    モデレータ
  • Azuleanさん、貴重なヒントをありがとうございました。(返事が遅くなってすみません。)

    さっそくトライしてみたいと思います。ただ何分当方は初心者ですので、テストされたアプリのコードなど、さらにご教示いただければ感謝の極みです。どうぞ宜しくお願いします。

     

    <その後>>>せっかくAzuleanさんからよいヒントをいただきましたが、残念ながらわが家のVisualStudio2005ではWindows API Code Pack のいずれのバージョンも利用できませんでした(残念)。このパッケージはVS2008以降が対象のようです。VS2005で解決する方法を是非お願いします。

    2011年1月15日 3:15
  • VREさん、ご教示有難うございました。

    WIAを通して画像データにアクセスする方法についてはhttp://msdn.microsoft.com/ja-jp/library/7eh90ebz%28VS.100%29.aspxを参考にあれこれ挑戦してみました。しかし、デジカメの媒体にあるファイル(例えばニコンですとDSC-1001.JPG)をプログラムからアクセスする方法を得るには至りませんでした。

    デジカメのファイルにはドライブ名がありません。エクスプローラではルートディレクトリとしてカメラの機種名(ニコンですとD90など)が現れます。ちなみにファイルまでのパスはD90→リムーバブル記憶域→DCIM→DSC-1001.jpgとなっています。

    教えて頂きたいことは例えば、DSC-1001.jpgというファイルをデジカメからC:\Photoにコピーする方法なのですが、如何でしょうか。

    2011年1月21日 14:58
  • <その後>>>せっかくAzuleanさんからよいヒントをいただきましたが、残念ながらわが家のVisualStudio2005ではWindows API Code Pack のいずれのバージョンも利用できませんでした(残念)。このパッケージはVS2008以降が対象のようです。VS2005で解決する方法を是非お願いします。

    Windows API Code Pack は必要ありません。(そもそも ネイティブ C++ では使えません)
    あくまで私が試行錯誤する際に利用したに過ぎません。
    また、その後、C++ で試した際には Windows API Code Pack を利用しないコードです。
    (Shobjidl.h をインクルードして、CComPtr<IShellItem> など)

    IShellItem などが Shobjidl.h に定義されていれば、実現可能なはずです。
    ( http://msdn.microsoft.com/en-us/library/bb761144(v=vs.85).aspx )

    ただ、私が以前提示した手順のうち、SHGetKnownFolderIDList は Windows Vista 以降の API であるため、お手持ちの SDK に定義がないかもしれません。
    この部分は、SHGetSpecialFolderLocation 代用することになるかもしれません。


    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    2011年1月22日 1:17
    モデレータ
  • Azulean さん、ご丁寧にありがとうございました。

    アドバイス頂いた方法でトライしてみましたところ、「コンピュータ」以下のフォルダーを取得することができました。(大いに参考になりました)。しかし、USBにデジカメを接続しましたところ、USBに何かが接続されているとの情報は得られましたが、それ以上は得られませんでした。たぶんカメラのファームウェアなどから別の方法で情報の取得が必要なように思います。IExplorerBrowserなども含め、いろいろと試してみたいと思います。

    2011年1月30日 3:50
  • すでに解決されたようですが、知らない間にコメントを求められていたようですので、一応返信しておきます。

    先の返信で WIA でのハンドリングをお勧めしたのは、Windows ドライバ アーキテクチャにおいて、デジカメなどのイメージング デバイス内の記憶領域は、USB メモリなどの記憶領域とは全く異なる方法で認識されているため、通常のディスク アクセスと同等の処理では出来ないと思ったからです。

    たとえば、Windows PC に USB メモリを接続した場合は DiskDrive クラス デバイスとして認識されるので、そのディスク デバイスに対応するボリューム オブジェクト (汎用ボリューム) が生成されます。
    ボリューム オブジェクトが生成されることにより、マウント マネージャがそのボリュームに対してドライブ レター(のシンボリック リンク)を割り当てるので、最終的にドライブ レター ベースでのアクセスが可能になるわけです。

    一方、デジカメなどのイメージング デバイスは MTP (Media Transfer Protocol) で通信を行うWPD デバイスとして認識されます。
    確認したことはありませんが、モバイル デバイスなんかも WPD デバイスとして認識されたはずです。
    (厳密には USB メモリも WPD デバイスとして「も」認識されますが、話が複雑になるので割愛します。)
    つまり、WPD デバイスとしてのみ認識されるデバイスでは、ボリューム オブジェクトは生成されません。
    ですので、低レベルでの I/O を考えた場合、ドライブ レター ベースと同じ方法でのアクセスは当然できない訳です。
    (ちなみに、WPD デバイス内の記憶領域へのアクセスには USBStor.sys ドライバは使用されないようです。)

    つまり、シングルハンドさんがご要望されている機能を実現しようと考えた場合、WPD デバイスとしてオープンしてその中の記憶領域にアクセスしないとストレージ内のデータは読み取れない訳ですが、Shell Function などのインターフェースではボリューム オブジェクト(汎用ボリューム)を前提とした実装しか行われていないだろう。。。という誤った先入観があったため、汎用ボリュームと同等の処理では実現出来ないだろう。。。と思ったい次第です。
    で、WIA を使えば WPD デバイスとしてアクセスするための処理の一部を肩代わりしてくれるなずなので、先の返信で WIA をご提案させていただいたわけです。

    結果的には Shell Function での実装で出来たようですので、私の認識が間違っていた。。。ということですね。
    誤った先入観での返信をしてしまい、大変申し訳ありませんでした。
    この場をお借りして、お詫びさせていただきます。

    2011年3月25日 15:29