P/Invoke and NotSupportedExceptions

  • Thread starter Thread starter BVayer
  • Start date Start date
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?
 
Check the actual DLL which supposedly implements the call and make sure that
it exports a function with *exactly* that name.

Paul T.
 
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.
 
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).
 
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?
 
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?
 
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
 
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.
 
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.
 
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?
 
In CF2 you can indeed:

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=xxxx)]
string structMember;
 
I tried to declare the struct with the lines you suggested and I was
able to successfully retrieve the struct. Thank you.
 
Back
Top