How do I declare and get back the equivalent to a C unsigned char** or to a pointer to an array of structs
-
Wednesday, December 29, 2010 11:03 AM
Hi, thanks for the help,
I have a further question about parameters marshaling to unmanaged dlls:
I was able to pass and get back simple integers or strings with the use of ref or out.
How do I declare and get back the equivalent to a C unsigned char** or to a pointer to an array of structs where the struct is something like:
struct Camera {
int id;
char camname 30;
}
and the structs are filled by the callee ?
Thank you
Marco
marco Furlan- Split by Cookie Luo Thursday, December 30, 2010 3:19 AM new topic
All Replies
-
Thursday, December 30, 2010 3:17 AM
Hi Marco
This is a new question. I will split it as a new thread.
Best Regards,
Cookie Luo[MSFT]
MSDN Community Support | Feedback to us
Get or Request Code Sample from Microsoft
Please remember to mark the replies as answers if they help and unmark them if they provide no help.

-
Thursday, December 30, 2010 7:17 AM
Hi Marco
Supposing we have following c++ code.
struct Camera { int id; char* camname; }; extern "C" __declspec(dllexport) void Test1(char** strArray) { *strArray = "efg"; } extern "C" __declspec(dllexport) void Test2(Camera* value) { /*value->camname = "name"; value->id=*/ }
you should have following code in c# to call the function in c++.
class Program { [DllImport("cpplib.dll")] static extern string Test1(ref string teststring); [DllImport("cpplib.dll")] static extern void Test2(ref Camera value); static void Main(string[] args) {
string str = "abc";
Test1(ref str);Camera value = new Camera(); value.id = 10; value.camname = "name"; Test(ref value); Console.WriteLine(str); } } [StructLayout(LayoutKind.Sequential)] struct Camera { public Int32 id; [MarshalAs(UnmanagedType.LPStr, SizeConst=30)] public string camname; }
This is simple sample. I f you have any other questions, Please let me know.
Best Regards,
Cookie Luo[MSFT]
MSDN Community Support | Feedback to us
Get or Request Code Sample from Microsoft
Please remember to mark the replies as answers if they help and unmark them if they provide no help.

-
Thursday, December 30, 2010 9:31 AM
Hi, thanks for your reply, nevertheless I think my problem is a bit more complex:
I must call some methods from a dll, probably written in delphi or old C++ Builder (Borland world).
these are the signatures
int WINAPI tvcc_get_cameras(int server_handle, struct Camera *camera[],int *num_cameras)
struct Camera {
int id;
char coder_name[40];
char camera_name[40];
int status;
int is_controllable;
};
and
int WINAPI tvcc_get_frame(int server_handle,int *handle,unsigned char **frame, int *size,int *status,int *width,int *height,long *tv_sec, long *tv_usec)
to get the array of structures cameras filled and the buffer frame to show it on a bitmap.
------------------------------------------------------------------------------------------
I declared the methods as
[
StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi),Serializable]
struct CameraInfo1
{
public Int32 id;
[
MarshalAs(UnmanagedType.LPStr, SizeConst = 40)]
public string codername;
[
MarshalAs(UnmanagedType.LPStr, SizeConst = 40)]
public string camname;
public Int32 status;
public Int32 is_controllable;
}
unsafe class BettiniMethods
{
public const int CAMERA_LENGTH = 40;
[
DllImport("GamsSDK.dll", EntryPoint = "@tvcc_get_cameras$qqsipp6Camerapi", SetLastError = true, ExactSpelling = false, CallingConvention = CallingConvention.StdCall)]
public static extern int tvcc_get_cameras(int ch, ref CameraInfo1[] cam, out int ncams);
//public static extern int tvcc_get_cameras(int ch, IntPtr[] cams, out int ncams);
[
DllImport("GamsSDK.dll", EntryPoint = "@tvcc_get_frame$qqsipippct2t2t2t2plt8", SetLastError = true, ExactSpelling = false, CallingConvention = CallingConvention.StdCall)]
public static extern int tvcc_get_frame(int ch, ref int lconn, ref IntPtr frame, out int size, out int stat, out int w, out int h, out long sec, out long usec);
}
and I called the methods as:
CameraInfo1[] cams = new CameraInfo1[64];
result =
BettiniMethods.tvcc_get_cameras(chnd, ref cams, out ncams);
and
IntPtr
pF = new IntPtr();
pF = new IntPtr();
pF = new IntPtr();pF = new IntPtr();
result =
BettiniMethods.tvcc_get_frame(chnd, ref lconn, ref pF, out size, out stat, out w, out h, out sec, out usec);
The result is that I don't get any error, the number of cameras is right (ncams), the integer values of the structures are ok, but the names have just the first character.
For get_frame, again no error, the size, width and height are reasonable, but I'm not able to build up a bitmap from the address I get back.
I know it's a long question, though I would really appreciate your help.
best regards
Marco
-
Sunday, January 02, 2011 7:35 PM
Hi, thanks for your reply.
Sorry to bother you but I can't get out of it.
Let me be more precise
Suppose I have the following structure in C
struct Camera { int id; char camname[30]; }; suppose this unmanaged dll exposes a method as
int WINAPI tvcc_get_cameras(int server_handle, struct Camera *camera[],int *num_cameras);
so there is a pointer to an array of structuresI tried to translate it in managed code both as
[StructLayout(LayoutKind.Sequential)] unsafe public struct Camera { public Int32 id; [MarshalAs(UnmanagedType.LPStr, SizeConst=30)] public string camname; } and
[
StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi),Serializable]
unsafe
public struct CameraInfo
{
public int id;
//[MarshalAs(UnmanagedType.ByValTStr, SizeConst = BettiniMethods.CAMERA_LENGTH)]
//public string camera_name;
public fixed char camera_name[30];
}
and I declared the method as
[
DllImport("GamsSDK.dll", EntryPoint = "@tvcc_get_cameras$qqsipp6Camerapi", SetLastError = true, ExactSpelling = false, CallingConvention = CallingConvention.StdCall)]
1)public static extern int tvcc_get_cameras(int ch, ref Camera[] cam, out int ncams);
2)public static extern int tvcc_get_cameras(int ch, IntPtr[] cams, out int ncams);
for the two options of the structures.and I call the method in the following way:
Camera[] cams = new Camera[64];
result = BettiniMethods.tvcc_get_cameras(chnd, ref cams, out ncams);
for the structure cameraand as
IntPtr[] ps = new IntPtr[128];
for (int n = 0; n < 128; n++)
ps[n] =
Marshal.AllocHGlobal(Marshal.SizeOf(typeof(CameraInfo)));
result = BettiniMethods.tvcc_get_cameras(chnd, ps,
out ncams);
listBox1.Items.Add(
string.Format("Get cameras ritorna {0} telecamere", ncams.ToString()));
CameraInfo[] s =
new CameraInfo[ncams];
for (int i = 0; i < ncams; i++)
s[i] = (CameraInfo0)
Marshal.PtrToStructure(ps[i], typeof(CameraInfo));
In the first case I get an access violation; in the second case I can retrieve just the first letter of the name.
I will really appreciate your help
best regards
Marco
marco Furlan -
Thursday, January 06, 2011 8:09 AM
Hi marco Furlan,
Sorry for late response to you. I am just back from a holiday.
We are doing on research on it. It will take some to reply to you.
Best Regards,
Cookie Luo[MSFT]
MSDN Community Support | Feedback to us
Get or Request Code Sample from Microsoft
Please remember to mark the replies as answers if they help and unmark them if they provide no help.

