DOBON.NET DOBON.NETプログラミング掲示板過去ログ

null区切りされた文字配列について

環境/言語:[VB.NET]
分類:[.NET]

こんにちは。

アンマネージコード(C++)で書かれたDLLを呼び出し、
返却された文字配列データを取得したいのですが、
null区切りされている為、String型やStringBuilderで
取得できず困っています。
どなたか、良い方法がないものか教えてください。

<開発言語>
VisualBasic2005

<DLLインターフェース>
TEST_RESULT TEST_APICALL TEST_StrGet(
 //IN :ディレクトリ名 
 char[10] DirName,

 //OUT :0ターミネートしたファイル名リスト(ASCIZ文字列:SJIS)
 char[100] FileList
);

<作成中のプログラムコード>
Public Declare Function TEST_StrGet Lib "test.dll" ( _
 ByVal DirName As String, _
 ByVal FileList As StringBuilder, _
) As Integer

Public Function TEST( _
 ByVal strDirName As String, _
 ByVal strFileList() As String, _
) As Integer

 Dim i, rc As Integer
 Dim DirName As String = "C:\"
 Dim FileList As New StringBuilder(100)

 rc = TEST_StrGet(DirName, FileList)

 For i = 0 to FileList.length
  ★StringBuilderはnullターミネイトされてしまう為、「FileList(0)」
   しか返却されない
  strFileList = FileList(i)
 Next

  ・
  ・
  ・

End Function
■No12417に返信(taaさんの記事)
> こんにちは。
>
> アンマネージコード(C++)で書かれたDLLを呼び出し、
> 返却された文字配列データを取得したいのですが、
> null区切りされている為、String型やStringBuilderで
> 取得できず困っています。
> どなたか、良い方法がないものか教えてください。
C++のDLLを変更するのは可能でしょうか?
文字列配列等はVariant型でやり取りするほうがいいと思いますが。

TEST_StrGet( LPCSTR pDirName, Variant* FileList );

見たいに。
> アンマネージコード(C++)で書かれたDLLを呼び出し、
> 返却された文字配列データを取得したいのですが、
> null区切りされている為、String型やStringBuilderで
> 取得できず困っています。

byte 配列で受けて、System.Text.Encoding.GetString() するとか。
> TEST_StrGet( LPCSTR pDirName, Variant* FileList );
Variantは大文字でした。(VARIANT)

一応 VB5との連携ならできるサンプルがあるのでURL載せときます。
http://support.microsoft.com/default.aspx?scid=http://www.microsoft.com/japan/support/kb/articles/410/8/37.asp
(.NETではまったく仕様が変わっていたらスイマセン。)

ちなみに C++ のコンパイラは何でしょうか?
■No12423に返信(Blueさんの記事)
>>TEST_StrGet( LPCSTR pDirName, Variant* FileList );
> Variantは大文字でした。(VARIANT)
>
> 一応 VB5との連携ならできるサンプルがあるのでURL載せときます。
> http://support.microsoft.com/default.aspx?scid=http://www.microsoft.com/japan/support/kb/articles/410/8/37.asp
> (.NETではまったく仕様が変わっていたらスイマセン。)
>
> ちなみに C++ のコンパイラは何でしょうか?
本当は、DLL側を変更したいのですが、C++のDLLは変更できません。
■No12422に返信(渋木宏明(ひどり)さんの記事)
>>アンマネージコード(C++)で書かれたDLLを呼び出し、
>>返却された文字配列データを取得したいのですが、
>>null区切りされている為、String型やStringBuilderで
>>取得できず困っています。
>
> byte 配列で受けて、System.Text.Encoding.GetString() するとか。
>
実は既にBYTE配列で受けて、System.Text.Encoding.GetString()で
暫定的にプログラミングをしているのですが、お粗末なため質問を
あげていました。
やはり、この方法しかないですかね〜。
あれ。Stringでいけませんでしたか?

C++には詳しくないので、DLL側の話は良く分かりませんが……少なくとも、
GetPrivateProfileSectionNames APIは問題なく呼べるみたいですし。

