C# - DLLImport and function default values - c#

I'm interfacing with a native 3rd party C++ DLL via C# and the provided interop layer looks like below:
C#:
[DllImport("csvcomm.dll")]
public static extern int CSVC_ValidateCertificate(byte[] certDER, int length);
C++:
CSVC_Status_t CSVCOMM_API CSVC_ValidateCertificate(BYTE* certDER, DWORD length,
DWORD context = CONTEXT_DEFAULT);
Note, there are only two parameters in the C# extern definition since the the C++ function provides a default value for the third parameter. Is this correct? I was receiving some non-deterministic results when using the provided definition, but when I added the third parameter like below, it seems to be working correctly each time rather than sporadically.
[DllImport("csvcomm.dll")]
public static extern int CSVC_ValidateCertificate(byte[] certDER, int length,
int context);
Any ideas? Would the addition of the 3rd parameter really fix this issue?

The optional parameter in C++ is resolved at compile time. When you call into this via P/Invoke, you need to always specify all three parameters.
If you want to have an optional parameter, you'll need to make a C# wrapper around this method with an overload that provides the optional support (or a C# 4 optional parameter). The actual call into the C++ library should always specify all three arguments, however.

Related

Use functions in C# from unmanaged C-DLL (AccessViolationException)

I have a C-DLL with a short documentation and I'd like to use this DLL in my C# program.
Unfortunately the documentation is for an Excel-Makro which is password-protected and so I don't know the exact function names and parameter types.
I used DependencyWalker to find all export functions of the DLL and together with the documentation I figured out that the documented function ptx is called FU_PTX in the DLL and expects one parameter and has a return value. Unfortuntely I still don't know the type of the parameter or the return value but I know that it is a number.
So I wrote following code:
...
[DllImport("dmata.dll")]
public static extern UInt32 FU_PTX(UInt32 x);
FU_PTX(11);
...
This code throws an AccessViolationException. I also tryed other types as int, long, double but I always get the same exception.
As far as I know there is no way to get the required types from the dll directly but perhaps anyone has an idea what might be wrong or can point me in the right direction.
Edit:
I managed to get the signatures from the vba-file:
Private Declare Function FU_PTX# Lib "dmata.dll" (FT#)
I ported this to following C# code:
[DllImport("dmata.dll")]
public static extern double FU_PTX(double x);
FU_PTX(1.5);
I still receive the same AccessViolationException.
Anyone an idea why I still get the same exception?
This syntax:
Private Declare Function FU_PTX# Lib "dmata.dll" (FT#)
Is rather obscure with its use of the # suffix; in "modern" VBA (if there can be said to be such a thing) the declaration would be
Private Declare Function FU_PTX Lib "dmata.dll" (ByRef FT As Double) As Double
Note the unfortunate default of ByRef; arguments are passed by reference in VBA by default (even if the function has no intention of modifying them).
This should correspond with the following C# declaration:
[DllImport("dmata.dll")]
public static extern double FU_PTX(ref double FT);
Since the argument is passed by reference, you can't pass a constant and must always use a variable:
double ft = 11.0;
FU_PTX(ref ft);

Convert C++ function for use in C#

I have a C++ DLL with partial documentation only and no source code access. I need to use functions of this C++ library in my C# application. This is what I have so far:
[DllImport(cpplib.dll)]
public static extern long someFunctionsWithNoParameters();
When I declare and call a function from the C++ DLL in my C# application like this (function with no arguments) and than call it, it works, the function returns a long value returned by the C++ function.
However I don't know how to handle functions with pointer or reference parameters, or parameters defined as in and out by the C++ function. For example this C++ function:
long functionWithParameters(long &State, char *pName, int nLen)
This is how the function is declared (I have access to the header file of the DLL, but not to the source). The parameters State and pName are declared as out parameters and the parameter nLen is declared as in parameter. How do I declare this C++ function in my C# application under the [DllImport] line and than use it (what form of parameters should I pass in and how to read the out parameters)? Is there some conversion convention between the C/C++ pointer and reference types to some C# types?
Thank you!
You need to declare a matching call convention for the imported function. You could try __cdecl or __stdcall, like this:
[DllImport(cpplib.dll, CallingConvention=CallingConvention.Cdecl)]
public static extern long someFunctionsWithNoParameters();
About pointers and references (which are the same in most practical implementations), you need to use unsafe context and C# pointers, consult MSDN for more detail.

