Marshaling Problem when calling API function! Please help!

W

Webdiyer

I want to integrate SecurID two-factor authentication system of the
RSASecurity.inc into our asp.net application,but I get into trouble when
trying to call the API functions of the ACE Agent,I got an error message
saying "Cannot marshal parameter #2: Invalid managed/unmanaged type
combination (this value type must be paired with Struct)" when calling
"AceGetPinParams(iHandle,ref sd_pin)" function,here's my test code:


[DllImport("aceclnt")]
private static extern bool AceInitialize();

[DllImport("aceclnt")]
private static extern int SD_Init(ref IntPtr iHandle);

[DllImport("aceclnt")]
private static extern int SD_Close(IntPtr iHandle);

[DllImport("aceclnt")]
private static extern int SD_Lock(IntPtr iHandle,string uname);

[DllImport("aceclnt")]
private static extern int SD_Check(IntPtr iHandle,string passwd,string
uname);

[DllImport("aceclnt")]
private static extern int SD_Pin(IntPtr iHandle,string pin);

[DllImport("aceclnt")]
private static extern int AceGetPinParams(IntPtr iHandle,ref SD_PinParams
pin);


private void button1_Click(object sender, System.EventArgs e)
{
AuthStatus aStatus=AuthStatus.InitFailed;
if(AceInitialize())//Initialize succeeded
{
int statusCode;
aStatus=AuthStatus.CommunicationFailed;
IntPtr iHandle=new IntPtr(0);
statusCode=SD_Init(ref iHandle);
if(statusCode==0)//Communication with the auth server succeeded
{
aStatus=AuthStatus.AccessDenied;
statusCode=SD_Lock(iHandle,uname.Text);//user has been locked
if(statusCode==0)
{
statusCode=SD_Check(iHandle,pwd.Text,uname.Text);
aStatus=(AuthStatus)statusCode;
if(aStatus==AuthStatus.NewPinRequired)
{
MessageBox.Show("New Pin Required£¡");
SD_PinParams sd_pin=new SD_PinParams();
int i=AceGetPinParams(iHandle,ref sd_pin);
if(i==1)
{
MessageBox.Show(sd_pin.Min.ToString());
MessageBox.Show(sd_pin.Selectable.ToString());
}
}
}

}
SD_Close(iHandle);
}
}



public const int LENPRNST = 16;
[StructLayout(LayoutKind.Sequential)]
public struct SD_PinParams
{
public byte Min;
public byte Max;
public byte Selectable;
public byte Alphanumeric;
[MarshalAs(UnmanagedType.LPArray, SizeConst=LENPRNST+2)]
public byte[] System;
}


public enum AuthStatus
{
InitFailed=1000,//Initialize Failed
CommunicationFailed=1001,//Communication failed
NextCodeRequired=2,//Next token code required
NewPinRequired=5,//New Pin required
Succeeded=0,//Authentication succeeded
AccessDenied=1,//Access denied
InvalidPassCode=902,//Invalid passcode
InvalidUserName901,//Invalid user name
InvalidHandle=101,//Invalid handle
}

public enum NewPinStatus
{
InvalidPin=800,//Invalid pin
Accepted=6,//new pin accepted
Rejected=7,//new pin rejected
InvalidHandle=101,//invalid handle
}


Here's the description of the ACEGetPinParams API function:

Description

int WINAPI AceGetPinParams(
SDI_HANDLE Sdi_handle,
SD_PIN *val)

typedef struct{
SD_CHAR Min;
SD_CHAR Max;
SD_CHAR Selectable;
SD_CHAR Alphanumeric;
SD_CHAR System[LENPRNST+2];
}SD_PIN


The AceGetPinParams function obtains all of the PIN-related parameters at
once. It is
helpful to retrieve this value when the result code from AceCheck is
ACM_NEW_PIN_REQUIRED and the Agent is designed to validate that the new PIN
entered by the user conforms to the required PIN characteristics set by the
RSA ACE/Server
administrator. Any such checking done by the Agent is simply as a
convenience to the user.
The PIN will be fully checked for correctness by the RSA ACE/Server.
Architecture
The caller of this synchronous function must supply, as the second argument,
a pointer to a
structure of type SD_PIN, into which the function will copy the PIN
parameters.
AceGetPinParams does not allocate storage for the data on its own.
Input Arguments
SdiHandle The value of a handle originally assigned by a call to AceInit.
Val A pointer to a structure of type SD_PIN that will contain
copies of the PIN parameters.
Outputs and Post Conditions
The function returns ACE_SUCCESS if the handle to the authentication data
was found and
the PIN value was provided by the function.
Error Handling
A value of ACE_ERR_INVALID_HANDLE is returned if the handle to the
authentication
data cannot be found.

//type definition

typedef int SDI_HANDLE, * LP_SDI_HANDLE;
typedef char SD_CHAR; /* ch or sz */

#define LENPRNST 16

How can I solve this problem,any help will be greatly appreciated!
 
M

Mattias Sjögren

[StructLayout(LayoutKind.Sequential)]
public struct SD_PinParams
{
public byte Min;
public byte Max;
public byte Selectable;
public byte Alphanumeric;
[MarshalAs(UnmanagedType.LPArray, SizeConst=LENPRNST+2)]
public byte[] System;
}

You can't use LPArray this way. If the member really is a pointer to
the array, use IntPtr as its type. If it's an inline array, use
UnmanagedType.ByValArray instead.



Mattias
 
W

Webdiyer

Thank you very much,I changed byte[] to IntPtr and it works!!
Thanks again!!
Mattias Sjögren said:
[StructLayout(LayoutKind.Sequential)]
public struct SD_PinParams
{
public byte Min;
public byte Max;
public byte Selectable;
public byte Alphanumeric;
[MarshalAs(UnmanagedType.LPArray, SizeConst=LENPRNST+2)]
public byte[] System;
}

You can't use LPArray this way. If the member really is a pointer to
the array, use IntPtr as its type. If it's an inline array, use
UnmanagedType.ByValArray instead.



Mattias
 
W

Webdiyer

Thank you very much,I changed type[] to IntPtr and it works!!
Mattias Sjögren said:
[StructLayout(LayoutKind.Sequential)]
public struct SD_PinParams
{
public byte Min;
public byte Max;
public byte Selectable;
public byte Alphanumeric;
[MarshalAs(UnmanagedType.LPArray, SizeConst=LENPRNST+2)]
public byte[] System;
}

You can't use LPArray this way. If the member really is a pointer to
the array, use IntPtr as its type. If it's an inline array, use
UnmanagedType.ByValArray instead.



Mattias
 

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