'=====================================
Imports System
Imports Microsoft.VisualBasic
Module A
  Private Declare Auto Function GetPrivateProfileSectionNames Lib "kernel32" _
    (ByVal Buf As String, ByVal Size As Integer, ByVal File As String) As Integer
  Sub Main()
    Dim S As New String(" "c, 1000)
    Dim F As String = "C:\Windows\WIN.INI"

    GetPrivateProfileSectionNames(S, S.Length, F)

    '終端の二連nullを以降を取り除く
    Dim Term As New String(ChrW(0), 2)
    S = Split(S & Term, Term)(0)

    'nullで区切りで表示
    For Each X As String In Split(S, ChrW(0))
      Console.WriteLine("[" & X & "]")
    Next
  End Sub
End Module
■No12427に返信(魔界の仮面弁士さんの記事)
> あれ。Stringでいけませんでしたか?
>
> C++には詳しくないので、DLL側の話は良く分かりませんが……少なくとも、
> GetPrivateProfileSectionNames APIは問題なく呼べるみたいですし。
>
> '=====================================
> Imports System
> Imports Microsoft.VisualBasic
> Module A
> Private Declare Auto Function GetPrivateProfileSectionNames Lib "kernel32" _
> (ByVal Buf As String, ByVal Size As Integer, ByVal File As String) As Integer
> Sub Main()
> Dim S As New String(" "c, 1000)
> Dim F As String = "C:\Windows\WIN.INI"
>
> GetPrivateProfileSectionNames(S, S.Length, F)
>
> '終端の二連nullを以降を取り除く
> Dim Term As New String(ChrW(0), 2)
> S = Split(S & Term, Term)(0)
>
> 'nullで区切りで表示
> For Each X As String In Split(S, ChrW(0))
> Console.WriteLine("[" & X & "]")
> Next
> End Sub
> End Module

説明が足りていなかったみたいですみません。
DLL(アンマネージコード)側から返却される
FileList文字配列は、文字コードがSJISの為、
String型(unicode)に格納すると文字が化けて
しまいます。
その為、String型では駄目だったと質問して
いました。
この投稿はマルチポストです。

●マルチポストされている場所
http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=23972&forum=7

----------
この掲示板ではマルチポストが禁止されています。詳しくは、「書き込みのマナーについて」をお読みください。

●書き込みのマナーについて
http://dobon.net/vb/bbs/index.html
■No12437に返信((報告)さんの記事)
> この投稿はマルチポストです。
>
> ●マルチポストされている場所
> http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=23972&forum=7
>
> ----------
> この掲示板ではマルチポストが禁止されています。詳しくは、「書き込みのマナーについて」をお読みください。
>
> ●書き込みのマナーについて
> http://dobon.net/vb/bbs/index.html
すみません。マナーを読んでいませんでした。
至急、削除致します。
■No12439に返信(taaさんの記事)
> ■No12437に返信((報告)さんの記事)
>>この投稿はマルチポストです。
>>
>>●マルチポストされている場所
>>http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=23972&forum=7
>>
>>----------
>>この掲示板ではマルチポストが禁止されています。詳しくは、「書き込みのマナーについて」をお読みください。
>>
>>●書き込みのマナーについて
>>http://dobon.net/vb/bbs/index.html
> すみません。マナーを読んでいませんでした。
> 至急、削除致します。
>

度々、すみません。削除キーを忘れてしまい削除もできないので
解決した際には、必ず情報を共有致します。
皆さん、大変失礼致しました。
> DLL(アンマネージコード)側から返却される
> FileList文字配列は、文字コードがSJISの為、
> String型(unicode)に格納すると文字が化けて
> しまいます。

あれれ?

少なくとも当方では、GetPrivateProfileSectionNames を ANSIエントリにて
呼び出した場合にも、漢字(Shift_JIS)のセクション名を正しく列挙できて
いるようなので、日本語版Windowsの上で実行させている限りは、
そのままString型で受ける事ができると判断したのですが……。

