Fixed lenght string in struct to use in EnumDisplaySettings() P/INVOKE

M

minimega

Hello to all NG.

I'm using the EnumDisplaySettings to get information on current display
driver properties. The EnumDisplaySettings require a DEVMODE structure
that in C++ is declared as:

typedef struct_devicemode {
WCHAR dmDeviceName[CCHDEVICENAME];
WORD dmSpecVersion;
WORD dmDriverVersion;
WORD dmSize;
WORD dmDriverExtra;
DWORD dmFields;
short dmOrientation;
short dmPaperSize;
short dmPaperLength;
short dmPaperWidth;
short dmScale;
short dmCopies;
short dmDefaultSource;
short dmPrintQuality;
short dmColor;
short dmDuplex;
short dmYResolution;
short dmTTOption;
short dmCollate;
BCHAR dmFormName[CCHFORMNAME];
WORD dmLogPixels;
DWORD dmBitsPerPel;
DWORD dmPelsWidth;
DWORD dmPelsHeight;
DWORD dmDisplayFlags;
DWORD dmDisplayFrequency;
DWORD dmDisplayOrientation;
} DEVMODE;

where CCHDEVICENAME and CCHFORMNAME = 32.

The only woking example I found in internet
(http://blogs.msdn.com/davidklinems/archive/2005/02/01/364834.aspx) is
one that declares the struct as follow:

// managed version of the DEVMODE structure
struct DeviceMode
{
// these 32 elements are DEVMODE.dmDeviceName
public char DeviceName0;
public char DeviceName1;
public char DeviceName2;
public char DeviceName3;
public char DeviceName4;
public char DeviceName5;
public char DeviceName6;
public char DeviceName7;
public char DeviceName8;
public char DeviceName9;
public char DeviceName10;
public char DeviceName11;
public char DeviceName12;
public char DeviceName13;
public char DeviceName14;
public char DeviceName15;
public char DeviceName16;
public char DeviceName17;
public char DeviceName18;
public char DeviceName19;
public char DeviceName20;
public char DeviceName21;
public char DeviceName22;
public char DeviceName23;
public char DeviceName24;
public char DeviceName25;
public char DeviceName26;
public char DeviceName27;
public char DeviceName28;
public char DeviceName29;
public char DeviceName30;
public char DeviceName31;

public Int16 SpecVersion;
public Int16 DriverVersion;
public Int16 Size;
public Int16 DriverExtra;
public Int32 Fields;
public Int16 Orientation;
public Int16 PaperSize;
public Int16 PaperLength;
public Int16 PaperWidth;
public Int16 Scale;
public Int16 Copies;
public Int16 DefaultSource;
public Int16 PrintQuality;
public Int16 Color;
public Int16 Duplex;
public Int16 YResolution;
public Int16 TTOption;
public Int16 Collate;

// these 32 elements are DEVMODE.dmFormName
public char FormName0;
public char FormName1;
public char FormName2;
public char FormName3;
public char FormName4;
public char FormName5;
public char FormName6;
public char FormName7;
public char FormName8;
public char FormName9;
public char FormName10;
public char FormName11;
public char FormName12;
public char FormName13;
public char FormName14;
public char FormName15;
public char FormName16;
public char FormName17;
public char FormName18;
public char FormName19;
public char FormName20;
public char FormName21;
public char FormName22;
public char FormName23;
public char FormName24;
public char FormName25;
public char FormName26;
public char FormName27;
public char FormName28;
public char FormName29;
public char FormName30;
public char FormName31;

public Int16 LogPixels;
public Int32 BitsPerPel;
public Int32 PelsWidth;
public Int32 PelsHeight;
public Int32 DisplayFlags;
public Int32 DisplayFrequency;
public Int32 DisplayOrientation;
}

Now, I've tried to convert the 32 <public char DeviceNameX> lines in
only one:
public char [32] DeviceName; or
public char DeviceName[32]; or
public char [] DeviceName = new char[32];

but I get only compiler errors.

Then I've tryed to declare an explicit constructor like this:

// managed version of the DEVMODE structure
struct DeviceMode

public char [] DeviceMode;
....

public DeviceMode(int dummy)
{
DeviceName[] = new char[32];

SpecVersion=0;
DriverVersion=0;
Size=0;
DriverExtra=0;
Fields=0;
....

but the code hangs at the call EnumDisplaySettings() with the
System.NotSupportedException error that is the tipical error when wrong
parameters are passend in P/INVOKE calling.

Now, what I've understand is that my struct must start with 32 byte,
where the DeviceName must be stored, but I don't understand how to
declare a fixed lenght string (or fixed lenght char array).

Why the only 32 lines char declare method is working?

How can I solve this problem without using 32 declares of single char?
What happens if I P/INVOKE functions with string parameter of 1024
bytes? My struct must declare 1024 lines of char?

Thanks,
massimo
 
P

Peter Foot [MVP]

In .NETCF v1.0 you can either use David's approach with the individual char
members or you can pass the whole structure as a single byte array of the
total size and use BitConverter and System.Text.Encoding to pull out the
various fields from within the byte array.

Peter

--
Peter Foot
Windows Embedded MVP
http://www.inthehand.com | http://www.peterfoot.net

minimega said:
Hello to all NG.

I'm using the EnumDisplaySettings to get information on current display
driver properties. The EnumDisplaySettings require a DEVMODE structure
that in C++ is declared as:

typedef struct_devicemode {
WCHAR dmDeviceName[CCHDEVICENAME];
WORD dmSpecVersion;
WORD dmDriverVersion;
WORD dmSize;
WORD dmDriverExtra;
DWORD dmFields;
short dmOrientation;
short dmPaperSize;
short dmPaperLength;
short dmPaperWidth;
short dmScale;
short dmCopies;
short dmDefaultSource;
short dmPrintQuality;
short dmColor;
short dmDuplex;
short dmYResolution;
short dmTTOption;
short dmCollate;
BCHAR dmFormName[CCHFORMNAME];
WORD dmLogPixels;
DWORD dmBitsPerPel;
DWORD dmPelsWidth;
DWORD dmPelsHeight;
DWORD dmDisplayFlags;
DWORD dmDisplayFrequency;
DWORD dmDisplayOrientation;
} DEVMODE;

where CCHDEVICENAME and CCHFORMNAME = 32.

The only woking example I found in internet
(http://blogs.msdn.com/davidklinems/archive/2005/02/01/364834.aspx) is
one that declares the struct as follow:

// managed version of the DEVMODE structure
struct DeviceMode
{
// these 32 elements are DEVMODE.dmDeviceName
public char DeviceName0;
public char DeviceName1;
public char DeviceName2;
public char DeviceName3;
public char DeviceName4;
public char DeviceName5;
public char DeviceName6;
public char DeviceName7;
public char DeviceName8;
public char DeviceName9;
public char DeviceName10;
public char DeviceName11;
public char DeviceName12;
public char DeviceName13;
public char DeviceName14;
public char DeviceName15;
public char DeviceName16;
public char DeviceName17;
public char DeviceName18;
public char DeviceName19;
public char DeviceName20;
public char DeviceName21;
public char DeviceName22;
public char DeviceName23;
public char DeviceName24;
public char DeviceName25;
public char DeviceName26;
public char DeviceName27;
public char DeviceName28;
public char DeviceName29;
public char DeviceName30;
public char DeviceName31;

public Int16 SpecVersion;
public Int16 DriverVersion;
public Int16 Size;
public Int16 DriverExtra;
public Int32 Fields;
public Int16 Orientation;
public Int16 PaperSize;
public Int16 PaperLength;
public Int16 PaperWidth;
public Int16 Scale;
public Int16 Copies;
public Int16 DefaultSource;
public Int16 PrintQuality;
public Int16 Color;
public Int16 Duplex;
public Int16 YResolution;
public Int16 TTOption;
public Int16 Collate;

// these 32 elements are DEVMODE.dmFormName
public char FormName0;
public char FormName1;
public char FormName2;
public char FormName3;
public char FormName4;
public char FormName5;
public char FormName6;
public char FormName7;
public char FormName8;
public char FormName9;
public char FormName10;
public char FormName11;
public char FormName12;
public char FormName13;
public char FormName14;
public char FormName15;
public char FormName16;
public char FormName17;
public char FormName18;
public char FormName19;
public char FormName20;
public char FormName21;
public char FormName22;
public char FormName23;
public char FormName24;
public char FormName25;
public char FormName26;
public char FormName27;
public char FormName28;
public char FormName29;
public char FormName30;
public char FormName31;

public Int16 LogPixels;
public Int32 BitsPerPel;
public Int32 PelsWidth;
public Int32 PelsHeight;
public Int32 DisplayFlags;
public Int32 DisplayFrequency;
public Int32 DisplayOrientation;
}

Now, I've tried to convert the 32 <public char DeviceNameX> lines in
only one:
public char [32] DeviceName; or
public char DeviceName[32]; or
public char [] DeviceName = new char[32];

but I get only compiler errors.

Then I've tryed to declare an explicit constructor like this:

// managed version of the DEVMODE structure
struct DeviceMode

public char [] DeviceMode;
...

public DeviceMode(int dummy)
{
DeviceName[] = new char[32];

SpecVersion=0;
DriverVersion=0;
Size=0;
DriverExtra=0;
Fields=0;
...

but the code hangs at the call EnumDisplaySettings() with the
System.NotSupportedException error that is the tipical error when wrong
parameters are passend in P/INVOKE calling.

Now, what I've understand is that my struct must start with 32 byte,
where the DeviceName must be stored, but I don't understand how to
declare a fixed lenght string (or fixed lenght char array).

Why the only 32 lines char declare method is working?

How can I solve this problem without using 32 declares of single char?
What happens if I P/INVOKE functions with string parameter of 1024
bytes? My struct must declare 1024 lines of char?

Thanks,
massimo
 
M

minimega

Hi Peter,
perhaps working, but not good solution however..

Yes, I can declare a unique byte array with the size of the struct that
EnumDisplaySettings() expects, but I find a very "low quality"
development level.
And in this case, how can I declare a fixed byte struct to pass
EnumDisplaySettings()? Do I still need a struct or a declaration of
"private byte [] buffer = new byte[132];" is sufficient?

A new solution I've found in the "Advanced P/Invoke on the Microsoft
..NET Compact Framework" MSDN article, but they use direct access to
memory, copy struct and char array in allocated memory and pass to the
EnumDisplaySettings() the allocated memory pointer, then dealloc
memory.. but is very "unmanaged" development in managed language!

Is the CF 2.0 more flexible to this problems?

Thanks,
Massimo
 
C

Chris Tacke, eMVP

Look at the SDF - especially in the Adapter stuff. There are plenty of
examples of how this works.

--
Chris Tacke
Co-founder
OpenNETCF.org
Are you using the SDF? Let's do a case study.
Email us at d c s @ o p e n n e t c f . c o m
http://www.opennetcf.org/donate
 
M

minimega

In the DEVMODE.cs source file I can see that is using the "byte array"
way, declaring mData = new byte[192];
This is a working way, as the David's approach.

However I'd like to understand why fixed lenght string can't be used in
struct as I can do in full .net framework.

Thanks,
Massimo
 
C

Chris Tacke, eMVP

The CF marshaler can't handle it. You can use a byte array in the struct,
then an accessor to turn it into a string with the Encoding class.

--
Chris Tacke
Co-founder
OpenNETCF.org
Are you using the SDF? Let's do a case study.
Email us at d c s @ o p e n n e t c f . c o m
http://www.opennetcf.org/donate
 
P

Peter Foot [MVP]

You can do this from .NETCF v2.0 - the marshalling capabilities are greatly
improved.

Peter
 
M

minimega

Hi Chris,
what do you mean? Declare all the struct as array of 192 byte, or
declare the only two string fields as byte array? If the second case,
can you explain me how this new struct must be correctly declared? I'm
not able to initialize the array on the struct without create a
explicit costructor, where I must initialize then ALL the members, not
only the byte arrays, and I must pass at least 1 parameter to the
costructor. Is better to use a class instead struct?

Thanks,
Massimo

Chris Tacke, eMVP ha scritto:
 
M

minimega

Hi Peter, next thuesday I'll go to Milan, at the Microsoft forum, where
they present the new VS 2005. There I'll take a full working version
(NFR) of VS2005, so I'll can try the new improvements of CF 2.0.

However, I want to be able to do also with CF 1.0!

Thanks,
Massimo
 

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