Solved

Use unmanaged C++ DLL in C#

Posted on 2008-10-31
12
2,032 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
Salesforce Made Easy to Use

On-screen guidance at the moment of need enables you & your employees to focus on the core, you can now boost your adoption rates swiftly and simply with one easy tool.

 
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

PeopleSoft Has Never Been Easier

PeopleSoft Adoption Made Smooth & Simple!

On-The-Job Training Is made Intuitive & Easy With WalkMe's On-Screen Guidance Tool.  Claim Your Free WalkMe Account Now

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
Adjust the codes 3 65
asp.net repeater 2 38
c#  FTP ftpwebrequest URI invalid 6 47
SSIS Column mapping 5 42
Today I had a very interesting conundrum that had to get solved quickly. Needless to say, it wasn't resolved quickly because when we needed it we were very rushed, but as soon as the conference call was over and I took a step back I saw the correct …
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 goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
The goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…

710 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