Private Declare Ansi Function GetPrivateProfileSectionNames _
Lib "kernel32" Alias "GetPrivateProfileSectionNamesA" _
(ByVal Buf As String, ByVal Size As Integer, _
ByVal File As String) As Integer
■No12440に返信(taaさんの記事)
> ■No12439に返信(taaさんの記事)
>>■No12437に返信((報告)さんの記事)
> >>この投稿はマルチポストです。
> >>
> >>●マルチポストされている場所
> >>http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=23972&forum=7
> >>
> >>----------
> >>この掲示板ではマルチポストが禁止されています。詳しくは、「書き込みのマナーについて」をお読みください。
> >>
> >>●書き込みのマナーについて
> >>http://dobon.net/vb/bbs/index.html
>>すみません。マナーを読んでいませんでした。
>>至急、削除致します。
>>
>
> 度々、すみません。削除キーを忘れてしまい削除もできないので
> 解決した際には、必ず情報を共有致します。
> 皆さん、大変失礼致しました。
解決したが、報告なし。
自分の勘違いだったらしいです。かなりタチ悪いで砂。
■No12517に返信((報告)さんの記事)
> ■No12440に返信(taaさんの記事)
>>■No12439に返信(taaさんの記事)
> >>■No12437に返信((報告)さんの記事)
>>>>この投稿はマルチポストです。
>>>>
>>>>●マルチポストされている場所
>>>>http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=23972&forum=7
>>>>
>>>>----------
>>>>この掲示板ではマルチポストが禁止されています。詳しくは、「書き込みのマナーについて」をお読みください。
>>>>
>>>>●書き込みのマナーについて
>>>>http://dobon.net/vb/bbs/index.html
> >>すみません。マナーを読んでいませんでした。
> >>至急、削除致します。
> >>
>>
>>度々、すみません。削除キーを忘れてしまい削除もできないので
>>解決した際には、必ず情報を共有致します。
>>皆さん、大変失礼致しました。
> 解決したが、報告なし。
> 自分の勘違いだったらしいです。かなりタチ悪いで砂。

あのー、まだ解決はしていません。
現在、調べている所です。
解決次第、必ず報告しますのでもうしばらくお待ちください。
2005/08/31(Wed) 10:37:14 編集(投稿者)

> あのー、まだ解決はしていません。
ここの『書き込みのマナーについて』http://dobon.net/vb/bbs/index.html には、

   質問の回答に対して必ずフィードバック(結果報告、返事、お礼)を
   すること(できるだけ早く)。

とある事ですし、まだ解決していなかったとしても、知りえた情報の
フィードバックや状況報告などは、適宜行って頂けると助かります。
# 一方にだけ返信していて、他方が無反応だと、無視された気になりますし。


> 解決次第、必ず報告しますのでもうしばらくお待ちください。
ひとつ確認させてください。

taaさんが用意された C++製の DLL ではなく、先に No12449 で回答した
"GetPrivateProfileSectionNamesA" の API を呼び出した場合に、
データを正しく取得できるのか、調べてみてもらえませんか?
# GetPrivateProfileSectionNamesA は、null区切りデータを
# Shift_JIS形式で返すAPIです。

当方環境は、(VB2005ではなく).NET SDK 1.1 なのですが、下記のコードで
null区切りデータを取得し、文字列として正しく処理できています。

ですから、DLL側の実装と、コードの記述の両方が適切であれば、
> 文字コードがSJISの為、String型(unicode)に格納すると文字が化けてしまいます。
という状況にはならないと思うのですが……。


《当方がテストに使ったコード (C:\A.VB) 》
-------------------------------------------------------------
Imports System
Imports Microsoft.VisualBasic
Module A
 '先のNo12427との違いは、Auto→Ansi、およびAlias句の追加です。
 Private Declare Ansi Function GetPrivateProfileSectionNames _
  Lib "kernel32" Alias "GetPrivateProfileSectionNamesA" _
  (ByVal Buf As String, ByVal Size As Integer, _
  ByVal File As String) As Integer
 Sub Main()
  Dim S As New String(" "c, 1000)
  Dim F As String = "C:\TEST.INI"

  GetPrivateProfileSectionNames(S, S.Length, F)

  '終端の二連nullを以降を取り除く
  Dim Term As New String(ChrW(0), 2)
  S = Split(S & Term, Term)(0)

  'nullごとに区切って配列化
  Dim SectionNames() As String = Split(S, ChrW(0))

  '配列の中身を確認
  For Each X As String In SectionNames
   Console.WriteLine("[" & X & "]")
  Next
 End Sub
End Module


