C# と VB.NET の質問掲示板

わんくま同盟

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

ツリー一括表示

作業用フォルダについてご相談 /ザイーガ (17/05/11(Thu) 17:51) #84050
Re[1]: 作業用フォルダについてご相談 /とっちゃん (17/05/11(Thu) 20:10) #84051
│└ Re[2]: 作業用フォルダについてご相談 /ザイーガ (17/05/12(Fri) 10:38) #84054
│  ├ Re[3]: 作業用フォルダについてご相談 /渋木宏明 (17/05/12(Fri) 10:58) #84056
│  │└ Re[4]: 作業用フォルダについてご相談 /ザイーガ (17/05/12(Fri) 11:26) #84058
│  ├ Re[3]: 作業用フォルダについてご相談 /とっちゃん (17/05/12(Fri) 12:33) #84062
│  │└ Re[4]: 作業用フォルダについてご相談 /ザイーガ (17/05/12(Fri) 17:01) #84070
│  │  ├ Re[5]: 作業用フォルダについてご相談 /魔界の仮面弁士 (17/05/12(Fri) 17:27) #84072
│  │  └ Re[5]: 作業用フォルダについてご相談 /みい (17/05/12(Fri) 17:41) #84073
│  ├ Re[3]: 作業用フォルダについてご相談 /みい (17/05/12(Fri) 11:43) #84060
│  └ Re[3]: 作業用フォルダについてご相談 /shu (17/05/13(Sat) 14:37) #84083
Re[1]: 作業用フォルダについてご相談 /shu (17/05/11(Thu) 22:18) #84052
Re[1]: 作業用フォルダについてご相談 /大谷刑部 (17/05/12(Fri) 10:18) #84053
  └ Re[2]: 作業用フォルダについてご相談 /774RR (17/05/12(Fri) 11:27) #84059
    └ Re[3]: 作業用フォルダについてご相談 /774RR (17/05/12(Fri) 12:09) #84061
      └ Re[4]: 作業用フォルダについてご相談 /774RR (17/05/12(Fri) 12:44) #84063
        └ Re[5]: 作業用フォルダについてご相談 /774RR (17/05/12(Fri) 18:14) #84074
          └ Re[6]: 作業用フォルダについてご相談 /とっちゃん (17/05/12(Fri) 18:29) #84076
            └ Re[7]: 作業用フォルダについてご相談 /渋木宏明 (17/05/13(Sat) 12:41) #84082


親記事 / ▼[ 84051 ] ▼[ 84052 ] ▼[ 84053 ]
■84050 / 親階層)  作業用フォルダについてご相談
□投稿者/ ザイーガ (1回)-(2017/05/11(Thu) 17:51:31)

分類:[VB.NET/VB2005 以降] 

C++で作成されたdllを、以下のような感じでVB2013より呼び出しています。
<DllImport("test.dll")> _
Private Shared Function GetTestData(ByVal filePath As String, ByVal testResult As System.Text.StringBuilder) As Integer
End Function

ただし、dllの文字列引数(具体的にはファイルのパス)に全角文字が含まれていると
うまく動かないことが分かりました。
(すべての全角文字ではないようですが、問題の文字の特定までは行っておりません。)

おそらく、dll側では文字列をANSIで扱っているのだろうと思いますので、
最悪、dll側をUnicode対応することで解決するとは思うのですが、
このdllを作った人はすでに退職し、私はC++については詳しくありません。

そこで、VB側で何とか回避できないかと色々考え、
最終的にパスの文字列がすべて半角文字にしてしまうという方法を思いつきました。
具体的には、dllに渡すファイルを任意のフォルダーにコピーし、
ファイル名も半角文字にしてあげる、というものです。

試しにdllに渡すファイルをユーザのtempフォルダ内にコピーしたところ
とりあえずはうまく動いたのですが、
別の問題が出てきました。

それは、ユーザ名そのものに問題の全角文字が使われていると、
「C:\Users\ユーザ名\AppData\Local\Temp」のようになり、
結局ファイルパスに全角文字が含まれてしまう、ということです。

