P/Invoke structure question

D

Duncan Mole

Hi,

This is probably an easy one but it iy first bit of p/invoke. I am trying to
use the following C struct in a call:

typedef struct
{
BYTE SRB_Cmd;
BYTE SRB_Status,
BYTE SRB_HaId;
BYTE SRB_Flags;
DWORD SRB_Hdr_Rsvd;
BYTE HA_Count;
BYTE HA_SCSI_ID;
BYTE HA_ManagerId[16];
BYTE HA_Identifiyer[16];
BYTE HA_Unique[16];
BYTE HA_SRsvd1;
}
SRB_HAInquiry, *PSRB_HAInquiry;

The function prototype is as follows:

SendASPI32Command((LPSRB)&srbHAInquiry)

According to the docs LPSRB is 4 bit generic pointer to a command strucure.

Fort this I have:

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]

public class SRB_HAInquiry

{

public const int STRING_LEN = 16;

public byte SRB_Cmd;

public byte SRB_Status;

public byte SRB_HaId;

public byte SRB_Flags;

public UInt32 SRB_Hdr_Rsvd;

public byte HA_Count;

public byte HA_SCSI_ID;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]

public string HA_ManagerId = new string(' ', STRING_LEN);

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]

public string HA_Identifier = new string(' ', STRING_LEN);

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]

public string HA_Unique = new string(' ', STRING_LEN);

public UInt16 HA_Rsvd1 = 0;

}

my invokke is :

[DllImport("wnaspi32.dll", EntryPoint="SendASPI32Command",

ExactSpelling=true, CharSet=CharSet.Ansi, SetLastError=true)]

private static extern UInt32 SendASPI32Command(

ref SRB_HAInquiry str);



and my call is:



public SRB_HAInquiry ScHaInquiry(int haId)

{

SRB_HAInquiry enq = new SRB_HAInquiry();

enq.SRB_Cmd = (byte)Commands.SC_HA_INQUIRY;

enq.SRB_HaId = (byte)haId;

UInt32 result = SendASPI32Command(ref enq);


return enq;

}

Any help would be much appreciated.
 
G

Guest

Hi Duncan Mole,

So just wondering, what is the problem? Do you face any problems? Is yes, mind to share us the errors?

Thanks. Sorry for the trouble.
 
I

Irfan

Hi,

I too had a similar problem with the structure containing
a string array variable.

Better see if you run your application on .NET 1.1 as that
solved mine.

Thanks,
irfan
 
B

BMermuys

Hi,

3 problems:

- You don't have to initialize the strings

- If you use a class as struct, then you don't have to pass it by reference,
objects are already passed by reference.
If you use a struct then you have to pass it by reference.

- HA_SRsvd1 is a BYTE inside the c structure and a Uint16 inside the managed
class, they don't match.


HTH,
greetings
 
G

Guest

Hi BMermuys,

What if i have a structure like this?

typedef unsigned short uint16;

typedef uint16 *puint16;

typedef struct StructA
{
puint16 Data;
} StructTest;

Any idea how to do this in C#?

Thanks.
--
Regards,
Chua Wen Ching :)


BMermuys said:
Hi,

3 problems:

- You don't have to initialize the strings

- If you use a class as struct, then you don't have to pass it by reference,
objects are already passed by reference.
If you use a struct then you have to pass it by reference.

- HA_SRsvd1 is a BYTE inside the c structure and a Uint16 inside the managed
class, they don't match.


HTH,
greetings


Duncan Mole said:
Hi,

This is probably an easy one but it iy first bit of p/invoke. I am trying to
use the following C struct in a call:

typedef struct
{
BYTE SRB_Cmd;
BYTE SRB_Status,
BYTE SRB_HaId;
BYTE SRB_Flags;
DWORD SRB_Hdr_Rsvd;
BYTE HA_Count;
BYTE HA_SCSI_ID;
BYTE HA_ManagerId[16];
BYTE HA_Identifiyer[16];
BYTE HA_Unique[16];
BYTE HA_SRsvd1;
}
SRB_HAInquiry, *PSRB_HAInquiry;

The function prototype is as follows:

SendASPI32Command((LPSRB)&srbHAInquiry)

According to the docs LPSRB is 4 bit generic pointer to a command strucure.

Fort this I have:

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]

public class SRB_HAInquiry

{

public const int STRING_LEN = 16;

public byte SRB_Cmd;

public byte SRB_Status;

public byte SRB_HaId;

public byte SRB_Flags;

public UInt32 SRB_Hdr_Rsvd;

public byte HA_Count;

public byte HA_SCSI_ID;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]

public string HA_ManagerId = new string(' ', STRING_LEN);

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]

public string HA_Identifier = new string(' ', STRING_LEN);

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]

public string HA_Unique = new string(' ', STRING_LEN);

public UInt16 HA_Rsvd1 = 0;

}

my invokke is :

[DllImport("wnaspi32.dll", EntryPoint="SendASPI32Command",

ExactSpelling=true, CharSet=CharSet.Ansi, SetLastError=true)]

private static extern UInt32 SendASPI32Command(

ref SRB_HAInquiry str);



and my call is:



public SRB_HAInquiry ScHaInquiry(int haId)

{

SRB_HAInquiry enq = new SRB_HAInquiry();

enq.SRB_Cmd = (byte)Commands.SC_HA_INQUIRY;

enq.SRB_HaId = (byte)haId;

UInt32 result = SendASPI32Command(ref enq);


return enq;

}

Any help would be much appreciated.
 
B

BMermuys

Hi,
[inline]

Chua Wen Ching said:
Hi BMermuys,

What if i have a structure like this?

typedef unsigned short uint16;

typedef uint16 *puint16;

typedef struct StructA
{
puint16 Data;
} StructTest;

[StructLayout(LayoutKind.Sequential)]
public struct StructTest
{
IntPtr pData; // PUSHORT
}

Here you end up with the "pointer-problem". If you work with pointers, you
should think about allocating and de-allocating memory.

Think about:
1. The side (managed or unmanaged) that allocates the memory for the
ushort should also de-allocate it.
2. This also means that the side that initial set the pointer can only
change it (re-allocation).
3. After allocation happened, any side can change the value the pointer
points to, that's no problem.


Example allocating memory from c# and de-allocating from c#:
----
StructTest myStruct = new StructTest();
myStruct.pData = Marshal.AllocHGlobal(sizeof(typeof(ushort));
//allocation

// eg write to it
ushort x = 100;
Marshal.WriteInt16( myStruct.pData, (short) x );

// suppose here you call an unmanaged function that alters (*pData), it
shouldn't change the pointer,
// then you can get the new value:
x = (ushort)Marshal.ReadInt16( myStruct.pData );

Marshal.FreeHGlobal( myStruct.pData );
//de-allocation


HTH,
greetings


Any idea how to do this in C#?

Thanks.
--
Regards,
Chua Wen Ching :)


BMermuys said:
Hi,

3 problems:

- You don't have to initialize the strings

- If you use a class as struct, then you don't have to pass it by reference,
objects are already passed by reference.
If you use a struct then you have to pass it by reference.

- HA_SRsvd1 is a BYTE inside the c structure and a Uint16 inside the managed
class, they don't match.


HTH,
greetings


Duncan Mole said:
Hi,

This is probably an easy one but it iy first bit of p/invoke. I am
trying
to
use the following C struct in a call:

typedef struct
{
BYTE SRB_Cmd;
BYTE SRB_Status,
BYTE SRB_HaId;
BYTE SRB_Flags;
DWORD SRB_Hdr_Rsvd;
BYTE HA_Count;
BYTE HA_SCSI_ID;
BYTE HA_ManagerId[16];
BYTE HA_Identifiyer[16];
BYTE HA_Unique[16];
BYTE HA_SRsvd1;
}
SRB_HAInquiry, *PSRB_HAInquiry;

The function prototype is as follows:

SendASPI32Command((LPSRB)&srbHAInquiry)

According to the docs LPSRB is 4 bit generic pointer to a command strucure.

Fort this I have:

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]

public class SRB_HAInquiry

