Link to home
Start Free TrialLog in
Avatar of ttnetworks
ttnetworks

asked on

C++ SDK Access from C#

I'm trying to call a C++ function in an SDK from a C# app.

The function is defined as:

         prCAPI PR_GetDeviceList(

               prUInt32*         pBufferSize,

               prDeviceList*     pDeviceList

         );

where pBufferSize is a pointer to the buffer size and pDeviceList is a pointer to a prDeviceList struct.
prCAPI is an UInt32 and is 0x00 if the function is successful.

The structs are defined in a header file as the following:

typedef struct{
    prWChar DeviceInternalName[512]; /* Internal device name (512 characters) */
    prWChar ModelName[32]; /* Camera model name (32 characters) */
    prUInt16 Generation; /* Camera generation number */
    prUInt32 Reserved1; /* Reserved */
    prUInt32 ModelID; /* Camera model ID */
    prUInt16 Reserved2; /* Reserved */
    prPorttype PortType; /* Port type 0x01FWIA / 0x02FSTI */
    prUInt32 Reserved3; /* Reserved */
}prDeviceInfoTable;

typedef struct{
    prUInt32 NumList; /* Number of camera device information included in this structure */
    prDeviceInfoTable DeviceInfo[prANY]; /* Camera device information. This array is variable */
}prDeviceList;

The types are defined as:

        unsigned long prCAPI
    unsigned ushort prWChar  
    usigned long prUInt32
    unsigned short prUInt16
    unsigned short prPorttype
    prAny        1

 

Using InteropServices in C#, I re wrote the function and the structs:

public static extern UInt32 PR_GetDeviceList(ref UInt32 pBufferSize, out IntPtr pDeviceList);



public struct prDeviceList
{
    public UInt32 NumList; /* Number of camera device information included in the struct */
    public prDeviceInfoTable[] DeviceInfo; /* Camera device information */
}



[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
public struct prDeviceInfoTable
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=512)]
    public string DeviceInternalName; /* Internal device name (512 characters) */

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
    public string ModelName; /* Camera model name (32 characters) */

    public UInt16 Generation; /* Camera generation number */
    public UInt32 Reserved1; /* Reserved */
    public UInt32 ModelID; /* Camera model ID */
    public UInt16 Reserved2; /* Reserved */
    public UInt16 PortType; /* Port type 0x01FWIA / 0x02FSTI */
    public UInt32 Reserved3; /* Reserved */
}

Can anyone tell me how i go about calling the function then retrieve the prDeviceList struct using the pointer and then enumerate the prDeviceInfoTable structs in the array prDeviceList.DeviceInfo?
ASKER CERTIFIED SOLUTION
Avatar of AlexFM
AlexFM

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of ttnetworks
ttnetworks

ASKER

Hi,

This work needs to be completed in C#...
Do you have C++ code sample for this? Or description of function algorithm?

prCAPI PR_GetDeviceList(
               prUInt32*         pBufferSize,
               prDeviceList*     pDeviceList);

Assuming that pBufferSize points to single Int32 value, and pDeviceList points to single DeviceList structure, function declaration should be:

public static extern UInt32 PR_GetDeviceList(ref UInt32 pBufferSize, ref prDeviceList);

Pass int and prDeviceList this bunction by reference.

The trick is to define prDeviceList structure:
typedef struct{
    prUInt32 NumList; /* Number of camera device information included in this structure */
    prDeviceInfoTable DeviceInfo[prANY]; /* Camera device information. This array is variable */
}prDeviceList;

