Solved

Use unmanaged C++ DLL in C#

Posted on 2008-10-31
12
2,021 Views
Last Modified: 2012-05-05
Hi,

I like to use an unmanaged C++ DLL in my program.
As I've less knownledge about C++ is not my prefered solution to write an own wrapper in C++.
However I found the entries in the C++ DLL and so I'm able for DLLImport in my C# application.
But the result is ever an exeption.

Now somebody told me, that the matter is that the library need to be used in it's own class.

In the snippet you can see how the class is done there and a short source that explain how to use it.
Is it possible to use it with C# without an wrapper writen in C++?

Thanks,

Andre
// Library Class
 
class RSCT_TERMINALCONNECT_API Rsct_TerminalConnect 
{
public:
	// Konstruktion / Destruktion
								Rsct_TerminalConnect(void);
	virtual						~Rsct_TerminalConnect(void);
 
	// Verbindungshandling
			int					Connect(int _port);
			int					UpdateConnect(int _port, const char* _model);
			int					Disconnect(int _port);
 
 
protected:
			BOOL				CheckDownloadmode(Reader* _pReader);
 
private:
			void				Init();
			void				Terminate();
 
			Rsct_TerminalManager* m_pTerminalManager;	
};
 
extern RSCT_TERMINALCONNECT_API int nRsct_TerminalConnect;
 
// CPP access it like
 
	Rsct_TerminalConnect* pTC = new Rsct_TerminalConnect();
 
	ret = pTC->Connect(GetPort());

Open in new window

0
Comment
Question by:andre72
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 7
  • 5
12 Comments
 
LVL 9

Expert Comment

by:jhshukla
ID: 22850276
Could you show the C# code that you used with DLLImport?