{

public const int STRING_LEN = 16;

public byte SRB_Cmd;

public byte SRB_Status;

public byte SRB_HaId;

public byte SRB_Flags;

public UInt32 SRB_Hdr_Rsvd;

public byte HA_Count;

public byte HA_SCSI_ID;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]

public string HA_ManagerId = new string(' ', STRING_LEN);

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]

public string HA_Identifier = new string(' ', STRING_LEN);

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]

public string HA_Unique = new string(' ', STRING_LEN);

public UInt16 HA_Rsvd1 = 0;

}

my invokke is :

[DllImport("wnaspi32.dll", EntryPoint="SendASPI32Command",

ExactSpelling=true, CharSet=CharSet.Ansi, SetLastError=true)]

private static extern UInt32 SendASPI32Command(

ref SRB_HAInquiry str);



and my call is:



public SRB_HAInquiry ScHaInquiry(int haId)

{

SRB_HAInquiry enq = new SRB_HAInquiry();

enq.SRB_Cmd = (byte)Commands.SC_HA_INQUIRY;

enq.SRB_HaId = (byte)haId;

UInt32 result = SendASPI32Command(ref enq);


return enq;

}

Any help would be much appreciated.
 
D

Duncan Mole

Hi BMermuys,

Thanks for the response. I wrote it last last night, trying new tricks that
late is never a good idea! I look forward to making the fixes you have
flagged when I get home tonight, interestingly HA_SRsvd1 was the only member
whose value changed - hopefully this is a good sign! I'll post my results to
this thread.

Duncan


BMermuys said:
Hi,

3 problems:

- You don't have to initialize the strings

- If you use a class as struct, then you don't have to pass it by reference,
objects are already passed by reference.
If you use a struct then you have to pass it by reference.

- HA_SRsvd1 is a BYTE inside the c structure and a Uint16 inside the managed
class, they don't match.


HTH,
greetings


Duncan Mole said:
Hi,

This is probably an easy one but it iy first bit of p/invoke. I am
trying
to
use the following C struct in a call:

typedef struct
{
BYTE SRB_Cmd;
BYTE SRB_Status,
BYTE SRB_HaId;
BYTE SRB_Flags;
DWORD SRB_Hdr_Rsvd;
BYTE HA_Count;
BYTE HA_SCSI_ID;
BYTE HA_ManagerId[16];
BYTE HA_Identifiyer[16];
BYTE HA_Unique[16];
BYTE HA_SRsvd1;
}
SRB_HAInquiry, *PSRB_HAInquiry;

The function prototype is as follows:

SendASPI32Command((LPSRB)&srbHAInquiry)

According to the docs LPSRB is 4 bit generic pointer to a command strucure.

Fort this I have:

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]

public class SRB_HAInquiry

{

public const int STRING_LEN = 16;

public byte SRB_Cmd;

public byte SRB_Status;

public byte SRB_HaId;

public byte SRB_Flags;

public UInt32 SRB_Hdr_Rsvd;

public byte HA_Count;

public byte HA_SCSI_ID;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]

public string HA_ManagerId = new string(' ', STRING_LEN);

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]

public string HA_Identifier = new string(' ', STRING_LEN);

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]

public string HA_Unique = new string(' ', STRING_LEN);

public UInt16 HA_Rsvd1 = 0;

}

my invokke is :

[DllImport("wnaspi32.dll", EntryPoint="SendASPI32Command",

ExactSpelling=true, CharSet=CharSet.Ansi, SetLastError=true)]

private static extern UInt32 SendASPI32Command(

ref SRB_HAInquiry str);



and my call is:



public SRB_HAInquiry ScHaInquiry(int haId)

{

SRB_HAInquiry enq = new SRB_HAInquiry();

enq.SRB_Cmd = (byte)Commands.SC_HA_INQUIRY;

enq.SRB_HaId = (byte)haId;

UInt32 result = SendASPI32Command(ref enq);


return enq;

}

Any help would be much appreciated.
 
D

Duncan Mole

Hi BMermuys,

Well, unfortuantley the changes did not help. None of the fields are being
set, this I can confirm becase SRB_Status is supposed to be set to the
return value of SendASPI32Command and it isn't. With regards to HA_SRsvd1 ,
this was a mistake in the post, it is acually a WORD.

Any other ideas?

Duncan Mole said:
Hi BMermuys,

Thanks for the response. I wrote it last last night, trying new tricks that
late is never a good idea! I look forward to making the fixes you have
flagged when I get home tonight, interestingly HA_SRsvd1 was the only member
whose value changed - hopefully this is a good sign! I'll post my results to
this thread.

Duncan


BMermuys said:
Hi,

3 problems:

- You don't have to initialize the strings

- If you use a class as struct, then you don't have to pass it by reference,
objects are already passed by reference.
If you use a struct then you have to pass it by reference.

- HA_SRsvd1 is a BYTE inside the c structure and a Uint16 inside the managed
class, they don't match.


HTH,
greetings


Duncan Mole said:
Hi,

This is probably an easy one but it iy first bit of p/invoke. I am
trying
to
use the following C struct in a call:

typedef struct
{
BYTE SRB_Cmd;
BYTE SRB_Status,
BYTE SRB_HaId;
BYTE SRB_Flags;
DWORD SRB_Hdr_Rsvd;
BYTE HA_Count;
BYTE HA_SCSI_ID;
BYTE HA_ManagerId[16];
BYTE HA_Identifiyer[16];
BYTE HA_Unique[16];
BYTE HA_SRsvd1;
}
SRB_HAInquiry, *PSRB_HAInquiry;

The function prototype is as follows:

SendASPI32Command((LPSRB)&srbHAInquiry)

According to the docs LPSRB is 4 bit generic pointer to a command strucure.

Fort this I have:

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]

public class SRB_HAInquiry

{

public const int STRING_LEN = 16;

public byte SRB_Cmd;

public byte SRB_Status;

public byte SRB_HaId;

public byte SRB_Flags;

public UInt32 SRB_Hdr_Rsvd;

public byte HA_Count;

public byte HA_SCSI_ID;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]

public string HA_ManagerId = new string(' ', STRING_LEN);

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]

public string HA_Identifier = new string(' ', STRING_LEN);

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]

public string HA_Unique = new string(' ', STRING_LEN);

public UInt16 HA_Rsvd1 = 0;

}

my invokke is :

[DllImport("wnaspi32.dll", EntryPoint="SendASPI32Command",

ExactSpelling=true, CharSet=CharSet.Ansi, SetLastError=true)]

private static extern UInt32 SendASPI32Command(

ref SRB_HAInquiry str);



and my call is:



public SRB_HAInquiry ScHaInquiry(int haId)

{

SRB_HAInquiry enq = new SRB_HAInquiry();

enq.SRB_Cmd = (byte)Commands.SC_HA_INQUIRY;

enq.SRB_HaId = (byte)haId;

UInt32 result = SendASPI32Command(ref enq);


return enq;

}

Any help would be much appreciated.
 
B

BMermuys

Hi,

Duncan Mole said:
Hi BMermuys,

Well, unfortuantley the changes did not help. None of the fields are being
set, this I can confirm becase SRB_Status is supposed to be set to the
return value of SendASPI32Command and it isn't. With regards to HA_SRsvd1 ,
this was a mistake in the post, it is acually a WORD.

I always use a struct not a class. A quick test using a class as a struct
failed when an inline array is used, I gonna look into that later.

In the meantime if you didn't already tried it, try using a struct. This
should work, if it doesn't check if the function doesn't return an error and
check if you can call it succesfully from c.

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
public struct SRB_HAInquiry
{
public const int STRING_LEN = 16;
public byte SRB_Cmd;
public byte SRB_Status;
public byte SRB_HaId;
public byte SRB_Flags;
public uint SRB_Hdr_Rsvd;
public byte HA_Count;
public byte HA_SCSI_ID;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]
public string HA_ManagerId;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]
public string HA_Identifier;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]
public string HA_Unique;

public ushort HA_Rsvd1;
}

[DllImport("wnaspi32.dll", EntryPoint="SendASPI32Command",
ExactSpelling=true, CharSet=CharSet.Ansi, SetLastError=true)]
private static extern UInt32 SendASPI32Command(ref SRB_HAInquiry str);

HTH,
greetings


Any other ideas?