NumList should be defined as int or Int32 ot UInt32 - doesn't matter.
prDeviceInfoTable should be defined as IntPtr. Allocate unmanaged memory block for it using Marshal.AllocHGlobal. Allocation size should be Marshal.SizeOf(prDeviceInfoTable) * n, n is number of structures. To fill this unmanaged clock you need Marshal.StructureToPtr Method. Make this n times incrementing IntPtr handle to Marshal.SizeOf(prDeviceInfoTable) bytes.
I made the suggested changes to the function and the prDeviceList struct and was able to execute the function successfully, but when i tried to marshal the pointer into a prDeviceInfoTable struct using Marshal.StructureToPtr, my program just exited at that point without throwing any exception. Here's my code:

            //Allocate enough memory for n devices
            int n = 5;
            IntPtr pDeviceInfo = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(prType.prDeviceInfoTable)) * n);
            UInt32 bufferSize = (UInt32)(Marshal.SizeOf(typeof(prType.prDeviceList)) + (Marshal.SizeOf(typeof(prType.prDeviceInfoTable)) * n));
            prType.prDeviceList DeviceList = new prType.prDeviceList();
            DeviceList.pDeviceInfo = pDeviceInfo;
            err = PsRecApi.PR_GetDeviceList(ref bufferSize, ref DeviceList);
            if (err != prError.prOK)
                Console.WriteLine("Error: 0x" + string.Format("{0:x0}", err));
            else
            {
                Console.WriteLine("The buffer size is " + bufferSize);

                prType.prDeviceInfoTable info = new prType.prDeviceInfoTable();
                Marshal.StructureToPtr(info, DeviceList.pDeviceInfo, false);
               
            }

            Marshal.FreeHGlobal(pDeviceInfo);



The SDK in question is the Canon Remote Capture SDK (PS-RecSDK). Here's some of their sample code:

      prResponse            err = prOK;
      prUInt32             count = 0L;
      prUInt32            index;
      prUInt32            BufferSize = 0L;
      prDeviceList*      pGetDevList = NULL;

      /* Allocate memory 10 devices */
      BufferSize = (prUInt32)sizeof(prDeviceList) + (prUInt32)(sizeof(prDeviceInfoTable) * 9L);
      for(;;)
      {
            pGetDevList = (prDeviceList*)new prUInt8[BufferSize];
            /* Enumerate camera devices by PS-ReC SDK */
            err = PR_GetDeviceList( &BufferSize, (prDeviceList*)pGetDevList );
            if(!err)
            {
                  break;
            }
            if((err & prERROR_ERRORID_MASK) != prINSUFFICIENT_BUFFER)
            {
                  goto ErrHandler;
            }
            /* If error is prINSUFFICIENT_BUFFER, */
            /* then change the buffer size. */
            delete [] pGetDevList;
            pGetDevList = NULL;
      }

      if(pGetDevList->NumList > 0)
      {      
          for(index = 0; index<(pGetDevList->NumList); index++)
            {
                  SDK_AND_INFO* pDeviceInfo = new SDK_AND_INFO;
                  char MBModelName[40];
                  pDeviceInfo->m_SelectedSDK = CAMERA_ENUM_PRSDK;
                  memcpy( &((pDeviceInfo->SrcInfo).SelectedSrc_PRSDK), &(pGetDevList->DeviceInfo[index]), sizeof(prDeviceInfoTable) );
                  WideCharToMultiByte(CP_ACP, 0, (pDeviceInfo->SrcInfo).SelectedSrc_PRSDK.ModelName, -1, MBModelName, 40-1, 0, 0);
                  m_CameraList.InsertString(index, (const char *)MBModelName);
                  m_CameraList.SetItemDataPtr( index, pDeviceInfo );
            }
    }

      /* Enumerate camera devices by CD-SDK */
      err = (prResponse)Enum_CDSDK( (cdUInt32*)&count, (cdUInt32)pGetDevList->NumList );
      if(err)
      {
            goto ErrHandler;
      }

      if((pGetDevList->NumList == 0) && (count == 0))
      {
            m_CameraList.InsertString( 0, "(None)" );
      }

      m_CameraList.SetCurSel( 0 );

ErrHandler:

    if(pGetDevList)
        delete [] pGetDevList;

      if(err)
      {
            char      szErrStr[256];
            wsprintf( szErrStr, "ErrorCode = 0x%08X", err );
            MessageBox( szErrStr );

            EndDialog(0);
      }