I'm trying to write a bare-bones ultra-simple light-weight wrapper for the LibVLC DLL Library. I don't need access to much, just the ability to play pause and stop media files. I'm looking at the documentation and this other link I found that explains an older version of LibVLC, but it's outdated for the most recent version. I also tried LibVLC.Net but it too is outdated and I can't find what I'm looking for in the source code to match it to the functions I'm trying to export.
I have the following signature I'm trying to export:
libvlc_new (int argc, const char *const *argv)
The description:
argc the number of arguments (should be 0)
argv list of arguments (should be NULL)
And this is the method I'm trying.
[DllImport("libvlc", EntryPoint = "libvlc_new")]
public static extern IntPtr New(Int32 argc, String[] argv);
The description suggests it should be an array, and I think the problem is the second argument. I've tried:
[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStr)] String[] argv
as according to here, and there are a couple of other options such as a String and StringBuilder as suggested here but it still happens that every time I call the function I get an Imbalanced PInvoke stack.
I need to know what the proper calling convention of this, and very likely several other, functions are. A "PInvoke For Dummies" online reference would be super good.
Not much point in declaring the argument type if only NULL is permitted. Just declare it IntPtr and pass IntPtr.Zero.
The debugger is pointing out that you forgot to declare the CallingConvention. It is not the default for .NET, this is a __cdecl function. So the proper declaration would be:
[DllImport("libvlc", EntryPoint = "libvlc_new",
CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr New(int argc, IntPtr argv);
Called as:
New(0, IntPtr.Zero);
Do try to pick a better name...
Related
I am using DLL runtime which is made with C language into C#.
I came across below statement.
typedef void *JCCP_PROPERTY_HANDLE;
In function it is being used as:
JCCP_RESULT __JCCP_FUNCTION__ jccpGetProperty(
JCCP_HANDLE hjccp,
const char *name,
JCCP_PROPERTY_HANDLE *phproperty);
Now I want to call jccpGetProperty() method in my C# code.
Can anybody tell how can I pass third parameter(JCCP_PROPERTY_HANDLE *phproperty) to function from C#.
I tried with below code but not working.
Extern Method:
[DllImport(DLL_NAME, EntryPoint = "_jccpGetProperty", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr jccpGetProperty(IntPtr hjccp, string name, ref IntPtr JCCP_PROPERTY_HANDLE);
Usage
IntPtr handle = IntPtr.Zero;
string tag = "server.version";
var result = jccpGetProperty(hjccp, tag, ref handle);
Can anybody help me in this?
IntPtr is the correct type mapping for void*. The native type void* is generally used for an opaque pointer, and that is mapped to IntPtr in C#.
Those parts of the p/invoke declaration that we can verify are correct. The unverifible parts are:
The calling convention. You believe that it is cdecl, but we can't check.
The return type. You believe it to be pointer sized. Again we cannot check. My guess is that a 32 bit integer, int or uint is more likely. That would make a difference in a 64 bit process.
The values passed to the function. It's perfectly possible that the function is declared correctly, but you are passing invalid values.
Because you only showed partial code and details, it's hard to say much more. You will have to verify all the parts of the program that we cannot.
I suggest that you start with working C or C++ code and translate that, looking for the first point of deviation in behaviour between that code and your C# translation.
For different purposes I need to provide an interface that implementents the following functions in C#
malloc
calloc
realloc
free
But I would prefer to not to code it myself (why reinvent the wheel).
A better solution would be when my alloc-functions was called, I would simplely call the alloc-functions in stdlib.h, the interface is made so I "just" need to call those functions.
The question is, how do I access the functions in the stdlib.h from C#?
I know about platform invoke, and I am getting better at it. But for platform invoke to work, I need a .dll
And I don't know which .dll implements the stdlib.h
I don't think this sounds like the best solution for your problem. But to answer the question you first need to decide which C runtime to use. One possibility is the system component in msvcrt.dll. Access the functions like this:
[DllImport("msvcrt.dll", CallingConvention=CallingConvention.Cdecl)]
static extern IntPtr malloc(IntPtr size);
[DllImport("msvcrt.dll", CallingConvention=CallingConvention.Cdecl)]
static extern void free(IntPtr ptr);
[DllImport("msvcrt.dll", CallingConvention=CallingConvention.Cdecl)]
static extern IntPtr calloc(IntPtr num, IntPtr size);
[DllImport("msvcrt.dll", CallingConvention=CallingConvention.Cdecl)]
static extern IntPtr realloc(IntPtr ptr, IntPtr size);
However, the official position from MS is that msvcrt.dll is private and not for use by third party applications. So you might prefer to link to a C++ runtime associated with a specific version of MSVC. For example, to link to the VS2013 runtime specify msvcr120.dll. This of course would require you to distribute that runtime.
I'm having an issue calling a function in a c++ dll inside of a c# app. I'm calling the function inside of c# like so:
[DllImport("cryptopp.dll")]
public static extern IntPtr RSAEncryptString(string filename, string seed, string message);
It is being exported in the c++ dll as shown below.
extern "C" __declspec(dllexport) const char* __cdecl RSAEncryptString(const char *pubFilename, const char *seed, const char *message);
What I get when I try to call this, however, is an "An External component has thrown an exception." exception, which is not very descriptive at all, and extremely unhelpful.
When I pull up the dll in an export viewer, it shows all the other exported functions with fully quantified declarations (I.E. public: void __cdecl CryptoPP::X509PublicKey::`vbase destructor'(void) __ptr64 ) , except for the function I am calling, which just displays the function name RSAEncryptString.
This is the only possible issue I can see, besides maybe mis-calling the function with an invalid declaration on the c# side. Am I using System.Runtime.InteropServices.Marshal wrong?
Please help <3 and thanks in advance.
I think you need to change the first line to:
[DllImport("cryptopp.dll",
CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
If you want to get very descriptive, you can also add these:
public static extern IntPtr RSAEncryptString(
[In, MarshalAs(UnmanagedType.LPStr)] string filename,
[In, MarshalAs(UnmanagedType.LPStr)] string seed,
[In, MarshalAs(UnmanagedType.LPStr)] string message);
IIRC think the CharSet should take care of the encoding thing for you, but if it doesn't, use the MarshalAs also, as shown above.
Edit:
Oh I think I got why you still get an error! Your code still had the above problems, but it's still erring because you can't return a string object since it's not a managed object; you need to return a pointer (like IntPtr) and then use Marshal.PtrToStringAnsi!
(I didn't really look at your return type when answering this at first.)
It appears you're trying to store the return value of type const char * (an LPCSTR) into an IntPtr type (usually used for HANDLEs, not LPSTRs.) Try this:
[DllImport("cryptopp.dll", CharSet = CharSet.Auto)]
public static extern String RSAEncryptString(String filename, String seed, String message);
Also keep in mind that if any argument is getting written to, you'll need to add out before its type, i.e. ..., out String message)
In a function in my C++ DLL, I'm returning a std::string to my c# application. It pretty much looks like this:
std::string g_DllName = "MyDLL";
extern "C" THUNDER_API const char* __stdcall GetDLLName()
{
return g_DllName.c_str();
}
But when my C# code calls this function, I get this message in my output window:
Invalid Address specified to RtlFreeHeap( 00150000, 0012D8D8 )
The function declaration in c# looks like this:
[DllImport("MyDll", EntryPoint = "GetDLLName")]
[return: MarshalAs(UnmanagedType.LPStr)]
public static extern string GetDLLName();
From what I've been able to find online, sometimes this message appears when there's an inconsistency between which version of new(debug or release, etc) is being used with delete. But I'm not sure if that is what is going on in my case. So I'm not sure exactly what's causing it. Maybe the MashallAs might have something to do with it?
Any ideas?
Thanks!
I managed to find the issue. It was the way the C# definition was done. From what I can understand, using the MarshallAs(UnmanagedType.LPStr) in combination with the string return type makes it so that it'll attempt to free the string when its done. But because the string comes from the C++ DLL, and most likely a totally different memory manager, it fails. And even if it didn't fail, I don't want it to be freed anyway.
The solution I found was to change the C# declaration to this (the C++ code is unchanged):
[DllImport("MyDll", EntryPoint = "GetDLLName")]
public static extern IntPtr GetDLLName();
So this makes it so that it just returns a pointer to the string data. And then to change it to a string, pass it to Marshal.PtrToStringAnsi()
return Marshal.PtrToStringAnsi(GetDLLName());
And that gets wrapped into another function for cleanliness.
I found the solution from this page:
http://discuss.fogcreek.com/dotnetquestions/default.asp?cmd=show&ixPost=1108
I am working on my phd in chemistry and for that reason I need to write a software application to help me with the imaging of samples under a microscope. This microscope is fitted with an x-y-z nanopositioning stage. The stage is controlled using an unmanaged DLL written in VC++ by the hardware vendor. I could provide you with more specifics of needed but let me start with this;
One of the methods in the dll allows me to read settings for the axis of motion:
C++ syntax:
BOOL E7XX_qSVO (int ID, const char* szAxes, BOOL* pbValueArray)
Where BOOL is int 0 or 1 according to the convention.
My C# wrapper contains:
[DllImport("E7XX_GCS_DLL.dll", EntryPoint = "E7XX_qSVO")]
public static extern int qSVO(int iId, string sAxes, int []iValArray);
This seems correct to me. However when I try something like this in my main application (to query axis 1,2 and 3):
Int32 [] _iValues = new Int32[3];
E7XXController.qSVO(m_iControllerID, "123", _iValues);
I consistently get an array like this:
{6, 0, 10} while I should get {0, 0 , 0} according to the display on the device itself. The complementary function:
BOOL E7XX_SVO (int ID, const char* szAxes, const BOOL* pbValueArray) to set the same status bits on the stage also don't work...
Other commands in the dll work perfectly. I can pass strings and doubles in and out without troublem but not the BOOL type...
Do you guys have any idea what could be wrong?
BOOL in C++ is actually an "int" so make sure you use System.Int32 and not System.Boolean.
Alternatively it might be using COM data types i.e. VARIANT_BOOL, in which case you need do need System.Boolean.
Have you tried running dependency viewer to confirm the function prototype?
Have you tried specifying the MarshalAs attribute, e.g.:-
[DllImport("E7XX_GCS_DLL.dll", EntryPoint = "E7XX_qSVO")]
public static extern int qSVO(int iId,
[MarshalAs(UnmanagedType.AnsiBStr)]string sAxes,
[MarshalAs(UnmanagedType.LPArray)]int[] iValArray);
Also, have you tried literally passing the sAxes string as a char array, e.g.:-
[DllImport("E7XX_GCS_DLL.dll", EntryPoint = "E7XX_qSVO")]
public static extern int qSVO(int iId,
[MarshalAs(UnmanagedType.LPArray)]char[] sAxes,
[MarshalAs(UnmanagedType.LPArray)]int[] iValArray);
I've found that with interop you often need to experiment a fair bit to get it working, so try different combinations, check out the different members of the UnmanagedType enumeration and also play about with other people's suggestions too. However, please try the above two techniques and let me know whether they help sort it!
This isn't going to answer your question directly but a sweet tool for getting common Interop Win32 calls easily is using Pinvoke.net The even have a Visual Studio plugin.
http://www.pinvoke.net/index.aspx
The docs for your function say:
The VC++ compiler needs an extern "C" modifier. The declaration must also specify that these functions are to be called like standard Win-API functions. That means the VC++ compiler needs to see a WINAPI or __stdcall modifier in the declaration.
The default calling convention for DllImport is WinApi. On Windows, that's StdCall. But on CE, that's Cdecl. You want to make sure that you use the right calling convention. You might want to tray adding:
CallConvention = CallingConvention.StdCall
Also, specify our string character set:
CharSet = CharSet.Ansi
But it should work even without these. It's quite odd as your code looks right.