Duncan Mole said:
Hi BMermuys,

Thanks for the response. I wrote it last last night, trying new tricks that
late is never a good idea! I look forward to making the fixes you have
flagged when I get home tonight, interestingly HA_SRsvd1 was the only member
whose value changed - hopefully this is a good sign! I'll post my
results
to
this thread.

Duncan


BMermuys said:
Hi,

3 problems:

- You don't have to initialize the strings

- If you use a class as struct, then you don't have to pass it by reference,
objects are already passed by reference.
If you use a struct then you have to pass it by reference.

- HA_SRsvd1 is a BYTE inside the c structure and a Uint16 inside the managed
class, they don't match.


HTH,
greetings


Hi,

This is probably an easy one but it iy first bit of p/invoke. I am trying
to
use the following C struct in a call:

typedef struct
{
BYTE SRB_Cmd;
BYTE SRB_Status,
BYTE SRB_HaId;
BYTE SRB_Flags;
DWORD SRB_Hdr_Rsvd;
BYTE HA_Count;
BYTE HA_SCSI_ID;
BYTE HA_ManagerId[16];
BYTE HA_Identifiyer[16];
BYTE HA_Unique[16];
BYTE HA_SRsvd1;
}
SRB_HAInquiry, *PSRB_HAInquiry;

The function prototype is as follows:

SendASPI32Command((LPSRB)&srbHAInquiry)

According to the docs LPSRB is 4 bit generic pointer to a command
strucure.

Fort this I have:

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]

public class SRB_HAInquiry

{

public const int STRING_LEN = 16;

public byte SRB_Cmd;

public byte SRB_Status;

public byte SRB_HaId;

public byte SRB_Flags;

public UInt32 SRB_Hdr_Rsvd;

public byte HA_Count;

public byte HA_SCSI_ID;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]

public string HA_ManagerId = new string(' ', STRING_LEN);

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]

public string HA_Identifier = new string(' ', STRING_LEN);

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]

public string HA_Unique = new string(' ', STRING_LEN);

public UInt16 HA_Rsvd1 = 0;

}

my invokke is :

[DllImport("wnaspi32.dll", EntryPoint="SendASPI32Command",

ExactSpelling=true, CharSet=CharSet.Ansi, SetLastError=true)]

private static extern UInt32 SendASPI32Command(

ref SRB_HAInquiry str);



and my call is:



public SRB_HAInquiry ScHaInquiry(int haId)

{

SRB_HAInquiry enq = new SRB_HAInquiry();

enq.SRB_Cmd = (byte)Commands.SC_HA_INQUIRY;

enq.SRB_HaId = (byte)haId;

UInt32 result = SendASPI32Command(ref enq);


return enq;

}

Any help would be much appreciated.
 
G

Guest

Hi BMermuys,

Wow. Thanks a lot. I always thought IntPtr is for integer. Not sure can be done with ushort. Had been thinking of using other ways. I had few doubts. Maybe you can help me to clarify it. Thanks.

From your code:
--------------------
// eg write to it
ushort x = 100;
Marshal.WriteInt16( myStruct.pData, (short) x );

--> Is this to write 100 value to myStruct.pData?

// suppose here you call an unmanaged function that alters (*pData), it
shouldn't change the pointer,
// then you can get the new value:
x = (ushort)Marshal.ReadInt16( myStruct.pData );

--> I assume if we use *pData, normally we expect the out value there. So it also means you are transfering the *pData out value to x.

Marshal.FreeHGlobal( myStruct.pData );
//de-allocation

--> Is it always a must to do the de-allocation?

Wow, if i had this:

struct StructTest
{
int Var1;
int Var2;
float Var3;
IntPtr pData;
IntPtr pHeader;
IntPtr pBits;
}

--> So i declare IntPtr for 3 times, had to marshal for 3 times and deallocated for 3 times. Is that right?

--> I am also curious about UIntPtr. I saw this before. What is the difference between UIntPtr and IntPtr. Why can't i use UIntPtr, as i am using unsigned short pointer.

--> Is there any good resources to pick up marshalling for this kind of scenario. I am always looking forward on this, but I am not sure what is the right keywords to search in the Internet.

Thanks again for the wonderful tips.

--
Regards,
Chua Wen Ching :)


BMermuys said:
Hi,
[inline]

Chua Wen Ching said:
Hi BMermuys,

What if i have a structure like this?

typedef unsigned short uint16;

typedef uint16 *puint16;

typedef struct StructA
{
puint16 Data;
} StructTest;

[StructLayout(LayoutKind.Sequential)]
public struct StructTest
{
IntPtr pData; // PUSHORT
}

Here you end up with the "pointer-problem". If you work with pointers, you
should think about allocating and de-allocating memory.

Think about:
1. The side (managed or unmanaged) that allocates the memory for the
ushort should also de-allocate it.
2. This also means that the side that initial set the pointer can only
change it (re-allocation).
3. After allocation happened, any side can change the value the pointer
points to, that's no problem.


Example allocating memory from c# and de-allocating from c#:
----
StructTest myStruct = new StructTest();
myStruct.pData = Marshal.AllocHGlobal(sizeof(typeof(ushort));
//allocation

// eg write to it
ushort x = 100;
Marshal.WriteInt16( myStruct.pData, (short) x );

// suppose here you call an unmanaged function that alters (*pData), it
shouldn't change the pointer,
// then you can get the new value:
x = (ushort)Marshal.ReadInt16( myStruct.pData );

Marshal.FreeHGlobal( myStruct.pData );
//de-allocation


HTH,
greetings


Any idea how to do this in C#?

Thanks.
--
Regards,
Chua Wen Ching :)


BMermuys said:
Hi,

3 problems:

- You don't have to initialize the strings

- If you use a class as struct, then you don't have to pass it by reference,
objects are already passed by reference.
If you use a struct then you have to pass it by reference.

- HA_SRsvd1 is a BYTE inside the c structure and a Uint16 inside the managed
class, they don't match.


HTH,
greetings


Hi,

This is probably an easy one but it iy first bit of p/invoke. I am trying
to
use the following C struct in a call:

typedef struct
{
BYTE SRB_Cmd;
BYTE SRB_Status,
BYTE SRB_HaId;
BYTE SRB_Flags;
DWORD SRB_Hdr_Rsvd;
BYTE HA_Count;
BYTE HA_SCSI_ID;
BYTE HA_ManagerId[16];
BYTE HA_Identifiyer[16];
BYTE HA_Unique[16];
BYTE HA_SRsvd1;
}
SRB_HAInquiry, *PSRB_HAInquiry;

The function prototype is as follows:

SendASPI32Command((LPSRB)&srbHAInquiry)

According to the docs LPSRB is 4 bit generic pointer to a command
strucure.

Fort this I have:

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]

public class SRB_HAInquiry

{

public const int STRING_LEN = 16;

public byte SRB_Cmd;

public byte SRB_Status;

public byte SRB_HaId;

public byte SRB_Flags;

public UInt32 SRB_Hdr_Rsvd;

public byte HA_Count;

public byte HA_SCSI_ID;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]

public string HA_ManagerId = new string(' ', STRING_LEN);

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]

public string HA_Identifier = new string(' ', STRING_LEN);

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]

public string HA_Unique = new string(' ', STRING_LEN);

public UInt16 HA_Rsvd1 = 0;

}

my invokke is :

[DllImport("wnaspi32.dll", EntryPoint="SendASPI32Command",

ExactSpelling=true, CharSet=CharSet.Ansi, SetLastError=true)]

private static extern UInt32 SendASPI32Command(

ref SRB_HAInquiry str);



and my call is:



public SRB_HAInquiry ScHaInquiry(int haId)

{

SRB_HAInquiry enq = new SRB_HAInquiry();

enq.SRB_Cmd = (byte)Commands.SC_HA_INQUIRY;

enq.SRB_HaId = (byte)haId;

UInt32 result = SendASPI32Command(ref enq);


return enq;

}

Any help would be much appreciated.
 
G

Guest

Hi BMermuys,

Sorry Duncan to really interrupt.

I am not sure since in C, you do this:

BYTE HA_ManagerId[16];

Why in C#, you need to code this for:

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]
public string HA_ManagerId;

