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 / .NET Framework / Interop / March 2007

Tip: Looking for answers? Try searching our database.

Native DLL and callback in C++

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Erik Wikström - 06 Mar 2007 15:40 GMT
I'm trying to figure out how some stuff can be done when calling
functions in a native DLL from managed C++ and the called functions
have callbacks. What I want is to be able to use an opaque type as a
handle for the user of the DLL, in this case it's called Test and the
user can create/delete instances of this type, set the callback
function and call a function that, in turn, will call the callback
function. However I can't get it to compile and I suspect that it
might have something to do with the calling convention of the
functions of the DLL. Code as follows.

/*
* The DLL, two files in a standard Win32 project
*/
/* MyTest.h */

namespace MyTest
{
    struct Test;
    typedef void (__cdecl *CallBackFunc)(int);
    __declspec(dllexport) Test* newTest(int i);
    __declspec(dllexport) void delTest(Test* t);
    __declspec(dllexport) void setCallback(Test* t, CallBackFunc);
    __declspec(dllexport) void useCallBack(Test* t);
}

/* MyTest.cpp */

#include "MyTest.h"

namespace MyTest
{
    struct Test {
        int i_;
        CallBackFunc ptr_;
        Test(int i) : i_(i) { }
    };

    Test* newTest(int i) {
        return new Test(i);
    }

    void delTest(Test* t) {
        delete t;
    }

    void setCallback(Test* t, CallBackFunc p) {
        t->ptr_ = (CallBackFunc)p;
    }

    void useCallBack(Test* t) {
        t->ptr_(1);
    }
}

/*
* The app using the DLL, a .Net console app
*/
/* App.cpp */
#include "MyTest.h"

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

ref class Tester
{
public:
    void called(int i)
    {
        Console::WriteLine(i);
    }
};

delegate void CallBack(int);

int main()
{
    Tester^ test = gcnew Tester();
    CallBack^ cb = gcnew CallBack(test, &Tester::called);

    MyTest::Test* t = MyTest::newTest(7);
    MyTest::setCallback(t,
   
((MyTest::CallBackFunc)Marshal::GetFunctionPointerForDelegate(cb).ToPointer));

    MyTest::useCallBack(t);
    MyTest::delTest(t);

    return 0;
}

I've added the DLL-project as a reference and added the directory
containing MyTest.h as an additional include directory, and that
should make it all work (except for the compilation, error I get). The
error is on the MyTest::setCallBack(...)-line and has error code C2440
[1].

If anyone can help figure out what's needed to fix this I'd be very
grateful!

[1] http://msdn2.microsoft.com/en-us/library/sy5tsf8z.aspx

--
Erik Wikström
Mattias Sjögren - 06 Mar 2007 20:46 GMT
Hej Erik,

>    MyTest::setCallback(t,
>   
>((MyTest::CallBackFunc)Marshal::GetFunctionPointerForDelegate(cb).ToPointer));
[...]
>The error is on the MyTest::setCallBack(...)-line and has error code C2440
>[1].

That's because you're not calling the ToPointer method, so you're
trying to cast the function itself rather than its return value. Add a
pair of parentheses after ToPointer and it should work.

Note also that the cb delegate is eligible for garbage collection
immediately after the GetFunctionPointerForDelegate call, which would
render the function pointer stored in the native code invalid. You
have to keep a reference to the delegate alive as long as the function
pointer is in use to prevent this from happening.

And finally, you should use the UnmanagedFunctionPointer attribute on
the CallBack delegate to set the calling convention to cdecl to match
the CallBackFunc signature.

Mattias

Signature

Mattias Sjögren [C# MVP]  mattias @ mvps.org
http://www.msjogren.net/dotnet/ | http://www.dotnetinterop.com
Please reply only to the newsgroup.

Erik Wikström - 07 Mar 2007 07:27 GMT
On 6 Mar, 21:46, Mattias Sjögren <mattias.dont.want.s...@mvps.org>
wrote:
> Hej Erik,
>
[quoted text clipped - 5 lines]
> trying to cast the function itself rather than its return value. Add a
> pair of parentheses after ToPointer and it should work.

Yes, of course, should have notices that myself.

> Note also that the cb delegate is eligible for garbage collection
> immediately after the GetFunctionPointerForDelegate call, which would
> render the function pointer stored in the native code invalid. You
> have to keep a reference to the delegate alive as long as the function
> pointer is in use to prevent this from happening.

I'll keep that in mind, thanks for telling.

> And finally, you should use the UnmanagedFunctionPointer attribute on
> the CallBack delegate to set the calling convention to cdecl to match
> the CallBackFunc signature.

Yes, it all works like a charm now. Thank you very much.

--
Erik Wikström

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.