《実験用の C:\TEST.INI の内容》
-------------------------------------------------------------
[infoいんふぉ]
symbolfile=dummy.h

[languagesらんげーじ]
009=English
011=Japanese

[textてきすと]
NAME=Total pages

[おぶじぇくつobjects]
009_NAME=Fax Services
011_NAME=Faxサービス


《実行結果》
-------------------------------------------------------------
[infoいんふぉ]
[languagesらんげーじ]
[textてきすと]
[おぶじぇくつobjects]
★解決しました!!
いろいろ、ご迷惑をお掛けして申し訳ありません。

■No12526に返信(魔界の仮面弁士さんの記事)
> 2005/08/31(Wed) 10:37:14 編集(投稿者)
>
>>あのー、まだ解決はしていません。
> ここの『書き込みのマナーについて』http://dobon.net/vb/bbs/index.html には、
>
>    質問の回答に対して必ずフィードバック(結果報告、返事、お礼)を
>    すること(できるだけ早く)。
>
> とある事ですし、まだ解決していなかったとしても、知りえた情報の
> フィードバックや状況報告などは、適宜行って頂けると助かります。
> # 一方にだけ返信していて、他方が無反応だと、無視された気になりますし。
>
★すみません。今後は解決していなかったとしても、入手した情報の
フィードバックや状況報告などは、適宜行っていきます。

>>解決次第、必ず報告しますのでもうしばらくお待ちください。
> ひとつ確認させてください。
>
> taaさんが用意された C++製の DLL ではなく、先に No12449 で回答した
> "GetPrivateProfileSectionNamesA" の API を呼び出した場合に、
> データを正しく取得できるのか、調べてみてもらえませんか?
> # GetPrivateProfileSectionNamesA は、null区切りデータを
> # Shift_JIS形式で返すAPIです。
>
> 当方環境は、(VB2005ではなく).NET SDK 1.1 なのですが、下記のコードで
> null区切りデータを取得し、文字列として正しく処理できています。
>
> ですから、DLL側の実装と、コードの記述の両方が適切であれば、
>>文字コードがSJISの為、String型(unicode)に格納すると文字が化けてしまいます。
> という状況にはならないと思うのですが……。
★その通りでした。文字化けしませんでした。WIN32APIを使用した事が
なく、"GetPrivateProfileSectionNamesA"の動作も良くわからなかった
事もあり、ずっとBYTE型のエンコードとマーシャリングの使用方法に
時間を使っていました。
正直なところ、オブジェクトの意味が良く理解していなかった事が時間が
かかってしまった原因だと思います。
未だに、今回キーとなる以下の2行はまだ完全に理解はしていません。
使いこなすにはもう少し時間がかかりそうです。
**** Dim S As New String(" "c, 1000)
**** Dim Term As New String(ChrW(0), 2)
ただ、後はオブジェクトを作成するにあたっての理解だけなので
頑張って理解していこうと思います。

いろいろと、ご迷惑をお掛けして申し訳ありませんでした。
また、たくさんのレスを感謝致します。

尚、今回知り得た情報をこのトピックの最後に記載し、"解決"と
させて頂きますのでよろしくお願い致します。
それでは、ありがとうございました。


>
> 《当方がテストに使ったコード (C:\A.VB) 》
> -------------------------------------------------------------
> Imports System
> Imports Microsoft.VisualBasic
> Module A
>  '先のNo12427との違いは、Auto→Ansi、およびAlias句の追加です。
>  Private Declare Ansi Function GetPrivateProfileSectionNames _
>   Lib "kernel32" Alias "GetPrivateProfileSectionNamesA" _
>   (ByVal Buf As String, ByVal Size As Integer, _
>   ByVal File As String) As Integer
>  Sub Main()
>   Dim S As New String(" "c, 1000)
>   Dim F As String = "C:\TEST.INI"
>
>   GetPrivateProfileSectionNames(S, S.Length, F)
>
>   '終端の二連nullを以降を取り除く
>   Dim Term As New String(ChrW(0), 2)
>   S = Split(S & Term, Term)(0)
>
>   'nullごとに区切って配列化
>   Dim SectionNames() As String = Split(S, ChrW(0))
>
>   '配列の中身を確認
>   For Each X As String In SectionNames
>    Console.WriteLine("[" & X & "]")
>   Next
>  End Sub
> End Module
>
>
> 《実験用の C:\TEST.INI の内容》
> -------------------------------------------------------------
> [infoいんふぉ]
> symbolfile=dummy.h
>
> [languagesらんげーじ]
> 009=English
> 011=Japanese
>
> [textてきすと]
> NAME=Total pages
>
> [おぶじぇくつobjects]
> 009_NAME=Fax Services
> 011_NAME=Faxサービス
>
>
> 《実行結果》
> -------------------------------------------------------------
> [infoいんふぉ]
> [languagesらんげーじ]
> [textてきすと]
> [おぶじぇくつobjects]
最後に、今回知り得た情報を以下に記載致します。

