プロが教える店舗&オフィスのセキュリティ対策術

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で質問しましょう!