I'm working on a C# application that supports two communications interfaces, each supported by its own DLL. Each DLL contains the same function names, but their implementation varies slightly depending on the supported interface. As it is, users will typically have only one DLL installed on their machine, not both. The DLL for the old interface is imported like this:
[DllImport("myOldDll.dll",
CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall)]
public static extern int MyFunc1( void );
public static extern int MyFunc2( void );
public static extern int MyFunc3( void );
Would this be a valid way to attempt to bring in either DLL?
[DllImport("myOldDll.dll",
CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall)]
[DllImport("myNewDll.dll",
CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall)]
public static extern int MyFunc1( void );
public static extern int MyFunc2( void );
public static extern int MyFunc3( void );
Ideally, I suppose it would be nice to detect a missing DLL and load the second DLL if the attempt to load the first fails. Is there a graceful way to do that?
How about doing a P/Invoke to `LoadLibrary'?
In .NET 1.1 you would need to create a proxy unmanaged DLL (write it in C or Delphi or ... ) and call it's methods, and that unmanaged DLL would do the rest. In .NET 2.0 and later you use Assembly.LoadFile() and further. Not as elegant as just declarations you attempted to use, and requires quite a lot of coding. So I'd suggest a proxy way if possible.
Perhaps you should give the methods imported from either DLL different names, and then have a delegate in your program that you point to one or the other (whichever is appropriate), and only call the delegate.
It sounds like you would be best served re-architecting to a modular plugin style interface.
There are a billion and a half examples of this on the web, like this one. In a nutshell though, you use LoadAssembly() on a directory of DLLs, then cast back to your common base interface.
I think I found a workable solution:
C# check that a file destination is valid
Thanks, everyone, for your input!
Related
I have this native interface:
void CLASS_Version(char *Version);
I tried to import it with:
[DllImport("class.dll", EntryPoint = "CLASS")]
private static extern void CLASS_Version(ref string[] Version);
or
[DllImport("class.dll", EntryPoint = "CLASS")]
private static extern void CLASS_Version(ref char[] Version);
[DllImport("class.dll", EntryPoint = "CLASS")]
private static extern void CLASS_Version(out string[] Version);
[DllImport("class.dll", EntryPoint = "CLASS")]
private static extern void CLASS_Version(out char[] Version);
But I alway get "AccessViolation" error,
The only good run was made with
[DllImport("class.dll", EntryPoint = "CLASS")]
private static extern void CLASS_Version(ref char Version);
but this way I got only the first char of the strings... how to get all string?
char * is ambiguous, but it definitely isn't an array of strings. Most likely, it's a pointer to a string, so you'll use just a simple StringBuilder (no ref or out).
Also, make sure to use the proper marshalling attributes. .NET strings are always widechars, unlike your signature.
In general, a signature of a function isn't enough for proper interop with native code. You need to understand the meaning of the arguments and the return values, and you need to know the calling convention. You need to read the documentation, in other words :)
Basically pointers are represented with IntPtr type.
plus, the entry point should be the string representing the function name
try:
[DllImport("class.dll", EntryPoint = "CLASS_Version")]
private static extern void CLASS_Version(IntPtr Version);
try this:
[DllImport("class.dll", EntryPoint = "CLASS")]
private static extern void CLASS_Version([MarshalAs(UnmanagedType.VBByRefStr)] ref string Version);
And when you are going to call your method:
Version = Space(14);// first declare memory space requiered ¿14 bytes? ¿more?
CLASS_Version(Version);
Sadly the answer cannot be determined by type alone.
If it were that simple there would be parsers that could write the native wrapper for you.
The type you have to use depends on what the function is actually doing.
In your case the char * is not marked const, and it is being accepted as a parameter, which implies that it's intended to be a user-allocated area of memory available for the function to write to. As there is no size parameter, there is most likely a maximum size that the version string can be, which should be indicated in the documentation of the code.
Given that this is string handling, you also have to worry about the encoding. For the sake of simplicity I'm going to assume (and hope) your string is in ASCII/Windows-1252 and not UTF8, UTF7 or some other format.
Given these assumptions, you have several options, but I will be presenting just the preferred way of handling this based on the information provided. (It may be that your situation requires something different, but this is the best solution I can suggest based on asumptions inferred from the information in your question.)
[DllImport("class.dll", EntryPoint = "CLASS_Version", , CharSet = CharSet.Ansi)] // CharSet is important
private static extern void CLASS_Version(StringBuilder Version);
This is the 'correct' way to manage the situation - rely on the compiler to handle the marshalling for you. One small caveat however is that you must manually set the capacity of the StringBuilder before passing it to the method.
// be sure to allocate a correct size,
// there will be no error if it overflows because it's too small
StringBuilder buffer = new StringBuilder(size);
// automagically marshalled to and from unmanaged code byt the compiler
CLASS_Version(buffer);
string version = buffer.ToString();
I'd like to take this opportunity to point out that CLASS_Version shouldn't be private. All your native methods should be made public and grouped together in one internal static class.
Some additional resources about string marshalling that you may find handy:
https://limbioliong.wordpress.com/2011/11/01/using-the-stringbuilder-in-unmanaged-api-calls/
I'm rewriting some C++ code to C#. The code I'm refactoring uses AddIPAddress in C++ but I cannot find a way to do the same in C#. Can anyone help?
You can use P/Invoke to call the method directly. This page has the details (and a sample) of how you can go about that.
The basic idea is to create a C# method that corresponds to the native method by declaring it as extern, and decorating it with the DllImport attribute:
DllImport("iphlpapi.dll", EntryPoint = "AddIPAddress", SetLastError = true)]
private static extern UInt32 AddIPAddress(UInt32 Address, UInt32 IpMaskint, int IfIndex, out int NTEContext, out int NTEInstance);
I have used DLL Export viewer to try and find the functions that are in this DLL, I have found a list of functions and here it is:
public: int __thiscall CSTVdsDisk::GetPartitionCount(void);
the question is within in C# I am not able to call the function using either:
[DllImport("Some.dll",
ExactSpelling = true,
EntryPoint = "GetPartitionCount",
CallingConvention = CallingConvention.StdCall,
SetLastError = true)]
or:
[DllImport("Some.dll",
ExactSpelling = true,
EntryPoint = "CSTVdsDisk::GetPartitionCount",
CallingConvention = CallingConvention.StdCall,
SetLastError = true)]
private static extern int GetPartitionSize();
They all fail. Is there something that I am doing wrong? Can anyone help? Thanks!
You can't call that function using P/Invoke. The __thiscall calling reference means that this function is a class member function. It is a member function of the CSTVdsDisk class.
To be able to call the function you will have to create an instance of the CSTVdsDisk class and call GetPartitionCount from that instance.
You'll have to do that in C++ or C++/CLR as you can't create a C++ class in C#. See also Create unmanaged c++ object in c#.
Based on the name, that appears to be a C++ class method. That is going to make it very difficult to call that method directly from P/Invoke for two reasons:
You need to find the "real" name; the Export Viewer is apparently showing up the unmangled name, but the actual C++ function name will look much uglier, like #0GetPartitionCount#CSTVdsDisk##QPBAEXA or similar. You may need to use a lower-level tool like dumpbin to find that name.
You need to fake the "thiscall" style call; this means you need to pass an instance of a C++ class as the first parameter. This is only going to work if the C++ class constructor is also exposed from the DLL; in which case, you can call the class constructor, store the result in an IntPtr, and pass it to every subsequent call. (If the constructor is exposed as a DLL export its mangled name will start with ??, like `??0CSTVdsDisk##QAE#ABV0##Z
This CodeProject article shows you how to do most of that, but it's pretty fragile, so expect problems. I'd strongly suggest you look for a non-C++ library that does something similar, or at least one that's designed to be usable from C code.
In your native code, make sure you're exporting the function. By default you function wont be listed in the Exports table so you need to mark it so that the compiler knows to export it. You also need to mark the function as
extern "C"
so that the compiler doesn't mangle the name.
Typically I define the following macro:
#define DLLEXPORT extern "C" __declspec(dllexport)
to handle all of this, and then simply declare exported functions like:
DLLEXPORT __cdecl int Example(int x, int y)
If you find you're still having troubles with the name, try using a free PE explorer program on the dll and checking the exported function table for the correct name.
I have a couple of questions regarding the following:
[DllImport("libmp3lame.dll", CharSet = CharSet.Ansi)]
static extern IntPtr get_lame_version();
public static string GetLameVersion()
{
IntPtr pVersion = get_lame_version();
string version = Marshal.PtrToStringAnsi(pVersion);
return version;
}
Where is the memory of the string pointed to by pVersion allocated?
Is this memory automatically freed when pVersion goes out of scope?
If yes, how does that happen?
If no, how do I free the memory?
The string returned by this function is statically allocated and you do not need to free that memory. This means that your current code is already exactly what you need.
This is an open source project and so a websearch leads to the source code for the implementation of this function to confirm this.
As an aside, your p/invoke is incorrect, although it is benign. It should be:
[DllImport("libmp3lame.dll", CallingConvention=CallingConvention.Cdecl)]
static extern IntPtr get_lame_version();
There's no need to specify CharSet since the function has no text parameters. And in any case Ansi is the default so you still would not need to specify that. The calling convention is, in general, important and will need to be set for all your LAME imports. It doesn't actually matter for a function with no parameters, but specifying the calling convention is a good habit to get in to.
I can't find any example signatures for .NET to use this function (GetSystemDEPPolicy).
http://msdn.microsoft.com/en-us/library/windows/desktop/bb736298(v=vs.85).aspx
It's a fairly simple function but I don't know how to create the signature to call it. Can someone please help?
GetSystemDEPPolicy is defined as
DEP_SYSTEM_POLICY_TYPE WINAPI GetSystemDEPPolicy(void);
and DEP_SYSTEM_POLICY_TYPE is an enum (see winbase.h assuming you have the C++ components installed in your development environment - if not try winbase.h) and enums in C default to int, as such I would go with
[DllImport("kernel32.dll", CharSet=CharSet.Auto, ExactSpelling=true)]
public static extern int GetSystemDEPPolicy();
May I recommend you follow this tutorial on PInvoke