Unmanaged C++ calling managed C# dll 
Author Message
 Unmanaged C++ calling managed C# dll

Is it possible, and how?

Many thanks

-Dan



Tue, 26 Aug 2003 11:32:05 GMT  
 Unmanaged C++ calling managed C# dll
You can expose a .NET class as a COM component that can be called from
unmanaged code.


Quote:
> Is it possible, and how?

> Many thanks

> -Dan



Tue, 26 Aug 2003 13:47:07 GMT  
 Unmanaged C++ calling managed C# dll
Wrap your managed C# dll as a COM component with regasm.
But perhaps you are thinking of some way ?

--
Per Thygesen


Quote:
> Is it possible, and how?

> Many thanks

> -Dan



Tue, 26 Aug 2003 13:55:49 GMT  
 Unmanaged C++ calling managed C# dll

Quote:

> Is it possible,

    Yes, it is.  Your .NET component written in C# is a COM object, you
may use it from unmanaged C++ code.  Use RegAsm.exe to create a CLSID
entry in the Registry so that your C# object implementation can be located.

Quote:
>                      and how?

    Let's walk through an academic "real-world" example.  Pretend you're
employed by MyCompany as an application developer of MyApplication.
You've been assigned the challenging task of implementing the Arithmetic-
Unit component, and being the leading-edge programmer that you are, you
want to use C# to write ArithmeticUnit.

    Unfortunately, nobody on your development team knows C#, as the primary
language of MyApplication is C++.  If ArithmeticUnit is to be implemented in
C#, it must seamlessly integrate with unmanaged C++.  You've discussed this
approach with your project and operations managers, and let's assume they
agree with you because:

    1.  The project manager doesn't mind that MyApplication will only work on
         the Microsoft Windows platform for the forseeable future, because our
         customers all use Microsoft Windows anyway.

    2.  The operations manager doesn't mind installing .NET with MyApplication
         since MyApplication is distributed on CD-ROM and you have 500 megs
         of space to spare.  Anyway, a smaller redistributable should be released
         soon, right?

    3.  Neither manager have any qualms about asking you to work overtime if
         prevailing winds change in the future, and you must re-write ArithmeticUnit
         as a COM component in C++.

    The consumate software architect that you are, your analysis of ArithmeticUnit's
requirements lead you to design it with two interfaces: IAdder and IMultiplier.  You
reason not everybody needs the full feature set of the ArithmeticUnit, and this makes
it easier for others to use.  There will be one component implementation, that imple-
ments both IAdder and IMultiplier.

    Almost for free, C# will throw in IDispatch because an assembly is virtually a
ready-made dual interface automation server.  You're going to keep this under
your hat for when the product managers come to the team and ask that the
ArithmeticUnit component be exposed to VBScript for a Web-based product
line.

    First, you write ArithmeticUnit in C# -- this is the easy part, you think to
yourself.

- - - adder.cs
namespace MyCompany.MyApplication
{
    public interface IAdder
    {
        int Add( int lAddend1, int lAddend2);
    }

    public interface IMultiplier
    {
        int Multiply( int lMultiplier, int lMultiplicand);
        int Multiply( int lMultiplier, int lMultiplicand, int lDenominator);
    }

    public class ArithmeticUnit : IAdder, IMultiplier
    {
        public int Add( int lAddend1, int lAddend2)
        {
            return lAddend1 + lAddend2;
        }

        public int Multiply( int lMultiplicand, int lMultiplier)
        {
            return lMultiplicand * lMultiplier;
        }

        public int Multiply( int lMultiplicand, int lMultiplier, int lDenominator)
        {
            return lMultiplicand * lMultiplier / lDenominator;
        }
    }

Quote:
}

- - -

    What fun!  It's only too bad it went by so fast, no sooner than you build
this assembly with,

        csc.exe /target:library /out:ArithmeticUnit.dll Adder.cs

    than the C# part of this exercise ends.

    Next you want ArithmeticUnit to appear in the registry.  This is done with the
