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.
Related
Looking to dll import from vssapi.dll,
Looking at the GetSnapshotDeviceName function, and DLL export viewer gives me:
protected: long __cdecl CVssWriter::GetSnapshotDeviceName(unsigned short const * __ptr64,unsigned short const * __ptr64 * __ptr64)const __ptr64
protected: long __cdecl CVssJetWriter::GetSnapshotDeviceName(unsigned short const * __ptr64,unsigned short const * __ptr64 * __ptr64)const __ptr64
Assuming I want the first one, how do I declare the dll import,
for instance:
[DllImport("vssapi.dll", EntryPoint = "CVssWriter::GetSnapshotDeviceName", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)]
private static extern uint GetSnapshotDeviceName(string wszOriginalVolume, out string ppwszSnapshotDevice);
[With or without the ExactSpelling] always gives me the
Unable to find an entry point named
'CVssWriter::GetSnapshotDeviceName' in DLL 'vssapi.dll
error. Variations on the colons (removing etc), and reversing the names (as the decorated version) gave me no joy either.
I know it can work using the decorated name or the ordinal, but I'd like the code to be reasonably portable (decls being compiler dependent, and nothing I've ever seen says ordinals will stay the same in updates either).
Yeah I already know with this dll it won't port to pre Vista ... that I can live with.
Also heard about AlphaVSS too - but for what I need would be like using an aircraft carrier to go fishing on a lake (- and did they really need to make it so ungainly to use?)
These are C++ instance methods, that is member functions. As such, they cannot be imported using p/invoke. This API for VSS that you are attempting to use is available either as C++ classes, or via COM.
If the functionality that you need is available through the COM interface, then that will be the simplest way for you to proceed. Otherwise you will need to wrap the C++ classes one way or another. Surely the simplest way to do that will be with a mixed mode C++/CLI assembly.
Either way, p/invoke cannot help you here.
I have an unmanaged function call that is throwing this exception when I try to pass it the path to a file name.
I've read that this is likely caused by the DLL itself but I don't think that is the case since the DLL is used in another application, so the problem is likely in my method calling the function.
The specification:
libvlc_media_new_path (libvlc_instance_t *p_instance, const char *path)
Description:
p_instance the instance
path local filesystem path
And my method:
[DllImport("libvlc", EntryPoint = "libvlc_media_new_path")]
public static extern IntPtr NewMedia(IntPtr instance,
[MarshalAs(UnmanagedType.LPStr)] string path);
I think I'm missing the convention call but what would that likely be? Or would it be something else causing this exception?
EDIT: Based on some comments I did some poking around and found... well, nothing. The struct for the instance is opaque, which means I have no idea in Laymans terms. My guess is that it means you don't need to reconstruct it in the application that is using it?
In a blind guess based on this, I replaced the return value that I had been using with the function responsible for setting the *p_instance value to a long instead of an IntPtr since when it was an IntPtr it was returning 0, and with a long I was seeing a value. Again, what an IntPtr is I don't really know. I was pretty happy to see something not 0 in the instance variable but when I ran it past that, it errored out again.
EDIT: I've expanded the question to here.
Based on the exception you're seeing and the declaration you've provided for the native function,
libvlc_media_new_path (libvlc_instance_t *p_instance, const char *path)
your p/invoke declaration is incorrect. You've mismatched the calling conventions. The default for the .NET p/invoke system is stdcall (to match the Windows API functions), but the default for C and C++ code is cdecl. You have to tell .NET explicitly that your function uses the cdecl calling convention.
So change it to look like this:
[DllImport("libvlc", EntryPoint = "libvlc_media_new_path", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr NewMedia(IntPtr instance,
[MarshalAs(UnmanagedType.LPStr)] string path);
Of course, I'm guessing that you're right about the return value being a pointer. The native function declaration you've shown is missing the return type.
As for your question about the instance parameter, and whether you are correctly using the IntPtr type: The parameter is a pointer to a libvlc_instance_t, so you have two basic ways of making that work using p/invoke. First is to declare the parameter as an IntPtr, which gets it marshalled like a raw pointer value. This is not particularly useful for cases where the pointer needs to be anything other than opaque (i.e. retrieved from one native function, stored, and then passed to another native function). Second is to declare a managed structure that mirrors the native structure, and then write the p/invoke declaration to use this structure so that the marshaller will handle things automatically. This is most useful if you actually need to interact with the values stored in the structure pointed to by the pointer.
In this case, after a Google search, it looks like you're using one of the VLC APIs. Specifically this one. That also tells us what an libvlc_instance_t is: it is an opaque structure that represents a libvlc instance. So declaring a managed structure is not an option here, because the structure is treated as opaque even by the native code. All you really need is the pointer, passed back and forth; a perfect case for the first method I talked about above. So the declaration shown above is your winner.
The only battle now is obtaining a valid pointer to a libvlc instance that you can pass to the function whenever you call it. Chances are good that will come from a prior call to a function like libvlc_new, which is documented as creating and intializing a new libvlc instance. Its return value is exactly what you need here. So unless you've already created a libvlc instance (in which case, use that pointer), you will also need to call this function and store its result.
If the documentation is correct about the required values for the libvlc_new function's parameters, you can declare it very simply:
[DllImport("libvlc", EntryPoint = "libvlc_new", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr NewCore(int argc, IntPtr argv);
And call it thus:
IntPtr pLibVlc = NewCore(0, IntPtr.Zero);
// now pLibVlc should be non-zero
And of course, I know nothing about the VLC APIs, but my general knowledge of API design tells me that you will probably need to call the libvlc_release function with that same pointer to an instance once you're finished with it.
Try without the [MarshalAs(UnmanagedType.LPStr)], usually works for me.
I have a DLL with a set of functions. The DLL was used with "themidia" to make it safe.
When I try to call the functions, C# spits out errors due to the functions names.
[DllImport("safety.dll", CallingConvention=CallingConvention.StdCall, ExactSpelling=true)]
private static extern IntPtr _encryptLogin#8(string string_0, string string_1);
If I remove the #8 and remove ExactSpelling=true, it just returns an exception saying no entry point.
What exactly am I doing wrong?
Remove the "#", and in your attribute add EntryPoint="_encryptLogin#8"
As an alternative to specifying EntryPoint as rfmodulator suggested, you can use extern "C" in your C++ source, which will make the exported function names the same as their names in your C++ source.
C++ compiler normally mangles the names of functions, so that you can have overloaded functions (functions with the same name bu different parameters).
I'm using System.Runtime.InteropServices to call several functions written in C++ from my C# app. I'm just having problems with a particular function that returns an array.
I've seen that my function shouldn't return anything, and a pointer to the "returning variable" should be en entry. But I'm not managing to do it properly.
For instance if I have a function in c++
void func(double *y, double *x){...}
that manipulates an array x and returns an array y.
I'm doing:
-in my .h:
extern "C" __declspec(dllexport) void func(double *y,double *x);
-in my .cpp:
__declspec(dllexport) void func(double *y,double *x){...}
-in my c# code:
static class AnyClass
{
[DllImport(dllPath)]
public extern static void func(out double[] y, double[] x);
int otherfunc
{
double[] x = new double[5];
double[] y = new double[5];
...
func(out y, x);
}
}
but it gives me a System.EntryPointNotFoundException.
Any clue?
EntryPointNotFoundException means that nothing called 'function' was found in your DLL.
In your .h file you call it 'func'. But in your .cpp file you call it 'function'. And since your .h file is the only place which is declaring extern "C", what is effectively happening is that the function is being exported by your DLL c++-style-name-mangled, instead of plain-c-style. So, when C# looks for plain-c-style 'function', it cannot find it.
I think, you also have to specify extern "C" in your .cpp file. If not, you might end up with two different functions func, the one with the correct linkage only be declared and not defined.
Note: Afair the extern "C" linkage also specify how the functions are named in the DLL file. For C++ functions some pre- resp. postfixes are added to the name relating to the signature (i.e. the parameters and the return type). This is necessary because you can overload functions in C++. Therefore, if you don't specify extern "C", the functions are named differently in the DLL and thus cannot be found by the managed code.
An EntryPointNotFoundException means that the runtime failed to find the specified function name in your DLL.
Possible reasons are
You misspelled the function name in your DLL or your program
The you did not deactivate name mangling (extern "C")
The first reason is easy to find, just double-check all names and make sure they are really equal. If for some reason you can not change the DLL, but like a different name from C#, you can use the DllImportAttribute.EntryPoint property to point to a function of a different name.
The second one is more difficult to come by. To diagnose the problem, I suggest you use Dependency Walker to see what really is going on inside your compiled DLL. Using that tool, you can see the function names, and whether they are C++'ified or not.
You already tried to use extern "C" to make sure the function name is not afflicted by name mangling. Maybe you did not include the .h file from your .cpp file, so that the compiler did not see the extern "C" at all.
I have this signature in a delphi 2007 function I'm calling (the SomeOtherFile is another DLL that it in turn is calling):
function MyFunction(Place, Name: PChar):_Recordset; stdcall; far; external 'SomeOtherFile.DLL';
I'm trying to call it from C# code like this:
[DllImport("MyFile.dll", CallingConvention = CallingConvention.StdCall,
CharSet = CharSet.Ansi, EntryPoint="MyFunction")]
public static extern DataSet MyFunction(string Place, [MarshalAs(UnmanagedType.LPStr)]string Name);
Whenever I run this and store it into a variable, I get a runtime error about type mismatches. I guess I'm reading the signature wrong, but I can't figure out what it should be.
edit
The actual error is: A call to PInvoke function [...] has unbalanced the stack...I've also tried both params using the MarshalAs attribute, and it throws the same thing.
I've done a bit of digging around and I think you need to marshal the return value as a Recordset interface. I'm sure the P/Invoke marshaller won't magically convert your Delphi _Recordset into a .net DataSet class instance.
So I think you can write it something like this:
[DllImport("MyFile.dll")]
[return: MarshalAs(UnmanagedType.Interface)]
public static extern object MyFunction(string Place, string Name);
Call it like this
Recordset rs = (Recordset) MyFunction(Place, Name);
I'm assuming that the Place and Name parameters are input parameters, in which case the default marshalling for string is just fine.
You don't need to specify ANSI character set because that is the default too. You don't need to name the entry point if it has the same name as the C# function. You don't need to specify the calling convention because stdcall is the default.
The Recordset interface resides in the ADODB namespace.
As an aside, the use of far in your Delphi function import is spurious. The far keyword stopped having any effect once we left the 16 bit world behind.