Click here to Skip to main content
Click here to Skip to main content

Implementing Callback functions using IJW (avoiding DllImport)

By , 13 Jul 2002
 

Introduction

This whole business started one day when there was a post in the Microsoft dotnet.languages.vc newsgroup where someone was complaining that he was having trouble using EnumWindows from Managed C++. He stated very firmly that he did not want to use the DllImport attribute. This got me interested naturally, and I thought I could try and help him out. To my utter disappointment I found that I was having trouble too. The issue was that EnumWindows took as it's first argument a callback function. All my searches on MSDN and google took me to solutions that showed how to do this using the DllImport attribute. The technique suggested was simple. We are to declare a __delegate object identical to the callback function. Now we are to use DllImport to define EnumWindows so that it takes as first argument our __delegate type. Now we can simply write our callback function as a member of a managed class and pass this function to EnumWindows.

//declare our delegate
__delegate bool CallBack(IntPtr hwnd, IntPtr lParam);

...

//ugghhhhhhh!!!! so uglyyyyyy!!!
[DllImport("user32")] 
extern "C" int EnumWindows(CallBack* x, int y); 

...

//create the delegate
CallBack* cb = new CallBack(0, 
    &SomeClass::SomeMatchingMethod);
//call the function
EnumWindows(cb, 0); 

The problem

All this is well and good, but it was beginning to get annoying. My problem was that whatever I did I couldn't get the callback function to work. Obviously I couldn't pass a delegate directly because when we use IJW, the native API functions expect native arguments and not managed arguments. I even tried something as silly as casting a delegate object to a WNDENUMPROC and as you might have guessed failed thoroughly. I also tried passing both static and instance members of managed classes as the callback function, but I kept getting run time exceptions about NULL references and objects. This was really disappointing to say the least.

That's when I got a huge boost from Richard Grimes who is a Microsoft MVP, and who has written several quality books on Microsoft programming technologies. His latest book is on using the managed extensions to program with VC++ .NET. In reply to my query about calling EnumWindows using IJW, he replied to me and the reply included a sample code snippet from his latest book, but unfortunately he used DllImport. I replied back saying that I wasn't looking for DllImport and I must say my exasperation must have reflected poorly in my reply. Because Richard's answer was a little crispy too to begin with. But he gave me my first clue as to why I was going the wrong direction. He explained to me how managed class members use the __clrcall calling convention and how unmanaged callback functions use the __stdcall calling convention  In fact when I took a closer look at the compiler warnings, I was shocked to find a message that said that I was trying to attempt a redefinition of calling convention from __clrcall to __stdcall  which is not possible and was therefore being ignored. That's when I realized that I simply had to give up trying to use a managed class member method as my callback.

The solution

Richard's final answer was an emphatic NO. But I badly wanted to figure out a way by which a managed class can pass a delegate as the callback function. That's when this idea hit me out of the blue. Inner classes. We could use inner classes, see! All we had to do was to have an __gc class with an inner __nogc class and the outside managed class will wrap the inner unmanaged class and expose it to the outside world. The outer class has a delegate that acts as the managed callback. The inner __nogc class has a native __stdcall method as the callback function. This callback function will invoke the managed delegate each time it gets called. Thus we simulate a managed callback mechanism here. I have commented the code in vital areas so that you can understand this better.

__gc class CEnumWindows //outer class
{
private:
    __nogc class _CEnumWindows //inner class
    {
    private:
        /* This is a native function that follows the */
        /* __stdcall calling convention that's required */
        static  BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM)
        {               
            // We need to get the managed callback
            // up for each instance that our callback 
            // gets called. So we get a pointer to
            // the current instance of the outer class
            // and invoke the delegate that is holding
            // the managed callback method that the
            // callee code has passed to us
            CEnumWindows* pew = CEnumWindows::GetClass();
            pew->m_EnumProc->Invoke(hwnd, NULL);
            return TRUE;
        }       
    public:     
        void StartFinding()
        {
            EnumWindows((WNDENUMPROC)_CEnumWindows::EnumWindowsProc,NULL);
        }
    };
private:    
    _CEnumWindows* m_ew;
