2

ここで問題があります。Cで記述された関数にVB6文字列を渡そうとしていますが、LPSTRとは異なると思います。関数が呼び出されると、VB6IDEがクラッシュします。Cの関数に引数としてVB文字列を渡すにはどうすればよいですか?以下は私のコードです。ありがとうございます:

VB6

Private Declare Function WritestStr Lib “teststr.dll” (ByRef mystr As String) As Long

Private Sub command1_Click()

    Dim mystr as string

    Call WritestStr(mystr)
    Msgbox mystr

End Sub

VC6

include “windows.h”

Int __stdcall WritestStr(LPSTR *mystr)
{
    *mystr = “Venancio Guedes”;
    return 0;
}
4

2 に答える 2

3

VB/Win32 の関数宣言を書いてから何年も経ちましたが、VB6 の外部ライブラリ関数へのすべてのパラメータがデフォルトで ref; によって渡されることを覚えていると確信しています。ただし、VB6 の String 型は既にポインター ベースの型であるため、既に byref で渡された byref パラメーターは間違った値をスタックにプッシュします。これにより、参照が DLL 内でクラッシュします。代わりに、ByVal を渡してみてください。これは、パラメーターの「値」が実際には文字列ポインター自体であり、DLL 関数が期待するものだからです。

私が言ったように、私がこの種の宣言を書いてから長い時間が経ちましたので、すべての標準的な警告が適用されますが、それが近いと確信しています.

幸運を!

編集DLL 関数の ByVal 宣言は正しいです。修正は、スペースを使用して DLL 関数を呼び出す前に文字列を初期化/割り当てする必要があります。たとえば、次のようになります。

Dim vbString as String
Dim result as Long
vbString = Space$(255) ' just make sure this number is large enough
result = WritestStr(vbString)
于 2012-08-03T13:55:40.923 に答える
2

VB 文字列は、OLE ドキュメントでは BSTR と呼ばれ、LPWSTR とほぼ互換性があります。これらは 1 文字あたり 2 バイトの Unicode (UTF-16) 文字列で null で終了しますが、文字列ポインターが指すメモリの直前に 32 ビットの長さがあります。

コードは LPSTR* を使用します。これは、1 文字あたり 1 バイトの ANSI 文字列へのポインターへのポインターです。明らかに、文字列を VB6 コードに返すためにこれを行っています。

残念ながら、この 2 つは互換性がありません。

コードがクラッシュする理由は、VB6 変数 <mystr> を関数に渡しているためですが、デフォルトでは次のように vbNullString に設定されています。

BSTR mystr = NULL;

しかし、あなたの主な問題は、VB が C 関数を記述どおりに使用できない可能性があることです。LPSTR* の Declare ステートメントを記述する方法はありません。Cコードを次のように変更した場合

include “windows.h”

Int __stdcall WritestStr(LPSTR mystr)
{
    const LPSTR myconststr = “Venancio Guedes”;

    if (mystr)
        int destlen = strlen(mystr);
        int srclen = strlen(myconststr);
        if (destlen >= srclen)
        {
            strcpy(mystr, myconststr);
            return 0;
        }
    return srclen;
}

...宣言を次のように変更できます。

Private Declare Function WritestStr Lib “teststr.dll” (ByVal mystr As String) As Long

...そして、文字列を受け入れるバッファを宣言してください。LPSTR の Declare ステートメントを作成することもできますが、それを行う必要があります

Private Sub command1_Click()

    Dim mystr As string
    Dim nLen As Long

    mystr = Space$(1024)
    nLen = WritestStr(mystr)

    Msgbox Left$(mystr, nLen)

End Sub

これは、ほとんどの Win32 API 関数がどのように機能するかを非常に連想させます。

mystr を ByVal として渡すと、<mystr> を BSTR から一時的な LPSTR にコピーし、そのバッファーへのポインターを渡す必要があることが VB6 に通知されます。WriteStr() の実行が完了すると、LPSTR バッファーを元の BSTR にコピーします。

関数に渡す VB 文字列バッファー <mystr> を割り当てると、何かを書き戻すことができます。

または、C プログラムを書き直して、BSTR をネイティブに受け入れるようにすることもできます (多言語が必要な場合は、最もクリーンで移植性の高いソリューションです)。その場合、元の VB6 宣言は、つまり ByRef mystr As String になります。残念ながら、ここで行っているように、まだバッファに書き込む必要があります。

LPWSTR*、LPSTR*、または BSTR* が必要な場合は、タイプ ライブラリで関数を宣言する必要があります。これについては、ここで説明する時間がありません。

于 2012-08-03T18:16:27.390 に答える