固定長文字列作成

ActiveBasicでのプログラミングでわからないこと、困ったことなどがあったら、ここで質問してみましょう(質問を行う場合は、過去ログやWeb上であらかじめ問題を整理するようにしましょう☆)。
返信する
メッセージ
作成者
こまた

固定長文字列作成

#1 投稿記事 by こまた »

お世話になります。

固定長文字列を作成するDLL関数を作りたくて、以下のソースを作成し、エクセルのVBAで実行しました。

すると、エクセルが落ちてしまいました!

そこで
①エクセルが落ちた原因は下記コードにありますか?
②下記はmylenの値分の固定長文字列をつくるもので、nydataが桁数に満たない場合は半角スペースでうめるものです。けたあふれは無視します。
このコードであっていますか?
基本的にエクセルで使うので、mydataもmyLenもセルに入っている値です。


ちょっといい加減な質問で申し訳ございません。
そのあたりのマナーも含めてご教示ください。
よろしくお願いします。

Function export Lstrfix(myData as BytePtr, myLen as long) As String

'//変数の定義
dim mySpc As long


'▼▼▼処理▼▼▼
'//指定した固定長のバイト数から、データの分のバイト数を引いてスペースの数を取得
mySpc = myLen - Len(myData)

'//データとスペースで固定長の文字列を生成
Lstrfix = myData + Space$(mySpc)

end function
イグトランス
記事: 899
登録日時: 2005年5月31日(火) 17:59
お住まい: 東京都
連絡する:

#2 投稿記事 by イグトランス »

String型をDLL関数で受け渡すことはできません。また、ABとVBのStringは別物です。
その程度の関数だったらVBAで標準モジュール内に書けば良い気がしますが,敢えてABでやるならば,こうするとどうでしょうか?

Len関数が文字列を長さを返すのはString型の値を使ったときだけで,BytePtr型の値を引数に渡してもうまくいきません。
BytePtr型に対してはlstrlen関数を使います。

ところがVBから渡された文字列はSysStringByteLenを使う方が効率的です。
(lstrlenはABのStringにも使えますが同様にLenの方が効率的です)

そこで結局私ならこうします。

コード: 全て選択

Function LstrfixLen(myData as BytePtr, dataLen As Long, myLen as long) As String 
	Dim mySpc As long 
	mySpc = myLen - dataLen
	LstrfixLen = myData + Space$(mySpc) 
End Function
/*
Function Lstrfix(myData as BytePtr, myLen as long) As String 
	Lstrfix = LstrfixLen(myData, lstrlen(myData) As Long, myLen) 
End Function
*/
Function Export LstrfixVB(ByVal myData As BSTR, ByVal myLen As Long) As BSTR
	Dim ret As String
	ret = LstrfixLen(myData As BytePtr, SysStringByteLen(myData) As Long, myLen)
	LstrfixVB = SysAllocStringByteLen(StrPtr(ret), Len(ret))
End Function
SysAllocStringByteLenの戻り値を返すようにすると,VBでは戻り値をString型で受けることができます。
BSTR = VBのStringと思って差し支えありません。
(ただし文字列引数をDLLで受け取るときだけはこまたさんの元のLstrfixのようにBytePtrで受け取って構いません)

ABからLstrfixを使えるように公開したい場合は,別の方法を使います。(今は省略)

VBでは次のように宣言します。ByRef/Valを省略したときABではByValですが,VBではByRefであることに注意が必要です。

コード: 全て選択

Private Declare Function Lstrfix Lib "DLL名" Alias "LstrfixVB" ( _
    ByVal myData As String, _
    ByVal myLen As Long _
) As String
こまた

固定長文字列作成

#3 投稿記事 by こまた »

イグトランスさん、ありがとうございます。

DLL可するのは、他にも関数をまとめて作りたいのと、各VBAのモジュールにいちいちコピーするのが少し手間だったからです。まあ、我慢すればいいんでしょうけど。


ソースくださいましてありがとうございます。
ちょっと勉強して何かありましたらまた質問させていただきます!
こまた

#4 投稿記事 by こまた »

すみません。コンパイルしたら以下のエラーがでました.

xGVBDLL.abp(31) - "BSTR" 無効な識別子です
xGVBDLL.abp(33) - "SysStringByteLen(myData)" 無効な識別子です
xGVBDLL.abp(34) - "LstrfixVB" 無効な識別子です
xGVBDLL.abp(34) - "SysAllocStringByteLen(StrPtr(ret),Len(ret))" 無効な識別子です

BSTR型って何でしょうか?
ヘルプみても無いもので・・・。
見逃してますでしょうか?
イグトランス
記事: 899
登録日時: 2005年5月31日(火) 17:59
お住まい: 東京都
連絡する:

#5 投稿記事 by イグトランス »

それはすみませんでした。
この宣言類を書き加えてください。

コード: 全て選択

TypeDef BSTR = *WCHAR

Declare Function SysAllocStringByteLen Lib "oleaut32" (
	psz As BytePtr,
	len As DWord
) As BSTR 

Declare Function SysStringByteLen Lib "oleaut32" (
	bstr As BSTR
) As BSTR
M.K
記事: 18
登録日時: 2005年6月07日(火) 22:06
お住まい: 長崎県

これで、ダメでしょうか?

#6 投稿記事 by M.K »

こんばんは、

コード: 全て選択


・DLL側のコード
Function Export Lstrfix(myData As BytePtr, myLen As Long) As String  

	Dim mySpc     As Long
	Dim strMyData As String

	strMyData = MakeStr(myData)
	mySpc	  = myLen - Len(strMyData)

	Lstrfix = strMyData + Space$(mySpc)


End Function

・Excel側の定義

Declare Function Lstrfix Lib "????.dll" (ByVal myData As String, ByVal myLen As Long) As String

・Excel2000で試しました。
イグトランス
記事: 899
登録日時: 2005年5月31日(火) 17:59
お住まい: 東京都
連絡する:

#7 投稿記事 by イグトランス »

DLLでエクスポートされる関数にString型は使えないことになっているので,M.Kさんの方法ではメモリ周りが不安です。
憶測ですがVBに制御が戻った後,戻り値のStringのメモリは解放されずメモリリークになってしまうと思います。
こまた

固定長文字列作成

#8 投稿記事 by こまた »

みなさんありがとうございます。
M.Kさんの方法だとシンプルですが、メモリの問題がありそうなんですね。。。
VBでメモリを回復する方法があればいいのかな(でもそれはここで聞くことじゃないですね・・・)。

ちょっと整理します。。。
返信する