アンマネージコード(C++)のDLLを呼び出し、返却された
文字配列データ(null区切り)を取得する場合、私が知る限り
2つあります。

1つめは、マネージコード(VB.NET)をBYTE型の配列で受け取り、
SJISの文字コードをUnicodeへEncodeし、Null文字でSplitする方法。

2つめは、マーシャリングして、String型で受け取り、Null文字で
Splitする方法。

性能は測っていませんが、どちらでもいいと思います。
以下にアンマネージコードのインターフェースとマネージコード
のプログラムコードを2パターン記載します。

ちなみに、「書き込みのマナー」をよく読んでおらず誤って
マルチポスト(他のサイトの掲示板)にも書き込みしていますので
マルチポスト先の場所を以下に示します。
皆さんに不愉快な思いをさせて申し訳ありませんでした。

●マルチポストされている場所
http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=23972&forum=7

また、最後にこんなにご迷惑をお掛けしたにもかかわらず、本当にたくさんの
書き込みをありがとうございました。
この書き込みをもってこのトピックを「解決済み」とさせて頂きます。
本当にどうもありがとうございました。

------------------------------------------------------------------------

<アンマネージコード(DLLインターフェース)>
TEST_RESULT TEST_APICALL TEST_StrGet(
 //IN :ディレクトリ名 
 char[10] DirName,

 //OUT :0ターミネートしたファイル名リスト(ASCIZ文字列:SJIS)
 char[100] FileListBuf
);

<BYTE配列で受け取る場合のマネージコード>
Imports System
Public Declare Function TEST_StrGet Lib "test.dll" ( _
 ByVal DirName As String, _
 ByVal FileListBuf() As Byte, _  '★Byte配列で受け取る。
) As Integer

Sub Main()
   Dim FileName As String

   '★SJISの文字コードのByte配列(FileListBuf)の内容をUnicodeの文字列へEncodeする。
Dim strFileList As String = Encoding.GetEncoding("SHIFT_JIS").GetString(FileListBuf)
   '★UnicodeへEncode文字列データをNull文字毎にSplitする。
   ※separateを"Char.MinValue"に指定しないと分割されない。&H0、Nothing、VbNullでは分割されませんでした。
   ただし、少し工夫すれば可能らしいです。詳細はマルチポスト先の書き込みを参照してください。
  Dim strFileListArray() As String = strFileList.Split(Char.MinValue)

For Each FileName As String In strFileListArray
Debug.Print(FileName & vbCrLf)
Next FileName
End Sub

<マーシャリングしてString型で受け取る場合のマネージコード>
Imports System
Public Declare Ansi Function TEST_StrGet Lib "test.dll" ( _
 ByVal DirName As String, _
 ByVal FileListBuf As String, _  '★String型受け取る。
 ★「ByVal ・・・ As String」と宣言した場合、内部では「ByRef」扱いとなる。そして同時にMarshalAs属性がUnmanagedType.VBByRefStrで宣言されている状態になる。詳細はマルチポスト先の書き込みを参照してください。
) As Integer

Sub Main()
 Dim i rc As Integer
 Dim DirName As String = "C:\"
 Dim FileListBuf As New String(" "c,1000)  '★Stringオブジェクトを作成していますが明確な理由はわかりません

 rc = TEST_StrGet(DirName, FileListBuf)

'終端の二連nullを以降を取り除く
 '★Stringオブジェクトを作成していますが明確な理由はわかりません
