Codwiz51's Wiki

RSS

Navigation







Quick Search
»
Advanced Search »

Experiments in calling managed delegates

RSS
Modified on 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.

#include <iostream> #include <fstream> #include <msclr\gcroot.h> #include <msclr\auto_gcroot.h> #include <msclr\event.h>

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<DelegateDefinition^> _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; }

};

#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&#0091;sic&#0093; class // will invoke the managed delegates. void StartMeUp() { embeddedNativeClassPointer->DoWork(); }

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

int main(array<System::String ^> ^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, // <insert other failure modes here>... Console::WriteLine(L"Finished without a blue screen"); return 0; }

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