Author Topic: AddressOf operator in .net  (Read 6327 times)

0 Members and 1 Guest are viewing this topic.

Keith™

  • Villiage Idiot
  • Seagull
  • Posts: 16899
  • Superior Stupidity at its best
AddressOf operator in .net
« on: March 14, 2007, 09:10:40 AM »
I have been trying to figure out the proper syntax of using AddressOf in a .net assembly and I cannot seem to get it right and the help files are no help ....

I can use AddressOf properly ... well according to the help file, but I keep getting an error that the function is not a delegate .. there are a couple of examples, but they don't compile ...

I am hoping to tie a function in my code to an API call as a return function to the API, but so far no luck.
Proud provider of opinion and arrogance since November 22, 2003 at 09:35:31 am
CadJockey Militia Field Marshal

Find me on https://parler.com @kblackie

Bryco

  • Water Moccasin
  • Posts: 1883
Re: AddressOf operator in .net
« Reply #1 on: March 14, 2007, 10:27:12 AM »
Perhaps this may help as an explanation, even though vba not net
it's from http://www.mvps.org/btmtz/

Code: [Select]
Public Function FARPROC(pfn As Long) As Long
 
  'A dummy procedure that receives and returns
  'the value of the AddressOf operator.
 
  'This workaround is needed as you can't
  'assign AddressOf directly to a member of a
  'user-defined type, but you can assign it
  'to another long and use that instead!
  FARPROC = pfn

End Function


With bi
      .hOwner = ThisDrawing.hWnd
      .pidlRoot = 0
      .lpszTitle = "Pre-selecting a folder using the folder's pidl."
      .lpfn = FARPROC(AddressOf BrowseCallbackProc)

Chuck Gabriel

  • Guest
Re: AddressOf operator in .net
« Reply #2 on: March 14, 2007, 10:46:50 AM »
I'm not sure what you are trying to accomplish, but maybe you can avoid using AddressOf altogether.  I think you are trying to pass a function pointer to a WIN32 API function.

If so, maybe you can do something like this:

Code: [Select]
public delegate int HookProc(int code, IntPtr wParam, IntPtr lParam);

[DllImport("user32.dll")]
private static extern IntPtr SetWindowsHookEx(HookType code,
  HookProc func,
  IntPtr hInstance,
  int threadID);

Keith™

  • Villiage Idiot
  • Seagull
  • Posts: 16899
  • Superior Stupidity at its best
Re: AddressOf operator in .net
« Reply #3 on: March 14, 2007, 11:17:23 AM »
Ok .. maybe this will explain it a little better ...
Many controls in VB (all flavors) do not have an "OnScroll" event for the the mouse scroll, but windows forms does interpret it properly and allows you to hook into the event. That hook is what I am trying to set and trying to intercept with my callback procedure ...

This is the code I used in VB6 but I havn't been able to decipher the .net equivalent .. maybe I am looking too hard ...

Code: [Select]
Private Declare Function CallWindowProc Lib "user32.dll" Alias "CallWindowProcA" ( _
                                        ByVal lpPrevWndFunc As Long, _
                                        ByVal hwnd As Long, _
                                        ByVal Msg As Long, _
                                        ByVal Wparam As Long, _
                                        ByVal Lparam As Long) As Long

Private Declare Function SetWindowLong Lib "user32.dll" Alias "SetWindowLongA" ( _
                                       ByVal hwnd As Long, _
                                       ByVal nIndex As Long, _
                                       ByVal dwNewLong As Long) As Long
Private LocalHwnd As Long
Private LocalPrevWndProc As Long
Private MyForm As Form

Private Const GWL_WNDPROC = -4
Private Const WM_MOUSEWHEEL = &H20A

Private Function WindowProc(ByVal Lwnd As Long, ByVal Lmsg As Long, ByVal Wparam As Long, ByVal Lparam As Long) As Long

    Dim MouseKeys As Long
    Dim Rotation As Long
    Dim Xpos As Long
    Dim Ypos As Long

    If Lmsg = WM_MOUSEWHEEL Then
        MouseKeys = Wparam And 65535
        Rotation = Wparam / 65536
        Xpos = Lparam And 65535
        Ypos = Lparam / 65536
        MyForm.MouseWheel MouseKeys, Rotation, Xpos, Ypos
    End If
    WindowProc = CallWindowProc(LocalPrevWndProc, Lwnd, Lmsg, Wparam, Lparam)
End Function

Public Sub WheelHook(PassedForm As Form)
    Set MyForm = PassedForm
    LocalHwnd = PassedForm.hwnd
    LocalPrevWndProc = SetWindowLong(LocalHwnd, GWL_WNDPROC, AddressOf WindowProc)
End Sub

Public Sub WheelUnHook()
    SetWindowLong LocalHwnd, GWL_WNDPROC, LocalPrevWndProc
    Set MyForm = Nothing
