VBでOCXから値を取得するには?

解決


panda  2005-03-28 22:22:18  No: 120503

VBから構造体を引数でOCXに渡し、OCX側で値を格納し、それをVB側で取得したいのですが、うまくいきめせん。

OCX
[id(4), helpstring("メソッド GetData")] HRESULT GetData(wchar_t* output);
VB
AAA.GetData g_Data  ←General  Declationsで宣言した構造体
TipsにはGetData(output As Integer)と表示される。
実行すると、「パブリックオブジェクトモジュールで定義されたユーザー定義型に限り、変数に割り当てることができ、実行時バインディングの関数を渡すことができます」のエラーが発生する。

どなたかVBとVCでの構造体のデータやり取りの経験がある方、ご教授ください。
よろしくお願いいたします。


魔界の仮面弁士  2005-03-28 23:05:34  No: 120504

wchar_t って、定義上は『typedef unsigned short wchar_t;』ですから、
VB側で As Integer として認識されるのは、正常な動作ですよね。

> AAA.GetData g_Data  ←General  Declationsで宣言した構造体
上記が良くわかりません。
これって、C側の記述ですか? それともVB側?

いずれにしても、ActiveXコンポーネントとしての話なら、
その構造体が、Publicなものとしてレジストリに登録されている必要が
あるでしょうし、Declareステートメントで使うタイプのDLLの話なら、
その構造体定義を、VB側にTypeステートメント(VB.NETではStructure)で
記述する必要があるでしょう。

> どなたかVBとVCでの構造体のデータやり取りの経験がある方、ご教授ください。
経験は無いですが、dx8vb.dll などでは、RECT構造体が

typedef [helpcontext(0x0001544a)] struct tagRECT {
        long left;
        long top;
        long right;
        long bottom;
} RECT;

と定義されていて、メソッド側で

        [helpcontext(0x00015186)]
        int _stdcall DrawTextW(
                        [in] BSTR Text, 
                        [in] int count, 
                        [in] RECT* DestRect, 
                        [in] long Format, 
                        [in] long color
        );

などのようにして利用されていますね。


panda  2005-03-28 23:20:25  No: 120505

魔界の仮面弁士さん  ご解答ありがとうございます。
wchar_t って、定義上は『typedef unsigned short wchar_t;』ですから、
VB側で As Integer として認識されるのは、正常な動作ですよね。

  そうなんですね。VBしか知らなくて。。。けどここにユーザー定義型を
  引数にできるのでしょうか?

> AAA.GetData g_Data  ←General  Declationsで宣言した構造体
上記が良くわかりません。
これって、C側の記述ですか? それともVB側?

  上記はVB側での記述です。
  AAAはVBにコンポーネントとして追加しています。

いずれにしても、ActiveXコンポーネントとしての話なら、
その構造体が、Publicなものとしてレジストリに登録されている必要が
あるでしょうし、Declareステートメントで使うタイプのDLLの話なら、
その構造体定義を、VB側にTypeステートメント(VB.NETではStructure)で
記述する必要があるでしょう。

Publicなものとしてレジストリに登録するにはどうしたらいいのでしょうか。
よろしくお願いいたします。


魔界の仮面弁士  2005-03-29 01:23:44  No: 120506

# 構造体ではなく、別のCOMクラスを渡すと言う手もありますね。

>> AAA.GetData g_Data  ←General  Declationsで宣言した構造体
> 上記が良くわかりません。
> これって、C側の記述ですか? それともVB側?
>    上記はVB側での記述です。
>    AAAはVBにコンポーネントとして追加しています。

あぁ、なるほど。宣言部のコードではなく、呼び出し時のコードでしたか。

では、VB側における g_Data のユーザー定義型(≠構造体)の定義と、
対応する VC側の構造体(≠ユーザー定義型)の定義は、それぞれ
どのような物になっていますか?

> Publicなものとしてレジストリに登録するにはどうしたらいいのでしょうか。

VCでパブリックなユーザー定義を作るという話だとしたら、
ここはVisual Basic向けの掲示板ですから、回答いたしかねます。
(IDLでの定義なら、先ほど書いたRECT構造体のサンプルを参考に)

VBでパブリックなユーザー定義を作るという話なら、ActiveX DLLプロジェクトで
ClassモジュールのInstancingプロパティを Private 以外に設定しておき、
そこで Public Type なユーザー定義型を作れば OK です。


panda  2005-03-29 03:17:38  No: 120507

魔界の仮面弁士様  ご解答ありがとうございます。

VBでパブリックなユーザー定義を作るという話なら、ActiveX DLLプロジェクトで
ClassモジュールのInstancingプロパティを Private 以外に設定しておき、
そこで Public Type なユーザー定義型を作れば OK です。

DLLを作成するのでしょうか?
また、TipsにはGetData(output As Integer)と表示されるところに
構造体は引数としていれれるのでしょうか。

構造体は下記のとうりです。
VB側
Public Type DDD
    aaa As Long
    bbb As Long
    ccc As Byte
    ddd As Long
    eee  As Byte
    fff  As Long
End Type

VC側
    aaa 4byte
    bbb 4byte
    ccc 1byte
    ddd 2byte
    eee 1byte
    fff 2byte

以上、よろしくお願いいたします。