そこで質問なのですが、
すべてのユーザがフルアクセス可能で、
かつパスの文字列がすべて半角文字で構成されている、
上記の姑息な方法に利用可能な場所ってどこかありますか?

「C:\ProgramData」の配下も検討してみましたが、
フルアクセスができないアカウント権限があるようで、
以下のような例外が発生する場合があるようです。

System.UnauthorizedAccessException: パス 'C:\ProgramData\AAA\BBB\CCC.ddd' へのアクセスが拒否されました。
場所 System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
場所 System.IO.File.InternalCopy(String sourceFileName, String destFileName, Boolean overwrite)
場所 ...


あと、C++のdllをUnicode対応する場合、結構大変でしょうか?
C++の詳細な知識がなくとも、何か「おまじない」のような文字をコードに追加するだけでOK、
ということはないでしょうか?

以上、アドバイスの程どうぞよろしくお願いします。
[ □ Tree ] 返信 編集キー/

▲[ 84050 ] / ▼[ 84054 ]
■84051 / 1階層)  Re[1]: 作業用フォルダについてご相談
□投稿者/ とっちゃん (435回)-(2017/05/11(Thu) 20:10:36)
No84050 (ザイーガ さん) に返信

> すべてのユーザがフルアクセス可能で、
> かつパスの文字列がすべて半角文字で構成されている、
> 上記の姑息な方法に利用可能な場所ってどこかありますか?

ありません。

なので、アプリケーションとしてその部分が必須なら
インストール時にそういう専用フォルダを作成しておきます。



> あと、C++のdllをUnicode対応する場合、結構大変でしょうか?
> C++の詳細な知識がなくとも、何か「おまじない」のような文字をコードに追加するだけでOK、
> ということはないでしょうか?
>
ビルドオプション的には、UNICODEのコンパイルスイッチがあるので、それを設定するだけです。
が、ソースコードは多くの場合(経験的にコンバートしたプロジェクト100%で該当)、
最低1か所以上は修正が必要です。

ただし、これはそのプロジェクトを最初からUNICODE対応を想定して作っていた場合の話。
全く想定していない場合、文字列の数の数倍から数百倍は修正箇所が出ます。

[ 親 84050 / □ Tree ] 返信 編集キー/

▲[ 84051 ] / ▼[ 84056 ] ▼[ 84062 ] ▼[ 84060 ] ▼[ 84083 ]
■84054 / 2階層)  Re[2]: 作業用フォルダについてご相談
□投稿者/ ザイーガ (2回)-(2017/05/12(Fri) 10:38:44)
No84052 (shu さん) に返信
> この時点で作り直しを検討するべきかと思います。作ったものをメンテナンス
> 出来ないようでは今後も他の問題で同じことになります。

全く仰る通りです。
ただ、これは私が入社する前の話ですので、この点はご容赦願います。


No84051 (とっちゃん さん) に返信
> ありません。
>
> なので、アプリケーションとしてその部分が必須なら
> インストール時にそういう専用フォルダを作成しておきます。

ご回答ありがとうございます。
やはり、dll側(C++)を対応するしかないですね。
このプロジェクトはVS2008で開発されたものでしたので、
VS2008をインストールしたPCを用意して、
プロジェクトを開き、プロパティを見てみました。
文字セットには「マルチバイト文字セットを使用する」になっていました。
色々と調べてみると、マルチバイト文字セットはこのような問題があるらしく、
現在は非推奨とのことで、Unicode文字セットに変更しようと思います。

ただ、とっちゃん様のアドバイスによると、

1.文字セットを「Unicode文字セットを使用する」に変更する
2.必要に応じて文字列変数の部分を修正する
 (場合によっては文字列の数の数倍から数百倍は修正箇所が出る恐れあり)

ということで、特に2.については覚悟しなければならないと思っています。

2.については、色々と検索して調べて勉強しようと思いますが、
例えば以下サイトに記載のこと以外に注意すべき点はございますでしょうか?