End Sub


Then in my form I have my event defined

Code: [Select]
Public Sub MouseWheel(ByVal MouseKeys As Long, ByVal Rotation As Long, ByVal Xpos As Long, ByVal Ypos As Long)
    Dim NewValue As Long
    With MyForm.VScroll
        If Rotation > 0 Then
            NewValue = .Value - .LargeChange
            If NewValue < .Min + 1 Then
                NewValue = .Min + 1
            End If
        Else
            NewValue = .Value + .LargeChange
            If NewValue > .Max Then
                NewValue = .Max
            End If
        End If
        .Value = NewValue
    End With
End Sub

Ideally the event would be supported .. but alas it isn't so far as I know .. if it were supported, then I wouldn't have to define and store multiple hooks for each control .... and in the unlikely event there is a problem we don't compromize the stability of the system .. as you probably know well, if a hooked procedure is not unhooked, it can cause some serious problems when the control no longer exists.
Proud provider of opinion and arrogance since November 22, 2003 at 09:35:31 am
CadJockey Militia Field Marshal

Find me on https://parler.com @kblackie

Chuck Gabriel

  • Guest
Re: AddressOf operator in .net
« Reply #4 on: March 14, 2007, 12:21:28 PM »
I'm not sure if I've gotten the syntax exactly right here, or what the equivalent VB.NET syntax is for that matter, but I think you can do something like this.

Code: [Select]
public delegate int HookProc(IntPtr Lwnd, IntPtr Lmsg, IntPtr Wparam, IntPtr Lparam);

public static HookProc m_prevWndProc = 0;
public static IntPtr m_hwnd = 0;

[DllImport("user32.dll")]
private static extern HookProc SetWindowLong(IntPtr hwnd, long nIndex, HookProc func);

// snip

public static long WindowProc(IntPtr Lwnd, IntPtr Lmsg, IntPtr Wparam, IntPtr Lparam)
{
  // do some stuff
}

// snip

public static void WheelHook(IntPtr hwnd)
{
  m_hwnd = hwnd;
  m_prevWndProc = SetWindowLong(hwnd, GWL_WNDPROC, WindowProc);
}

public static void WheelUnHook()
{
  SetWindowLong(m_hwnd, GWL_WNDPROC, (IntPtr)m_prevWndProc);
}


<edit>I went back and corrected some of the more obvious errors in my code, but I feel certain there are more issues that need to be addressed.</edit>
« Last Edit: March 14, 2007, 12:50:25 PM by Chuck Gabriel »

Keith™

  • Villiage Idiot
  • Seagull
  • Posts: 16899
  • Superior Stupidity at its best
Re: AddressOf operator in .net
« Reply #5 on: March 14, 2007, 01:24:50 PM »
So in effect I don't even have to use the AddressOf operator? I see you are passing the function itself to SetWindowLong ...

bear with me while I try to digest the above code ...

First we declare our delegate "HookProc" along with the parameters required,
Then we declare our variables .. rather than a long pointer to the hook procedure, we declare it as a delegate ...
Import the SetWindowLong function, but rather than passing it a long pointer, we pass it our delegate "HookProc"

Define our call back function to do some stuff ... i.e. handle the messages from the window

Define our WheelHook procedure to set the hook into the window or control, passing the function to SetWindowLong rather than the pointer to the function. Since our result of SetWindowLong goes into our delegate variable all is well.
Finally unhook the control ...

Please feel free to correct my thought process here as I tend to be think in terms of logic and sometimes I miss whole concepts because I fail to see the logic behind it.
Proud provider of opinion and arrogance since November 22, 2003 at 09:35:31 am
CadJockey Militia Field Marshal

Find me on https://parler.com @kblackie

Chuck Gabriel

  • Guest
Re: AddressOf operator in .net
« Reply #6 on: March 14, 2007, 01:52:58 PM »
That's pretty much the way I mapped it out in my own head.  I'm a little uncertain whether you will be able to initialize m_prevWndProc to zero, but I'm pretty confident it will work other than that.  I used something very similar (except using SetWindowsHookEx, etc.) to do the hooking in the managed version of HotKeys.

I actually recently read an article by Kean Walmsley that got me wondering if there might be a way to handle all of this without resorting to p-invoke at all, but I haven't gotten around to trying it out.  Maybe you would like to play with the ideas presented in it:

http://through-the-interface.typepad.com/through_the_interface/2007/02/allowing_users_.html

TonyT

  • Guest
Re: AddressOf operator in .net
« Reply #7 on: March 14, 2007, 02:22:57 PM »
Hi.

In .NET, you don't use AddressOf to pass a pointer
to a function to native code.

