Definitive Prototypes for Structures etc.

J

Jeff Gaines

Is anybody aware of a source of definitive prototypes to use in NET?

I have spent 2 days working on a custom header control because the
prototypes I had for HDITEM, NMHDR and NMHEADER were wrong.

I went through the header files to try and get it right as well as
Googling, PInvoke.net and the source for Systems.Windows.Forms. They are
all different! Actually S.W.F. has something called HDITEM2 but not HDITEM
and uses int where the C prototype seems to call for Uint32. It's pretty
important as I am using Win7 x64 and, although the app didn't crash it
didn't work properly either!

I'm sure that once upon a time I found some MSFT code that had all these
prototypes, although it made heavy use of pointers and unsafe code, but I
can't find it now.

Any suggestions would be appreciated...
 
J

Jeff Gaines

I should have written an article about this when I was knee-deep in the
interop stuff a few years ago. Unfortunately, it's been long enough since I
have had to do anything like this that all I can remember are the
generalities.

There's still time - and a need!
Still, if there's a particular API you're having trouble with, feel free to
post a question here. Maybe I or someone else will know how to deal with
it.

Peter, many thanks for your comprehensive reply :)

Can I take up your offer in respect of HDITEM?

The help sets it out:
typedef struct _HDITEM {
UINT mask;
int cxy;
LPTSTR pszText;
HBITMAP hbm;
int cchTextMax;
int fmt;
LPARAM lParam;
#if (_WIN32_IE >= 0x0300)
int iImage;
int iOrder;
#endif
#if (_WIN32_IE >= 0x0500)
UINT type;
void *pvFilter;
#endif
#if _WIN32_WINNT >= 0x0600
UINT state;
#endif
} HDITEM, *LPHDITEM;

I ended up with (for Win7 x64):

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct HDITEM
{
public UInt32 mask;
public Int32 cxy;
[MarshalAs(UnmanagedType.LPTStr)]
public string lpszText;
public IntPtr hbm;
public Int32 cchTextMax;
public Int32 fmt;
public IntPtr lParam;
public Int32 iImage;
public Int32 iOrder;
public UInt32 type;
public IntPtr pvFilter;
public UInt32 state;
}

Does that seem correct to you?
There's enough in it for me to apply the principles to other prototypes.
 
A

Arne Vajhøj

The help sets it out:
typedef struct _HDITEM {
UINT mask;
int cxy;
LPTSTR pszText;
HBITMAP hbm;
int cchTextMax;
int fmt;
LPARAM lParam;
#if (_WIN32_IE >= 0x0300)
int iImage;
int iOrder;
#endif
#if (_WIN32_IE >= 0x0500)
UINT type;
void *pvFilter;
#endif
#if _WIN32_WINNT >= 0x0600
UINT state;
#endif
} HDITEM, *LPHDITEM;

I ended up with (for Win7 x64):

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct HDITEM
{
public UInt32 mask;
public Int32 cxy;
[MarshalAs(UnmanagedType.LPTStr)]
public string lpszText;
public IntPtr hbm;
public Int32 cchTextMax;
public Int32 fmt;
public IntPtr lParam;
public Int32 iImage;
public Int32 iOrder;
public UInt32 type;
public IntPtr pvFilter;
public UInt32 state;
}

Does that seem correct to you?
There's enough in it for me to apply the principles to other prototypes.

If lpszText is IN and not OUT or INOUT, then I think it would
work.

Arne
 
A

Arne Vajhøj

Is anybody aware of a source of definitive prototypes to use in NET?

I have spent 2 days working on a custom header control because the
prototypes I had for HDITEM, NMHDR and NMHEADER were wrong.

I went through the header files to try and get it right as well as
Googling, PInvoke.net and the source for Systems.Windows.Forms. They are
all different! Actually S.W.F. has something called HDITEM2 but not
HDITEM and uses int where the C prototype seems to call for Uint32. It's
pretty important as I am using Win7 x64 and, although the app didn't
crash it didn't work properly either!

I'm sure that once upon a time I found some MSFT code that had all these
prototypes, although it made heavy use of pointers and unsafe code, but
I can't find it now.

Any suggestions would be appreciated...

I would probably use this procedure:

1) look it up at pinvoke.net (SharpDevelop can
do it directly)

2) if it does not work then I will read the C/C++
version and convert manually

3) if that does not work then I will try my friend
Google

Arne
 
J

Jeff Gaines

I will reiterate Arne's comment about the lpszText field (though I'd stick
with the Windows header name of "pszText"...the "long pointer" distinction
hasn't been relevant in Windows for a long time, so no real reason to
reintroduce the "lp" Hungarian tag where it wasn't present before :) ). In
particular, note that in some uses, the "pszText" parameter of the original
interface is in fact used to return data, and so your declaration wouldn't
work. You'd need a StringBuilder as the type instead, so that there's a
buffer for the output text to be copied to.

I can't use a StringBuilder in a structure.
It would probably be better to use an IntPtr and marshal it between an
IntPtr and String. However I need to be sure the IntPtr memory is freed. I
need the ability to have a destructor for a structure - it would be easy
if it were a class but I guess I would lose control over the layout.
 
J

Jeff Gaines


Not allowed, it can't be marshaled.

I have just got the project I was working on actually working :)
Only problem is I can't remember if it is what I started out doing 6
months ago when I decided it just needs this and it just needs that etc.
etc.
Anyway now I know it works I will experiment with a class instead of a
structure, that will be interesting.

Many thanks again for your input :)
 
J

Jeff Gaines

Okay. I assume you get some sort of exception?

So are you only passing a string into the function you are using? Or does
p/invoke correctly handle marshaling an output string argument back into
the managed structure?

Pete

Sorry, it compiles but throws an error when run:

System.TypeLoadException was unhandled
Message="Cannot marshal field 'pszText' of type 'Win32API.HDITEM': Struct
or class fields cannot be of type StringBuilder. The same effect can
usually be achieved by using a String field and preinitializing it to a
string with length matching the length of the appropriate buffer."

I will experiment with a class that uses an IntPtr as that would ensure I
can release the memory in one central place. It does need to be IN and OUT.
 

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

Similar Threads


Top