F
Functional Illiterate
Hey all,
I am having a little bit of a problem with Complex Marshalling in
differing versions of CF2.0. I am trying to decide if it is me or the
CF 2.0 SP1. I've found a workaround, but the core problem is really
bugging me. So, here's a bit of background, the error I am seeing, my
questions, my workaround.
Background
------------------
Device has a ARMV4i processor. C# app interfaces with a smartcard
reader on the device through P/Invokes. With .NET CF 2.0 everything
worked fine. However, with .NET CF 2.0 SP1, the app throws an
unmanaged exception (0x8000 0002) on P/Invokes to SCardGetStatusChange
only when a smartcard is inserted.
This is where it gets interesting (to me at least, yet my world is
small). SCardGetStatusChange is in declared winscard.h as follows:
SCardGetStatusChange(
IN SCARDCONTEXT hContext,
IN DWORD dwTimeout,
IN OUT LPSCARD_READERSTATEW rgReaderStates,
IN DWORD cReaders);
Where LPSCARD_READERSTATEW is defined as
typedef struct {
LPCWSTR szReader; // reader name
LPVOID pvUserData; // user defined data
DWORD dwCurrentState; // current state of reader at time of
call
DWORD dwEventState; // state of reader after state change
DWORD cbAtr; // Number of bytes in the returned ATR.
BYTE rgbAtr[36]; // Atr of inserted card, (extra
alignment bytes)
} SCARD_READERSTATEW, *PSCARD_READERSTATEW, *LPSCARD_READERSTATEW;
Super. In C# we declare the managed complements as:
[DllImport("winscard.dll")]
public static extern uint SCardGetStatusChange(IntPtr hContext,
uint dwTimeout,
[In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex=3)]
SCARD_READERSTATE[] rgReaderState,
uint cReaders);
and
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
public struct SCARD_READERSTATE
{
[MarshalAs(UnmanagedType.LPTStr)]
public string szReader;
public IntPtr pvUserData;
public uint dwCurrentState;
public uint dwEventState;
public uint cbAtr;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=36)]
public byte[] rgbAtr;
}
(Thanks Fitim Skenderi).
Problem
-----------------
When a card is inserted in the smartcard reader, the byte array rgbAtr
gets populated with the ATR of the card.
In CF v2.0 a call to SCardGetStatusChange passing an array of
SCARD_READERSTATE structs works fine. However, CF v2.0 SP1 CANNOT
marshal the updated byte array back to managed code. Instead we get
the ExceptionCode 0x80000002 - a datatype misalignment.
Question
--------------
So, was the way we were P/Invoking incorrect from the begginning and
the CLR did not inform us, but SP1 it is correctly throwing an
exception????
Or, has the marshalling of complex structures been inadvertantly
changed in CF 2.0 SP1? Did somebody change the implementation so it's
writing byte for byte and incrementing a pointer rather than writing
along DWORD boundaries??
Is this a breaking change????
The app is once again working, it just required a small change. We
changed the declaration to the following:
public static extern uint SCardGetStatusChange(
IntPtr hContext,
uint dwTimeout,
IntPtr rgReaderState,
uint cReaders);
Now we do this fun stuff;
-allocate unmanged memory - Marshal.AllocHGlobal
-marshalling StructToPtr - Marshal.StructToPtr
-call SCardGetStatusChange
-Marshal PtrToStruct - Marshal.PtrToStruct
-free unmanaged memory - finally{ Marshal.FreeHGlobal}
The problem was worked around with a more forgiving alternative, but
any insight on what change introduced in SP1 would be greatly
appreciated.
Thanks,
IllFunc
I am having a little bit of a problem with Complex Marshalling in
differing versions of CF2.0. I am trying to decide if it is me or the
CF 2.0 SP1. I've found a workaround, but the core problem is really
bugging me. So, here's a bit of background, the error I am seeing, my
questions, my workaround.
Background
------------------
Device has a ARMV4i processor. C# app interfaces with a smartcard
reader on the device through P/Invokes. With .NET CF 2.0 everything
worked fine. However, with .NET CF 2.0 SP1, the app throws an
unmanaged exception (0x8000 0002) on P/Invokes to SCardGetStatusChange
only when a smartcard is inserted.
This is where it gets interesting (to me at least, yet my world is
small). SCardGetStatusChange is in declared winscard.h as follows:
SCardGetStatusChange(
IN SCARDCONTEXT hContext,
IN DWORD dwTimeout,
IN OUT LPSCARD_READERSTATEW rgReaderStates,
IN DWORD cReaders);
Where LPSCARD_READERSTATEW is defined as
typedef struct {
LPCWSTR szReader; // reader name
LPVOID pvUserData; // user defined data
DWORD dwCurrentState; // current state of reader at time of
call
DWORD dwEventState; // state of reader after state change
DWORD cbAtr; // Number of bytes in the returned ATR.
BYTE rgbAtr[36]; // Atr of inserted card, (extra
alignment bytes)
} SCARD_READERSTATEW, *PSCARD_READERSTATEW, *LPSCARD_READERSTATEW;
Super. In C# we declare the managed complements as:
[DllImport("winscard.dll")]
public static extern uint SCardGetStatusChange(IntPtr hContext,
uint dwTimeout,
[In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex=3)]
SCARD_READERSTATE[] rgReaderState,
uint cReaders);
and
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
public struct SCARD_READERSTATE
{
[MarshalAs(UnmanagedType.LPTStr)]
public string szReader;
public IntPtr pvUserData;
public uint dwCurrentState;
public uint dwEventState;
public uint cbAtr;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=36)]
public byte[] rgbAtr;
}
(Thanks Fitim Skenderi).
Problem
-----------------
When a card is inserted in the smartcard reader, the byte array rgbAtr
gets populated with the ATR of the card.
In CF v2.0 a call to SCardGetStatusChange passing an array of
SCARD_READERSTATE structs works fine. However, CF v2.0 SP1 CANNOT
marshal the updated byte array back to managed code. Instead we get
the ExceptionCode 0x80000002 - a datatype misalignment.
Question
--------------
So, was the way we were P/Invoking incorrect from the begginning and
the CLR did not inform us, but SP1 it is correctly throwing an
exception????
Or, has the marshalling of complex structures been inadvertantly
changed in CF 2.0 SP1? Did somebody change the implementation so it's
writing byte for byte and incrementing a pointer rather than writing
along DWORD boundaries??
Is this a breaking change????
The app is once again working, it just required a small change. We
changed the declaration to the following:
public static extern uint SCardGetStatusChange(
IntPtr hContext,
uint dwTimeout,
IntPtr rgReaderState,
uint cReaders);
Now we do this fun stuff;
-allocate unmanged memory - Marshal.AllocHGlobal
-marshalling StructToPtr - Marshal.StructToPtr
-call SCardGetStatusChange
-Marshal PtrToStruct - Marshal.PtrToStruct
-free unmanaged memory - finally{ Marshal.FreeHGlobal}
The problem was worked around with a more forgiving alternative, but
any insight on what change introduced in SP1 would be greatly
appreciated.
Thanks,
IllFunc