Register Assembly utility (RegAsm.exe).  While it's optional to generate a type
library, you do this to simplify grasping the Interface IDs for IAdder and IMulti-
plier.

        regasm.exe ArithmeticUnit.dll /tlb

    You confirm in the registry (using regedit.exe) that a CLSID entry was added
to the Classes for "MyCompany.MyApplication.ArithmeticUnit".

    Using the Ole Type Viewer utility from the common Developer Studio toolchest,
you make a cursory examination of the type library produced by regasm.exe to get
the relevant GUIDs from the uuid attribute annotating IAdder, IMultiplier and
ArithmeticUnit.

        oleview.exe ArithmeticUnit.tlb

    Now the attention turns to creating a C++ header file, ArithmeticUnit.h.  This
header needs to include the Interface and Class IDs to use the ArithmeticUnit
COM component, and interface definitions for IAdder and IMultiplier that derive
from IDispatch (remember the assembly is a dual-interface component).

[ It's important to note that your GUIDs will be different, and they will have been
obtained from their uuid attributes using OleView.]

- - - ArithmeticUnit.h
DEFINE_GUID( IID_IAdder, 0x425F5AA9L, 0x36FE, 0x3662, 0xAD, 0xE6, 0x39, 0x88, 0x76, 0xA6, 0x8D, 0x9E);
DEFINE_GUID( IID_IMultiplier, 0x6B589CC4L, 0x61FD, 0x3E10, 0xB2, 0x1F, 0x3C, 0x06, 0x03, 0x7D, 0x6E, 0x9A);
DEFINE_GUID( CLSID_ArithmeticUnit, 0x074545C5L, 0x3420, 0x3D9A, 0x86, 0xE0, 0xC3, 0x17, 0x01, 0xAE, 0xFD, 0xD4);

class IAdder : public IDispatch  // could also use __interface in Visual C++
{
public:
    HRESULT virtual _stdcall Add( long lAddend1, long lAddend2, long* retVal) = 0;

Quote:
};

class IMultiplier : public IDispatch
{
public:
    HRESULT virtual _stdcall Multiply( long lMultiplier, long lMultiplicand,
                                                           long* retVal) = 0;
    HRESULT virtual _stdcall Multiply( long lMultiplier, long lMultiplicand,
                                                           long Denominator, long* retVal) = 0;
Quote:
};

- - -

    Another method for generating this include file is to feed the ArithmeticUnit.tlb
to the Make Type Library utility (MkTypLib.exe) with the /h switch to generate
a header file.  The macros of an auto-generated header obfuscate the requirements
for this header.

    You throw together a Console-based test driver app named CsComApp by
creating a new Visual C++ Projects | Win32 Projects | Win32 Project project in
Visual Studio.NET.  In stdafx.h, you add the following headers to enable COM:

        #include <unknwn.h>    // for IUnknown API
        #include <initguid.h>     // for DEFINE_GUID

    In stdafx.cpp, you make sure to include the header that describes ArithmeticUnit,

        #include "ArithmeticUnit.h"

    Finally, your implementation of the main( ) method looks as follows:

- - -CsComApp.cpp
#include "stdafx.h"

int main(int argc, char* argv[])
{
    HRESULT           _resultCode;
    LPUNKNOWN  _pUnk    = NULL;
    IAdder*               _pAdder = NULL;

    CoInitialize( NULL);

    _resultCode = CoCreateInstance( CLSID_ArithmeticUnit,
                                                         NULL,
                                                         CLSCTX_INPROC_SERVER,
                                                         IID_IUnknown,
                                                         (LPVOID*)&_pUnk);
    if ( _resultCode == S_OK )
    {
        _resultCode = _pUnk->QueryInterface( IID_IAdder,
                                                                      (LPVOID*)&_pAdder);
        if ( _resultCode == S_OK )
        {
            long _lSum = 0L;

            if ( _pAdder->Add( 200, 300, &_lSum) == S_OK )
            {
                fprintf( stdout, "Add( 200, 300) returned %ld\n", _lSum);
            }
            else
            {
                fprintf( stdout, "Call to IAdder::Add() failed, hresult=0x%x\n", _resultCode);
            }
            _pAdder->Release();
        }
        else
        {
            fprintf( stdout, "QueryInterface( IID_IAdder, ...) failed, hresult=0x%x\n", _resultCode);
        }
        _pUnk->Release();
    }
    else
    {
        fprintf( stdout, "Failed to create ArithmeticUnit component, hresult=0x%x\n", _resultCode);
    }

    CoUninitialize();

    return 0;

Quote:
}