public:
    __delegate bool EnumProc(IntPtr hwnd, IntPtr lParam);
    static CEnumWindows* GetClass()
    {   
        //This for the unmanaged class to use
        //when it needs a pointer to the managed class
        return m_pclass;        
    }
    static CEnumWindows* m_pclass=NULL;
    CEnumWindows()
    {
        m_pclass = this;
        m_ew = new _CEnumWindows(); //unmanaged heap
    }
    ~CEnumWindows()
    {
        // we need to delete the object manually
        // as is is on the unmanaged heap
        delete m_ew;
    }
    void StartFinding()
    {       
        m_ew->StartFinding();       
    }
    EnumProc* m_EnumProc;
};

Now we can use this from any managed class and pass any managed class member function as the callback function. In the example below, I create a new instance of CEnumWindows which is the outer class. Then I associate a managed function from one of my classes to the delegate member of the CEnumWindows object. Alright, alright, I know that using a public delegate member is not a proper way to do this, but I am only trying to demonstrate how this is done. Put this in a property if you want to, or write a function that'll do this for you.

CEnumWindows* p = new CEnumWindows();
p->m_EnumProc = new CEnumWindows::EnumProc(this,&NForm::EWHandler);
p->StartFinding(); 

Conclusion

For my own whimsical reasons I am a big fan of using IJW which I feel is a lot more natural for a C++ programmer than the use of weird looking attributes that makes your code look like C# or VB .NET. I don't have anything against other languages but I prefer my C++ code too look like C++ and not like some kind of ugly mutation of other subjectively inferior languages. Anyway thanks goes to Richard Grimes for pointing me in the correct direction. Those of you who are interested in his new book on using the managed extensions can go to this link. Programming with Managed Extensions for Microsoft® Visual C++® .NET (Microsoft Press)

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Nish Sivakumar
United States United States
Member
Nish is a real nice guy who has been writing code since 1990 when he first got his hands on an 8088 with 640 KB RAM. Originally from sunny Trivandrum in India, he has been living in various places over the past few years and often thinks it’s time he settled down somewhere.
 
Nish has been a Microsoft Visual C++ MVP since October, 2002 - awfully nice of Microsoft, he thinks. He maintains an MVP tips and tricks web site - www.voidnish.com where you can find a consolidated list of his articles, writings and ideas on VC++, MFC, .NET and C++/CLI. Oh, and you might want to check out his blog on C++/CLI, MFC, .NET and a lot of other stuff - blog.voidnish.com.
 
Nish loves reading Science Fiction, P G Wodehouse and Agatha Christie, and also fancies himself to be a decent writer of sorts. He has authored a romantic comedy Summer Love and Some more Cricket as well as a programming book – Extending MFC applications with the .NET Framework.
 
Nish's latest book C++/CLI in Action published by Manning Publications is now available for purchase. You can read more about the book on his blog.
 
Despite his wife's attempts to get him into cooking, his best effort so far has been a badly done omelette. Some day, he hopes to be a good cook, and to cook a tasty dinner for his wife.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralCalling managed code from MFCmemberLithium0220 Dec '10 - 13:30 
Hello Nishant!
 
I'm a novice programmer and I'm trying to use a C# class in a MFC project. First I did this via an assembly generated from my C# library class, and now I'm wondering if there exist a way to do this without using a library or DLL reference, calling the code from the C# class and using it on my MFC classes. Is that posible? If so I'd like to know what's the technique or technology to use for it.
Thanks in advance.
 
Jorge Andres
GeneralNice Trick but Confusing Code !!!memberVivek Ragunathan19 Mar '08 - 19:17 
Hi Nishant
 
Nice trick. I am not able to understand one thing here. The CEnumWindows::GetClass() is a static method which returns the static member m_pclass. And m_pclass is assigned this on every creation of CEnumWindows. So m_pclass will hold the last created instance. Later, _CEnumWindows::EnumWindowsProc uses that instance to invoke the EnumProc delegate. Even though the code is for demonstration purpose, I guess there is some confusion here. Does the code mena the right thing ? Or am I missing something ? Please explain.
 
Regards
Vivek Ragunathan
GeneralMixed Mode to the rescue!membervillalvilla5 May '06 - 0:55 
Hi there!
 
You are complicating yourself too much, aren't you? why don't you use a mixed mode dll, declare the __gc class and the __nogc (templated) class inside, declare a pointer to the __nogc class inside the __gc one and then pass a pointer to a __gc function as a delegate? this way, you receive in the __nogc class only a function as its delegate and not the whole class!! it's only an idea, i have to try, but it appears to be a working solution, i will tell you!
 
