こんにちは。
WinXP/Visual Studio 2008 SP1/C++/MFC にてアプリケーションを作成しております。
現在 IMAPI v1 を利用して指定したディレクトリ以下の全てのディレクトリとファイルを
CD-Rに書き込む部分を作成しております。
書き込み自体は意図した通りに問題なく動作しているようですが、一つ大きな問題に当
たってしまいました。
「32バイト以上のディレクトリ/ファイル名で書き込めない」
というものです。
IMAPIの制限というよりは、IJolietDiscMaster::AddData()に渡すIStorage/IStreamの「名前
」の文字数制限に引っかかってしまうためです。
エクスプローラでのCD書込みウィザードでは長いファイル名であっても書込みが可能なの
ですが...
開発環境が、XP/SP3 なので IMAPI v2 だからなのかもしれません。(とはいえv2はまだ
調べてないのですが)
IMAPI v1 で長いディレクトリ/ファイル名を利用する方法をご存じないでしょうか?
宜しくお願いいたします。
IMAPI v1 では Joliet しか使えません(ISO 9660 はオーディオ CD しかサポートしてい
ません)。
で、Joliet でも ISO 9660 でも、ファイル名に使えるのは最大 32 文字までです。
Wikipedia
http://ja.wikipedia.org/wiki/Joliet_(%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%
B7%E3%82%B9%E3%83%86%E3%83%A0)#Joliet
には 64 文字まで可能と書いてありますが、MSDN
http://msdn.microsoft.com/en-us/library/aa364836.aspx
には 32 文字までとあります。どっちが正しいんでしょうね?
まぁ、そんなわけですので、IStorage の制限をどうにか回避しても、ファイルシステム
の問題で無理なんじゃないでしょうか。
IMAPI v2 なら、UDF がサポートされますし、IStorage を使わなくなっていますから、可
能なんじゃないでしょうか。
aetosさん、ありがとうございます。
Jolietでも32文字なんですか...てっきり128文字と思い込んでおりました。
ただ、「CD書込みウィザード」では50文字くらいのファイル名を作成できましたので64文
字といったところでしょうか。
v2 を使う方向で検討してみます。
v1 はたまたまサンプルが WEB にあったのと、各インターフェースのメソッドが少ないこ
ともあって楽だったのですが、v2 はまだ各インターフェースの関係すらよくできていな
い状況です。
ご助言ありがとうございました。
XP では、IMAPI v2 が勝手にインストールされることはありません。
以下の修正プログラム
http://www.microsoft.com/downloads/details.aspx?
displaylang=ja&FamilyID=b5f726f1-4ace-455d-bad7-abc4dd2f147b
をインストールしない限り、XP SP3 でも IMAPI v2 は使えません。
で、v2 がインストールされていないことを確認した XP SP3 で試してみましたが、どう
やら 64 文字まで可能なようですね。
さて、ファイル名の上限が 32 文字というのは、どのようなコードを書いてのことでしょ
う?
このページ
http://forums.microsoft.com/msdn/ShowPost.aspx?PostID=2409363&SiteID=1
のコードを参考にして、IShellFolder::BindToStorage で作った IStorage は、64 文字
以上のストリームを持つこともできました(手元にブランクメディアがないので、実際に
書き込めるかどうかは試していません)。
まぁ、IStorage 自体に 31 文字という制限が明記されている以上、それより長い名前を
受け付ける実装は望ましくないのですが。
IMAPI v2 では IStorage を使わなくなった理由のうちには、そのあたりもありそうで
す。
参考までに、俺が書いたコードを載せておきます。
HRESULT CreateDirectoryStorage(
LPCWSTR pszDirectory,
IStorage ** pStorage
)
{
if( pStorage == NULL )
{
return E_POINTER;
}
*pStorage = NULL;
if( pszDirectory == NULL )
{
return E_INVALIDARG;
}
IShellFolder * psfDesktop = NULL;
HRESULT hr = SHGetDesktopFolder( &psfDesktop );
if( FAILED( hr ) )
{
return hr;
}
LPITEMIDLIST pidl = NULL;
hr = SHParseDisplayName( pszDirectory, NULL, &pidl, 0, NULL );
if( SUCCEEDED( hr ) )
{
hr = psfDesktop->BindToStorage( pidl, NULL, IID_IStorage,
reinterpret_cast< LPVOID * >( pStorage ) );
ILFree( pidl );
}
psfDesktop->Release();
return hr;
}
aetosさん
ご返答ありがとうございます。ほぼ諦めていたもので返信を頂いていたことに気づかず申
し訳ございません。
確かに XP SP2 以降であっても別途インストールしないといけないようですね。
ご質問頂いた、IStorage、IStream の作成については、以下のように行っておりま
す。(抜粋)
1. CD のルートストレージ作成
CComPtr<IStorage> pStorage;
hResult = ::StgCreateStorageEx(
NULL,
STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE | TGM_DELETEONRELEASE,
STGFMT_STORAGE,
0,
NULL,
NULL,
IID_IStorage,
reinterpret_cast<void**>(&pStorage));
2. ルートストレージにハードディスク内のフォルダ構成と同じようにIStorage/IStream
を再帰的に作成
・IStorageにサブディレクトリ(IStorage)を作成
CComPtr<IStorage> pStorage; ← 親ディレクトリに当たるIStorage
CComPtr<IStorage> pNewStorage; ← 作成するサブディレクトリに当たるIStorage
hResult = pStorage->CreateStorage([長いディレクトリ名], STGM_READWRITE |
STGM_SHARE_EXCLUSIVE, 0, 0, &pNewStorage);
・IStorageにファイル(IStream)を作成
CComPtr<IStorage> pStorage; ← 親ディレクトリに当たるIStorage
CComPtr<IStream> pNewStream; ← 作成するファイルに当たるIStream
hResult = pStorage->CreateStream([長いファイル名], STGM_READWRITE |
STGM_SHARE_EXCLUSIVE, 0, 0, &pNewStream);
名前が31バイトを超えると、HRESULT=0x800300fc(名前%1は無効です)というエラーに
なってしまうのです。
IStorageやIStreamの他の作り方もあるのでしょうか。
> IStorageやIStreamの他の作り方もあるのでしょうか。
俺がそのサンプルを書いたつもりですが…
(書き込みがうまくいくかどうかまでは検証していません。とりあえずディレクトリか
ら IStorage を作ることはできました)
aetosさん
すみません。Shellのインターフェースをよく理解していないもので...提示頂いた
ソースをおぼろげにしか理解できておりませんでした。
勉強します。
もっともドキュメント上で 31文字以下と記されているのでそこは自己責任になりますが。
aetos様
ようやくご提示頂いたソースの意味が理解できました。言い訳にしかなりませんが、以前
シェルの何かのインターフェースでBindToStorageは使ったことがあったのですが全く意
味がわかっておりませんでした。(サンプルを真似しただけ)
今回IMAPIを使ってみるに当たってようやくIStorageって何なのかが理解できた次第です。
さて、おっしゃるとおりの方法で 31バイト以上の名前の IStorage が作成可能であるこ
とを確認しました。
同様にIShellFolder::BindToObject()でIStreamも作成可能であることがわかりました。
32文字以上の名前はつけられないと言いつつ、このような正規の方法でそのような名前の
IStorage/IStreamが作成できるということは、IStorage::CreateStorage()
/CreateStream()の制限ということでしょうか(変な話ですが)。
ありがとうございます。作るだけはこの方法で作ってみます。実際に使うかは別途考えます。
IMAPI v1 では DVD-R は利用できないようなのでいずれはIMAPI v2 バージョンも作成し
ようと思います。
余談ですが、気分的にシェルのインターフェースってオーバーヘッドが大きそうで、用途
によりますが敬遠しがちになってしまいます。(全く根拠はありません。気分だけです。)
> IStorage::CreateStorage()
> /CreateStream()の制限ということでしょうか(変な話ですが)。
シェル経由で取得した IStorage インターフェイスを使って CreateStream を呼び出す
と、32 文字を超える名前のファイルを作ることができます。
制限というなら、IStorage / IStream の、OLE による実装の制限と言えるでしょう。