- - -

    Build this into CsComApp.exe, and then make sure to copy ArithmeticUnit.dll
into the same directory as CsComApp.exe.

    If you receive error 0x80131522, it's probably because ArithmeticUnit.dll can't
be found.  Remember when you looked in the registry?  RegAsm.exe didn't set an
InprocServer32 key, which is how COM normally locates the DLL to load.  In fact,
COM must do work under-the-hood to create a managed execution environment
for ArithmeticUnit.dll and just adding an InprocServer32 key doesn't help.

    An option, if ArithmeticUnit.dll can't co-reside in the same directory as the
application that uses it, is to sign and register ArithmeticUnit.dll in the Global
Assembly Cache.

    If you run CsComApp.exe with ArithmeticUnit.dll present, you should observe
the following results confirming that you've successfully integrated C# with unmanaged
C++.

        Add( 200, 300) returned 500

- - -

Derek Harmon



Wed, 27 Aug 2003 04:22:53 GMT  
 Unmanaged C++ calling managed C# dll
Wow, Thanks, and many thanks for the replies and specially the detailed one.

I am running into a problem which I am the only one know C#/.NET in the
group.

-Dan



Quote:
> > Is it possible,

>     Yes, it is.  Your .NET component written in C# is a COM object, you
> may use it from unmanaged C++ code.  Use RegAsm.exe to create a CLSID
> entry in the Registry so that your C# object implementation can be
located.

> >                      and how?

>     Let's walk through an academic "real-world" example.  Pretend you're
> employed by MyCompany as an application developer of MyApplication.
> You've been assigned the challenging task of implementing the Arithmetic-
> Unit component, and being the leading-edge programmer that you are, you
> want to use C# to write ArithmeticUnit.

>     Unfortunately, nobody on your development team knows C#, as the
primary
> language of MyApplication is C++.  If ArithmeticUnit is to be implemented
in
> C#, it must seamlessly integrate with unmanaged C++.  You've discussed
this
> approach with your project and operations managers, and let's assume they
> agree with you because:

>     1.  The project manager doesn't mind that MyApplication will only work
on
>          the Microsoft Windows platform for the forseeable future, because
our
>          customers all use Microsoft Windows anyway.

>     2.  The operations manager doesn't mind installing .NET with
MyApplication
>          since MyApplication is distributed on CD-ROM and you have 500
megs
>          of space to spare.  Anyway, a smaller redistributable should be
released
>          soon, right?

>     3.  Neither manager have any qualms about asking you to work overtime
if
>          prevailing winds change in the future, and you must re-write
ArithmeticUnit
>          as a COM component in C++.

>     The consumate software architect that you are, your analysis of
ArithmeticUnit's
> requirements lead you to design it with two interfaces: IAdder and
IMultiplier.  You
> reason not everybody needs the full feature set of the ArithmeticUnit, and
this makes
> it easier for others to use.  There will be one component implementation,
that imple-
> ments both IAdder and IMultiplier.

>     Almost for free, C# will throw in IDispatch because an assembly is
virtually a
> ready-made dual interface automation server.  You're going to keep this
under
> your hat for when the product managers come to the team and ask that the
> ArithmeticUnit component be exposed to VBScript for a Web-based product
> line.

>     First, you write ArithmeticUnit in C# -- this is the easy part, you
think to
> yourself.