Why just cannot be:
public string HA_ManagerId;

or public byte[] HA_ManagerID;

Why must there be a MarshalAs?

Just curious. Thanks again.
--
Regards,
Chua Wen Ching :)


BMermuys said:
Hi,

Duncan Mole said:
Hi BMermuys,

Well, unfortuantley the changes did not help. None of the fields are being
set, this I can confirm becase SRB_Status is supposed to be set to the
return value of SendASPI32Command and it isn't. With regards to HA_SRsvd1 ,
this was a mistake in the post, it is acually a WORD.

I always use a struct not a class. A quick test using a class as a struct
failed when an inline array is used, I gonna look into that later.

In the meantime if you didn't already tried it, try using a struct. This
should work, if it doesn't check if the function doesn't return an error and
check if you can call it succesfully from c.

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
public struct SRB_HAInquiry
{
public const int STRING_LEN = 16;
public byte SRB_Cmd;
public byte SRB_Status;
public byte SRB_HaId;
public byte SRB_Flags;
public uint SRB_Hdr_Rsvd;
public byte HA_Count;
public byte HA_SCSI_ID;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]
public string HA_ManagerId;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]
public string HA_Identifier;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]
public string HA_Unique;

public ushort HA_Rsvd1;
}

[DllImport("wnaspi32.dll", EntryPoint="SendASPI32Command",
ExactSpelling=true, CharSet=CharSet.Ansi, SetLastError=true)]
private static extern UInt32 SendASPI32Command(ref SRB_HAInquiry str);

HTH,
greetings


Any other ideas?

Duncan Mole said:
Hi BMermuys,

Thanks for the response. I wrote it last last night, trying new tricks that
late is never a good idea! I look forward to making the fixes you have
flagged when I get home tonight, interestingly HA_SRsvd1 was the only member
whose value changed - hopefully this is a good sign! I'll post my
results
to
this thread.

Duncan


Hi,

3 problems:

- You don't have to initialize the strings

- If you use a class as struct, then you don't have to pass it by
reference,
objects are already passed by reference.
If you use a struct then you have to pass it by reference.

- HA_SRsvd1 is a BYTE inside the c structure and a Uint16 inside the
managed
class, they don't match.


HTH,
greetings


Hi,

This is probably an easy one but it iy first bit of p/invoke. I am
trying
to
use the following C struct in a call:

typedef struct
{
BYTE SRB_Cmd;
BYTE SRB_Status,
BYTE SRB_HaId;
BYTE SRB_Flags;
DWORD SRB_Hdr_Rsvd;
BYTE HA_Count;
BYTE HA_SCSI_ID;
BYTE HA_ManagerId[16];
BYTE HA_Identifiyer[16];
BYTE HA_Unique[16];
BYTE HA_SRsvd1;
}
SRB_HAInquiry, *PSRB_HAInquiry;

The function prototype is as follows:

SendASPI32Command((LPSRB)&srbHAInquiry)

According to the docs LPSRB is 4 bit generic pointer to a command
strucure.

Fort this I have:

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]

public class SRB_HAInquiry

{

public const int STRING_LEN = 16;

public byte SRB_Cmd;

public byte SRB_Status;

public byte SRB_HaId;

public byte SRB_Flags;

public UInt32 SRB_Hdr_Rsvd;

public byte HA_Count;

public byte HA_SCSI_ID;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]

public string HA_ManagerId = new string(' ', STRING_LEN);

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]

public string HA_Identifier = new string(' ', STRING_LEN);

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]

public string HA_Unique = new string(' ', STRING_LEN);

public UInt16 HA_Rsvd1 = 0;

}

my invokke is :

[DllImport("wnaspi32.dll", EntryPoint="SendASPI32Command",

ExactSpelling=true, CharSet=CharSet.Ansi, SetLastError=true)]

private static extern UInt32 SendASPI32Command(

ref SRB_HAInquiry str);



and my call is:



public SRB_HAInquiry ScHaInquiry(int haId)

{

SRB_HAInquiry enq = new SRB_HAInquiry();

enq.SRB_Cmd = (byte)Commands.SC_HA_INQUIRY;

enq.SRB_HaId = (byte)haId;

UInt32 result = SendASPI32Command(ref enq);


return enq;

}

Any help would be much appreciated.
 
B

BMermuys

Hi,
[inline]

Chua Wen Ching said:
Hi BMermuys,

Wow. Thanks a lot. I always thought IntPtr is for integer.
Not sure can be done with ushort. Had been thinking of using other ways.
I had few doubts. Maybe you can help me to clarify it. Thanks.

From your code:
--------------------
// eg write to it
ushort x = 100;
Marshal.WriteInt16( myStruct.pData, (short) x );

--> Is this to write 100 value to myStruct.pData?

Storing the value 100 at the location where myStruct.pData points to.
// suppose here you call an unmanaged function that alters (*pData), it
shouldn't change the pointer,
// then you can get the new value:
x = (ushort)Marshal.ReadInt16( myStruct.pData );

--> I assume if we use *pData, normally we expect the out value there. So
it also means you are transfering the *pData out value to x.

This is basicly reading the value where pData points at and storing it in x.
Marshal.FreeHGlobal( myStruct.pData );
//de-allocation

--> Is it always a must to do the de-allocation?

Well, if you allocate it using Marshal.AllocHGlobal then you need to free it
using FreeHGlobal. But the example was allocation and de-allocation from
C#. It's also possible that the allocation happens inside the dll, in this
case you should not de-allocate it in c#.
Wow, if i had this:

struct StructTest
{
int Var1;
int Var2;
float Var3;
IntPtr pData;
IntPtr pHeader;
IntPtr pBits;
}

--> So i declare IntPtr for 3 times, had to marshal for 3 times and
deallocated for 3 times. Is that right?

You should only de-allocate if you allocated the memory. Again, it's
possible that the dll allocates memory, but then the dll should also
de-allocate it.

You can use Marshal.Copy, Marshal.ReadXXX, Marshal.WriteXXX,
Marshal.PtrToStruct, Marshal.StructToPtr, depending on what the pointer
points at. Eg. for pData you probely want Marshal.Copy, so you can copy the
data into a managed byte array.
--> I am also curious about UIntPtr. I saw this before. What is the
difference between UIntPtr and IntPtr. Why can't i use UIntPtr, as i am
using unsigned short pointer.

You can, but it won't make a difference, since marshalling happens with
Marshal.WriteInt16/ReadInt16.

Realize that a pointer is an address. An address can point to anything.
It's also possible to *see* this address as a number which will have the
same wide as the pointer (32 or 64 bits).

UIntPtr and IntPtr both can represent any pointer (ushort*, int*, short*,
void*,etc). The difference is that IntPtr has methods to convert the
pointer to an signed integer, while UIntPtr has methods to convert the
pointer to an unsigned integer. Unsigned or signed they are still
addresses, and mostly used for pointer arithmetic, not for reading or
writing a value.

--> Is there any good resources to pick up marshalling for this kind of
scenario. I am always looking forward on this, but I am not sure what is the
right keywords to search in the Internet.

IMHO you must really know C, and more important the concept of pointers.

I don't think you should try to learn it all at once. When you have a
concrete marshalling problem and you can't figure it out, post it here with
sufficient information, and we'll help you. And after a while you will see
a pattern. Offcourse .Net framework sdk documentation (which is also
online at microsoft) is a good starting place (it has a lot of examples
too), look for platform invoke.

HTH,
greetings

Thanks again for the wonderful tips.

--
Regards,
Chua Wen Ching :)


BMermuys said:
Hi,
[inline]

Chua Wen Ching said:
Hi BMermuys,

What if i have a structure like this?

typedef unsigned short uint16;

typedef uint16 *puint16;

typedef struct StructA
{
puint16 Data;
} StructTest;

[StructLayout(LayoutKind.Sequential)]
public struct StructTest
{
IntPtr pData; // PUSHORT
}

Here you end up with the "pointer-problem". If you work with pointers, you
should think about allocating and de-allocating memory.

Think about:
1. The side (managed or unmanaged) that allocates the memory for the
ushort should also de-allocate it.
2. This also means that the side that initial set the pointer can only
change it (re-allocation).
3. After allocation happened, any side can change the value the pointer
points to, that's no problem.


