Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / Languages / Managed C++ / March 2008

Tip: Looking for answers? Try searching our database.

Cannot pass a __delegate pointer to C++ function?

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
glutz7878 - 08 Jul 2005 22:27 GMT
I have no trouble passing __delegate ptrs to native C functions in DLLs,
however when attempting to pass the __delegate ptr to a native C++ function
in a DLL I get the following runtime exception: An unhandled exception of
type 'System.EntryPointNotFoundException'.  

This is confusing b/c if the entry point was not found, I would think I'd
get an unresolved symbol error during linking.  Furthermore, I can
successfully pass void, int *, and function pointers, etc to C++ DLL
functions, but this error persists when attempting to pass a __delegate
pointer, which is used for callbacks to managed C++ functions.

Here is the relevant code snippet - the DLL code simply contains stubs of
the functions called here:

#include "stdafx.h"
#using <mscorlib.dll>

using namespace System;
using namespace System::Runtime::InteropServices;

__delegate void testCB();
[DllImport("unmdll.dll")]
void fnunmdll_2(testCB *UpdateProgMeter);

int fnunmdll_0(void);
void fnunmdll_1(int *x);//testCB *UpdateProgMeter);

__gc class C1
{
public:
    static void handleCB()
    {   
        return;
    }
};

int _tmain()
{
      int k = 9;

       //always works (as both C/C++)
    fnunmdll_0();

       //always works (as both C/C++)
    fnunmdll_1(&k);

    testCB *pCB = new testCB(0, &C1::handleCB);

       //if this is a C++ function expecting a function pointer, the
aforementioned error occurs.  If this is an extern "C" function, all is ok!
    fnunmdll_2(pCB);  

    return 0;
}

As crazy as it sounds, I'm beginning to think this is not possible to do
with native C++ functions.

Thanks in advance, George
Willy Denoyette [MVP] - 08 Jul 2005 23:18 GMT
This has nothing to do with delegates, this is a C++ name mangling issue,
your DllImport functions (fnunmdll_2) must use C linkage exports, or an
appropriate .DEF file.
extern "C"
{
...

}

Willy.

>I have no trouble passing __delegate ptrs to native C functions in DLLs,
> however when attempting to pass the __delegate ptr to a native C++
[quoted text clipped - 57 lines]
>
> Thanks in advance, George
glutz7878 - 08 Jul 2005 23:35 GMT
Thanks for the post but do you know why there are no problems when passing
void or int *, even function pointers?  Wouldn't they also have name mangling
issues?  It seems strange that the only thing that fails is passing
__delegates.

Thanks again, George
glutz7878 - 09 Jul 2005 00:09 GMT
Using a .DEF file to get rid of mangled names fixes the problem.  extern C
also works of course but the .Def is better.

If anyone can explain why this worked all along for all non-delegate types,
i would really love to know.  I'm not sure why name-mangling would affect the
function call based on argument type.

Thanks, George
Willy Denoyette [MVP] - 09 Jul 2005 00:12 GMT
> Thanks for the post but do you know why there are no problems when passing
> void or int *, even function pointers?  Wouldn't they also have name
[quoted text clipped - 3 lines]
>
> Thanks again, George