Dim Term As New String(ChrW(0), 2)
FileListBuf = Split(FileListBuf & Term, Term)(0)

'nullごとに区切って配列化
Dim SectionNames() As String = Split(FileListBuf, ChrW(0))

'配列の中身を確認
For Each X As String In SectionNames
Console.WriteLine("[" & X & "]")
Next
End Sub

------------------------------------------------------------------------
■No12549に返信(taaさんの記事)
> 最後に、今回知り得た情報を以下に記載致します。
>
> アンマネージコード(C++)のDLLを呼び出し、返却された
> 文字配列データ(null区切り)を取得する場合、私が知る限り
> 2つあります。
>
> 1つめは、マネージコード(VB.NET)をBYTE型の配列で受け取り、
> SJISの文字コードをUnicodeへEncodeし、Null文字でSplitする方法。
>
> 2つめは、マーシャリングして、String型で受け取り、Null文字で
> Splitする方法。
>
> 性能は測っていませんが、どちらでもいいと思います。
> 以下にアンマネージコードのインターフェースとマネージコード
> のプログラムコードを2パターン記載します。
>
> ちなみに、「書き込みのマナー」をよく読んでおらず誤って
> マルチポスト(他のサイトの掲示板)にも書き込みしていますので
> マルチポスト先の場所を以下に示します。
> 皆さんに不愉快な思いをさせて申し訳ありませんでした。
>
> ●マルチポストされている場所
> http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=23972&forum=7
>
> また、最後にこんなにご迷惑をお掛けしたにもかかわらず、本当にたくさんの
> 書き込みをありがとうございました。
> この書き込みをもってこのトピックを「解決済み」とさせて頂きます。
> 本当にどうもありがとうございました。
>
> ------------------------------------------------------------------------
>
> <アンマネージコード(DLLインターフェース)>
> TEST_RESULT TEST_APICALL TEST_StrGet(
>  //IN :ディレクトリ名 
>  char[10] DirName,
>
>  //OUT :0ターミネートしたファイル名リスト(ASCIZ文字列:SJIS)
>  char[100] FileListBuf
> );
>
> <BYTE配列で受け取る場合のマネージコード>
> Imports System
> Public Declare Function TEST_StrGet Lib "test.dll" ( _
>  ByVal DirName As String, _
>  ByVal FileListBuf() As Byte, _  '★Byte配列で受け取る。
> ) As Integer
>
> Sub Main()
>    Dim FileName As String
>
>    '★SJISの文字コードのByte配列(FileListBuf)の内容をUnicodeの文字列へEncodeする。
> Dim strFileList As String = Encoding.GetEncoding("SHIFT_JIS").GetString(FileListBuf)
>    '★UnicodeへEncode文字列データをNull文字毎にSplitする。
>    ※separateを"Char.MinValue"に指定しないと分割されない。&H0、Nothing、VbNullでは分割されませんでした。
>    ただし、少し工夫すれば可能らしいです。詳細はマルチポスト先の書き込みを参照してください。
>   Dim strFileListArray() As String = strFileList.Split(Char.MinValue)
>
> For Each FileName As String In strFileListArray
> Debug.Print(FileName & vbCrLf)
> Next FileName
> End Sub
>
> <マーシャリングしてString型で受け取る場合のマネージコード>
> Imports System
> Public Declare Ansi Function TEST_StrGet Lib "test.dll" ( _
>  ByVal DirName As String, _
>  ByVal FileListBuf As String, _  '★String型受け取る。
>  ★「ByVal ・・・ As String」と宣言した場合、内部では「ByRef」扱いとなる。そして同時にMarshalAs属性がUnmanagedType.VBByRefStrで宣言されている状態になる。詳細はマルチポスト先の書き込みを参照してください。
> ) As Integer
>
> Sub Main()
>  Dim i rc As Integer
>  Dim DirName As String = "C:\"
>  Dim FileListBuf As New String(" "c,1000)  '★Stringオブジェクトを作成していますが明確な理由はわかりません
>
>  rc = TEST_StrGet(DirName, FileListBuf)
>
> '終端の二連nullを以降を取り除く
>  '★Stringオブジェクトを作成していますが明確な理由はわかりません
> Dim Term As New String(ChrW(0), 2)
> FileListBuf = Split(FileListBuf & Term, Term)(0)
>
> 'nullごとに区切って配列化
> Dim SectionNames() As String = Split(FileListBuf, ChrW(0))
>
> '配列の中身を確認
> For Each X As String In SectionNames
> Console.WriteLine("[" & X & "]")
> Next
> End Sub
>
> ------------------------------------------------------------------------
解決済み!
2005/08/31(Wed) 16:50:12 編集(投稿者)