-
Saturday, January 08, 2011 2:38 PM
Hello Marco Furlan,
1. There are 2 ways to declare the CameraInfo structure :
1.1
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct CameraInfo
{
public Int32 id;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 30)]
public char [] camname;
}The "camname" field is declared as a char [] array and attributed with MarshalAsAttribute with the UnmanagedType.ByValArray enumeration value set.
1.2
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct CameraInfo
{
public Int32 id;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 30)]
public string camname;
}The second way is to declare "camname" as a string and attributed with MarshalAsAttribute with the UnmanagedType.ByValTStr enumeration value set.
1.3 Note that in both cases the SizeConst field is cricual in determining how many characters "camname" contains.
2. The version of "tvcc_get_cameras()" suitable for use is :
public static extern int tvcc_get_cameras(int ch, IntPtr[] cams, out int ncams);
2.1 It will work with the sample code that you provided :
IntPtr[] ps = new IntPtr[128];
for (int n = 0; n < 128; n++)
ps[n] = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(CameraInfo)));result = BettiniMethods.tvcc_get_cameras(chnd, ps, out ncams);
...
CameraInfo[] s = new CameraInfo[ncams];
for (int i = 0; i < ncams; i++)
s[i] = (CameraInfo)Marshal.PtrToStructure(ps[i], typeof(CameraInfo));2.2 Remember to call FreeHGlobal() :
for (int n = 0; n < 128; n++)
{
Marshal.FreeHGlobal(ps[n]);
}3. A few more points to remember :
3.1 The struct pack alignment of the CameraInfo struct as declared in the unmanaged code must match that of the struct as declared in the managed code.
Hence if CameraInfo as been declared in C++ as :
#pragma pack(1)
struct Camera
{
int id;
char camname[30];
};Then it must be declared as follows in C# :
[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
public struct CameraInfo
{
...
...
...
}3.2 The character set (Ansi or Unicode) used in the unmanaged code must also match that of the managed one. Both must use the same character set.
3.3 If the structure pack alignment and/or the character sets do not match, trouble will surface (in the form of garbage field data) when the unmanaged struct is marshaled to the managed world via Marshal.PtrToStructure().
- Bio.
- Marked As Answer by MarcoFurlan Sunday, January 09, 2011 5:13 PM

