C++でVB用にポインタをラップするようなクラスを作ろうと思っています。
VBからByRefで変数を受け取って、そのポインタを保持し、
そのポインタの参照先の変数の値を取得したり、代入するメソッドを実装します。

しかし、ポインタを受け取る時点で、正しいポインタが受け取れていないようです。

idlファイルはおよそウィザードに任せていますが、扱うのは初めてなので、
ドのようにすればByRefで正しいポインタを受け取れるのか教えていただけないでしょうか。


---------------------------------------------
VbHelpLibrary.idl
...
interface ILongRef : IDispatch{

[propget, id(1), helpstring("プロパティ Ptr")] HRESULT Ptr([out, retval] long *pVal);
[propput, id(1), helpstring("プロパティ Ptr")] HRESULT Ptr([in] long* newVal);
[propget, id(2), helpstring("プロパティ Value")] HRESULT Value([out, retval] long *pVal);
[propput, id(2), helpstring("プロパティ Value")] HRESULT Value([in] long newVal);

};

---------------------------------------------
LongRef.cpp

STDMETHODIMP CLongRef::get_Ptr(long *pVal){

*pVal = (long)this->m_ptr;
return S_OK;

}

STDMETHODIMP CLongRef::put_Ptr(long *newVal){

this->m_ptr = newVal; //ここでnewValがVarPtr(X)と一致しない
//*newVal = 100; //試しにここでこのポインタの先に値を入れてもXは変化しない
return S_OK;

}

STDMETHODIMP CLongRef::get_Value(long *pVal){

*pVal = *m_ptr;
return S_OK;

}

STDMETHODIMP CLongRef::put_Value(long newVal){

*m_ptr = newVal;
return S_OK;

}

---------------------------------------------
Module1.bas

Sub Main()

Dim X As Long, Y As New LongRef
Debug.Print "VarPtr(X) = ", VarPtr(X)
Y.Ptr = X
Debug.Print "Y.Ptr = ", Y.Ptr

---------------------------------------------
結果
VarPtr(X) = 1308376
Y.Ptr = 1929464

A 回答 (2件)

>>STDMETHODIMP CLongRef::get_Ptr(long *pVal)


>としたのは、long**にするとVBで扱えなくなってしまったからです。

なるほど、試してみましたが確かに VB ではエラーになってしまいました。
プロパティとして考えると違和感がありますが、これはこれで仕方がないかなと思います。


>[id(3), helpstring("メソッド setPtr")] HRESULT setPtr([in] long* newVal);
>を作ってみたのですが、結果が同じでした。

私も試してみましたが、意図したものになりましたよ。

.idl
==================================================================================
[propget, id(1), helpstring("プロパティ Ptr")] HRESULT Ptr([out, retval] long * pVal);
[id(3), helpstring("メソッド SetPtr")] HRESULT SetPtr(long * newVal);


.cpp
==================================================================================
STDMETHODIMP CLongRef::get_Ptr(long * pVal)
{
*pVal = (long)m_ptr;
return S_OK;
}

STDMETHODIMP CLongRef::SetPtr(long * newVal)
{
m_ptr = newVal;
return S_OK;
}

VB
==================================================================================
Dim X As Long
Dim Y As New LongRef

X = 100
Debug.Print "VarPtr(X) = " & VarPtr(X)

'Y.Ptr = X
Y.SetPtr X
Debug.Print "Y.Ptr = " & Y.Ptr

実行結果
==================================================================================
VarPtr(X) = 1306696
Y.Ptr = 1306696


STDMETHODIMP CLongRef::SetPtr(long * newVal)

の中身はどのようになってますか?


>idlとcppとhだけだと思っていたのですが、他にも対にしなければならないものがありますか?

.idl、.cpp、.h だけで良いと思います。
    • good
    • 0
この回答へのお礼

遅くなってすみません。

>私も試してみましたが、意図したものになりましたよ
もういちどクラスからウィザードで作り直したら、意図した結果になりました。
やはり、クラスウィザードが管理している触ってはいけない部分を、いつの間にか変えてしまっていたのかもしれません。

また、Long変数をputしてlong*の値をgetするのも変なので、Ptrプロパティは単にm_ptrをLongとしてラップするプロパティとして、SetPtrを別に設けることにします。

ありがとうございました。

お礼日時:2011/05/03 19:37

VB では Integer や Long 等の値型の変数に対して



Z = X

のようにすると値渡しで代入されます。これは代入先がプロパティの場合でも同じです。
つまり、

Y.Ptr = X

とすると、VB 側で X のコピーが作られ、X のコピーが Y.Ptr に渡されます。

STDMETHODIMP CLongRef::put_Ptr(long *newVal)

の newVal は [ X のコピーのアドレス] になります。

