Go Premium for a chance to win a PS4. Enter to Win

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 2097
  • Last Modified:

Use unmanaged C++ DLL in C#

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
andre72
Asked:
andre72
  • 7
  • 5
1 Solution
 
jhshuklaCommented:
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
 
jhshuklaCommented:
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
 
andre72Author Commented:
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
Fill in the form and get your FREE NFR key NOW!

Veeam is happy to provide a FREE NFR server license to certified engineers, trainers, and bloggers.  It allows for the non‑production use of Veeam Agent for Microsoft Windows. This license is valid for five workstations and two servers.

 
jhshuklaCommented:
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
 
andre72Author Commented:
I tried it out and get an Exception AccessViolationException at the function call
IntPtr procAddress = GetProcAddress("??0Rsct_TerminalConnect@@QAE@XZ");

Any more idea?
0
 
andre72Author Commented:
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
 
jhshuklaCommented:
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
 
andre72Author Commented:
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
 
andre72Author Commented:
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
 
jhshuklaCommented:
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
 
andre72Author Commented:
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
 
andre72Author Commented:
Thanks a lot - it works fine now ...
0

Featured Post

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!

  • 7
  • 5
Tackle projects and never again get stuck behind a technical roadblock.
Join Now