Example allocating memory from c# and de-allocating from c#:
----
StructTest myStruct = new StructTest();
myStruct.pData = Marshal.AllocHGlobal(sizeof(typeof(ushort));
//allocation

// eg write to it
ushort x = 100;
Marshal.WriteInt16( myStruct.pData, (short) x );

// suppose here you call an unmanaged function that alters (*pData), it
shouldn't change the pointer,
// then you can get the new value:
x = (ushort)Marshal.ReadInt16( myStruct.pData );

Marshal.FreeHGlobal( myStruct.pData );
//de-allocation


HTH,
greetings


Any idea how to do this in C#?

Thanks.
--
Regards,
Chua Wen Ching :)


:

Hi,

3 problems:

- You don't have to initialize the strings

- If you use a class as struct, then you don't have to pass it by reference,
objects are already passed by reference.
If you use a struct then you have to pass it by reference.

- HA_SRsvd1 is a BYTE inside the c structure and a Uint16 inside the managed
class, they don't match.


HTH,
greetings


Hi,

This is probably an easy one but it iy first bit of p/invoke. I am trying
to
use the following C struct in a call:

typedef struct
{
BYTE SRB_Cmd;
BYTE SRB_Status,
BYTE SRB_HaId;
BYTE SRB_Flags;
DWORD SRB_Hdr_Rsvd;
BYTE HA_Count;
BYTE HA_SCSI_ID;
BYTE HA_ManagerId[16];
BYTE HA_Identifiyer[16];
BYTE HA_Unique[16];
BYTE HA_SRsvd1;
}
SRB_HAInquiry, *PSRB_HAInquiry;

The function prototype is as follows:

SendASPI32Command((LPSRB)&srbHAInquiry)

According to the docs LPSRB is 4 bit generic pointer to a command
strucure.

Fort this I have:

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]

public class SRB_HAInquiry

{

public const int STRING_LEN = 16;

public byte SRB_Cmd;

public byte SRB_Status;

public byte SRB_HaId;

public byte SRB_Flags;

public UInt32 SRB_Hdr_Rsvd;

public byte HA_Count;

public byte HA_SCSI_ID;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]

public string HA_ManagerId = new string(' ', STRING_LEN);

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]

public string HA_Identifier = new string(' ', STRING_LEN);

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]

public string HA_Unique = new string(' ', STRING_LEN);

public UInt16 HA_Rsvd1 = 0;

}

my invokke is :

[DllImport("wnaspi32.dll", EntryPoint="SendASPI32Command",

ExactSpelling=true, CharSet=CharSet.Ansi, SetLastError=true)]

private static extern UInt32 SendASPI32Command(

ref SRB_HAInquiry str);



and my call is:



public SRB_HAInquiry ScHaInquiry(int haId)

{

SRB_HAInquiry enq = new SRB_HAInquiry();

enq.SRB_Cmd = (byte)Commands.SC_HA_INQUIRY;

enq.SRB_HaId = (byte)haId;

UInt32 result = SendASPI32Command(ref enq);


return enq;

}

Any help would be much appreciated.
 
B

BMermuys

Hi,

Chua Wen Ching said:
Hi BMermuys,

Sorry Duncan to really interrupt.

I am not sure since in C, you do this:

BYTE HA_ManagerId[16];

This is inside a structure, so the bytes are actually part of the struct.
Why in C#, you need to code this for:

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]
public string HA_ManagerId;

Because if you want, you can see an array of bytes as a (ansi)string with a
fixed length.
Why just cannot be:
public string HA_ManagerId;

As far as I know, this would translate to a char* or byte* if you want. Not
to an inlined array.
or public byte[] HA_ManagerID;

This is possible, but you still need the MarshalAs :

[MarshalAs(UnmanagedType.ByValArray,SizeConst=STRING_LEN)]
public byte[] HA_ManagerID;
Why must there be a MarshalAs?

You need it mostly because of the const size.

EG.
struct // in C
{
byte b[10];
}

Now what's the size of this struct ? Always 10 bytes.

struct // in c#
{
byte[] b;
}

Now what's the size of this struct ? You can't tell, it depends on b. But
since you're using platform invoke. The struct's must match in size.
That's why you must specify the const size.


HTH,
greetings


Just curious. Thanks again.
--
Regards,
Chua Wen Ching :)


BMermuys said:
Hi,

Duncan Mole said:
Hi BMermuys,

Well, unfortuantley the changes did not help. None of the fields are being
set, this I can confirm becase SRB_Status is supposed to be set to the
return value of SendASPI32Command and it isn't. With regards to
HA_SRsvd1
,
this was a mistake in the post, it is acually a WORD.

I always use a struct not a class. A quick test using a class as a struct
failed when an inline array is used, I gonna look into that later.

In the meantime if you didn't already tried it, try using a struct. This
should work, if it doesn't check if the function doesn't return an error and
check if you can call it succesfully from c.

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
public struct SRB_HAInquiry
{
public const int STRING_LEN = 16;
public byte SRB_Cmd;
public byte SRB_Status;
public byte SRB_HaId;
public byte SRB_Flags;
public uint SRB_Hdr_Rsvd;
public byte HA_Count;
public byte HA_SCSI_ID;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]
public string HA_ManagerId;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]
public string HA_Identifier;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]
public string HA_Unique;

public ushort HA_Rsvd1;
}

[DllImport("wnaspi32.dll", EntryPoint="SendASPI32Command",
ExactSpelling=true, CharSet=CharSet.Ansi, SetLastError=true)]
private static extern UInt32 SendASPI32Command(ref SRB_HAInquiry str);

HTH,
greetings


Any other ideas?

Hi BMermuys,

Thanks for the response. I wrote it last last night, trying new tricks
that
late is never a good idea! I look forward to making the fixes you have
flagged when I get home tonight, interestingly HA_SRsvd1 was the only
member
whose value changed - hopefully this is a good sign! I'll post my results
to
this thread.

Duncan


Hi,

3 problems:

- You don't have to initialize the strings

- If you use a class as struct, then you don't have to pass it by
reference,
objects are already passed by reference.
If you use a struct then you have to pass it by reference.

- HA_SRsvd1 is a BYTE inside the c structure and a Uint16 inside the
managed
class, they don't match.


HTH,
greetings


Hi,

This is probably an easy one but it iy first bit of p/invoke. I am
trying
to
use the following C struct in a call:

typedef struct
{
BYTE SRB_Cmd;
BYTE SRB_Status,
BYTE SRB_HaId;
BYTE SRB_Flags;
DWORD SRB_Hdr_Rsvd;
BYTE HA_Count;
BYTE HA_SCSI_ID;
BYTE HA_ManagerId[16];
BYTE HA_Identifiyer[16];
BYTE HA_Unique[16];
BYTE HA_SRsvd1;
}
SRB_HAInquiry, *PSRB_HAInquiry;

The function prototype is as follows:

SendASPI32Command((LPSRB)&srbHAInquiry)

According to the docs LPSRB is 4 bit generic pointer to a command
strucure.

Fort this I have:

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]

public class SRB_HAInquiry

{

public const int STRING_LEN = 16;

public byte SRB_Cmd;

public byte SRB_Status;

public byte SRB_HaId;

public byte SRB_Flags;

public UInt32 SRB_Hdr_Rsvd;

public byte HA_Count;

public byte HA_SCSI_ID;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]

public string HA_ManagerId = new string(' ', STRING_LEN);

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]

public string HA_Identifier = new string(' ', STRING_LEN);

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]

public string HA_Unique = new string(' ', STRING_LEN);

public UInt16 HA_Rsvd1 = 0;

}

my invokke is :

[DllImport("wnaspi32.dll", EntryPoint="SendASPI32Command",

ExactSpelling=true, CharSet=CharSet.Ansi, SetLastError=true)]

private static extern UInt32 SendASPI32Command(

ref SRB_HAInquiry str);



and my call is:



public SRB_HAInquiry ScHaInquiry(int haId)

{

SRB_HAInquiry enq = new SRB_HAInquiry();

enq.SRB_Cmd = (byte)Commands.SC_HA_INQUIRY;

enq.SRB_HaId = (byte)haId;

UInt32 result = SendASPI32Command(ref enq);


return enq;

}