----
meanwhile, you can do the following.
it's possible but ugly.
1. Download Dependency Walker (http://www.dependencywalker.com/)
2. Open the DLL in Dependency walker. You get function names appearing like "??1mwDestructor@@UAE@XZ". If not, then right click on them and uncheck "undecorate C++ functions"
3. Use LoadLibrary function (in kernel32.dll) to load your DLL
4. Use GetProcAddress function (in kernel32.dll) to get a function pointer for the method you want to call.
http://msdn.microsoft.com/en-us/library/64tkc9y5.aspx
5. Use Marshal class to convert it to delegate.
http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshal.getdelegateforfunctionpointer(VS.80).aspx

Note: I do not know how a class's member functions will fare with the below method. use them at your own risk.
Avoid calling c'tors and d'tors directly from managed code. someone more experienced than me can help you there.
// this is in C#
class Wrapper
{
    delegate void NiceName(/*param list*/); << this signature must match C++ function's signature.
    NiceName niceFunction;
 
    [DllImport(kernel32.dll)]
    IntPtr LoadLibrary(string);
    [DllImport(kernel32.dll)]
    IntPtr GetProcAddress(string);
 
    void LoadNice()
    {
        IntPtr libHandle = LoadLibrary("path to your.dll");
 
        // for every function you want to use in C#, repeat the following.
        IntPtr procAddress = GetProcAddress("%^$^niceName@$#@"); <<< this is whatever you found in DepWalker
        if (procAddress == IntPtr.Zero)
            MessageBox.Show("method not found in DLL");
        else
            niceFunction = (NiceName) Marshal.GetDelegateForFunctionPointer
                (procAddress, typeof(NiceName));
            // after this you can make calls like niceFunction(arg1, arg2).
    }
}

Open in new window

0
 
LVL 9

Expert Comment

by:jhshukla
ID: 22850288
better highlighted code.
// this is in C#
class Wrapper
{
    delegate void NiceName(/*param list*/); //<< this signature must match C++ function's signature.
    NiceName niceFunction;
 
    [DllImport(kernel32.dll)]
    IntPtr LoadLibrary(string);
    [DllImport(kernel32.dll)]
    IntPtr GetProcAddress(string);
 
    void LoadNice()
    {
        IntPtr libHandle = LoadLibrary("path to your.dll");
 
        // for every function you want to use in C#, repeat the following.
        IntPtr procAddress = GetProcAddress("%^$^niceName@$#@"); //<< this is whatever you found in DepWalker
        if (procAddress == IntPtr.Zero)
            MessageBox.Show("method not found in DLL");
        else
            niceFunction = (NiceName) Marshal.GetDelegateForFunctionPointer
                (procAddress, typeof(NiceName));
            // after this you can make calls like niceFunction(arg1, arg2).
    }
}

Open in new window

0
 

Author Comment

by:andre72
ID: 22850532
Thanks - So depending from the library function is "int Connect(int _port);" and Dependency Walker shows ??0Rsct_TerminalConnect@@QAE@XZ for this function this would be right?

Ugly or not - if it will work I'm glad ;-)
// this is in C#
class Wrapper
{
    // Connect(int _port);
    delegate int Connect(int _port); //<< this signature must match C++ function's signature.
    Connect doconnect;
 
    [DllImport(kernel32.dll)]
    IntPtr LoadLibrary(string);
    [DllImport(kernel32.dll)]
    IntPtr GetProcAddress(string);
 
    void LoadNice()
    {
        IntPtr libHandle = LoadLibrary("path to your.dll");
 
        // for every function you want to use in C#, repeat the following.
        IntPtr procAddress = GetProcAddress("??0Rsct_TerminalConnect@@QAE@XZ"); //<< this is whatever you found in DepWalker
        if (procAddress == IntPtr.Zero)
            MessageBox.Show("method not found in DLL");
        else
            doconnect = (Connect) Marshal.GetDelegateForFunctionPointer
                (procAddress, typeof(Connect));
            // after this you can make calls like niceFunction(arg1, arg2).
    }
}

Open in new window

0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 9

Expert Comment

by:jhshukla
ID: 22854853
Yes, it will work.

one little thing to give you more room. the signature must match, i.e. the return type and parameter list must be identical. you can name the delegate & parameters whatever you want. so something like
delegate int ConnectDelegate(int portNumber);
would work just as well.
0
 

Author Comment

by:andre72
ID: 22854883
I tried it out and get an Exception AccessViolationException at the function call
IntPtr procAddress = GetProcAddress("??0Rsct_TerminalConnect@@QAE@XZ");

Any more idea?
0
 

Author Comment

by:andre72
ID: 22854913
I include the DemoProject in C++ an the DLL itself.
I think nobody can realy test it without the Terminal it access but I hope it will help to find a solution.

Thanks,

Andre
0
 
LVL 9

Expert Comment

by:jhshukla
ID: 22855741
AccessViolationException is a new one. I normally get ArgumentNullException if the dll is missing or if the method is not exported properly. can you attach the code in a zip file?
0
 

Author Comment

by:andre72
ID: 22856147
Yes thanks - my project is included here ...
Args - I try to include it but at first the sln was not allowed, than the exe, than the cs files not allowed in an archive ...
How to attach a file here when nothing inside is allowed?
The extension of one or more files in the archive is not in the list of allowed extensions: RSCT_Terminal/Form1.cs
0
 

Author Comment

by:andre72
ID: 22866220
As is not possible to attach my whole project here's the class
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
 
namespace RSCT_Terminal
{
    public partial class Form1 : Form
    {
            delegate int Connect(int _port); //<< this signature must match C++ function's signature.
    Connect doconnect;
 
    [DllImport("kernel32.dll")]
    public static extern IntPtr LoadLibrary(string LibName);
 
    [DllImport("kernel32.dll")]
    public static extern bool FreeLibrary(IntPtr LibPointer);
 
    [DllImport("kernel32.dll")]
    public static extern IntPtr GetProcAddress(string FuncName);
 
    void LoadNice()
    {
        IntPtr libHandle = LoadLibrary("rsct_TerminalConnect.dll");
        if (libHandle == IntPtr.Zero)
        {
            MessageBox.Show("DLL not found");
        }
        else
        {
            // for every function you want to use in C#, repeat the following.
            IntPtr procAddress = GetProcAddress("??0Rsct_TerminalConnect@@QAE@XZ"); //<< this is whatever you found in DepWalker
            if (procAddress == IntPtr.Zero)
                MessageBox.Show("method not found in DLL");
            else
                doconnect = (Connect)Marshal.GetDelegateForFunctionPointer
                    (procAddress, typeof(Connect));
            // after this you can make calls like niceFunction(arg1, arg2).
        }
 
    }
        public Form1()
        {
            InitializeComponent();
            LoadNice();
        }
    }
}

Open in new window

0
 
LVL 9

Accepted Solution

by:
jhshukla earned 500 total points
ID: 22897897
Ahh Sorry, my mistake. see the code below.

If that doesn't work, can you rename all of them to filename.extension.txt before packing into a zip file? It is a pretty standard practice to get around stupid filters.
// declaration
[DllImport(kernel32.dll)]
IntPtr GetProcAddress(IntPtr, string);
 
// usage
IntPtr libHandle = LoadLibrary("path to your.dll");
 
// for every function you want to use in C#, repeat the following.
IntPtr procAddress = GetProcAddress(libHandle, "??0Rsct_TerminalConnect@@QAE@XZ"); //<< this is whatever you found in DepWalker

Open in new window

0
 

Author Comment

by:andre72
ID: 22899205
Thanks, I'll have a look.

Well, it had been a Zip archive and after my problem I'd searched how to load a zip archive here and found information about that zip archives are also be scanned and also there're only allowed the file types bmp doc gif jpeg jpg log mdb pdf png txt xls ....

I don't understand this because of is sometimes very useful to get a source - but these are not my rules...
0
 

Author Closing Comment

by:andre72
ID: 31512032
Thanks a lot - it works fine now ...
0

Featured Post

On Demand Webinar - Networking for the Cloud Era

This webinar discusses:
-Common barriers companies experience when moving to the cloud
-How SD-WAN changes the way we look at networks
-Best practices customers should employ moving forward with cloud migration
-What happens behind the scenes of SteelConnect’s one-click button

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

More often than not, we developers are confronted with a need: a need to make some kind of magic happen via code. Whether it is for a client, for the boss, or for our own personal projects, the need must be satisfied. Most of the time, the Framework…
Calculating holidays and working days is a function that is often needed yet it is not one found within the Framework. This article presents one approach to building a working-day calculator for use in .NET.
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.
The viewer will be introduced to the member functions push_back and pop_back of the vector class. The video will teach the difference between the two as well as how to use each one along with its functionality.

756 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question