regards,
villalvilla
QuestionWhy?memberhanifku9 Apr '06 - 14:02 
I am sorry that I just began code in .NET
 
But is there anything wrong with DLLImport?
Like, performance penalty or anything?
 
Hei, I don't know!
 
Thanks for the answer.
AnswerRe: Why?memberPunCha20 Nov '06 - 15:21 
For C#, DllImport is the only way to invoke API.
 
But for C++/CLI, it provides an easy way to invoke API function directly.
GeneralConverting the sample to remove the singletonmemberNigel de Costa4 Apr '05 - 5:11 
Following on from my previous post (see earlier thread) where I was attempting to use managed events in preference to the delegate / callback mechanism in the article. I wanted to be able to hold a pointer in the unmanaged inner class to the managed outer class in order to invoke the callbacks. The article has CEnumWindows as a singleton and uses a static member GetClass() to return a pointer to the outer object for the same purpose.
 
The stumbling block is that the compiler won't allow unmanaged classes to contain attributes that are pointers to managed classes.
 
The way around that is actually fairly simple (although not all that obvious). What is required is a helper template class called gcroot:
 
gcroot<CEnumWindows*> _pOuter
 
This wraps the managed pointer and allows it to be used within the unmanaged class (the pointer does not need to be pinned).
 
The steps to convert the sample (taking my previous example as a base) are:
 
Include the following to get gcroot<>...
 
#include <vcclr.h>
 
Add this attribute to _CEnumWindows...
 
gcroot<CEnumWindows*> _pOuter;
 
Initialise this attribute via the constructor for _CEnumWindows...
 
_CEnumWindows(gcroot<CEnumWindows*> pOuter)
{
     _pOuter = pOuter;
}
 
Remove the GetClass() impliementation from CEnumWindows and create it in the NForm object using new.
 
Pass the pointer to the inner class as the state parameter of the call to EnumWindows...
 
::EnumWindows((WNDENUMPROC)_CEnumWindows::EnumWindowsProc, (LPARAM) this);
 
and cast it back to its original type in the callback...
 
_CEnumWindows* pMe = (_CEnumWindows*) param;
 
then can be used to invoke the callback via the delegate as before...
 
pMe->_pOuter->m_EnumProc->Invoke(hwnd, NULL);
 
There is no great value in doing this for this particular example except as means to demonstrate the mechanism. However I can see a use for it when wrapping unmanaged APIs where a singleton wrapper is inappropriate.
 
Full listing below...
 
#include "stdafx.h"
 
#include <vcclr.h>
 
#using <mscorlib.dll>
#using <System.dll>
#using <System.Drawing.dll>
#using <System.Windows.Forms.dll>
 
#include <tchar.h>
#include <windows.h>
 
using namespace System;
using namespace System::ComponentModel;
using namespace System::Drawing;
using namespace System::Windows::Forms;
 
__gc class CEnumWindows
{
private:
    
     __nogc class _CEnumWindows
     {
     private:
 
          // pointer to outer class to invoke callbacks
          gcroot<CEnumWindows*> _pOuter;
 
          static BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM param)
          {    
               _CEnumWindows* pMe = (_CEnumWindows*) param;
 
               if (pMe->_pOuter!=NULL)
               {
                    pMe->_pOuter->m_EnumProc->Invoke(hwnd, NULL);
               }
 
               return TRUE;
          }         
 
     public:         
 
          // Constructor takes pointer to outer class - use gcroot<CEnumWindows*> as
          // type-safe wrapper to point to managed object
          _CEnumWindows(gcroot<CEnumWindows*> pOuter)
          {
               _pOuter = pOuter;
          }
 
          void StartFinding()
          {
               ::EnumWindows((WNDENUMPROC)_CEnumWindows::EnumWindowsProc, (LPARAM) this);
          }
     };
 
private:
 
     _CEnumWindows* m_ew;
 
     void OnEnumProc(IntPtr hwnd, IntPtr lParam)
     {
          __raise this->EnumProc(hwnd, lParam);
     }
 