Any help would be much appreciated.
 
G

Guest

Hi BMermuys,

Thanks a lot.

You think is necessary for me to buy Adam Nathan's .NET and COM book?

Yeah, soon i need to code C. Sad story. Haha!

Thanks again.
--
Regards,
Chua Wen Ching :)


BMermuys said:
Hi,
[inline]

Chua Wen Ching said:
Hi BMermuys,

Wow. Thanks a lot. I always thought IntPtr is for integer.
Not sure can be done with ushort. Had been thinking of using other ways.
I had few doubts. Maybe you can help me to clarify it. Thanks.

From your code:
--------------------
// eg write to it
ushort x = 100;
Marshal.WriteInt16( myStruct.pData, (short) x );

--> Is this to write 100 value to myStruct.pData?

Storing the value 100 at the location where myStruct.pData points to.
// suppose here you call an unmanaged function that alters (*pData), it
shouldn't change the pointer,
// then you can get the new value:
x = (ushort)Marshal.ReadInt16( myStruct.pData );

--> I assume if we use *pData, normally we expect the out value there. So
it also means you are transfering the *pData out value to x.

This is basicly reading the value where pData points at and storing it in x.
Marshal.FreeHGlobal( myStruct.pData );
//de-allocation

--> Is it always a must to do the de-allocation?

Well, if you allocate it using Marshal.AllocHGlobal then you need to free it
using FreeHGlobal. But the example was allocation and de-allocation from
C#. It's also possible that the allocation happens inside the dll, in this
case you should not de-allocate it in c#.
Wow, if i had this:

struct StructTest
{
int Var1;
int Var2;
float Var3;
IntPtr pData;
IntPtr pHeader;
IntPtr pBits;
}

--> So i declare IntPtr for 3 times, had to marshal for 3 times and
deallocated for 3 times. Is that right?

You should only de-allocate if you allocated the memory. Again, it's
possible that the dll allocates memory, but then the dll should also
de-allocate it.

You can use Marshal.Copy, Marshal.ReadXXX, Marshal.WriteXXX,
Marshal.PtrToStruct, Marshal.StructToPtr, depending on what the pointer
points at. Eg. for pData you probely want Marshal.Copy, so you can copy the
data into a managed byte array.
--> I am also curious about UIntPtr. I saw this before. What is the
difference between UIntPtr and IntPtr. Why can't i use UIntPtr, as i am
using unsigned short pointer.

You can, but it won't make a difference, since marshalling happens with
Marshal.WriteInt16/ReadInt16.

Realize that a pointer is an address. An address can point to anything.
It's also possible to *see* this address as a number which will have the
same wide as the pointer (32 or 64 bits).

UIntPtr and IntPtr both can represent any pointer (ushort*, int*, short*,
void*,etc). The difference is that IntPtr has methods to convert the
pointer to an signed integer, while UIntPtr has methods to convert the
pointer to an unsigned integer. Unsigned or signed they are still
addresses, and mostly used for pointer arithmetic, not for reading or
writing a value.

--> Is there any good resources to pick up marshalling for this kind of
scenario. I am always looking forward on this, but I am not sure what is the
right keywords to search in the Internet.

IMHO you must really know C, and more important the concept of pointers.

I don't think you should try to learn it all at once. When you have a
concrete marshalling problem and you can't figure it out, post it here with
sufficient information, and we'll help you. And after a while you will see
a pattern. Offcourse .Net framework sdk documentation (which is also
online at microsoft) is a good starting place (it has a lot of examples
too), look for platform invoke.

HTH,
greetings

Thanks again for the wonderful tips.

--
Regards,
Chua Wen Ching :)


BMermuys said:
Hi,
[inline]

Hi BMermuys,

What if i have a structure like this?

typedef unsigned short uint16;

typedef uint16 *puint16;

typedef struct StructA
{
puint16 Data;
} StructTest;

[StructLayout(LayoutKind.Sequential)]
public struct StructTest
{
IntPtr pData; // PUSHORT
}

Here you end up with the "pointer-problem". If you work with pointers, you
should think about allocating and de-allocating memory.

Think about:
1. The side (managed or unmanaged) that allocates the memory for the
ushort should also de-allocate it.
2. This also means that the side that initial set the pointer can only
change it (re-allocation).
3. After allocation happened, any side can change the value the pointer
points to, that's no problem.


Example allocating memory from c# and de-allocating from c#:
----
StructTest myStruct = new StructTest();
myStruct.pData = Marshal.AllocHGlobal(sizeof(typeof(ushort));
//allocation

// eg write to it
ushort x = 100;
Marshal.WriteInt16( myStruct.pData, (short) x );

// suppose here you call an unmanaged function that alters (*pData), it
shouldn't change the pointer,
// then you can get the new value:
x = (ushort)Marshal.ReadInt16( myStruct.pData );

Marshal.FreeHGlobal( myStruct.pData );
//de-allocation


HTH,
greetings




Any idea how to do this in C#?

Thanks.
--
Regards,
Chua Wen Ching :)


:

Hi,

3 problems:

- You don't have to initialize the strings

- If you use a class as struct, then you don't have to pass it by
reference,
objects are already passed by reference.
If you use a struct then you have to pass it by reference.

- HA_SRsvd1 is a BYTE inside the c structure and a Uint16 inside the
managed
class, they don't match.


HTH,
greetings


Hi,

This is probably an easy one but it iy first bit of p/invoke. I am
trying
to
use the following C struct in a call:

typedef struct
{
BYTE SRB_Cmd;
BYTE SRB_Status,
BYTE SRB_HaId;
BYTE SRB_Flags;
DWORD SRB_Hdr_Rsvd;
BYTE HA_Count;
BYTE HA_SCSI_ID;
BYTE HA_ManagerId[16];
BYTE HA_Identifiyer[16];
BYTE HA_Unique[16];
BYTE HA_SRsvd1;
}
SRB_HAInquiry, *PSRB_HAInquiry;

The function prototype is as follows:

SendASPI32Command((LPSRB)&srbHAInquiry)

According to the docs LPSRB is 4 bit generic pointer to a command
strucure.

Fort this I have:

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]

public class SRB_HAInquiry

{

public const int STRING_LEN = 16;

public byte SRB_Cmd;

public byte SRB_Status;

public byte SRB_HaId;

public byte SRB_Flags;

public UInt32 SRB_Hdr_Rsvd;

public byte HA_Count;

public byte HA_SCSI_ID;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]

public string HA_ManagerId = new string(' ', STRING_LEN);

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]

public string HA_Identifier = new string(' ', STRING_LEN);

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]

public string HA_Unique = new string(' ', STRING_LEN);

public UInt16 HA_Rsvd1 = 0;

}

my invokke is :

[DllImport("wnaspi32.dll", EntryPoint="SendASPI32Command",

ExactSpelling=true, CharSet=CharSet.Ansi, SetLastError=true)]

private static extern UInt32 SendASPI32Command(

ref SRB_HAInquiry str);



and my call is:



public SRB_HAInquiry ScHaInquiry(int haId)

{

SRB_HAInquiry enq = new SRB_HAInquiry();

enq.SRB_Cmd = (byte)Commands.SC_HA_INQUIRY;

enq.SRB_HaId = (byte)haId;

UInt32 result = SendASPI32Command(ref enq);


return enq;

}

Any help would be much appreciated.
 
G

Guest

Hi BMermuys,

I understand now. I had one more question.

struct // in C
{
byte b[10];
}

Now what's the size of this struct ? Always 10 bytes.

struct // in c#
{
byte[] b;
}

Now what's the size of this struct ? You can't tell, it depends on b. But
since you're using platform invoke. The struct's must match in size.
That's why you must specify the const size.
--> Quite true. But then how do you allocate size 10 to byte[] b in c#?

By this:

Struct aStruct = new Struct();
aStruct.b = new byte[10]; // ???? not sure what i am doing!

Thanks again.
--
Regards,
Chua Wen Ching :)


BMermuys said:
Hi,

Chua Wen Ching said:
Hi BMermuys,

Sorry Duncan to really interrupt.