> - - - adder.cs
> namespace MyCompany.MyApplication
> {
>     public interface IAdder
>     {
>         int Add( int lAddend1, int lAddend2);
>     }

>     public interface IMultiplier
>     {
>         int Multiply( int lMultiplier, int lMultiplicand);
>         int Multiply( int lMultiplier, int lMultiplicand, int
lDenominator);
>     }

>     public class ArithmeticUnit : IAdder, IMultiplier
>     {
>         public int Add( int lAddend1, int lAddend2)
>         {
>             return lAddend1 + lAddend2;
>         }

>         public int Multiply( int lMultiplicand, int lMultiplier)
>         {
>             return lMultiplicand * lMultiplier;
>         }

>         public int Multiply( int lMultiplicand, int lMultiplier, int
lDenominator)
>         {
>             return lMultiplicand * lMultiplier / lDenominator;
>         }
>     }
> }
> - - -

>     What fun!  It's only too bad it went by so fast, no sooner than you
build
> this assembly with,

>         csc.exe /target:library /out:ArithmeticUnit.dll Adder.cs

>     than the C# part of this exercise ends.

>     Next you want ArithmeticUnit to appear in the registry.  This is done
with the
> Register Assembly utility (RegAsm.exe).  While it's optional to generate a
type
> library, you do this to simplify grasping the Interface IDs for IAdder and
IMulti-
> plier.

>         regasm.exe ArithmeticUnit.dll /tlb

>     You confirm in the registry (using regedit.exe) that a CLSID entry was
added
> to the Classes for "MyCompany.MyApplication.ArithmeticUnit".

>     Using the Ole Type Viewer utility from the common Developer Studio
toolchest,
> you make a cursory examination of the type library produced by regasm.exe
to get
> the relevant GUIDs from the uuid attribute annotating IAdder, IMultiplier
and
> ArithmeticUnit.

>         oleview.exe ArithmeticUnit.tlb

>     Now the attention turns to creating a C++ header file,

ArithmeticUnit.h.  This
Quote:
> header needs to include the Interface and Class IDs to use the
ArithmeticUnit
> COM component, and interface definitions for IAdder and IMultiplier that
derive
> from IDispatch (remember the assembly is a dual-interface component).

> [ It's important to note that your GUIDs will be different, and they will
have been
> obtained from their uuid attributes using OleView.]

> - - - ArithmeticUnit.h
> DEFINE_GUID( IID_IAdder, 0x425F5AA9L, 0x36FE, 0x3662, 0xAD, 0xE6, 0x39,

0x88, 0x76, 0xA6, 0x8D, 0x9E);
Quote:
> DEFINE_GUID( IID_IMultiplier, 0x6B589CC4L, 0x61FD, 0x3E10, 0xB2, 0x1F,

0x3C, 0x06, 0x03, 0x7D, 0x6E, 0x9A);
Quote:
> DEFINE_GUID( CLSID_ArithmeticUnit, 0x074545C5L, 0x3420, 0x3D9A, 0x86,

0xE0, 0xC3, 0x17, 0x01, 0xAE, 0xFD, 0xD4);

- Show quoted text -

Quote:

> class IAdder : public IDispatch  // could also use __interface in Visual
C++
> {
> public:
>     HRESULT virtual _stdcall Add( long lAddend1, long lAddend2, long*
retVal) = 0;
> };

> class IMultiplier : public IDispatch
> {
> public:
>     HRESULT virtual _stdcall Multiply( long lMultiplier, long
lMultiplicand,
>                                                            long* retVal) =
0;
>     HRESULT virtual _stdcall Multiply( long lMultiplier, long
lMultiplicand,
>                                                            long

Denominator, long* retVal) = 0;

- Show quoted text -

Quote:
> };
> - - -

>     Another method for generating this include file is to feed the
ArithmeticUnit.tlb
> to the Make Type Library utility (MkTypLib.exe) with the /h switch to
generate
> a header file.  The macros of an auto-generated header obfuscate the
requirements
> for this header.