VB の言語仕様として Integer や Long の参照型変数というものがない以上、プロパティで参照渡しはできないでしょう。
なので、プロパティでなく関数にしなければならないと思います。(いうまでもなく、引数は参照渡しにしなければなりません。)



実行結果が

>VarPtr(X) = 1308376
>Y.Ptr = 1929464

のように、値が大きく異なっているのは、


STDMETHODIMP CLongRef::get_Ptr(long **pVal)

とすべきところが

STDMETHODIMP CLongRef::get_Ptr(long *pVal)

となっているためではないかと思います。
( ただしいコピーのアドレスであれば、もっと近い値になるのあ普通だと思います。)


ちなみに、VB は 6.0 ですか?

この回答への補足

解凍ありがとうございます。
すいません、バージョンを書いていませんでした。
VBもVC++も6.0です。

>STDMETHODIMP CLongRef::get_Ptr(long *pVal)
としたのは、long**にするとVBで扱えなくなってしまったからです。

>VB の言語仕様として Integer や Long の参照型変数というものがない以上、プロパティで参照渡しはできないでしょう
VBで書いたら以下のようになることを、C++で書こうと思いました。

Property Get Ptr() As Long
Ptr = m_ptr
End Property
Property Let Ptr(ByRef RHS As Long)
m_ptr = VarPtr(RHS)
End Property

上記のコードではLetで実際に渡るのはLongポインタで、Getで返すのはLong値だとおもいます。
このため、long *pValとしましたが、イレギュラーでしょうか・・・?

ためしに、

[id(3), helpstring("メソッド setPtr")] HRESULT setPtr([in] long* newVal);

を作ってみたのですが、結果が同じでした。


ためしに、別のクラスVariantRefを作って同じようなことをやってみたのですが、

[id(3), helpstring("メソッド setPtr")] HRESULT setPtr([in] VARIANT* newVal);

は、ちゃんと正しいなポインタを受取れました。

あとから作ったVariantRefはプロパティとメソッドの作成をすべてウィザードに任せたのですが、LongRefでは試行錯誤しながらだったので、メンバを作ったり消したり、型を変えたりしてしまったのが行かなかったのでしょうか?

ウィザードがメンバの作成時に追記したのは、質問のところで書いた、idlとcppとhだけだと思っていたのですが、他にも対にしなければならないものがありますか?

VBでクラスを作ったり、C++で普通のクラスを作ったりはしているのですが、C++でATLクラスを作るのは初めてなうえ、文献もあまり見つからないため、ご教授いただきたいと思っております。

補足日時:2011/04/30 19:36
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

Q.NETでActiveXコントロールを使う

開発系初心者です。

ある事情にて.NETの環境でActiveXコントロールの使用を行うことになりました。
そこで、下記アドレスの方の方法を参考にさせていただいたのですが、
ラッパークラスライブラリの生成が行えません。

.NET環境でActiveXコントロールの実装を行うことに参考にさせていただいたサイト
http://blogs.wankuma.com/ganfield/archive/2007/03/13/66556.aspx

サイトに記載されているActiveXの登録には、下記のアドレスの方のを参考に、
regsvr32で登録済みとなっています。

ActiveX登録に参考にさせていただいたサイト
http://www3.ocn.ne.jp/~tonko/HP13_02.htm

二つのラッパーライブラリが生成できないというのは、コマンドプロンプトの作業時、
AxImp c:\WINDOWS\system32\msdxm.ocx
と、入力しても
AxImp エラー: タイプ ライブラリ/DLL の読み込みエラーです。(HRESULTからの例外:0x80029C4A (TYPE_E_CANTLOADLIBRARY))
と出てしまい、ラッパーライブラリが生成できません。上記サイト以外に、何か準備する必要があるのでしょうか?
なお、開発環境は、
OS     :Windows 7
開発環境 :Visual Studio 2010
です。プログラミング言語ではC#の使用を予定しています。

どなたかご回答をお願い致します。

開発系初心者です。

ある事情にて.NETの環境でActiveXコントロールの使用を行うことになりました。
そこで、下記アドレスの方の方法を参考にさせていただいたのですが、
ラッパークラスライブラリの生成が行えません。

.NET環境でActiveXコントロールの実装を行うことに参考にさせていただいたサイト
http://blogs.wankuma.com/ganfield/archive/2007/03/13/66556.aspx

サイトに記載されているActiveXの登録には、下記のアドレスの方のを参考に、
regsvr32で登録済みとなっています。

ActiveX登録に参考にさせ...続きを読む

Aベストアンサー

http://social.msdn.microsoft.com/forums/en-US/vblanguage/thread/a2a04bb7-8523-4b39-b3bc-a1e2b02b7aca/
で解決しているっぽい


人気Q&Aランキング

おすすめ情報