public:
 
     __delegate void EnumProcDelegate(IntPtr hwnd, IntPtr lParam);
     __event bool EnumProc(IntPtr hwnd, IntPtr lParam);
 
     CEnumWindows()
     {
          m_ew = new _CEnumWindows(this);
          this->m_EnumProc = new CEnumWindows::EnumProcDelegate(this, &CEnumWindows::OnEnumProc);
     }
 
     ~CEnumWindows()
     {
          delete m_ew;
     }
 
     void StartFinding()
     {         
          m_ew->StartFinding();         
     }
 
     EnumProcDelegate* m_EnumProc;
};
 
public __gc class NForm : public Form
{
public:
         
     bool EWHandler(IntPtr hwnd, IntPtr lParam)
     {
          char buff[512];    
          if(GetWindowText((HWND)hwnd.ToInt32(),buff,511))
          {
               String* s = String::Format("{0}{1}",
                    __box(hwnd.ToInt32())->ToString("X8")->PadRight(30),
                    Convert::ToString(buff));              
               lbox->Items->Add(s);
          }
          return false;
     }
 
     NForm()
     {
          StartPosition = FormStartPosition::CenterScreen;
            Text = "Callbacks with IJW - Nish for CodeProject - Avoid DllImport";
            Size = Drawing::Size(750,550);
            FormBorderStyle = System::Windows::Forms::FormBorderStyle::FixedDialog;
          MaximizeBox = false;
 
          lbox = new ListBox();         
            lbox->Location=Point(5,5);
            lbox->Size=Drawing::Size(730,500);                   
          lbox->Sorted = true;
 
            Controls->Add(lbox);
 
          CEnumWindows* p = new CEnumWindows();
          __hook(&CEnumWindows::EnumProc, p, &NForm::EWHandler);
 
          p->StartFinding();
         
     }
     ListBox* lbox;
 
};
 
int __stdcall WinMain(HINSTANCE,HINSTANCE,LPSTR,int)
{    
     Application::Run(new NForm());
      return 0;
}
 

GeneralConverting the sample to use managed events...memberNigel de Costa3 Apr '05 - 22:48 
I found this article when I was looking to design a IJW wrapper for a legacy C++ API. In particular I wanted to understand how I could include events within my wrapper that could be easily consumed by the APIs client (a C# application).
 
I have tried to update this example to replace the delegate / callback mechanism with an event.
 
Initially I created the event in CEnumWindows as follows:
 
__event bool EnumProc(IntPtr hwnd, IntPtr lParam);
 
I then replaced the class to instatiate the delegate in NForm with a __hook call as follows:
 
//p->m_EnumProc = new CEnumWindows::EnumProc(this,&NForm::EWHandler);
 
__hook(&CEnumWindows::EnumProc, p, &NForm::EWHandler);
 
I then replaced the call to invoke the delegate pointer:
 
pew->m_EnumProc->Invoke(hwnd, NULL);
 
with call to raise the event:
 
__raise pew->EnumProc(hwnd, NULL);
 
This proved to be a false start. The sample compiled OK but failed to run. The call to EnumWindows((WNDENUMPROC)_CEnumWindows::EnumWindowsProc,NULL); threw the exception System.MethodAccessException. I guess because the framework does not like managed events to be raised within an unmanaged call.
 
So...
 
I then modified the sample again to put the delegated callback back in. This time it is contained in the class CEnumWindows using the procedure:
 
void OnEnumProc(IntPtr hwnd, IntPtr lParam)
{
__raise this->EnumProc(hwnd, lParam);
}
 
This procedure raises the managed event when called and all is well. It is unfortunate that this extra level of indirection is required but is not too onerous. If anybody can see a simpler way of doing this then I'd be glad of the advice.
 
Full listing below...
 
#include "stdafx.h"
 
#using
#using
#using
#using
 
#include
 
#include
 
using namespace System;
using namespace System::ComponentModel;
using namespace System::Drawing;
using namespace System::Windows::Forms;
 
__gc class CEnumWindows
{
private:

__nogc class _CEnumWindows
{
private:
 
static BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM)
{
CEnumWindows* pew = CEnumWindows::GetClass();
pew->m_EnumProc->Invoke(hwnd, NULL);
return TRUE;
}
 
public:
 
void StartFinding()
{
::EnumWindows((WNDENUMPROC)_CEnumWindows::EnumWindowsProc,NULL);
}
};
 
private:
 
_CEnumWindows* m_ew;
 
void OnEnumProc(IntPtr hwnd, IntPtr lParam)
{
__raise this->EnumProc(hwnd, lParam);
}
 
public:
 
__delegate void EnumProcDelegate(IntPtr hwnd, IntPtr lParam);
__event bool EnumProc(IntPtr hwnd, IntPtr lParam);
 
static CEnumWindows* GetClass()
{
if (m_pclass==NULL)
{
m_pclass = new CEnumWindows();
}
 
return m_pclass;
}
 
static CEnumWindows* m_pclass = NULL;
 
CEnumWindows()
{
m_ew = new _CEnumWindows();
this->m_EnumProc = new CEnumWindows::EnumProcDelegate(this, &CEnumWindows::OnEnumProc);
}
 
~CEnumWindows()
{
delete m_ew;
}
 
void StartFinding()
{
m_ew->StartFinding();
}
 
EnumProcDelegate* m_EnumProc;
};
 
