Tech Off Thread

41 posts

Forum Read Only

This forum has been made read only by the site admins. No new threads or comments can be added.

Please, I'm panicing and only have 2 days left.

Back to Forum: Tech Off
  • User profile image
    qwert231

    I am supposed to be passing the address of my managed function to the unmanaged code. So here's what I do:
     'Create my delegate
     Public Delegate Sub CameraAdded(ByRef useData As IntPtr)

     'Wrap the unmanaged function
     Declare Auto Function KSetCameraAddedNotification Lib "DCSPro4SLR.dll" Alias "KPDCSetCameraAddedNotification" (ByRef inManagerRef As IntPtr, ByRef inNotificationFunc As CameraAdded, ByRef inUserData As IntPtr) As Integer

     'Here's my function I want the unmanaged code to call
     'This is designed according to the documentation.

      Private Sub CameraAddedEvent(ByRef userData As IntPtr)
       '//This event handles the camera added events.//
       RaiseEvent NewFile("Hey, it fired CameraAddedEvent.")
      End Sub

    'And in my New I pass the address of my function to the unmanaged code.
     Public Sub New()
      myStatus = Me.KInitialize(Me.KPDCInitalizationOptions.KPDCInitOptionEnableIEEE1394, Me.myLibMgr)

      'Tell Kodak what function to call when there is a Camera Added Event
      myStatus = Me.KSetCameraAddedNotification(Me.myLibMgr, AddressOf Me.CameraAddedEvent, somePtr)

     End Sub

    When the event does happen, my code never get's called. Am I passing the address wrong?

    The definition of KSetCameraAddedNotification calls for the second parameter to be of type KPDCCameraAddedNotificationFunc. That type is defined like so:
    #define KPDCCALLBACK CALLBACK
    typedef void (KPDCCALLBACK *KPDCCameraAddedNotificationFunc)(void *userData);

    I'm trying to use VB, this is C++. I don't know what to do or where to look and I'm sure you guys are tired of me bugging you.

  • User profile image
    Rossj

    qwert231 wrote:
    I am supposed to be passing the address of my managed function to the unmanaged code. So here's what I do:

     'Create my delegate
     Public Delegate Sub CameraAdded(ByRef useData As IntPtr)

     'Wrap the unmanaged function
     Declare Auto Function KSetCameraAddedNotification Lib "DCSPro4SLR.dll" Alias "KPDCSetCameraAddedNotification" (ByRef inManagerRef As IntPtr, ByRef inNotificationFunc As CameraAdded, ByRef inUserData As IntPtr) As Integer


    Okay first thing. Stop panicking Smiley Go and get a coffee or take a walk. In fact don't get coffee drink something else Wink Panicking won't help and you'll make silly mistakes.

    Do you know if KSetCameraAddedNotification in the C code is defined as stdcall ?

    Also  if the callback is expecting a void* in C# I'd probably do something like
    public delegate CameraAddedDelegate( IntPtr useData );
    but you pass it ByRef, I'm not sure if this is relevant or not.

  • User profile image
    qwert231

    Thank you... a friendly voice is nice.

    KSetCameraAddedNotification defined as stdcall? Not sure, I don't have the source to the unmanaged code.
    I do have a demo app (written in c++) that uses a similar set of functions (passing the address of another function).

    I tried ByVal, and was getting NullReference errors outside of my code. (Or at least VS didn't tell me where they were.

  • User profile image
    Sven Groot

    If they're using the standard windows.h definition for CALLBACK, then it's __stdcall.

    Your function pointer code seems correct, so it's probably not there that the problem lies.

    However, passing a void* should be done as ByVal IntPtr. If you need to pass any actual data to it, you create the IntPtr using the Marshal class. I suspect the error is there. What type is Me.myLibMgr? What's the C++ definition of KSetCameraAddedNotification? Knowing that there might be a better way than mucking about with IntPtrs.

  • User profile image
    qwert231

    Here is some demo code doing something similar with the same unmanaged DLL. This demo code is C++, but I'm using VB.

    theStatus = theProcs.SetCameraEventNotification(theCamera, CameraEventHandler, NULL);

    void KPDCCALLBACK CameraEventHandler(KPDCUInt32  inEvent,  KPDCUInt32  inParam1,  const char  *inParam2,  KPDCUInt32  inParam2Length,  void *userData )
    {
     if( (inEvent == KPDCAddFile) || (inEvent == KPDCFolderContent) )
     {
      SetEvent(g_hImageReady);
     }
    }

  • User profile image
    qwert231

    As far as I know the userData doesn't need any data. I don't plan to pass any to it. I was not sure if the unmanaged code would try to play with it.

    Me.myLibMgr is an IntPtr. I create a an IntPtr like this:
     Private myLibMgr As IntPtr = Marshal.AllocHGlobal(1)

    Then I pass it to the DLL ByRef and it fills it.

    Here is the def for KSetCameraAddedNotification as per documentation:
    KPDCStatus KPDCSetCameraAddedNotification( KPDCLibMgrRef inManagerRef, KPDCCameraAddedNotificationFunc inNotificationFunc, void *inUserData);

    And how I wrap it:
    Declare Auto Function KSetCameraAddedNotification Lib "DCSPro4SLR.dll" Alias "KPDCSetCameraAddedNotification" (ByRef inManagerRef As IntPtr, ByRef inNotificationFunc As CameraAdded, ByRef inUserData As IntPtr) As Integer

    It's probably something stupid, like me not knowing when the DLL wants ByRef or ByVal. Thank you guys so much for your help.

  • User profile image
    qwert231

    Set userData to by ByVal. But nothing. Wondering if I should pass it IntPtr.Zero

  • User profile image
    qwert231

    Passing IntPtr.Zero when I pass the address doesn't do anything either.

  • User profile image
    Sven Groot

    The ByRef and ByVal bit is a bit difficult to understand, especially if you don't know C++ all that well and thus don't understand pointers.

    What it hinges on is value types and references types. For a value type in .Net (which is stuff like Integer, Single, Boolean, enums and structures), passing ByVal means the value of the variable gets copied into the function. A reference type exists as a reference to an object in the managed heap, and when passing ByVal, it is the reference, not the object that gets copied. In C++ pointer terms, this means that passing a reference type ByVal, you're still passing a pointer to your actual object, while passing a value type ByVal, you're passing the actual object.

    ByRef means the value doesn't get copied, but a reference to the original value gets passed into the function. For value types, that's a pointer to the actual variable. For reference types, that's a pointer to the reference, i.e. a double pointer.

    When doing PInvokes you'll typically only have to deal with value types. If a C++ function wants and int, you give it a ByVal Integer. If it wants an int*, you give it a ByRef Integer. If it wants an int**, you're stuck. If it wants a void*, you can either figure out what type it really wants and use that (ByRef) or use ByVal IntPtr.

    You only use ByRef IntPtr if whenever a function has a void** argument.

    "Private myLibMgr As IntPtr = Marshal.AllocHGlobal(1)

    Then I pass it to the DLL ByRef and it fills it."

    That can't be right. Think what is happening. You assign a value to myLibMgr. You then pass it ByRef to the dll, which thus gets a pointer to myLibMgr. The only reason the function would want a pointer to myLibMgr is if it wants to overwrite its value (or really bad design Wink, which means the value you've just assigned it gets overwritten. Is it a void** in C++? Then you create an IntPtr, don't assign a value, and pass it ByRef. If it's a void*, you create an IntPtr, assign it a value, and pass it ByVal.

    I suspect your problem here is because you're already doing somethine like the above wrong earlier. Without a complete compilable example that demonstrates the problem we can't be certain though.

  • User profile image
    Sven Groot

    qwert231 wrote:
    Set userData to by ByVal. But nothing. Wondering if I should pass it IntPtr.Zero

    I expect userData isn't used. Set it to ByVal and passing IntPtr.Zero is therefor the correct course of action.

  • User profile image
    Sven Groot

    Sven Groot wrote:
    "Private myLibMgr As IntPtr = Marshal.AllocHGlobal(1)

    Then I pass it to the DLL ByRef and it fills it."

    That can't be right. Think what is happening. You assign a value to myLibMgr. You then pass it ByRef to the dll, which thus gets a pointer to myLibMgr. The only reason the function would want a pointer to myLibMgr is if it wants to overwrite its value (or really bad design Wink, which means the value you've just assigned it gets overwritten. Is it a void** in C++? Then you create an IntPtr, don't assign a value, and pass it ByRef. If it's a void*, you create an IntPtr, assign it a value, and pass it ByVal.

    Put a little more succinctly: Marshal.AllocHGlobal creates a pointer to an unmanaged block of memory. If the C++ wants this pointer, pass it ByVal. If the C++ code wants a pointer to that pointer (hence it'd be a void**) then you pass it ByRef.

  • User profile image
    Sven Groot

    VB.Net obviously. VB6 doesn't have delegates.

  • User profile image
    littleguru

    Is this VB 6 or VB.Net?
    --
    sorry for this posting - must be VB.Net

  • User profile image
    littleguru

    hmmmm: I see that there are a lot guys having problems with .Net and delegates (callbacks) from c++ dlls.

    Have a look at google groups.
    A MVP who has answered there suggests to use:

    "You can still use the UCOMIConnectionPoint* interfaces in System.Runtime.InteropServices to hook up the connection point stuff manually if that's required."

    for callbacks that come from C++ dlls...

    [edit]the problem there has been with TAPI
    http://groups.google.de/groups?hl=de&lr=&threadm=O97NL9bXDHA.2236%40TK2MSFTNGP10.phx.gbl&rnum=1&prev=/groups%3Fq%3Dinterop%2Bproblem%2Bcallback%26hl%3Dde%26lr%3D%26selm%3DO97NL9bXDHA.2236%2540TK2MSFTNGP10.phx.gbl%26rnum%3D1
    [/edit]

  • User profile image
    qwert231

    K, here's the def for the unmanaged function that fills myLibMgr:
    KPDCStatus KPDCInitialize( KPDCUInt32 inOptionBits, KPDCLibMgrRef *outManagerRef);

    So, according to the documentation, I just create a blank Pointer like so:
    Private myLibMgr As IntPtr

    and pass that by reference to the unmanaged code. Which works.

    Now, when I pass it byVal, and call that function, I get a nullReferenceException error.

    So, from this I assume, I don't have to Alloc anything when I create my pointers, but for this one it should be passed ByRef. (Otherwise, why the error when passed ByVal?)

  • User profile image
    Or-n

    what are the return values from each function call?

  • User profile image
    Sven Groot

    To know for certain I'd need to know what KPDCLibMgrRef is. Could you give me that typedef?

    However, the word Ref in the name suggests it is a pointer type, meaning KPDCLibMgrRef* is a double pointer, in which case passing a ByRef IntPtr is the right thing to do. You don't have to alloc it beforehand, because its value will get overwritten by the KPDCInitialize function. If you would allocate it, you create a memory leak.

    You should, however, pass it ByVal to the KPDCSetCameraAddedNotification function!

  • User profile image
    qwert231

    If you want, my source is available zipped here. It's a lot to go through, and messy as I have lot's of comments for my own use. Thank you for all your help though.

Conversation locked

This conversation has been locked by the site admins. No new comments can be made.