I am not sure since in C, you do this:

BYTE HA_ManagerId[16];

This is inside a structure, so the bytes are actually part of the struct.
Why in C#, you need to code this for:

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]
public string HA_ManagerId;

Because if you want, you can see an array of bytes as a (ansi)string with a
fixed length.
Why just cannot be:
public string HA_ManagerId;

As far as I know, this would translate to a char* or byte* if you want. Not
to an inlined array.
or public byte[] HA_ManagerID;

This is possible, but you still need the MarshalAs :

[MarshalAs(UnmanagedType.ByValArray,SizeConst=STRING_LEN)]
public byte[] HA_ManagerID;
Why must there be a MarshalAs?

You need it mostly because of the const size.

EG.
struct // in C
{
byte b[10];
}

Now what's the size of this struct ? Always 10 bytes.

struct // in c#
{
byte[] b;
}

Now what's the size of this struct ? You can't tell, it depends on b. But
since you're using platform invoke. The struct's must match in size.
That's why you must specify the const size.


HTH,
greetings


Just curious. Thanks again.
--
Regards,
Chua Wen Ching :)


BMermuys said:
Hi,

Hi BMermuys,

Well, unfortuantley the changes did not help. None of the fields are being
set, this I can confirm becase SRB_Status is supposed to be set to the
return value of SendASPI32Command and it isn't. With regards to HA_SRsvd1
,
this was a mistake in the post, it is acually a WORD.

I always use a struct not a class. A quick test using a class as a struct
failed when an inline array is used, I gonna look into that later.

In the meantime if you didn't already tried it, try using a struct. This
should work, if it doesn't check if the function doesn't return an error and
check if you can call it succesfully from c.

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
public struct SRB_HAInquiry
{
public const int STRING_LEN = 16;
public byte SRB_Cmd;
public byte SRB_Status;
public byte SRB_HaId;
public byte SRB_Flags;
public uint SRB_Hdr_Rsvd;
public byte HA_Count;
public byte HA_SCSI_ID;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]
public string HA_ManagerId;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]
public string HA_Identifier;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]
public string HA_Unique;

public ushort HA_Rsvd1;
}

[DllImport("wnaspi32.dll", EntryPoint="SendASPI32Command",
ExactSpelling=true, CharSet=CharSet.Ansi, SetLastError=true)]
private static extern UInt32 SendASPI32Command(ref SRB_HAInquiry str);

HTH,
greetings




Any other ideas?

Hi BMermuys,

Thanks for the response. I wrote it last last night, trying new tricks
that
late is never a good idea! I look forward to making the fixes you have
flagged when I get home tonight, interestingly HA_SRsvd1 was the only
member
whose value changed - hopefully this is a good sign! I'll post my
results
to
this thread.

Duncan


Hi,

3 problems:

- You don't have to initialize the strings

- If you use a class as struct, then you don't have to pass it by
reference,
objects are already passed by reference.
If you use a struct then you have to pass it by reference.

- HA_SRsvd1 is a BYTE inside the c structure and a Uint16 inside the
managed
class, they don't match.


HTH,
greetings


Hi,

This is probably an easy one but it iy first bit of p/invoke. I am
trying
to
use the following C struct in a call:

typedef struct
{
BYTE SRB_Cmd;
BYTE SRB_Status,
BYTE SRB_HaId;
BYTE SRB_Flags;
DWORD SRB_Hdr_Rsvd;
BYTE HA_Count;
BYTE HA_SCSI_ID;
BYTE HA_ManagerId[16];
BYTE HA_Identifiyer[16];
BYTE HA_Unique[16];
BYTE HA_SRsvd1;
}
SRB_HAInquiry, *PSRB_HAInquiry;

The function prototype is as follows:

SendASPI32Command((LPSRB)&srbHAInquiry)

According to the docs LPSRB is 4 bit generic pointer to a command
strucure.

Fort this I have:

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]

public class SRB_HAInquiry

{

public const int STRING_LEN = 16;

public byte SRB_Cmd;

public byte SRB_Status;

public byte SRB_HaId;

public byte SRB_Flags;

public UInt32 SRB_Hdr_Rsvd;

public byte HA_Count;

public byte HA_SCSI_ID;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]

public string HA_ManagerId = new string(' ', STRING_LEN);

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]

public string HA_Identifier = new string(' ', STRING_LEN);

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]

public string HA_Unique = new string(' ', STRING_LEN);

public UInt16 HA_Rsvd1 = 0;

}

my invokke is :

[DllImport("wnaspi32.dll", EntryPoint="SendASPI32Command",

ExactSpelling=true, CharSet=CharSet.Ansi, SetLastError=true)]

private static extern UInt32 SendASPI32Command(

ref SRB_HAInquiry str);



and my call is:



public SRB_HAInquiry ScHaInquiry(int haId)

{

SRB_HAInquiry enq = new SRB_HAInquiry();

enq.SRB_Cmd = (byte)Commands.SC_HA_INQUIRY;

enq.SRB_HaId = (byte)haId;

UInt32 result = SendASPI32Command(ref enq);


return enq;

}

Any help would be much appreciated.
 
B

BMermuys

Hi,

<snip>

--> Quite true. But then how do you allocate size 10 to byte[] b in c#?
By this:

Struct aStruct = new Struct();
aStruct.b = new byte[10]; // ???? not sure what i am doing!

Yes, that's right, you *must* do that before passing the struct to some
unmanaged function.



HTH,
greetings




Thanks again.
--
Regards,
Chua Wen Ching :)


BMermuys said:
Hi,

Chua Wen Ching said:
Hi BMermuys,

Sorry Duncan to really interrupt.

I am not sure since in C, you do this:

BYTE HA_ManagerId[16];

This is inside a structure, so the bytes are actually part of the struct.
Why in C#, you need to code this for:

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]
public string HA_ManagerId;

Because if you want, you can see an array of bytes as a (ansi)string with a
fixed length.
Why just cannot be:
public string HA_ManagerId;

As far as I know, this would translate to a char* or byte* if you want. Not
to an inlined array.
or public byte[] HA_ManagerID;

This is possible, but you still need the MarshalAs :

[MarshalAs(UnmanagedType.ByValArray,SizeConst=STRING_LEN)]
public byte[] HA_ManagerID;
Why must there be a MarshalAs?

You need it mostly because of the const size.

EG.
struct // in C
{
byte b[10];
}

Now what's the size of this struct ? Always 10 bytes.

struct // in c#
{
byte[] b;
}

Now what's the size of this struct ? You can't tell, it depends on b. But
since you're using platform invoke. The struct's must match in size.
That's why you must specify the const size.


HTH,
greetings


Just curious. Thanks again.
--
Regards,
Chua Wen Ching :)


:

Hi,

Hi BMermuys,

Well, unfortuantley the changes did not help. None of the fields
are
being
set, this I can confirm becase SRB_Status is supposed to be set to the
return value of SendASPI32Command and it isn't. With regards to HA_SRsvd1
,
this was a mistake in the post, it is acually a WORD.

I always use a struct not a class. A quick test using a class as a struct
failed when an inline array is used, I gonna look into that later.

In the meantime if you didn't already tried it, try using a struct. This
should work, if it doesn't check if the function doesn't return an
error
and
check if you can call it succesfully from c.

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
public struct SRB_HAInquiry
{
public const int STRING_LEN = 16;
public byte SRB_Cmd;
public byte SRB_Status;
public byte SRB_HaId;
public byte SRB_Flags;
public uint SRB_Hdr_Rsvd;
public byte HA_Count;
public byte HA_SCSI_ID;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]
public string HA_ManagerId;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]
public string HA_Identifier;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]
public string HA_Unique;

public ushort HA_Rsvd1;
}

[DllImport("wnaspi32.dll", EntryPoint="SendASPI32Command",
ExactSpelling=true, CharSet=CharSet.Ansi, SetLastError=true)]
private static extern UInt32 SendASPI32Command(ref SRB_HAInquiry str);

HTH,
greetings




Any other ideas?

Hi BMermuys,

Thanks for the response. I wrote it last last night, trying new tricks
that
late is never a good idea! I look forward to making the fixes
you
have
flagged when I get home tonight, interestingly HA_SRsvd1 was the only
member
whose value changed - hopefully this is a good sign! I'll post my
results
to
this thread.