A call backwards from C++ to C#

I'm using from C# a C++ library that wasn't quite developed for using from another languages, but it's difficult to change something now. I'm using [DllImport] calls, and nearly everything works fine.
But know I need to use a "backward" call from C++ to C#. So, in C# I need to subscribe to the C++ function. In C++ it is implemented like this:
INTF_API void __stdcall Intf_InstallHandler(Intf_MailHdlPtrType Hdl)
typedef void (STDCALL *Intf_MailHdlPtrType)(InstanceNoType instno,
const MailType* mail, rsuint16 mailsize);
(I've removed a few arguments from the method to make it simplier. They are two bytes - not important)
So in C# I have:
public delegate void MailEventHandler(byte Instance, MailType Mail, UInt16 MailLength);
MailHandlerDef defHandler = (f) =>
{
var structure =
(MailType)Marshal.PtrToStructure(f, typeof(MailType));
handler(structure);
};
Externs.Intf_InstallMailHandler(defHandler);
[DllImport(DLL_NAME, CallingConvention = CallingConvention.StdCall)]
public static extern void Intf_InstallMailHandler(byte Instance, [MarshalAs(UnmanagedType.FunctionPtr)] MailHandlerDef MailHandler, PrimitiveType Primitive);
We have different primitives (in C++ dll every method is a primitive, and every method is implemented as a call-and-wait method, or as an async method, where mailHandler is called on the end of the computation), and all primitives work, except one.
If this primitive is called, the NullRef exception is thrown, without any stacktrace. And I already lost my mind in trying to search what causing this. Intresting is that this doesn't work at our large application (even I tried to switch everyting off, and just call it at start up), but on my small test application it works.
Any help is appreciated.
you could use a .Net CLI C++ wrapper which would then call your standard C++ code.

Issue using __declspec(dllexport) signature declaration from C++ dll to call in C#

I´m trying to call a method that is in a C++ dll declarated as __declspec(dllexport) to use in C#, but I don´t know how to return a string value from C++ and how to declare the signature using DllImport in C#.
C++ code "VNVAPI.dll"
__declspec(dllexport) char * GetGpuName(int phyGPUid)
{
CNvidia * pInstance = CNvidia::GetInstance();
char szName[512]={0};
pInstance->GetGpuName(phyGPUid,szName,512);
return szName;
}
C# method signature:
[DllImport("VNVAPI.dll")]
public static extern char GetGpuName(int phyGPUid);
Error generated:
A call to PInvoke function
'Core!Core.Hardware.IO.NVAPI::GetGpuName'
has unbalanced the stack. This is
likely because the managed PInvoke
signature does not match the unmanaged
target signature. Check that the
calling convention and parameters of
the PInvoke signature match the target
unmanaged signature.
Thanks.
As has been pointed out by others you need to specify the C calling convention in your P/Invoke and also use string on the managed side to marshal the null terminated char*.
However you should rejig the C++ routine to take a char* as an input parameter, together with a buffer length parameter. You then write into this buffer in the native code. This avoids the current problem that the data, as you presently have the code, is returned from the stack which, of course, is unwound as the function returns.
The suggestion to use static will make this memory global and so avoid stack unwind problems, at the expense of thread safety. Yes it will likely work for this use case but its a bad habit to get into.
The error message might be confusing.
Without going into detail, try this:
static char szName[512]={0};
If you still get the error, the you need to specify the calling convention in the DllImport attribute.
Edit:
Also make the return type string for C# method declaration.
The error message suggests checking the calling convention. I suspect that the function is using C calling convention, which would explain the unbalanced stack. I would suggest that you specify the calling convention (as #leppi suggested) in your DllImport attribute. Like this:
[DllImport("VNVAPI.dll", CallingConvention=CallingConvention.Cdecl)]
According to the Strings samples, the return value should be string:
static extern string GetGpuName(int phyGPUid);

unmanaged/managed interop - trouble passing int[]

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.

Categories

Resources