< C++ .NET Delegates & Events 6 | Main | C++ .NET WinForm 1 >


 

 

Delegates and Events 7

generate, fire and handle the events...

 

 

 

  1. Passing a Delegate^ to a Native Function Expecting a Function Pointer

  2. The Generic Delegates (C++)

 

 

Passing a Delegate^ to a Native Function Expecting a Function Pointer

 

From a managed component you can call a native function with function pointer parameters where the native function then can call the member function of the managed component's delegate. The following program sample created the .dll (mydll.dll) that exports the native function.

 

1.        Create a new CLR Class Library named mydll.

 

C++ .Net - creating Class library, the Dll program

 

2.        Add the following code to the mydll.h file.

// mydll.h

// For windows.h and uuid.lib, make sure

// you install the Windows SDK and set the include

// and lib directories properly through the

// Tools->Options...->VC++ Directories folder

// Compile with /clr

 

#pragma once

#include <windows.h>

 

using namespace System;

 

namespace mydll {

 

     // TODO: Add your methods for this class here.

     extern "C"{

     __declspec(dllexport)

     void nativeFunction(void (CALLBACK *mgdFunc)(const char* str))

     {

         mgdFunc("Call to the Managed Function...this string is in xxxx.dll lor!");

     }

  }

}

 

 

 

 

3.        Make sure you have installed the Windows SDK. Then make sure you set the SDK’s include and lib (library) path in your project setting. The following are the steps to set the path for those directories provided that you already installed the SDK. Click Tools menu and select Options… sub menu.

 

Invoking the VC++ .NET 2005 project Options page

 

4.        Expand the Projects and Solutions folder and select VC++ Directories. Under the Show directories for: select the Include files.

 

C++ .NET 2005 - setting the Include files directory

 

5.        Click the New Line icon and then click the three dots at the end of the empty new line.

 

VC++ .NET 2005 - adding new Include file directory to the project

 

6.        Browse and find the Windows SDK’s Include directory and click Open. The path for the Include will be added.

 

Windows SDK Include directory

 

7.        The following Figure shows the added Windows SDK’s Include path has been added to the project’s VC++ Directories.

 

The added Windows SDK Include files directory

 

 

 

 

8.        Next, repeat the same step for the Libraries files. Browse and find the Windows SDK’s Lib directory shown below.

 

Adding the Windows SDK Library, Lib files directory

 

9.        The following Figure shows the added Lib path to the project. Click OK button to close the project options page.

 

The Windows SDK added Lib directory to the project

 

10.     Build your project. The DLL file will be generated as shown below under the debug folder. You can’t run this program component. It will be used in the next program example.

 

The generated DLL file from the Class Library program example

 

11.     The following example will consumes the previous mydll.dll and passes a delegate handle to the native function expecting a function pointer. Next, create a new CLR Console Application and add the following code. The next section shows the steps.

// native.cpp : main project file.

// delegate to native function

// Calling the Dll (mydll.dll)

// compile with: /clr

#include "stdafx.h"

 

using namespace System;

using namespace System::Runtime::InteropServices;

 

delegate void Del(String ^s);

 

public ref class Test

{

   public:

       void delMember(String ^s)

       {

           Console::WriteLine(s);

       }

};

 

// mydll.dll is the previous DLL file, change accordingly if yours

// is different and it is copied to this project’s debug folder

[DllImportAttribute("mydll.dll", CharSet=CharSet::Ansi)]

extern "C" void nativeFunction(Del ^d);

 

int main(array<System::String ^> ^args)

{

      Test ^MyTest = gcnew Test;

      Del ^d = gcnew Del(MyTest, &Test::delMember);

      nativeFunction(d);   // Call to native function

      return 0;

}

 

Output:

Using the Class Library of the native function program output example

 

12.     Create a new CLR Console Application named native. Open the main file, native.cpp and add the previous code.

 

Creating a new CLR Console Application named native

 

13.     Before you can call the native function, the DLL file, mydll.dll must be found by this native program. Copy mydll.dll file and put it into the native debug’s folder. You can put it in the %System32% folder so that all the program can use it.

 

-------------------------------------------------

Putting the DLL file to the appropriate folder so that the main program can find it

 

14.     Build and run your native program. The following output should be expected.

 

Calling the native function of delegate program output example

 

The Generic Delegates (C++)

 

You can use generic type parameters with delegates. The following is the syntax.