Duncan


Hi,

3 problems:

- You don't have to initialize the strings

- If you use a class as struct, then you don't have to pass it by
reference,
objects are already passed by reference.
If you use a struct then you have to pass it by reference.

- HA_SRsvd1 is a BYTE inside the c structure and a Uint16
inside
the
managed
class, they don't match.


HTH,
greetings


Hi,

This is probably an easy one but it iy first bit of
p/invoke. I
am
trying
to
use the following C struct in a call:

typedef struct
{
BYTE SRB_Cmd;
BYTE SRB_Status,
BYTE SRB_HaId;
BYTE SRB_Flags;
DWORD SRB_Hdr_Rsvd;
BYTE HA_Count;
BYTE HA_SCSI_ID;
BYTE HA_ManagerId[16];
BYTE HA_Identifiyer[16];
BYTE HA_Unique[16];
BYTE HA_SRsvd1;
}
SRB_HAInquiry, *PSRB_HAInquiry;

The function prototype is as follows:

SendASPI32Command((LPSRB)&srbHAInquiry)

According to the docs LPSRB is 4 bit generic pointer to a command
strucure.

Fort this I have:

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]

public class SRB_HAInquiry

{

public const int STRING_LEN = 16;

public byte SRB_Cmd;

public byte SRB_Status;

public byte SRB_HaId;

public byte SRB_Flags;

public UInt32 SRB_Hdr_Rsvd;

public byte HA_Count;

public byte HA_SCSI_ID;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]

public string HA_ManagerId = new string(' ', STRING_LEN);

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]

public string HA_Identifier = new string(' ', STRING_LEN);

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]

public string HA_Unique = new string(' ', STRING_LEN);

public UInt16 HA_Rsvd1 = 0;

}

my invokke is :

[DllImport("wnaspi32.dll", EntryPoint="SendASPI32Command",

ExactSpelling=true, CharSet=CharSet.Ansi, SetLastError=true)]

private static extern UInt32 SendASPI32Command(

ref SRB_HAInquiry str);



and my call is:



public SRB_HAInquiry ScHaInquiry(int haId)

{

SRB_HAInquiry enq = new SRB_HAInquiry();

enq.SRB_Cmd = (byte)Commands.SC_HA_INQUIRY;

enq.SRB_HaId = (byte)haId;

UInt32 result = SendASPI32Command(ref enq);


return enq;

}

Any help would be much appreciated.
 
G

Guest

Thanks BMermuys for the confirmation. :)

--
Regards,
Chua Wen Ching :)


BMermuys said:
Hi,

<snip>

--> Quite true. But then how do you allocate size 10 to byte[] b in c#?
By this:

Struct aStruct = new Struct();
aStruct.b = new byte[10]; // ???? not sure what i am doing!

Yes, that's right, you *must* do that before passing the struct to some
unmanaged function.



HTH,
greetings




Thanks again.
--
Regards,
Chua Wen Ching :)


BMermuys said:
Hi,

Hi BMermuys,

Sorry Duncan to really interrupt.

I am not sure since in C, you do this:

BYTE HA_ManagerId[16];

This is inside a structure, so the bytes are actually part of the struct.


Why in C#, you need to code this for:

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]
public string HA_ManagerId;

Because if you want, you can see an array of bytes as a (ansi)string with a
fixed length.


Why just cannot be:
public string HA_ManagerId;

As far as I know, this would translate to a char* or byte* if you want. Not
to an inlined array.


or public byte[] HA_ManagerID;

This is possible, but you still need the MarshalAs :

[MarshalAs(UnmanagedType.ByValArray,SizeConst=STRING_LEN)]
public byte[] HA_ManagerID;


Why must there be a MarshalAs?

You need it mostly because of the const size.

EG.
struct // in C
{
byte b[10];
}

Now what's the size of this struct ? Always 10 bytes.

struct // in c#
{
byte[] b;
}

Now what's the size of this struct ? You can't tell, it depends on b. But
since you're using platform invoke. The struct's must match in size.
That's why you must specify the const size.


HTH,
greetings




Just curious. Thanks again.
--
Regards,
Chua Wen Ching :)


:

Hi,

Hi BMermuys,

Well, unfortuantley the changes did not help. None of the fields are
being
set, this I can confirm becase SRB_Status is supposed to be set to the
return value of SendASPI32Command and it isn't. With regards to
HA_SRsvd1
,
this was a mistake in the post, it is acually a WORD.

I always use a struct not a class. A quick test using a class as a
struct
failed when an inline array is used, I gonna look into that later.

In the meantime if you didn't already tried it, try using a struct.
This
should work, if it doesn't check if the function doesn't return an error
and
check if you can call it succesfully from c.

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
public struct SRB_HAInquiry
{
public const int STRING_LEN = 16;
public byte SRB_Cmd;
public byte SRB_Status;
public byte SRB_HaId;
public byte SRB_Flags;
public uint SRB_Hdr_Rsvd;
public byte HA_Count;
public byte HA_SCSI_ID;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]
public string HA_ManagerId;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]
public string HA_Identifier;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]
public string HA_Unique;

public ushort HA_Rsvd1;
}

[DllImport("wnaspi32.dll", EntryPoint="SendASPI32Command",
ExactSpelling=true, CharSet=CharSet.Ansi, SetLastError=true)]
private static extern UInt32 SendASPI32Command(ref SRB_HAInquiry str);

HTH,
greetings




Any other ideas?

Hi BMermuys,

Thanks for the response. I wrote it last last night, trying new
tricks
that
late is never a good idea! I look forward to making the fixes you
have
flagged when I get home tonight, interestingly HA_SRsvd1 was the
only
member
whose value changed - hopefully this is a good sign! I'll post my
results
to
this thread.

Duncan


Hi,

3 problems:

- You don't have to initialize the strings

- If you use a class as struct, then you don't have to pass it by
reference,
objects are already passed by reference.
If you use a struct then you have to pass it by reference.

- HA_SRsvd1 is a BYTE inside the c structure and a Uint16 inside
the
managed
class, they don't match.


HTH,
greetings


Hi,

This is probably an easy one but it iy first bit of p/invoke. I
am
trying
to
use the following C struct in a call:

typedef struct
{
BYTE SRB_Cmd;
BYTE SRB_Status,
BYTE SRB_HaId;
BYTE SRB_Flags;
DWORD SRB_Hdr_Rsvd;
BYTE HA_Count;
BYTE HA_SCSI_ID;
BYTE HA_ManagerId[16];
BYTE HA_Identifiyer[16];
BYTE HA_Unique[16];
BYTE HA_SRsvd1;
}
SRB_HAInquiry, *PSRB_HAInquiry;

The function prototype is as follows:

SendASPI32Command((LPSRB)&srbHAInquiry)

According to the docs LPSRB is 4 bit generic pointer to a
command
strucure.

Fort this I have:

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]

public class SRB_HAInquiry

{

public const int STRING_LEN = 16;

public byte SRB_Cmd;

public byte SRB_Status;

public byte SRB_HaId;

public byte SRB_Flags;

public UInt32 SRB_Hdr_Rsvd;

public byte HA_Count;

public byte HA_SCSI_ID;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]

public string HA_ManagerId = new string(' ', STRING_LEN);

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]

public string HA_Identifier = new string(' ', STRING_LEN);

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=STRING_LEN)]

public string HA_Unique = new string(' ', STRING_LEN);

public UInt16 HA_Rsvd1 = 0;

}

my invokke is :

[DllImport("wnaspi32.dll", EntryPoint="SendASPI32Command",

ExactSpelling=true, CharSet=CharSet.Ansi, SetLastError=true)]

private static extern UInt32 SendASPI32Command(

ref SRB_HAInquiry str);



and my call is:



public SRB_HAInquiry ScHaInquiry(int haId)

{

SRB_HAInquiry enq = new SRB_HAInquiry();

enq.SRB_Cmd = (byte)Commands.SC_HA_INQUIRY;

enq.SRB_HaId = (byte)haId;

UInt32 result = SendASPI32Command(ref enq);


return enq;

}

Any help would be much appreciated.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top