views:

505

answers:

4

Hello,

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?

+1  A: 

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?

Ady Kemp
A: 

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

Jeremy Edwards
A: 

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.

Frank Krueger
+1  A: 

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!

kronoz