What you do is define a delegate, and apply the
[UnmanagedFunctionPointer] attribute to it, and
then pass the delegate to the native function that
expects the function pointer. In other words, the
UnmanagedFunctionPointer attribute allows you to
treat native code that calls a managed funtion as
if it were an event, and the managed function that
is called as the event handler.

But if all you need to do is subclass a window,
even that isn't really necessary, as subclassing a
window is what the NativeWindow class is for.

You can see an example of it's use here:

   http://www.caddzone.com/AcadWindowHook.cs

So in effect I don't even have to use the AddressOf operator? I see you are passing the function itself to SetWindowLong ...

bear with me while I try to digest the above code ...

First we declare our delegate "HookProc" along with the parameters required,
Then we declare our variables .. rather than a long pointer to the hook procedure, we declare it as a delegate ...
Import the SetWindowLong function, but rather than passing it a long pointer, we pass it our delegate "HookProc"

Define our call back function to do some stuff ... i.e. handle the messages from the window

Define our WheelHook procedure to set the hook into the window or control, passing the function to SetWindowLong rather than the pointer to the function. Since our result of SetWindowLong goes into our delegate variable all is well.
Finally unhook the control ...

Please feel free to correct my thought process here as I tend to be think in terms of logic and sometimes I miss whole concepts because I fail to see the logic behind it.


Keith™

  • Villiage Idiot
  • Seagull
  • Posts: 16899
  • Superior Stupidity at its best
Re: AddressOf operator in .net
« Reply #8 on: March 14, 2007, 02:40:43 PM »
Wow .. lots to digest ... I will need to wrap my head around this stuff ....
Proud provider of opinion and arrogance since November 22, 2003 at 09:35:31 am
CadJockey Militia Field Marshal

Find me on https://parler.com @kblackie

TonyT

  • Guest
Re: AddressOf operator in .net
« Reply #9 on: March 14, 2007, 09:29:24 PM »
Sorry, looks like I was wrong about AddressOf (its not
used in C#, but of course, it doesn't even exist in C# :))

Here is a simple example of how a managed callback
function is passed to, and then called from native code:

Code: [Select]

Imports System
Imports System.Runtime.InteropServices

Namespace NativeInteropSample

    ' Declare the delegate:

    <UnmanagedFunctionPointer(CallingConvention.StdCall)> _
    Friend Delegate Sub FooHandler(ByVal x As Integer, ByVal y As Integer)

    Friend Class Class1

        Public Sub New()
            Me.Init
        End Sub

        ' The managed method that's called from native code:
        Public Sub foo(ByVal x As Integer, ByVal y As Integer)
            Console.WriteLine("foo({0},{1})", x, y)
        End Sub

        Public Sub Init()
            ' Create the delegate:
            Dim callback As FooHandler = New FooHandler(AddressOf Me.foo)
            ' Get a native pointer to the delegate:
            IntPtr CallBackPtr = Marshal.GetFunctionPointerForDelegate(callback)
            ' Pass the calback pointer to the native code:
            Class1.SetCallBack(CallBackPtr.ToPointer)
        End Sub

        ' The native function that takes the callback pointer:
        <DllImport("mylibrary.dll")> _
        Private Shared Sub SetCallBack(ByRef pfunc As Void)

    End Class
       
End Namespace



Wow .. lots to digest ... I will need to wrap my head around this stuff ....
« Last Edit: March 15, 2007, 06:25:31 AM by TonyT »

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: AddressOf operator in .net
« Reply #10 on: March 14, 2007, 09:56:15 PM »
Don't know if this will confuse matters more or not ...

These 2 are comparatively the same .. except for the catch statement
Code: [Select]
       
        void AddContextMenu()
        {
            try
            {
                m_ContextMenu = new ContextMenuExtension();
                m_ContextMenu.Title = "Acme Employee Menu";
                Autodesk.AutoCAD.Windows.MenuItem mi;
                mi = new Autodesk.AutoCAD.Windows.MenuItem("Create Employee");
                mi.Click += new EventHandler(CallbackOnClick);
                m_ContextMenu.MenuItems.Add(mi);

                AcadApp.AddDefaultContextMenuExtension(m_ContextMenu);
            }
            catch
            {
            }
        }
Code: [Select]
    Private Sub AddContextMenu()

        Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor

        Try

            m_ContextMenu = New ContextMenuExtension()
            m_ContextMenu.Title = "Acme Employee Menu"
            Dim mi As MenuItem
            mi = New MenuItem("Create Employee")
            AddHandler mi.Click, AddressOf CallbackOnClick
            m_ContextMenu.MenuItems.Add(mi)

            Application.AddDefaultContextMenuExtension(m_ContextMenu)

        Catch ex As System.Exception
            ed.WriteMessage("Error Adding Context Menu: " + ex.Message)
        End Try

    End Sub
« Last Edit: March 14, 2007, 09:57:59 PM by Kerry Brown »
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.