public __gc class NForm : public Form
{
public:

bool EWHandler(IntPtr hwnd, IntPtr lParam)
{
char buff[512];
if(GetWindowText((HWND)hwnd.ToInt32(),buff,511))
{
String* s = String::Format("{0}{1}",
__box(hwnd.ToInt32())->ToString("X8")->PadRight(30),
Convert::ToString(buff));
lbox->Items->Add(s);
}
return false;
}
 
NForm()
{
StartPosition = FormStartPosition::CenterScreen;
Text = "Callbacks with IJW - Nish for CodeProject - Avoid DllImport";
Size = Drawing::Size(750,550);
FormBorderStyle = System::Windows::Forms::FormBorderStyle::FixedDialog;
MaximizeBox = false;
 
lbox = new ListBox();
lbox->Location=Point(5,5);
lbox->Size=Drawing::Size(730,500);
lbox->Sorted = true;
 
Controls->Add(lbox);
 
CEnumWindows* p = CEnumWindows::GetClass();
__hook(&CEnumWindows::EnumProc, p, &NForm::EWHandler);
 
p->StartFinding();

}
ListBox* lbox;
 
};
 
int __stdcall WinMain(HINSTANCE,HINSTANCE,LPSTR,int)
{
Application::Run(new NForm());
return 0;
}
 

 

 

 

 

 

 

 

 

 

 

 

 

GeneralLNK2001: unresolved external symbol &quot;void * __cdecl operator new(unsigned int)&quot; (??2@$$FYAPAXI@Z)membermarkbanderson29 Jan '04 - 10:55 
Hi, I am having some linkage issues. Here is the code, very similar to the example:
 
__nogc class _EthernetIPCommunication
{
private:
// the callback method that will be invoked from the
// ethernetIP dll
static BOOL CALLBACK EthernetIPCallback( INT32 nEvent, INT32 nParam)
{
EthernetIPCommunication* p_EthernetIPCommunication = EthernetIPCommunication::GetClass();
p_EthernetIPCommunication->EthernetIPManagedCallback(nEvent,nParam);
return TRUE;
}
 
public:
// the method that will register the callback
void RegisterCallback()
{
// this method will register the internal static callback method with the eml library so that
// there is a non-managed way to get at and handle callbacks
LogEventCallbackType* callback = (LogEventCallbackType*)&_EthernetIPCommunication::EthernetIPCallback;
EtIPRegisterEventCallBack( callback );
}
};
 
And then i construct an instance as follows:
 
_EthernetIPCommunication* eip = new _EthernetIPCommunication;
eip->RegisterCallback();
 
Then i get this link error:
 
LNK2001: unresolved external symbol "void * __cdecl operator new(unsigned int)" (??2@$$FYAPAXI@Z)
 
Any ideas?
 
Mark
 

GeneralRe: LNK2001: unresolved external symbol &quot;void * __cdecl operator new(unsigned int)&quot; (??2@$$FYAPAXI@Z)membermarkbanderson30 Jan '04 - 0:11 
Fixed it:
 