http://cx5software.com/article_vcpp_unicode/

[ 親 84050 / □ Tree ] 返信 編集キー/

▲[ 84054 ] / ▼[ 84058 ]
■84056 / 3階層)  Re[3]: 作業用フォルダについてご相談
□投稿者/ 渋木宏明 (9回)-(2017/05/12(Fri) 10:58:31)
> 1.文字セットを「Unicode文字セットを使用する」に変更する

これ、解決策になるのかな?
MBCS では2バイト文字の扱いが甘いことが問題になるけど、Unicode でもサロゲート文字の扱いが問題になるケースがあります。
そもそもで言うと、.dll 内部でパス名を「おれおれ」な処理してるのがマズイわけなので「どーマズイか」によっては、今度はサロゲート文字で躓く可能性もあると思います。

[ 親 84050 / □ Tree ] 返信 編集キー/

▲[ 84056 ] / 返信無し
■84058 / 4階層)  Re[4]: 作業用フォルダについてご相談
□投稿者/ ザイーガ (3回)-(2017/05/12(Fri) 11:26:28)
No84056 (渋木宏明 さん) に返信
> そもそもで言うと、.dll 内部でパス名を「おれおれ」な処理してるのがマズイわけなので

コメントありがとうございます。
ところで、『「おれおれ」な処理』って、具体的にはどんなことなのでしょうか?
C++の世界では常識のことなのでしょうか?
ここら辺も勉強したいので、ご教示頂けるとありがたいです。

なお、サロゲート文字は考慮しない方向でいます。
[ 親 84050 / □ Tree ] 返信 編集キー/

▲[ 84054 ] / ▼[ 84070 ]
■84062 / 3階層)  Re[3]: 作業用フォルダについてご相談
□投稿者/ とっちゃん (436回)-(2017/05/12(Fri) 12:33:44)
No84054 (ザイーガ さん) に返信
> 1.文字セットを「Unicode文字セットを使用する」に変更する
> 2.必要に応じて文字列変数の部分を修正する
>  (場合によっては文字列の数の数倍から数百倍は修正箇所が出る恐れあり)
>
必要に応じてですが、対象はUNICODE化する文字列すべてです。
ただし、書き換えの必要があるかどうかはソースコードの内容によるので
作業量的なものがどの程度になるかはわかりません。

あとは、リテラル以外の文字列は文字コード変換処理で対応する必要もあります。
この部分はさらにはまるかな。。。



さて、ちょっとだけ深刻なお話。

パス名に全角文字(これの定義もまぁあれだがw)があると、うまくいかないのが本当に文字コードに起因する問題だとしたら
そのプログラムは、ANSIであること以前に、Shift-JIS以外の文字コード体系がこの世に存在しないと思って作られているもしくは
文字なんて127個よりもはるかに少ないだろ?と思っている人が作った可能性もあります。

もしそうだとすると、スイッチ変えて、文字列を _T でくくって程度では変換できません。
多くの場合、設計しなおしという対応が要求されます(それくらい文字コード問題というのは深刻)。

SBCSかどうかは、"表"があるとパスがおかしいとかで判断できるかもしれません。

あとは、意識してなくて、AnyCPU 問題ではまっている場合もありますね。
2008のようなのでEXEはデフォルトAnyCPUです。
C++は32bitモジュールです。
Windows 7 以降のOSは大半の環境が64ビットです。

この場合、DLLがロードできないという類のエラーになっているはず。
呼び出しのところで、クラッシュしてるかもしれませんけど。


[ 親 84050 / □ Tree ] 返信 編集キー/

▲[ 84062 ] / ▼[ 84072 ] ▼[ 84073 ]
■84070 / 4階層)  Re[4]: 作業用フォルダについてご相談
□投稿者/ ザイーガ (4回)-(2017/05/12(Fri) 17:01:43)
2017/05/12(Fri) 17:12:49 編集(投稿者)

皆様、色々とありがとうございます。
移動のため、返事が遅れて申し訳ございません。

