5

I am trying to access a Microscope from within my C# application. The SDK is written in C++ and I can not add the Dlls as references in my application (due to them being unmanaged code). As a result I found out that I will need to use DllImport in order to use the functions with C#.

Unfortunately this seems to be way over my head.

As an example some of the C++ code (from a sample app included in the SDK):

interface Camera;
typedef Camera * CameraHandle;

struct CameraInfo
{
  wchar_t               camera_name[64];        // camera head type
  wchar_t               controller_name[64];    // controller type
  wchar_t               firmware_version[64];   // firmware version
  long                  lib_id;                 // library ID
  long                  controller_id;          // controller ID
  long                  camera_id;              // camera ID
  CameraHandle          handle;                 // handle to opened camera
  long                  status;                 // status (0 = available)
  CameraInfo()
  {
    memset(this,0,sizeof(*this));
  }
};
typedef struct CameraInfo CameraInfo;

CamDiscoverCameras(OUT const struct CameraInfo ** info, OUT long * count);

And this is how it is used later on:

CamResult               result;          //enum CamResult{...}
const CameraInfo*       camera_info  = NULL;
long                    camera_count = 0, pre_lib_id, pre_controller_id;

result = CamDiscoverCameras(&camera_info, &camera_count);

How do I convert this to C# code? I have already tried something like:

    [StructLayout(LayoutKind.Sequential)]
    struct CameraInfo
    {
        string              camera_name;            // camera head type
        string              controller_name;        // controller type
        string              firmware_version;       // firmware version
        int                 lib_id;                 // library ID
        int                 controller_id;          // controller ID
        int                 camera_id;              // camera ID
        public IntPtr       handle;                 // handle to opened camera
        int                 status;                 // status (0 = available)
    }

    [DllImport("Cam.dll", EntryPoint = "CamDiscoverCameras")]

But basically I have no idea of what I am doing and what needs to be done next (like how the function needs to be defined, how to deal with that "interface" in the C++ code, is the structure converted correctly and so on).

4
  • 1
    Why the downvote? It's not the best question I have seen here but I don't think it deserves a downvote, what is asked here is quite clear... Commented Oct 9, 2014 at 11:22
  • Instead you could create a managed VC++ wrapper, or consider using reflection (although that is not recommended...) Take a look at Recommendations for Managed and Unmanaged Code Interoperability. Commented Oct 9, 2014 at 11:25
  • You can also takke a look at this post: stackoverflow.com/questions/2637571/… there are some links that can be usefull Commented Oct 9, 2014 at 11:26
  • 1
    It is a very unfriendly api, the structs have to marshaled by hand and there is not enough documentation to guess how to do it correctly, unclear who owns the array. Best way to go about it is to contact the camera vendor and ask for help, you are almost surely not the first .NET programmer to deal with it. Commented Oct 9, 2014 at 11:45

2 Answers 2

3

First of all, to convert those wchar_t arrays to .NET string you will need to set additional attributes.

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
struct CameraInfo
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
    string camera_name;            // camera head type
...

Next, the method CamDiscoverCameras returns a pointer to the struct, so in .NET you will be actually receiving an IntPtr and then converting that pointer to a struct using Marshal.PtrToStructure method:

[DllImport("Cam.dll", EntryPoint = "CamDiscoverCameras")]
// you can create enum of ints here and return it
static extern int CamDiscoverCameras(out IntPtr info, out int count);

CameraInfo DiscoverCameraInfos()
{
    IntPtr info; int count;
    int camResult = CamDiscoverCameras(out info, out count);
    var camInfo = (CameraInfo) Marshal.PtrToStructure(info, typeof(CameraInfo));
    // cleanup code - pass your IntPtr to C++ code
    // for it to delete the struct as it seems it was allocated there
    return camInfo;
}

And don't forget to cleanup - from your code it seems that the structure is being allocated somewhere in C++ code, so you likely would have to pass the IntPtr back to C++ code for it to deallocate it.

Sign up to request clarification or add additional context in comments.

4 Comments

First of all thank you very much for showing me how to convert the wchar_t and the correct function declaration. However when I use your code I get a "System.BadImageFormatException" with "An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)" Any idea?
@MarcMueller I'm pretty sure it's because you are compiling your C# code with AnyCPU platform target. Retarget your project (project properties -> Build -> Platform target) to the same architecture that your Cam.dll was built for (x86 / x64) and try again.
yep that was it - your code works :) awesome. Now I will try to do this with the rest of the functions I need - will see how that goes. One thing though: you posted "pass your IntPtr to C++ code for it to delete the struct as it seems it was allocated there" - I don't have any C++ code. The example above was just from a sample app included in the SDK, in my application I only use the dll so I have no idea how to pass anything to it.
@MarcMueller Well, since this function allocates the structure in the heap, there must be a mechanism to remove it from memory. Look at the API of the library, maybe there are some cleanup functions exported.
2

Your struct definition in C# is a bit more complex then yours. Have a look at the PInvoke Interop Assistant. https://clrinterop.codeplex.com/releases/view/14120 It helps a lot with the initial attributes.

4 Comments

This should be a comment at best. Even if this were good advice, it should be a comment. In this case PIA isn't going to get the job done.
Already tried that. For example for wchar_t it only says "typedef" and no further explanation - or I am just too dumb to use the program - in which case it is not very intuitive :)
You're right, I intended to make a comment, however I'm not allowed to. Not enough reputation :(
That's no excuse. I'm afraid you need to get the rep first and then comment.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.