all groups > dotnet interop > january 2007 >
You're in the

dotnet interop

group:

Marshalling DEV_BROADCAST_PORT: C# P/Invoke declaration?


Marshalling DEV_BROADCAST_PORT: C# P/Invoke declaration? Whitney Kew
1/26/2007 12:08:37 PM
dotnet interop:
Hello,

I have some VS 2005 code in which I am setting up a C# declaration of the
Platform SDK header DEV_BROADCAST_PORT. That structure is declared in the
Platform SDK header file dbt.h as follows:

typedef struct _DEV_BROADCAST_PORT_A {
DWORD dbcp_size;
DWORD dbcp_devicetype;
DWORD dbcp_reserved;
char dbcp_name[1];
} DEV_BROADCAST_PORT_A, *PDEV_BROADCAST_PORT_A;

typedef struct _DEV_BROADCAST_PORT_W {
DWORD dbcp_size;
DWORD dbcp_devicetype;
DWORD dbcp_reserved;
wchar_t dbcp_name[1];
} DEV_BROADCAST_PORT_W, DBTFAR *PDEV_BROADCAST_PORT_W;

#ifdef UNICODE
typedef DEV_BROADCAST_PORT_W DEV_BROADCAST_PORT;
typedef PDEV_BROADCAST_PORT_W PDEV_BROADCAST_PORT;
#else
typedef DEV_BROADCAST_PORT_A DEV_BROADCAST_PORT;
typedef PDEV_BROADCAST_PORT_A PDEV_BROADCAST_PORT;
#endif

In my C# code, I am declaring this structure as follows:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct DEV_BROADCAST_PORT
{
public uint dbcp_size;
public uint dbcp_devicetype;
public uint dbcp_reserved;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 512)]
public string dbcp_name;
}

My question is: Is this the correct P/Invoke declaration? It seems to
work, but I'm confused as to why the string marshalling declaration of
"dbcp_name" is working. According to the documentation for
DEV_BROADCAST_PORT, dbcp_name is a pointer to a null-terminated string. When
I started writing the C# declaration, I initially set the SizeConst parameter
equal to 1, because that's the fixed-array size of the dbcp_name member as
declared in the SDK header file. Of course, that didn't quite work; I only
received the first character of the COM port name when I ran my code. So I
picked some arbitrary character length (512, in this case) and assigned that
to the SizeConst parameter, and now it works. But, I don't know why. Am I
doing this right? Is it OK to just pick some arbitrary character length, as
I did above?

--
Whitney Kew
Re: Marshalling DEV_BROADCAST_PORT: C# P/Invoke declaration? Mattias Sjögren
1/28/2007 11:06:43 AM
[quoted text, click to view]

No it's not correct. Depending on how you read the structure, you
might end up with an access violation if you try to read more data
than was actually passed to you.

Here's some guidance how you can handle variable length structures

http://www.dotnetinterop.com/faq/?q=VariableLengthStruct


Mattias

--
Mattias Sjögren [C# MVP] mattias @ mvps.org
http://www.msjogren.net/dotnet/ | http://www.dotnetinterop.com
Re: Marshalling DEV_BROADCAST_PORT: C# P/Invoke declaration? wawang NO[at]SPAM online.microsoft.com
1/29/2007 6:34:30 AM
Hi Whitney,

I think Mattias's recommend approach should work for your question. The
DEV_BROADCAST_PORT struct's first field denotes the struct size, you need
to first use Marshal.ReadInt32 to read it and use that as reference to read
the string. Please feel free to let us know if you have any questions.

Regards,
Walter Wang (wawang@online.microsoft.com, remove 'online.')
Microsoft Online Community Support

==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.
Re: Marshalling DEV_BROADCAST_PORT: C# P/Invoke declaration? Whitney Kew
1/29/2007 10:44:00 AM
Great, Mattias, thank you. OK, so now I'm declaring just the fixed-length
portion of DEV_BROADCAST_PORT, and using the Marshal.PtrToStringUni() method
to get my port name. So, in my little Windows form, in my WndProc()
override, how does this code look?

protected struct DEV_BROADCAST_PORT_Fixed
{
public uint dbcp_size;
public uint dbcp_devicetype;
public uint dbcp_reserved;
// Variable-length field dbcp_name is declared here in the C header file.
}

// .... other Platform SDK declarations ....

protected override void WndProc(ref Message m)
{
if (m.Msg == WM_DEVICECHANGE)
{
switch (m.WParam.ToInt32())
{
case DBT_DEVICEARRIVAL:
{
DEV_BROADCAST_HDR hdr =
(DEV_BROADCAST_HDR)m.GetLParam(typeof(DEV_BROADCAST_HDR));
switch (hdr.dbch_devicetype)
{
case DBT_DEVTYP_PORT:
{
string portName = Marshal.PtrToStringUni(
(IntPtr)(m.LParam.ToInt32() +
Marshal.SizeOf(typeof(DEV_BROADCAST_PORT_Fixed))));
Debug.WriteLine("Port '" + portName + "' arrived.");
break;
}
}
break;
}
}
}
base.WndProc(ref m);
}

--
Whitney Kew
Senior Software Engineer


[quoted text, click to view]
Marshalling DEV_BROADCAST_PORT: C# P/Invoke declaration? - wmke Agent M
12/5/2007 2:30:04 PM
Is there a way to detect if a new Hardware device has been plugged in?
How do I use this code for DBT_DEVNODES_CHANGED?

Any help appreciated.

thank you.
AgentM


EggHeadCafe - .NET Developer Portal of Choice
AddThis Social Bookmark Button