# 解決済みのようですが、一応補足とツッコミを。


> <マーシャリングしてString型で受け取る場合のマネージコード>
こちらは、呼び出し部分も書かれているみたいですけれども、

> <BYTE配列で受け取る場合のマネージコード>
こちらについては、肝心の『TEST_StrGetを呼び出している部分』が抜けていませんか?


> ※separateを"Char.MinValue"に指定しないと分割されない。
> &H0、Nothing、VbNullでは分割されませんでした。
今回、区切り文字になっているのは、「文字コードが 0 の文字」ですよね。

これを、String型で書くならば、
Dim A As String = vbNullChar
Dim B As String = Char.MinValue
Dim C As String = ChrW(&H0)
と表す事ができます。(表現は異なりますが、AもBもCも内容は同じです)

これらは 1つのnull文字を表しているため、A.Length で文字数を調べると
いずれのパターンでも「1」という文字数を返します。

しかし、&H0、Nothing、VbNull については……これらはいずれも別物です。


まず Nothing は、いわば「空の状態」を表します。
http://www.microsoft.com/japan/msdn/library/ja/vblr7/html/vakeyNothing.asp
たとえば、「Dim A As String = Nothing」とした場合、参照型である
変数 A が空の状態となるため、A.Length が使えません(エラーとなります)。
この時点で、Char.MinValue と Nothing は別物です。
# 値型に代入した場合は、状況が若干異なりますが。

次に &H0 ですが、これは文字では無く数値です。
「Option Strict Off」による暗黙の型変換によって、これが
"0" という文字列、つまり ChrW(&H30) という値になる事はありますが、
それでも null文字である ChrW(0) とは別物といえます。


最後に VbNull ですが、これは VariantType.Null の別名です。
文字列ではなく、VarType関数の戻り値として使われる列挙値であり、
整数としてみた場合は 1 という値をとります。これも暗黙の型変換で、
"1" の文字――すなわち ChrW(&H31)――とみなされる場合がありますが、
null文字である ChrW(0) とは、やはり異なる物といえます。


>  '★Stringオブジェクトを作成していますが明確な理由はわかりません
>  Dim FileListBuf As New String(" "c,1000)
上記は、
Dim FileListBuf As String
FileListBuf = " " '←1000個の空白(のつもり)
と同じ意味です。
DLL側が結果を書き込むための領域として、1000文字分のバッファを用意しています。


>  '★Stringオブジェクトを作成していますが明確な理由はわかりません
> Dim Term As New String(ChrW(0), 2)
こちらも同様で、
Dim Term As String
Term = ChrW(0) & ChrW(0)
と同じ意味となります。

サンプル中で、2連のnull文字を用意しているのは、あくまでも、
私が例として使用した GetPrivateProfileSectionNames APIの場合です。

TEST_StrGet の内部仕様については知りませんので、この部分の処理が、
taaさんのコードに本当に必要なのかどうかは、私にはわかりません。


> "GetPrivateProfileSectionNamesA"の動作も良くわからなかった
このAPI について SDK で調べて見ますと、
  The buffer is filled with one or more null-terminated strings;
  the last string is followed by a second null character.
と記述されています。
文字列間に null文字が配置され、終端には2つのnull文字が配置されます。


言い換えると、このAPIは、"aa", "bb", "cc" という3つの文字列を返すために、
 [a] [a] [null] [b] [b] [null] [c] [c] [null] [null]
のような10個の文字列を返却するという事です。(11個目以降については不定)

そのため先のサンプルでは、上記の2連nullを取り去り、
 [a] [a] [null] [b] [b] [null] [c] [c]
に変える必要がありました。そこで私は、この2連nullを検索するために、
> Dim Term As New String(ChrW(0), 2)
という変数を用意した……というわけです。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板