No84062 (とっちゃん さん) に返信
>
> SBCSかどうかは、"表"があるとパスがおかしいとかで判断できるかもしれません。

はい。パスに「表」の文字があるとうまく動作しません。
元々は、問題のあったパスの「ソ」の文字が問題でしたので、
少なくとも5cの問題はあるのだろうと考えています。

> 2008のようなのでEXEはデフォルトAnyCPUです。
> C++は32bitモジュールです。

VB側はx86でビルドしていますので、パス文字以外の問題は
今のところ発生していません。

他の皆さんのご意見も参考に、ちょっと検討します。
このスレッドは閉じずにおきますので、また追加のアドバイスがございましたら
どうぞよろしくお願いします。
[ 親 84050 / □ Tree ] 返信 編集キー/

▲[ 84070 ] / 返信無し
■84072 / 5階層)  Re[5]: 作業用フォルダについてご相談
□投稿者/ 魔界の仮面弁士 (1274回)-(2017/05/12(Fri) 17:27:41)
No84070 (ザイーガ さん) に返信
> 他の皆さんのご意見も参考に、ちょっと検討します。
> このスレッドは閉じずにおきますので、また追加のアドバイスがございましたら
> どうぞよろしくお願いします。


VB から 文字列を渡す場合の注意点として

http://www5b.biglobe.ne.jp/~yone-ken/VBNET/Reference/ref2_GetPrivateProfileString.html
[ 親 84050 / □ Tree ] 返信 編集キー/

▲[ 84070 ] / 返信無し
■84073 / 5階層)  Re[5]: 作業用フォルダについてご相談
□投稿者/ みい (61回)-(2017/05/12(Fri) 17:41:24)
No84070 (ザイーガ さん) に返信
> はい。パスに「表」の文字があるとうまく動作しません。
> 元々は、問題のあったパスの「ソ」の文字が問題でしたので、
> 少なくとも5cの問題はあるのだろうと考えています。
社会人2年目くらいに、ファイルパス文字列を先頭から見ていって
'\\'マークがあったらフォルダを作る処理書いていて、
「ソ」で余分なフォルダができるってお客さんに怒られたこと
思い出しました(遠い目)。

↑マルチバイト文字の第1バイト判断処理を入れてなかったおバカ

dll作った人も同類だったりして
[ 親 84050 / □ Tree ] 返信 編集キー/

▲[ 84054 ] / 返信無し
■84060 / 3階層)  Re[3]: 作業用フォルダについてご相談
□投稿者/ みい (60回)-(2017/05/12(Fri) 11:43:28)
No84054 (ザイーガ さん) に返信
> やはり、dll側(C++)を対応するしかないですね。

あまりお奨めはしませんが…

dll側の引数を文字列→BYTE配列&BYTE数に変更
Unicode文字列→BYTE配列(S-JIS)に変換してdllに渡す
dll側は関数頭で引数のBYTE配列を元々のString型にセットして以降の処理はそのまま

という逃げの手もあります。

[ 親 84050 / □ Tree ] 返信 編集キー/

▲[ 84054 ] / 返信無し
■84083 / 3階層)  Re[3]: 作業用フォルダについてご相談
□投稿者/ shu (1020回)-(2017/05/13(Sat) 14:37:20)
No84054 (ザイーガ さん) に返信
> ■No84052 (shu さん) に返信
>>この時点で作り直しを検討するべきかと思います。作ったものをメンテナンス
>>出来ないようでは今後も他の問題で同じことになります。
>
> 全く仰る通りです。
> ただ、これは私が入社する前の話ですので、この点はご容赦願います。
>
>
このコメントは『このdllを作った人はすでに退職し、私はC++については詳しくありません。』に
対してしているので入社前にdllを作った人が退職したかは関係ないです。一番はC++につくて詳しくないため
現在問題になっているdllのソースを修正することが出来ないということではないでしょうか?
作り直しが無理なら修正をしないと解決しないと思いますよ。私が容赦したところでザイーガさんの
抱えている根本的な問題は解消できないでしょう。というか私は被害を被ってないので容赦するもないのですが。
[ 親 84050 / □ Tree ] 返信 編集キー/