See ms-help://MS.VSCC.2003/MS.MSDNQTR.2003FEB.1033/vcmex/html/vcconConvertingManagedExtensionsForCProjectsFromPureIntermediateLanguageToMixedMode.htm
GeneralRe: LNK2001: unresolved external symbol &quot;void * __cdecl operator new(unsigned int)&quot; (??2@$$FYAPAXI@Z)sussSudesh Sawant15 Mar '05 - 18:34 
The MSDN Online Link for the article is
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vcmex/html/vcconconvertingmanagedextensionsforcprojectsfrompureintermediatelanguagetomixedmode.asp[^]
and the caption is "Converting Managed Extensions for C++ Projects from Pure Intermediate Language to Mixed Mode"
 
This helped me to find a bug in my code and I thought it was helpful
GeneralRe: LNK2001: unresolved external symbol &quot;void * __cdecl operator new(unsigned int)&quot; (??2@$$FYAPAXI@Z)sussDenis Delarze7 May '04 - 6:12 
External names are mangled. Probably your program is in C++, not in C.
 
If your program is in C, you should change settings in ide to tell the
compiler about that, or use the extension '.c' rather than '.cpp'.
 
If your program is in C++, you should use the following construction:
 
extern "C" {
#include "glpk.h"
}
 
because all glpk headers are written in C, not in C++.

Generalpassing pointers from unmanaged to managedmembersivo8 Oct '03 - 6:44 
hi Nish,
 
thanks in advance for your cool articles.
 
assume i want to use some native function like:
WSAASyncGetServByName(hwnd,msg,"",buf,len);
 
my interface windows are all managed .net .
but this function require me to pass a pointer to
windows by hwnd .
 
what is the solution here .
GeneralConfusedmemberigor196023 Sep '03 - 7:58 
Please, clarify for me:
What exactly you mean and what is the value of this statement:
That's when this idea hit me out of the blue. Inner classes. We could use inner classes, see! All we had to do was to have an __gc class with an inner __nogc class...
Does it have to be inner class? For example small change and your example still works:
 
__nogc class _CEnumWindows
{
private:
static BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM);
public:
void StartFinding()
{
EnumWindows((WNDENUMPROC)_CEnumWindows::EnumWindowsProc,NULL);
}
};
 
__gc class CEnumWindows
{
private:
private:
_CEnumWindows* m_ew;
public:
__delegate bool EnumProc(IntPtr hwnd, IntPtr lParam);
static CEnumWindows* GetClass()
{
return m_pclass;
}
static CEnumWindows* m_pclass=NULL;
CEnumWindows()
{
m_pclass = this;
m_ew = new _CEnumWindows();
}
~CEnumWindows()
{
delete m_ew;
}
void StartFinding()
{
m_ew->StartFinding();
}
EnumProc* m_EnumProc;
};
 
BOOL _CEnumWindows::EnumWindowsProc(HWND hwnd, LPARAM)
{
CEnumWindows* pew = CEnumWindows::GetClass();
pew->m_EnumProc->Invoke(hwnd, NULL);
return TRUE;
}

 
As you can see _CEnumWindows is not inner class anymore.
 
So, what is the value of your experiment?...
 
"...Ability to type is not enough to become a Programmer. Unless you type in VB. But then again you have to type really fast..."
Me
QuestionHow to invoke the delegate asynchronously ?memberYoni Rabinovitch11 Sep '03 - 2:27 
Terrific article !! Thank you very much !! I've been tearing my hair out trying to figure out how to do this without DllImport.
 
Now, could you explain how to invoke the delegate asynchronously (with BeginInvoke etc.) using this pattern ? I have Ansi C++ libraries which constitute the "Worker Threads" of my application, and I want to be able to callback from them asynchronously to my C# GUI controls.
 
Using your pattern, I have finally been able to get a synchronous callback working. What do I need to do to make it work asynchronously ?
 
Thanks !!

AnswerRe: How to invoke the delegate asynchronously ?memberBumblebeeFromNewYork3 Nov '03 - 6:31 
Hi Yoni,
I am wondering if you found a solution how to make asynchronous callbacks from Unmanaged C++ libraries to C# GUI controls. I am researching that for a awhile, and still could not find the right way of doing that.
 
Thanks,
Eugene
GeneralRe: How to invoke the delegate asynchronously ?memberYoni Rabinovitch3 Nov '03 - 18:44 
Eugene -
 
I was able to get the method described in Nishant's article to to work with asynchronous delegates too, using BeginInvoke() and EndInvoke() etc.
 
