P/Invoke and NotSupportedExceptions

B

BVayer

I am trying to P/Invoke a Motorola API and all I keep getting is the
NotSupportException.

The api uses a struct to manipulate the data and returns a DWORD
variable which I converted to uint.

The Struct is made up of several variables of type WORD and 3 variables
which are TCHAR of a fixed length. Those I have as strings; I also
tried them as StringBuilders. The variables which are of type WORD I
am converting to UInt16's.

The API:
typedef TCHAR DIAG_BATTERY_STRINGS_T [BATTERY_STRINGS_SIZE];

typedef struct tagMAIN_BATTERY_PACK_PARAMS
{
WORD wRemainingCapacity;
WORD wCycleCount;
WORD wTimeToFull;
WORD wSerialNumber;
WORD wRatedCapacity;
WORD wActualCapacity;
WORD wManufactureDate;
WORD wBatteryStatus;

DIAG_BATTERY_STRINGS_T ManufactureName;
DIAG_BATTERY_STRINGS_T DeviceName;
DIAG_BATTERY_STRINGS_T DeviceChemistry;

}


MY CODE:
[DllImport("DiagApi.dll")]
private static extern uint DiagBatGetBatteryPackParams( ref
MAIN_BATTERY_PACK_PARAMS MainBatteryInfo);

[StructLayout(LayoutKind.Sequential)]
public struct MAIN_BATTERY_PACK_PARAMS
{
public UInt16 wRemainingCapacity;
public UInt16 wCycleCount;
public UInt16 wTimeToFull;
public UInt16 wSerialNumber;
public UInt16 wRatedCapacity;
public UInt16 wActualCapacity;
public UInt16 wManufactureDate;
public UInt16 wBatteryStatus;

public System.Text.StringBuilder ManufactureName;
public System.Text.StringBuilder DeviceName;
public System.Text.StringBuilder DeviceChemistry;

}

Can anyone give me a hand with this one?
 
P

Paul G. Tobey [eMVP]

Check the actual DLL which supposedly implements the call and make sure that
it exports a function with *exactly* that name.

Paul T.
 
P

Paul G. Tobey [eMVP]

The header file means close to nothing. If it was compiled with C++, the
actual exported name fo the function will *not* be what's in the header
file, but a mangled version indicating the parameter and return types of the
function, as well as that name.

Paul T.
 
I

Ilya Tumanov [MS]

Passing objects inside structures (StringBuilders in this case) is not
supported on NETCF V1, hence the exception.



Generic workaround:



For reference types: replace them with IntPtr fields, handle all memory
management (e.g. allocate unmanaged memory and copy data with Marshal class
or pin managed arrays with GCHandle class).



For nested types: declare byte array with size of structure, build structure
data inside array manually and pass this array to managed code.


--
Best regards,

Ilya

This posting is provided "AS IS" with no warranties, and confers no rights.

*** Want to find answers instantly? Here's how... ***

1. Go to
http://groups-beta.google.com/group/microsoft.public.dotnet.framework.compactframework?hl=en
2. Type your question in the text box near "Search this group" button.
3. Hit "Search this group" button.
4. Read answer(s).
 
M

Martin

Hi,
I believe that the problem is in DIAG_BATTERY_STRINGS_T fields of the structure
try to pass IntPtr value to the function and after function succeed perform custom marshaling
to obtain all the values of the structure.

I am trying to P/Invoke a Motorola API and all I keep getting is the
NotSupportException.

The api uses a struct to manipulate the data and returns a DWORD
variable which I converted to uint.

The Struct is made up of several variables of type WORD and 3 variables
which are TCHAR of a fixed length. Those I have as strings; I also
tried them as StringBuilders. The variables which are of type WORD I
am converting to UInt16's.

The API:
typedef TCHAR DIAG_BATTERY_STRINGS_T [BATTERY_STRINGS_SIZE];

typedef struct tagMAIN_BATTERY_PACK_PARAMS
{
WORD wRemainingCapacity;
WORD wCycleCount;
WORD wTimeToFull;
WORD wSerialNumber;
WORD wRatedCapacity;
WORD wActualCapacity;
WORD wManufactureDate;
WORD wBatteryStatus;

DIAG_BATTERY_STRINGS_T ManufactureName;
DIAG_BATTERY_STRINGS_T DeviceName;
DIAG_BATTERY_STRINGS_T DeviceChemistry;

}


MY CODE:
[DllImport("DiagApi.dll")]
private static extern uint DiagBatGetBatteryPackParams( ref
MAIN_BATTERY_PACK_PARAMS MainBatteryInfo);

[StructLayout(LayoutKind.Sequential)]
public struct MAIN_BATTERY_PACK_PARAMS
{
public UInt16 wRemainingCapacity;
public UInt16 wCycleCount;
public UInt16 wTimeToFull;
public UInt16 wSerialNumber;
public UInt16 wRatedCapacity;
public UInt16 wActualCapacity;
public UInt16 wManufactureDate;
public UInt16 wBatteryStatus;

public System.Text.StringBuilder ManufactureName;
public System.Text.StringBuilder DeviceName;
public System.Text.StringBuilder DeviceChemistry;

}

Can anyone give me a hand with this one?
 
B

BVayer

I defined the Struct with IntPtr's rather than with the String or
Stringbuilder. This worked; I think. Well, I am retrieving all the
data now however I am throwing a Exception ( 0xC0000005 ) I looked up
the error and see it has to do with File Access. I read several of the
examples and threads too but, the solution to this issue is not clear
to me. Do I just need to set the IntPtr x = IntPtr.Zero prior to
passing it in as a parameter?
 
A

Alex Feinman [MVP]

If I understand correctly what your umnanaged structure looks like, these
are supposed to be embedded char arrays. You cannot use IntPtr for them.
Declare the whole thing as a byte array of a proper size (important!) and
then use BitConverter to access DWORDs and Encoding.GetString to access
strings
 
B

BVayer

Is this nessicary for CF2 as well? I was under the impression that CF2
would make my life alittle easier. If it is the case that I need to
change to the byte array .. could you pelase point me to a C# example.
Thank you.
 
B

BVayer

Is this nessicary for CF2 as well? I was under the impression that CF2
would make my life alittle easier. If it is the case that I need to
change to the byte array .. could you pelase point me to a C# example.
Thank you.
 
M

Martin

Well, you should not pass zero pointers (IntPtr)
because of DIAG_BATTERY_STRINGS_T [BATTERY_STRINGS_SIZE];
are arrays, I would allocate enought memroy for entire structure
and passed the pointer to this memory (as IntPtr pointer) to the function,
when after function returns I would unmarshal all the structure members.
I defined the Struct with IntPtr's rather than with the String or
Stringbuilder. This worked; I think. Well, I am retrieving all the
data now however I am throwing a Exception ( 0xC0000005 ) I looked up
the error and see it has to do with File Access. I read several of the
examples and threads too but, the solution to this issue is not clear
to me. Do I just need to set the IntPtr x = IntPtr.Zero prior to
passing it in as a parameter?
 
A

Alex Feinman [MVP]

In CF2 you can indeed:

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=xxxx)]
string structMember;
 
B

BVayer

I tried to declare the struct with the lines you suggested and I was
able to successfully retrieve the struct. Thank you.
 

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