▲[ 84050 ] / 返信無し
■84052 / 1階層)  Re[1]: 作業用フォルダについてご相談
□投稿者/ shu (1019回)-(2017/05/11(Thu) 22:18:19)
No84050 (ザイーガ さん) に返信
> このdllを作った人はすでに退職し、私はC++については詳しくありません。
>
この時点で作り直しを検討するべきかと思います。作ったものをメンテナンス
出来ないようでは今後も他の問題で同じことになります。
[ 親 84050 / □ Tree ] 返信 編集キー/

▲[ 84050 ] / ▼[ 84059 ]
■84053 / 1階層)  Re[1]: 作業用フォルダについてご相談
□投稿者/ 大谷刑部 (30回)-(2017/05/12(Fri) 10:18:15)
No84050 (ザイーガ さん) に返信
> そこで、VB側で何とか回避できないかと色々考え、
> 最終的にパスの文字列がすべて半角文字にしてしまうという方法を思いつきました。
> 具体的には、dllに渡すファイルを任意のフォルダーにコピーし、
> ファイル名も半角文字にしてあげる、というものです。
>
> 試しにdllに渡すファイルをユーザのtempフォルダ内にコピーしたところ
> とりあえずはうまく動いたのですが、
> 別の問題が出てきました。
>
> それは、ユーザ名そのものに問題の全角文字が使われていると、
> 「C:\Users\ユーザ名\AppData\Local\Temp」のようになり、
> 結局ファイルパスに全角文字が含まれてしまう、ということです。
>
> そこで質問なのですが、
> すべてのユーザがフルアクセス可能で、
> かつパスの文字列がすべて半角文字で構成されている、
> 上記の姑息な方法に利用可能な場所ってどこかありますか?
>
> 「C:\ProgramData」の配下も検討してみましたが、
> フルアクセスができないアカウント権限があるようで、
> 以下のような例外が発生する場合があるようです。
>
> System.UnauthorizedAccessException: パス 'C:\ProgramData\AAA\BBB\CCC.ddd' へのアクセスが拒否されました。
> 場所 System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
> 場所 System.IO.File.InternalCopy(String sourceFileName, String destFileName, Boolean overwrite)
> 場所 ...

アプリのパスにTempフォルダでも作っておいて、そこを使うというのではだめ?
VB側からパスが渡せるなら、それが一番手っ取り早い気がしますが。
「Temp」のパス文字列自体は、iniファイルなり、configのXMLなりに定義しておけば、
汎用的にできるはずですし。



[ 親 84050 / □ Tree ] 返信 編集キー/

▲[ 84053 ] / ▼[ 84061 ]
■84059 / 2階層)  Re[2]: 作業用フォルダについてご相談
□投稿者/ 774RR (521回)-(2017/05/12(Fri) 11:27:16)
過去に何度かこの手の移植したことがある身としては MBCS→UNICODE の移植で手間を取るくらいなら
現 VC コードを C++/CLI なり C# なり VB に移植する、ほうがむしろ簡単なのではないか、と思う。
その意味で no84052 shu さんと同意見。

細かいことを省略して項目だけ挙げる。
1. sizeof(char) ≠ sizeof(wchar_t) 問題
2. wchar_t の endianess 問題
3. 全角の幅=半角の2倍 のはず問題
4. UNICODE のサロゲートペア(合字)問題
5. native/manage 相互運用における x86/x64/anycpu 問題

項目名だけ見て
なんぢゃそれ、と思う人だとこの手の問題を解決するのは困難。
あーあるある、と思う人でもめっちゃ面倒、だと思う。
[ 親 84050 / □ Tree ] 返信 編集キー/