However, in the final analysis, I decided that this method is too "tricky", and I ditched the whole idea altogether. Instead, my unmanaged C++ code just sends regular Windows messages to the C# GUI Controls, which processes them using WndProc().
 
Good luck !!
 
Yoni
GeneralRight waymemberRama Krishna27 Jul '02 - 3:45 
Right way is to use Marshal.GetUnmanagedThunkForManagedMethodPtr.
 
[EDIT] Found the right way to use from Commandprompt explorerbar article
GeneralRe: Right waymemberAlex Farber14 Apr '03 - 22:39 
Hi,
can you give some more details about this? Thanks.
GeneralAnother solutionmemberDaniel Lohmann15 Jul '02 - 7:15 
Nice work!
 
However, we don't have to use delegates under all circumstances, just because they are there Smile | :)
 
Another (and much more generic) solution is to go the pure C++ way and redirect the callback via adapter objects into the member function. This technique is shown in my article Use member functions for C-style callbacks and threads - a general solution.
 
It might also be a good idea to use templates to generalize your technique, so it is not necessary to write the same code again and again for EnumFonts(), EnumDesktops(), ...

 
--
 
Daniel Lohmann
 
http://www.losoft.de
GeneralRe: Another solutionsubeditorNishant S15 Jul '02 - 13:54 
Hi Daniel
 
Daniel Lohmann wrote:
However, we don't have to use delegates under all circumstances, just because they are there
 
Heheh. Just wanted to do it the managed way, that's all Blush | :O
 
Daniel Lohmann wrote:
It might also be a good idea to use templates to generalize your technique, so it is not necessary to write the same code again and again for EnumFonts(), EnumDesktops(),
 
Thanks, that's a very good idea
 
Regards,
Nish
 

Author of the romantic comedy

Summer Love and Some more Cricket [New Win]

Review by Shog9
Click here for review[NW]

GeneralRe: Another solutionmemberPVL23 Jun '03 - 8:16 
In this case the adapter should be an unmanaged class ( __nogc ) while a member function to call is a in managed class ( __gc ). But you cannot declare a pointer to managed class A in unmanaged class, thus the [ A* m_pObj ] in adaptor will not work if A is a managed class. Casting to managed class pointer is not working either. So, some other technique is needed for managed-unmanged callbacks to get the pointer to managed class instance. The one is shown in this article is to use static member that would hold the pointer to one [last created] instance.
GeneralGood workmemberKannan Kalyanaraman14 Jul '02 - 21:52 
I thought only underscores where ugly in MC++ Smile | :)
Maybe you can write another article or update this one to be thread safe.
Keep it up.
 
regards
Kannan
GeneralRe: Good worksubeditorNishant S15 Jul '02 - 13:51 
Kannan Kalyanaraman wrote:
Maybe you can write another article or update this one to be thread safe.
 
Thanks Kanna. Yeah, perhaps the next update should show how to make this thread safe and perhaps more generic in nature.
 
Nish
 

Author of the romantic comedy

Summer Love and Some more Cricket [New Win]

Review by Shog9
Click here for review[NW]

GeneralNot thread safememberRama Krishna14 Jul '02 - 2:27 
Only one thread can call EnumWindows in your case. DllImport requires less lines of code and is also thread safe.
 
You should use TLS or Context class to store m_pClass variable.
 
Step back, rub your eyes, take a deep breath, stretch a bit, and reflect on the relative importance of CP, CG, the age / travel time sustained by supposedly 'fresh' cheese curds, and Life in General. - Shog
GeneralRe: Not intended to be sosubeditorNishant S14 Jul '02 - 3:32 
Hello Rama
 
The class I have shown is *not* intended to be used directly. I simply wanted to demonstrate my way of using native API calls that required callbacks from MC++ without the use of DllImport attribute.
 
For actual use of the class, you'd have to write more code to make it thread safe and more OOPish and implement other safety checks etc...
 
That's why I have subjected it as "Implementing Callback functions using IJW" instead of as "CEnumWindows - an MC++ class that etc..." Smile | :)
 
I hope you got my point?
 
Warm regards,
Nish
 

Author of the romantic comedy

Summer Love and Some more Cricket [New Win]

Review by Shog9
Click here for review[NW]

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130516.1 | Last Updated 14 Jul 2002
Article Copyright 2002 by Nish Sivakumar
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid