DOBON.NET DOBON.NETプログラミング掲示板過去ログ

VB.NETでプロシージャのアドレスを取得する方法。

環境/言語:[Windows2000、VB.NET、.NET Framework 1.1]
分類:[.NET]

初めて質問させていただきます。うりゃです。

VB.NETでプロシージャのアドレスを取得し、Integer型の変数に収めるという操作をしたいのですが、方法がわかりません。

VB6.0ではAddressOf 演算子で取得できたのですが、VB.NETだと
「'Integer' は、デリゲート型でないため、'AddressOf' 式を 'Integer' に変換できません。」
というエラーが出てしまいます。
MSDNを読むと、どうもVB.NETのAddressOfではプロシージャのアドレスを取得することはできないようにも思えます。

プロシージャのアドレスを取得する方法をご存知の方、ご教示いただけないでしょうか。
うりゃさん、こんにちは。
http://www.atmarkit.co.jp/fdotnet/vb6tonet/vb6tonet23/vb6tonet23_04.html
こちらにサンプルありましたよー
■No4380に返信(ゆさんの記事)
> うりゃさん、こんにちは。
> http://www.atmarkit.co.jp/fdotnet/vb6tonet/vb6tonet23/vb6tonet23_04.html
> こちらにサンプルありましたよー

ゆさん、お返事ありがとうございました。
早速教えていただいたURLに行ってみたのですが、まだいまいち理解できていません。
申し訳ありませんが、もう少し詳しく教えていただけないでしょうか。

まず、目的はプロシージャのアドレスを取得して、それをInteger型の変数に渡すということです。(タイトルとちょっと違いますね。ごめんなさい。)

それで、サンプルにあるとおり、

Delegate Sub Sample()
Public Class Form1
  Dim test As Sample = AddressOf Sample
End Class

ここまでは書いてみたのですが、この先のSample()のアドレスをIntegerに格納する方法がわかりません。

そもそも、AddressOf というのはデリゲートのインスタンスが帰ってくるのですよね?
このインスタンスtestのアドレス=プロシージャSampleのアドレスと理解していいのでしょうか。
また、そのアドレスをDelegateではない型の変数に格納してやるにはどうしたらいいのでしょうか。

本当に基本的な質問ばかりで申し訳ないのですが、どうぞご教示ください。
上に書きましたことで間違いがございましたらそちらに対するご指摘もいただけると幸いです。
うりゃさん、こんにちは。
すいません、アドレスさえ取れればいいものかと思ってました^^;
Intに値として取得するのが本来の目的でしたね。
C++でDLLでも作ってアドレスを戻り値として返すようなものを
作るしかないのかもしれませんね。 もう少し調べてみますね。
うりゃさん、こんにちは

試しにDLLを作ってみたところ、それっぽいものは出来ました。

DLLは単純に
extern "C" int PASCAL EXPORT GetAdd(void *iproc)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
return (int)iproc;
}

この関数だけエクスポートしておき

VB.NETでは
Delegate Sub _test()
<DllImport("GetAddress", EntryPoint:="GetAdd")> _
Private Shared Function GetAdd( _
ByVal lpEnumFunc As _test) _
As Integer
End Function

Private Sub test()
Debug.WriteLine("TEST")
End Sub

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim ret As Integer
ret = GetAdd(AddressOf test)
End Sub

でも、本当にアドレスとれてるのか自信ないです^^;
ちがったらごめんなさい。
ゆさん、こんにちは。
お返事、ありがとうございます。

> C++でDLLでも作ってアドレスを戻り値として返すようなものを
そうか!!VB.NETでわからなくてもDLLを作るという手がありましたね。
全然思いつきませんでした(汗)。
もっとしっかり勉強しないとですね・・・

> 試しにDLLを作ってみたところ、それっぽいものは出来ました。
わざわざありがとうございます。m(__)m
早速やってみます。
結果も後日また改めて書き込みさせていただきますね。

ゆさん、本当にどうもありがとうございました。
> VB.NETでプロシージャのアドレスを取得し、
> Integer型の変数に収めるという操作をしたいのですが、方法がわかりません。

VB6ではできていたとのことなので、
アドレスを取得するのが目的ではなく、
APIに対して関数ポインタの指定が必要なのですよね?

APIの宣言で関数ポインタを指定する引数の部分を
VB6なら「As Long」などにしていたと思いますが、
VB.NETであれば、ここを「As そのDelegate型」とすればよいと思います。

http://www5b.biglobe.ne.jp/~yone-ken/VBNET/index.html
の「VB.NETに関するメモ書き」の
 25:[ 高精度タイマーのAPIを使用に関する実験]
で、APIのtimeSetEvent関数(AddressOf演算子が必要な関数)を使っている例があります。

(余談)
注意点としては、上の例ではAddressOfで指定するメソッドは
クラスのインスタンスメソッドとして定義していますが、
VB6同様に標準モジュールで関数を定義した方が面倒がなくてよいでしょう。
うりゃさん、こんにちは
> extern "C" int PASCAL EXPORT GetAdd(void *iproc)
これ、嘘ですね^^;
VBからByValでAddresofを渡してるからGetAdd(int iproc)
ですよね? すいませんm(__)m
よねKENさん、ゆさん、ご回答ありがとうございます。

> アドレスを取得するのが目的ではなく、
> APIに対して関数ポインタの指定が必要なのですよね?
はい。よねKENさんのご指摘どおりです。
SHBrowseForFolder(PBROWSEINFO)を呼び出すために、引数の構造体BROWSEINFOにアドレスを渡してやる必要があり、
vb6.0ではLongに変換して代入していたので、VB.NETでも同じようにIntegerにして渡そうとしていたのです。
この辺り、全く説明していませんでした。申し訳ありません。

> http://www5b.biglobe.ne.jp/~yone-ken/VBNET/index.html
> の「VB.NETに関するメモ書き」の
> 25:[ 高精度タイマーのAPIを使用に関する実験]
> で、APIのtimeSetEvent関数(AddressOf演算子が必要な関数)を使っている例があります。
早速行ってみました。
情報盛りだくさんでとても面白いサイトですね。勉強になります。
今後も参考にさせていただきます。
定義で引数の型をDelegateにしても呼び出すことができるんですね。
仰るとおり、BROWSEINFO内のアドレス格納の変数をIntegerではなくDeclare型で定義したら通りました。
以下のような感じです。

Delegate Function test_Delegate() As Integer
Private Declare Function BrowseCallbackProc Lib "SHELL32" (ByRef lpbi As BROWSEINFO) As Integer

Private Structure BROWSEINFO
Dim lpfn As test_Delegate
End Structure
Private m_Delegate As test_Delegate

Public Class Form1
  Dim BI As BROWSEINFO
Dim pIDL AS Integer

m_Delegate = New test_Delegate(AddressOf test)

BI.lpfn = (m_Delegate)

pIDL = SHBrowseForFolder(BI)
End Class

Private Function test() As Integer
return 1
End Function


またこれとは別に、DLLで取得する方法も試してみたいと思います。
よねKENさん、ゆさん、本当にどうもありがとうございました。m(_ _)m
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板