[attributes]

generic < [class | typename] type-parameter-identifiers >

[type-parameter-constraints-clauses]

[accessibility-modifiers] delegate result-type identifier ([formal-parameters]);

Parameters

attributes (Optional)

Additional declarative information.

type-parameter-identifier(s)

Comma-separated list of identifiers for the type parameters.

type-parameter-constraints-clauses

Takes the form specified in Constraints.

accessibility-modifiers (Optional)

Accessibility modifiers (e.g. public, private).

result-type

The return type of the delegate.

identifier

The name of the delegate.

formal-parameters (Optional)

The parameter list of the delegate.

 

Table 4

 

The delegate type parameters are specified at the point where a delegate object is created. Both the delegate and method associated with it must have the same signature. The following is an example of a generic delegate declaration.

// generics delegate

// compile with: /clr /c

generic < class ItemType>

delegate ItemType GenDelegate(ItemType p1, ItemType% p2);

The following sample shows that:

  1. You cannot use the same delegate object with different constructed types. Create different delegate objects for different types.

  2. A generic delegate can be associated with a generic method.

  3. When a generic method is called without specifying type arguments, the compiler tries to infer the type arguments for the call.

// generics delegate

// compile with: /clr

 

#include "stdafx.h"

 

using namespace System;

 

generic < class ItemType>

delegate ItemType GenDelegate(ItemType p1, ItemType% p2);

 

generic <class ItemType>

ref struct MyGenClass

{

   ItemType MyMethod(ItemType i, ItemType % j)

   {

      return ItemType();

   }

};

 

ref struct MyClass

{

   generic <class ItemType>

   static ItemType MyStaticMethod(ItemType i, ItemType % j)

   {

      return ItemType();

   }

};

 

int main(array<System::String ^> ^args)

{

      MyGenClass<int> ^ myObj1 = gcnew MyGenClass<int>();

      MyGenClass<double> ^ myObj2 = gcnew MyGenClass<double>();

      GenDelegate<int>^ myDelegate1 = gcnew GenDelegate<int>(myObj1, &MyGenClass<int>::MyMethod);

      GenDelegate<double>^ myDelegate2 = gcnew GenDelegate<double>(myObj2, &MyGenClass<double>::MyMethod);

      GenDelegate<int>^ myDelegate = gcnew GenDelegate<int>(&MyClass::MyStaticMethod<int>);

 

      return 0;

}

// No output

The following example declares a generic delegate GenDelegate<ItemType>, and then instantiates it by associating it to the method MyMethod that uses the type parameter ItemType. Two instances of the delegate (an integer and a double) are created and invoked.

// generics delegate in action

// compile with: /clr

 

#include "stdafx.h"

 

using namespace System;

 

// declare generic delegate

generic <typename ItemType>

delegate ItemType GenDelegate(ItemType p1, ItemType% p2);

 

// Declare a generic class

generic <typename ItemType>

 

ref class MyGenClass

{

   public:

       ItemType MyMethod(ItemType p1, ItemType% p2)

       {

           p2 = p1;

           return p1;

       }

};

 

int main(array<System::String ^> ^args)

{

  int i = 0, j = 0;

  double m = 0.0, n = 0.0;

 

  MyGenClass<int>^ myObj1 = gcnew MyGenClass<int>();

  MyGenClass<double>^ myObj2 = gcnew MyGenClass<double>();

  // Instantiate a delegate using int.

  GenDelegate<int>^ MyDelegate1 = gcnew GenDelegate<int>(myObj1, &MyGenClass<int>::MyMethod);

  // Invoke the integer delegate using MyMethod.

  i = MyDelegate1(123, j);

 

  Console::WriteLine("Invoking the integer delegate: i = {0}, j = {1}", i, j);

  // Instantiate a delegate using double.

  GenDelegate<double>^ MyDelegate2 = gcnew GenDelegate<double>(myObj2, &MyGenClass<double>::MyMethod);

  // Invoke the integer delegate using MyMethod.

  m = MyDelegate2(0.123, n);

  Console::WriteLine("Invoking the double delegate: m = {0}, n = {1}", m, n);

 

  return 0;

}

 

Output:

Program example output of the generic delegate

 

 

 

Part 1 | Part 2 | Part 3 | Part 4 | Part 5 | Part 6 | Part 7

 

 


< C++ .NET Delegates & Events 6 | Main | C++ .NET WinForm 1 >