>     You throw together a Console-based test driver app named CsComApp by
> creating a new Visual C++ Projects | Win32 Projects | Win32 Project
project in
> Visual Studio.NET.  In stdafx.h, you add the following headers to enable
COM:

>         #include <unknwn.h>    // for IUnknown API
>         #include <initguid.h>     // for DEFINE_GUID

>     In stdafx.cpp, you make sure to include the header that describes
ArithmeticUnit,

>         #include "ArithmeticUnit.h"

>     Finally, your implementation of the main( ) method looks as follows:

> - - -CsComApp.cpp
> #include "stdafx.h"

> int main(int argc, char* argv[])
> {
>     HRESULT           _resultCode;
>     LPUNKNOWN  _pUnk    = NULL;
>     IAdder*               _pAdder = NULL;

>     CoInitialize( NULL);

>     _resultCode = CoCreateInstance( CLSID_ArithmeticUnit,
>                                                          NULL,

CLSCTX_INPROC_SERVER,

- Show quoted text -

Quote:
>                                                          IID_IUnknown,
>                                                          (LPVOID*)&_pUnk);
>     if ( _resultCode == S_OK )
>     {
>         _resultCode = _pUnk->QueryInterface( IID_IAdder,

(LPVOID*)&_pAdder);
>         if ( _resultCode == S_OK )
>         {
>             long _lSum = 0L;

>             if ( _pAdder->Add( 200, 300, &_lSum) == S_OK )
>             {
>                 fprintf( stdout, "Add( 200, 300) returned %ld\n", _lSum);
>             }
>             else
>             {
>                 fprintf( stdout, "Call to IAdder::Add() failed,

hresult=0x%x\n", _resultCode);
Quote:
>             }
>             _pAdder->Release();
>         }
>         else
>         {
>             fprintf( stdout, "QueryInterface( IID_IAdder, ...) failed,

hresult=0x%x\n", _resultCode);
Quote:
>         }
>         _pUnk->Release();
>     }
>     else
>     {
>         fprintf( stdout, "Failed to create ArithmeticUnit component,

hresult=0x%x\n", _resultCode);
Quote:
>     }

>     CoUninitialize();

>     return 0;
> }
> - - -

>     Build this into CsComApp.exe, and then make sure to copy
ArithmeticUnit.dll
> into the same directory as CsComApp.exe.

>     If you receive error 0x80131522, it's probably because

ArithmeticUnit.dll can't

- Show quoted text -

Quote:
> be found.  Remember when you looked in the registry?  RegAsm.exe didn't
set an
> InprocServer32 key, which is how COM normally locates the DLL to load.  In
fact,
> COM must do work under-the-hood to create a managed execution environment
> for ArithmeticUnit.dll and just adding an InprocServer32 key doesn't help.

>     An option, if ArithmeticUnit.dll can't co-reside in the same directory
as the
> application that uses it, is to sign and register ArithmeticUnit.dll in
the Global
> Assembly Cache.

>     If you run CsComApp.exe with ArithmeticUnit.dll present, you should
observe
> the following results confirming that you've successfully integrated C#
with unmanaged
> C++.

>         Add( 200, 300) returned 500

> - - -

> Derek Harmon



Wed, 27 Aug 2003 05:06:46 GMT  
 
 [ 5 post ] 

 Relevant Pages 

1. C# client crashs when calling into Managed C++ which calls unmanaged c++ function

2. How to call managed C++ DLL from unmanaged C++ EXE

3. Problem calling into managed DLL that calls unmanaged DLL

4. Managed C++ call unmanaged DLL error

5. Interoperability UnManaged C++, Managed C++, C#

6. Calling a Managed DLL from and UnManaged DLL

7. Call C# dll from unmanaged C++

8. Calling function in managed dll from Unmanaged MFC Application doesn't work on XP

9. C++ Dot net: calling managed method from unmanaged code

10. Debugging into managed c++ DLL that is being used by unmanaged code

11. Unmanaged DLL calling a C# class

12. Unmanaged C++ calling GUI in C#

 

 
Powered by phpBB® Forum Software