02-24-2009 07:50 AM
I have a 1426 Camera Link board and camera. For various reasons I wanted to work in c#. Most of the information and solutions I found were directed at using Imaqdx with c#. As I can't see how to fake my cameralink board into pretending to be a dx board, and I don't want to use the ActiveX wrappers (because I don't want to have a component works widget in a forms app, I just want to get the data off the camera) I came up with the following approach. I'm posting it in case (a) anyone is looking for a similar solution or (b) people have tried this and run into complications.
I created a wrapper class in c# to provide access to the imaq.dll functions. This assumes that imaq.dll is installed /registered on your system, perhaps in windows/system32
(Code snippet)
public class ImaqWrapper : IDisposable
{
[DllImport("imaq")]
private static extern Int32 imgInterfaceOpen(char[] interfaceName, ref UInt32 pifid);
[DllImport("imaq")]
private static extern Int32 imgClose(UInt32 void_id, UInt32 freeResources);
[DllImport("imaq")]
private static extern Int32 imgSessionOpen(UInt32 ifid, ref UInt32 psid);
[DllImport("imaq")]
private static extern Int32 imgInterfaceReset(UInt32 ifid);
[DllImport("imaq")]
private static extern Int32 imgGrab(UInt32 sid, ref IntPtr bufPtr, UInt32 waitForNext);
[DllImport("imaq")]
private static extern Int32 imgGrabSetup(UInt32 sid, UInt32 startNow);
which have relatively simple implementations - c# default marshaling is pretty clever. I added a COM reference to Imaq3.0 (which is the dll, as it happens) and that also contains the constants like the maximum length of an Interface name, as below. My wrapper class keeps track of the internal interface and session pointers which are just uint32s (note I'm doing this on 32 bit win xp; no idea what happens on 64 bit vista for things like this.)
public void openInterface(string name)
{
disposeInterface();
char[] charArr = name.ToCharArray();
if (charArr.Length > imaq.Definitions.INTERFACE_NAME_SIZE)
throw new Exception("Interface name cannot exceed IMAQ defined maximum");
int rval = imgInterfaceOpen(charArr, ref interfacePointer);
validInterface = (rval == 0);
manageError(rval);
}
Then the only tricky piece, really, is getting the Marshalling right for void** in imgGrab. As seen in the extern call, I use an IntPtr for passing the data. I know that I have a 16 bit camera, and I know how big the image is, so I have a preallocated buffer I'm copying into.
public Int16[] grabImageData()
{
if (!validSession)
{
throw new Exception("Can't grab images on an invalid session.");
}
unsafe
{
IntPtr p = new IntPtr();
int rval = imgGrab(sessionPointer, ref p, waitForNext);
manageError(rval);
System.Runtime.InteropServices.Marshal.Copy(p, imageBuffer, 0, imageBuffer.Length);
}
return imageBuffer;
}
Hope that helps, or if its a spectacularly crazy and stupid way around an issue, I hope someone corrects me.
02-26-2009 08:48 AM
Hi mike.bush!
Thank you for sharing your code! In case you didn't know already, I thought would let you know that the NI Developer Zone Community was developed for doing just this! Here is a link to a KnowledgeBase that explains how to add your code: How Do I Add My Example Code to the NI Developer Zone Community? Thank you for sharing!!
Kristen H.