▲[ 84059 ] / ▼[ 84063 ]
■84061 / 3階層)  Re[3]: 作業用フォルダについてご相談
□投稿者/ 774RR (522回)-(2017/05/12(Fri) 12:09:20)
まあそもそもの最初の話「漢字が化ける」のが
・いわゆる「全角」文字全般、どれを渡しても化ける のか
・(日本語 Windows の場合) CP932 で表現できない文字を渡すと化ける のか
そのへんがはっきりしていないのでアレだけど

前者なのだったら C++ から当該 DLL を使っても化けそう=もともとバグっている?ってことだし
後者なのだったらそもそも CP932 に変換できない文字を使っている時点で MBCS では解決策が無い、ってことだし

どちらにせよ現状の DLL をそのまま使うのは限りなく無理っぽいような気のせいがする。

[ 親 84050 / □ Tree ] 返信 編集キー/

▲[ 84061 ] / ▼[ 84074 ]
■84063 / 4階層)  Re[4]: 作業用フォルダについてご相談
□投稿者/ 774RR (523回)-(2017/05/12(Fri) 12:44:19)
っていうかそもそも最初の DllImport 宣言はあってるのだろうか?

CallingConvention や CharSet を明示してない DllImport なんてオイラは怖くて書いたこと無いっす。
呼ぶ側は new StringBuilder で正しく要素数を渡しているのか?
関数宣言中にその要素数を渡す引数が無いんだけどバッファオーバーフローは大丈夫?

とかなんとかいろいろ思うことはあるのだけど
いかんせん情報が無さ杉なのでこれ以上は突っ込まないことにする。

[ 親 84050 / □ Tree ] 返信 編集キー/

▲[ 84063 ] / ▼[ 84076 ]
■84074 / 5階層)  Re[5]: 作業用フォルダについてご相談
□投稿者/ 774RR (524回)-(2017/05/12(Fri) 18:14:19)
で UNICODE 化するときはその手の第1バイト判断処理は全部削除しなきゃならない罠
あーやだやだ
[ 親 84050 / □ Tree ] 返信 編集キー/

▲[ 84074 ] / ▼[ 84082 ]
■84076 / 6階層)  Re[6]: 作業用フォルダについてご相談
□投稿者/ とっちゃん (437回)-(2017/05/12(Fri) 18:29:50)
No84074 (774RR さん) に返信
> で UNICODE 化するときはその手の第1バイト判断処理は全部削除しなきゃならない罠
> あーやだやだ

そして、サロゲートペア対応とか、合字、異体字セレクタ対応とかが入ってくる。
あーやだやだ

[ 親 84050 / □ Tree ] 返信 編集キー/

▲[ 84076 ] / 返信無し
■84082 / 7階層)  Re[7]: 作業用フォルダについてご相談
□投稿者/ 渋木宏明 (10回)-(2017/05/13(Sat) 12:41:50)
2017/05/13(Sat) 12:48:14 編集(投稿者)

>ところで、『「おれおれ」な処理』って、具体的にはどんなことなのでしょうか?

もう既にコメントで出てますが、例えば

>社会人2年目くらいに、ファイルパス文字列を先頭から見ていって
>'\\'マークがあったらフォルダを作る処理書いていて、
>「ソ」で余分なフォルダができるってお客さんに怒られたこと
>思い出しました(遠い目)。

なんてやつです。

パス名の分割を、Shift JIS の特性?を理解せずに「おれおれ」実装するとそーなります。

少なくとも Windows 向けのアプリであれば、パス名の分解には API や標準ライブラリを使用するのが適切です。

>C++の世界では常識のことなのでしょうか?

プログラミング言語がなんであるかはあまり関係ないですね。

文字コードや Windows という動作環境、プラットフォーム関連の理解が足りてるか足りてないかという問題だと思います。

>なお、サロゲート文字は考慮しない方向でいます。

大丈夫なのかなぁ。

特殊なことしなくても IME で変換したら出ちゃうからなぁ。
人名漢字もあるし。

まぁ、移行が大変なんだろうなというのは分かりますが。



[ 親 84050 / □ Tree ] 返信 編集キー/


管理者用

- Child Tree -