Codwiz51's Wiki

Experiments in calling managed delegates

Modified: 2009/06/29 06:26 by codewiz51 - Categorized as: CLI
I've been working on how to handle DccManSink (RAPI class and interface) in C++/CLI. I worked up this simple test code, which I hope will translate into my production RAPI code. codewiz51, 2008/07/10 10:22

Oops! I discovered the code I had posted did not keep the delegates alive. Here is the marked up code. codewiz51, 2008/07/10 14:32

// DelegateTesting.cpp : main project file.

  1. include
  2. include
  3. include
  4. include
  5. include

using namespace System;

delegate void DelegateDefinition(UInt32 x); // The equivalent function pointer (not used) typedef void (* ptrDelegateDefinition) (unsigned int x);

// This is more or less a native class // Reflection will not disassemble it public class CallDelegateFromNative { private: // I was not able to get this to work with auto_gcroot // Examining the auto_gcroot.h code indicates that I am // not smart enough to understand how to use auto_gcroot // with a delegate type. The truth hurts. msclr::gcroot _MyDelegate;

public: // This is the method that simulates raising an event in native code // I intend to use this code in my work with DccManSink. I hope it works // with RAPI int DoWork() { unsigned int i = 0; std::wcout << L"Entering DoWork" << std::endl; for each(DelegateDefinition^ dd in _MyDelegate->GetInvocationList()) { std::wcout << L"Calling delegate:" << std::endl; System::Threading::Thread::Sleep(1500); dd->Invoke(++i); } std::wcout << L"Exiting DoWork" << std::endl; return 1; }

// Subscribe and Unsubscribe // These only exist because I couln't figure out how to utilize // the += operator with the gcrooted pointer. Plus, I have a // deeply seated feeling _MyDelegate should be private. // With DccMan sink, I will need to use names like // SubscribeActive, SubscribeAnswer, etc. void Subscribe(DelegateDefinition^ pDel) { _MyDelegate = (DelegateDefinition^)System::Delegate::Combine(_MyDelegate, pDel); }

// With DccMan sink, I will need to use names like // UnsubscribeActive, UnsubscribeAnswer, etc. void Unsubscribe(DelegateDefinition^ pDel) { _MyDelegate = (DelegateDefinition^)System::Delegate::Remove(_MyDelegate, pDel); }

// dtor ~CallDelegateFromNative() { // Remove the delegates from the list System::Delegate::RemoveAll(_MyDelegate, _MyDelegate); // Delete the gcrooted pointer delete _MyDelegate; }

};

  1. pragma managed
public ref class ReceiveDelegateCall { private: // The neat thing is, this does not have to be // private. We could create the class somewhere // else and pass the pointer in via assignment. // (And then pray real hard the class instance // doesn't disappear. "It could happen" - Judy Tenuta) CallDelegateFromNative* embeddedNativeClassPointer; static DelegateDefinition^ pfn1; static DelegateDefinition^ pfn2;

public: // The delegates that get called from native code - sort of void TheDelegateMethod(UInt32 x) { String^ strTemp = String::Format("The Delegate has been called. Value: {0}", x); Console::WriteLine(strTemp); }

void TheSecondDelegateMethod(UInt32 x) { String^ strTemp = String::Format("The Second Delegate has been called. Value: {0}", x); Console::WriteLine(strTemp); }

// ctor ReceiveDelegateCall() { pfn1 = gcnew DelegateDefinition(this, &ReceiveDelegateCall::TheDelegateMethod); pfn2 = gcnew DelegateDefinition(this, &ReceiveDelegateCall::TheSecondDelegateMethod);

// Create the native class (more or less native) embeddedNativeClassPointer = new CallDelegateFromNative();

// I had to define this method to get around the += operator problem with _MyDelegate embeddedNativeClassPointer->Subscribe(pfn1); embeddedNativeClassPointer->Subscribe(pfn2); }

// dtor ~ReceiveDelegateCall() { delete embeddedNativeClassPointer; }

// This method kicks off the whole thing // If the juju works, the native[sic] class // will invoke the managed delegates. void StartMeUp() { embeddedNativeClassPointer->DoWork(); }

// Remove the first subscriber void RemoveSubscription() { embeddedNativeClassPointer->Unsubscribe(pfn1); } };

int main(array ^args) { // Create an instance of the managed class that will receive the // callbacks ReceiveDelegateCall theInstance;

// Progress Console::WriteLine(L"First Call to StartMeUp");

// Start up the process theInstance.StartMeUp();

// Remove a delegate and call StartMeUp again to make sure // the unsubscribe function works Console::WriteLine(L"Remove First Subscription"); theInstance.RemoveSubscription(); Console::WriteLine(L"Second Call to StartMeUp"); theInstance.StartMeUp();

// If we got here, then things worked. Now the question is, // will they work in the real world with different assemblies, // ... Console::WriteLine(L"Finished without a blue screen"); return 0; }


ScrewTurn Wiki version 2.0.36. Some of the icons created by FamFamFam.