Solved

Use unmanaged C++ DLL in C#

Posted on 2008-10-31
12
1,991 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
  • 7
  • 5
12 Comments
 
LVL 9

Expert Comment

by:jhshukla
Comment Utility
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
Comment Utility
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
Comment Utility
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
 
LVL 9

Expert Comment

by:jhshukla
Comment Utility
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
Comment Utility
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
Comment Utility
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
Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

 
LVL 9

Expert Comment

by:jhshukla
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
Thanks a lot - it works fine now ...
0

Featured Post

What Should I Do With This Threat Intelligence?

Are you wondering if you actually need threat intelligence? The answer is yes. We explain the basics for creating useful threat intelligence.

Join & Write a Comment

This document covers how to connect to SQL Server and browse its contents.  It is meant for those new to Visual Studio and/or working with Microsoft SQL Server.  It is not a guide to building SQL Server database connections in your code.  This is mo…
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…
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 viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.

763 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

Need Help in Real-Time?

Connect with top rated Experts

9 Experts available now in Live!

Get 1:1 Help Now