魔界の仮面弁士  2005-03-29 05:05:57  No: 120508

> ご解答ありがとうございます
解答にはなっていないと思います。ただの回答ですね。(^^;

> DLLを作成するのでしょうか?
パブリックな構造体としてレジストリに登録されてさえいれば、
形態は問いません。VB製のActiveX EXEにて作成しても良いですし、
VC++で作ったOCXに含めてあっても構いませんよ。

ただし、「VC,VB等で作成されたOCXを、VBで利用するための方法」や、
「VBでOCXを作成する方法」ならば答えられきますが、知りたいのが
「VBで作成したOCXを、VC側で利用するための方法」や、
「VCでOCXを作成する方法」だとしたら、ここで答える事はできません。

> また、TipsにはGetData(output As Integer)と表示されるところに
> 構造体は引数としていれれるのでしょうか。
そう言われましても。(^^;
回答側としては、OCX側の仕様を知らないのですから、
定義に関する事柄を聞かれても困ってしまいます。

> 構造体は下記のとうりです。
………本当に、これと同一の構造体なのですか?
どちらかが間違っている(or 両方が間違っている)ような気がするのですが。

1. 型名がDDDというのが疑わしい。
2. そもそも、VC側が構造体の定義(struct)になっていない。
3. ddd, fffメンバのサイズが、VB側とVC側で一致していない。

ただ少なくとも、最初に書かれた
> [id(4), helpstring("メソッド GetData")] HRESULT GetData(wchar_t* output);
という定義においては、そのDDD型の構造体がどこにも使われていませんので、
少なくともVB側では、この構造体の出番は無いと思います。


魔界の仮面弁士  2005-03-29 18:56:45  No: 120509

# もしかして、users.gr.jpの[VB:14284]の投稿の人でしょうか?

まだ、やりたい事が見えてこないので、参考になるかわかりませんが。

VB6にて、
'-------------------------- UDTSample.ctl
  Option Explicit
  Public Type COMUDT
    Member1 As Long
    Member2 As String
    Member3 As Integer
    member4 As Boolean
  End Type
  '☆イベントの引数にユーザー定義型を指定した場合
  Public Event Click(ByRef Param As COMUDT)
  Private Sub UserControl_Click()
    Dim X As COMUDT
    X.Member1 = ObjPtr(Me)
    X.Member2 = Ambient.DisplayName
    X.Member3 = 0
    X.member4 = True
    RaiseEvent Click(X)
  End Sub
'--------------------------

のような定義の ActiveXコントロールを作成し、そのocxを
OLEVIEW.EXE で解析してみると、下記のようなIDLが生成されますね。
"struct"にて、構造体が定義されている事がわかります。

  [uuid(……),……]
  library UDTSample
  {
    importlib("stdole2.tlb");
    interface _UDTControl;
    dispinterface __UDTControl;

    [uuid(……),……]
    interface _UDTControl : IDispatch {};

    [uuid(……),……,control]
    coclass UDTControl {
      [default] interface _UDTControl;
      [default, source] dispinterface __UDTControl;
    };

    [uuid(……),……]
    dispinterface __UDTControl {
      properties:
      methods:
        [id(0x00000001)]
        void Click([in, out] COMUDT* Param);
    };
    [uuid(……),……]

    typedef [uuid(……),……]
    struct tagCOMUDT {
      long Member1;
      BSTR Member2;
      short Member3;
      VARIANT_BOOL member4;
    } COMUDT;
  };

で。上記OCXをVBで利用した場合は、

  Private Sub UDTControl1_Click(Param As UDTSample.COMUDT)

  End Sub

のように、イベントの引数としてユーザー定義が受け渡せていますね。

という事で。技術的にはOCXで構造体を使う事は可能ですし、
それを利用する事も(VB6であれば)可能なはずです。

ただし、VC側云々という部分になってくると、この掲示板の範疇を
超えてしまいますので、その件については回答を控えさせていただきます。


panda  2005-04-01 18:46:01  No: 120510

魔界の仮面弁士様ありがとうございました。
解決いたしました。下記のとうりです。
本当に助かりました。

VB************************************************
Public Declare Sub CopyMemory Lib "kernel32" Alias
 "RtlMoveMemory" (pDest As Any, pSrc As Any, ByVal ByteLen As Long)

Public Type EVENT_REC
    Temp                  As Long         'アドレスがはいる
    sec                     As Long         '4byte
    usec                    As Long         '4byte
    eventType             As Byte         '1byte
    channelNo             As Integer      '2byte
    videoDataPossible   As Byte         '1byte
    area                As Integer      '2byte
End Type
Public g_EventRec(0)    As EVENT_REC

Dim tpos    As Long
Dim apos    As Long

    tpos = VarPtr(g_EventRec(0))    'アドレスを取得
    apos = tpos
    Window1.GetLatestEvent tpos
    (ここでtpos=0になる)
    CopyMemory g_EventRec(0), apos, Len(g_EventRec(0))    'コピー

VC************************************************
[id(4), helpstring("メソッド GetLatestEvent")] HRESULT GetLatestEvent(long* output);

STDMETHODIMP ReportWindow::GetLatestEvent(long *output)
{
        memcpy(output, &m_latest_log, sizeof(m_latest_log));        'コピー

}


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

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






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