No, the diference is that you are calling the function through PInvoke
([DllImport("unmdll.dll")]), that means you are dynamically binding against
the library and the entrypoint will be resolved at call time(that's why the
linker doesn't complain), while in the other cases you are statically
linking and the linker is able to resolve the functions called points.

Willy.
samm - 12 Mar 2008 01:58 GMT
Thank you for your help. It works fine, but I have weird problem. It works
only on one of my devices: HTC Touch phone. If I use HTC Mogul (the same
Windows Mobile 6.0, but less memory) it does not. I have the same .net CF 2.0
on both.

thanks again.

Passing managed delegates to native functions as callbacks

> > Thanks for the post but do you know why there are no problems when passing
> > void or int *, even function pointers?  Wouldn't they also have name
[quoted text clipped - 11 lines]
>
> Willy.
Ben Voigt [C++ MVP] - 12 Mar 2008 16:35 GMT
> Thank you for your help. It works fine, but I have weird problem. It
> works only on one of my devices: HTC Touch phone. If I use HTC Mogul
> (the same Windows Mobile 6.0, but less memory) it does not. I have
> the same .net CF 2.0 on both.

C++ interop doesn't work in the compact framework, but
Marshal::GetFunctionPointerForDelegate does.

__delegate doesn't exist in .NET 2.0, that's .NET 1.x Managed Extensions for
C++ syntax

Explain what you're trying to accomplish and what you're doing so far and we
should be able to help you.
samm - 12 Mar 2008 18:11 GMT
Sure.

1. I have C++ dll which needs to register callback in my C# application.
This callback returns a string:

C# side:

public delegate void RegisterCallBackDelegateInt(System.IntPtr response);
...
       RegisterCallBackDelegateInt Callback;
       IntPtr callbackPointer;
...

                   Callback = new
RegisterCallBackDelegateInt(RegisterCallBackInt);
                   callbackPointer =
Marshal.GetFunctionPointerForDelegate(Callback);
                   GC.KeepAlive(callbackPointer);
                   ret = RegisterCallBack(callbackPointer);
...
       public void RegisterCallBackInt(System.IntPtr response)
       {
               string myString = Marshal.PtrToStringUni(response);
               Log("Callback: " + myString);
               Marshal.FreeHGlobal(response);              
       }

C++ side

extern "C" {

__declspec( dllexport ) HRESULT RegisterCallBack(void(*CB)(BYTE *xmlResult) );

};

It works fine on Touch HTC phone, but not on Mogul.

2. The reason I do that is because I do not have ability to wrap my C++ dll
to C++ managed anymore. On win32 I can do that and my life is much better.

Thank you for your help.

Sam

> > Thank you for your help. It works fine, but I have weird problem. It
> > works only on one of my devices: HTC Touch phone. If I use HTC Mogul
[quoted text clipped - 9 lines]
> Explain what you're trying to accomplish and what you're doing so far and we
> should be able to help you.
Ben Voigt [C++ MVP] - 12 Mar 2008 19:23 GMT
> Sure.
>
[quoted text clipped - 40 lines]
>
> Thank you for your help.

You are misusing GC.KeepAlive, so you will experience random failures
whenever a collection takes place before the callback is finished.  Use
GCHandle.Alloc instead, on the delegate, not the native function pointer.

> Sam
samm - 12 Mar 2008 20:25 GMT
Thank you.
Can you give me an example?

> > Sure.
> >
[quoted text clipped - 46 lines]
>
> > Sam
Ben Voigt [C++ MVP] - 12 Mar 2008 21:32 GMT
> Thank you.
> Can you give me an example?

First, the runtime should do this for you if you do the DllImport right (see
the documentation for GCHandle.Alloc).  But you can do it by hand.

Modifying your example:

RegisterCallBackDelegateInt Callback;
IntPtr callbackPointer;
Callback = new RegisterCallBackDelegateInt(RegisterCallBackInt);
callbackPointer = Marshal.GetFunctionPointerForDelegate(Callback);
ret = RegisterCallBack(callbackPointer);

GCHandle cbKeepAlive = GCHandle.Alloc(Callback);
...

// when the callback will no longer be used from native code
cbKeepAlive.Free();

>>> Sure.
>>>
[quoted text clipped - 47 lines]
>>
>>> Sam
samm - 13 Mar 2008 02:35 GMT
I added code you recommended. My application works fine, but if I start
another application and switch back to mine I get a crash.

If I stay in my app it works without any problems.

> > Thank you.
> > Can you give me an example?
[quoted text clipped - 67 lines]
> >>
> >>> Sam
Ben Voigt [C++ MVP] - 13 Mar 2008 14:43 GMT
> I added code you recommended. My application works fine, but if I
> start another application and switch back to mine I get a crash.

Switching applications usually triggers a GC.

Try changing GCHandle.Alloc(x) to GCHandle.Alloc(x, GCHandleType.Pinned)

> If I stay in my app it works without any problems.
>
[quoted text clipped - 70 lines]
>>>>
>>>>> Sam
samm - 13 Mar 2008 18:48 GMT
Does not work. If I switch without using callback no problems.
I am suprised Microsoft released the product without straight forward
feature of calling C++ dlls from .net. Managed C++ was working just fine for
me as a glue between .net and C++ unmanaged.

> > I added code you recommended. My application works fine, but if I
> > start another application and switch back to mine I get a crash.
[quoted text clipped - 77 lines]
> >>>>
> >>>>> Sam
Ben Voigt [C++ MVP] - 13 Mar 2008 21:26 GMT
> Does not work. If I switch without using callback no problems.
> I am suprised Microsoft released the product without straight forward
> feature of calling C++ dlls from .net. Managed C++ was working just
> fine for me as a glue between .net and C++ unmanaged.

C++ interop is great (at least starting with 2005), but you're on Compact
Framework so you can't use it.

Try taking out the GCHandle.Free entirely?

>>> I added code you recommended. My application works fine, but if I
>>> start another application and switch back to mine I get a crash.
[quoted text clipped - 78 lines]
>>>>>>
>>>>>>> Sam
samm - 13 Mar 2008 22:01 GMT
I do not call free at all. I got interop file and llok what happens:
[pinvokeimpl][preservesig]
int  Averquest.Averquest::SendRequest(System.Byte[] );
int (I4_VAL) SendRequest(unsigned char *(ARRAY_BLIT_LPARRAY) );

[preservesig][delegate]
void  RegisterCallBackDelegateInt::Invoke(RegisterCallBackDelegateInt ,
IntPtr );
void (*)(INT_PTR (I_VAL) )
[preservesig][delegate]
void  RegisterCallBackDelegateInt::Invoke(RegisterCallBackDelegateInt ,
IntPtr );
void (*)(INT_PTR (I_VAL) )
[preservesig][delegate]
void  RegisterCallBackDelegateInt::Invoke(RegisterCallBackDelegateInt ,
IntPtr );
void (*)(INT_PTR (I_VAL) )
[preservesig][delegate]
void  RegisterCallBackDelegateInt::Invoke(RegisterCallBackDelegateInt ,
IntPtr );
void (*)(INT_PTR (I_VAL) )
[pinvokeimpl][preservesig]
IntPtr  SafeNativeMethods::LocalAlloc(int , int );
INT_PTR (I_VAL) LocalAlloc(int (I4_VAL) , int (I4_VAL) );

[pinvokeimpl][preservesig]
IntPtr  SafeNativeMethods::LocalAlloc(int , int );
INT_PTR (I_VAL) LocalAlloc(int (I4_VAL) , int (I4_VAL) );

[pinvokeimpl][preservesig]
int  Microsoft.WindowsMobile.Telephony.Phone::PhoneMakeCall(IntPtr );
int (I4_VAL) PhoneMakeCall(INT_PTR (I_VAL) );

[pinvokeimpl][preservesig]
IntPtr  SafeNativeMethods::LocalFree(IntPtr );
INT_PTR (I_VAL) LocalFree(INT_PTR (I_VAL) );

[pinvokeimpl][preservesig]
IntPtr  SafeNativeMethods::LocalFree(IntPtr );
INT_PTR (I_VAL) LocalFree(INT_PTR (I_VAL) );

> > Does not work. If I switch without using callback no problems.
> > I am suprised Microsoft released the product without straight forward
[quoted text clipped - 88 lines]
> >>>>>>
> >>>>>>> Sam

Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.