Split関数に近いDLL関数を作成するには?


ぽよん  2005-12-22 16:08:46  No: 93371

「"」で囲まれた中にある「,」は無視するなど
VB標準のSplit関数では物足りない部分を補うために
Public Function CsvSplit(ByVal iStr As String) As String()
のような形式でSplit関数とほぼ同じインターフェースを持つ
オリジナル関数を作ってみたのですが
処理速度向上のために(実際に速度があがるかどうかわかりませんが)
VC++でDLLを作ってみようと考えています。

そこでここの掲示板の過去ログやGoogle等で
VBから呼び出すためのDLLの作り方を色々探してみたところ、
引数としてVB側であらかじめ領域を確保した文字列変数を渡して
そこに結果を格納する方法などは見かけるのですが
「戻り値として文字列配列を返す」サンプルを見つけることができませんでした。

ということでお聞きしたいのは主に次の3点です。
・そもそも可能ですか?(^^;
・DLLソースでの関数宣言とVB側のDeclareはどのような形になりますか?
・文字列配列を返すとなるとメモリ確保/解放の仕組みはどうなりますか?
なるべくSplit関数に近い形にしたいと思うので
例えば引数に空文字列("")を受け取って返した結果を
VB側のLBound/Uboundでチェックすると0/-1になるのが理想ですが…

環境はVC++とVB6(SP6)、WindowsXPを想定しています。
以上、よろしくお願いいたします。


Blue  2005-12-22 16:29:43  No: 93372

> そもそも可能ですか?(^^;
可能です。

> 文字列配列を返すとなるとメモリ確保/解放の仕組みはどうなりますか?
GlobalAlloc等のAPIを使います。
文字列配列を返すときは、SAFEARRAYオブジェクトを使います。

とりあえず、「SAFEARRAY」をキーワードに検索してみてください。


Blue  2005-12-22 16:59:34  No: 93373

> 可能です。
断定しないほうがよさそう。

ByRefで配列をVariant変数を渡す方法は

http://support.microsoft.com/default.aspx?scid=kb;ja;410837#XSLTH3161121122120121120120
String 型の配列の引き渡しの サンプル

にあります。

Splitとは違う使われ方になると思うけど結構簡単にできそう。
Public Sub CsvSplit(ByRef oData, ByVal iStr As String)
見たいな感じで。
# どうしてもSplitのような形式にしたいならば、VBでDLL側との連携するラッパー関数を作ればいいと。


K.J.K.  2005-12-22 19:07:54  No: 93374

Splitの構文は、ODLで記すと、

VARIANT __stdcall Split
( [in] BSTR Expression, 
  [in, optional] VARIANT* Delimiter,
  [in, optional, defaultvalue(-1)] long Limit,
  [in, optional, defaultvalue(0), "1")] bCompareMethod Compare);

なのですから、それを参考にしてみるとか。もっともODL/IDLで記述
するのであれば、

HRESULT __stdcall Split
( [in] BSTR Expression, 
  [in, optional] VARIANT* Delimiter,
  [in, optional, defaultvalue(-1)] long Limit,
  [in, optional, defaultvalue(0), "1")] bCompareMethod Compare,
  [out, retval] VARIANT* pvarResult);

もしくは、

HRESULT __stdcall Split
( [in] BSTR Expression, 
  [in, optional] VARIANT* Delimiter,
  [in, optional, defaultvalue(-1)] long Limit,
  [in, optional, defaultvalue(0), "1")] bCompareMethod Compare,
  [out, retval] SAFEARRAY(BSTR)** psaResult);

のような構文にするのが無難かと。

タイプライブラリが作れない、という場合は、素直に戻り値を
VARIANTにするべきでしょう。Declareステートメントを用いる
と、文字列型そのものもしくはその配列を引数もしくは戻り値
として使う際には、VBによりAnsi<=>Unicodeの変換が行われて
しまうからです。


Blue  2005-12-23 00:02:03  No: 93375

COMベースで考えればよかったですね。
(といか、私はCOMはつくったことないですけど。)

適当につくってみたら

Private Declare Function SetStrArray Lib "xxx.dll" () As String()
__declspec( dllexport ) LPSAFEARRAY __stdcall SetStrArrayEx()

見たいなのはできました。(上手くいっているように見えるだけかも)

> VBによりAnsi<=>Unicodeの変換が行われて
これかなりうざったいですね。SysAllocStringByteLenなのかSysAllocStringなのか
よくわからなくなる。


K.J.K.  2005-12-23 00:09:23  No: 93376

まぁ、Declareするのならば、VARIANTで包むのが楽でしょうね。
SAFEARRAY*そのままに拘る必要はないと思いますよ。


ぽよん  2005-12-26 14:17:44  No: 93377

たくさんのご回答ありがとうございます。
SAFEARRAY等のキーワードがまだ消化し切れていないので
ちょっと試行錯誤してみようと思います。


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

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







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