I'm working with SafeCom (print server) and figured out that they have a Administrator DLL Programmer’s Manual. As a proof of concept I wanted to make a small C# application that sends and retrieves data using this library. I've managed to insert a user object by calling LoginByLogon() followed by AddUser().
However, I'm not able to retrieve/return a user struct by calling LoginByLogon() followed by GetUser. I can see that ptrTemp is set (not null), but all properties in newStructure are still null. I don't fully understand PInvoke yet, so I hope someone here can enlighten me a little. :)
I'm for now importing the following:
[DllImport("scAPI.dll", CallingConvention = CallingConvention.Cdecl)]
static extern int sc_LoginByLogon(string szIpAddr, string szUserName, string szPassword);
[DllImport("scAPI.dll", CallingConvention = CallingConvention.Cdecl)]
static extern int sc_Logoff();
[DllImport("scAPI.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
private static extern int sc_GetUserInfoByUserLogon(string szUserLogon, out IntPtr ppUserInfo);
[DllImport("scAPI.dll", CallingConvention = CallingConvention.Cdecl)]
static extern short sc_AddUser(ref sUserInfoApiV4 ppUserInfo, double fAccount, double FLowLimit, ref int pNewId);
Define my structs:
struct SYSTEMTIME
{
short wYear;
short wMonth;
// short wDayOfWeek;
short wDay;
short wHour;
short wMinute;
short wSecond;
short wMilliseconds;
public static implicit operator SYSTEMTIME(DateTime time)
{
return new SYSTEMTIME
{
wYear = (short)time.Year,
wMonth = (short)time.Month,
wDay = (short)time.Day,
// wDayOfWeek = (short)time.DayOfWeek,
wHour = (short)time.Hour,
wMinute = (short)time.Minute,
wSecond = (short)time.Second,
wMilliseconds = (short)time.Millisecond
};
}
public static implicit operator DateTime(SYSTEMTIME time)
{
return new DateTime(time.wYear, time.wMonth, time.wDay, time.wHour, time.wMinute, time.wSecond, time.wMilliseconds);
}
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct Card
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 40)]
public string m_szCardNo; //Card number
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 5)]
public string m_szPINCode; //PIN code - zero terminated
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 9)]
public string m_szPUKCode; //PUK code - zero terminated
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 1)]
public struct sUserInfoApiV4
{
[MarshalAs(UnmanagedType.I4)]
public Int32 m_nStructLength; //Length of the struct including this field
[MarshalAs(UnmanagedType.I2)]
public short m_nVersion; //Version Number (set to 4)
[MarshalAs(UnmanagedType.I2)]
public short m_nSubVersion; //Version of Reserved (set to 0)
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
public byte[] m_achReserved; // Get room for m_nAccessRights
[MarshalAs(UnmanagedType.I2)]
public short m_nUserType; //USER_STRUCT (uses as UserType - BitFields)
[MarshalAs(UnmanagedType.I4)]
public int m_nUserId; //Unique id identifying the user
public int m_nSubRights; // Sub version 2
[MarshalAs(UnmanagedType.I4)]
public int m_nNotUsed1; // Sub version 5
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 101)]
public string m_wzFullName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 101)]
public string m_wzDescription;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 101)]
public string m_wzEMail;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 21)]
public string m_wzUserLogon; //Asc-ii string identifying the user
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 17)]
public string m_wzPassword; //Asc-ii string password
public Card card;
[MarshalAs(UnmanagedType.I2)]
public short m_nLogonFails; //Number of failed logins
[MarshalAs(UnmanagedType.I2)]
public short m_bUserLocked; //Unlocked(0), Locked(1)
[MarshalAs(UnmanagedType.I2)]
public short m_bUserDisabled; //Not Disable(0), Open(1)
[MarshalAs(UnmanagedType.I2)]
public short m_bAvoidPin; //Pin Enabled(0), Pin disabled (1)
[MarshalAs(UnmanagedType.I2)]
public short m_bPrintAll; //Print All when card is slid - Yes(1) No(0)
[MarshalAs(UnmanagedType.I2)]
public short m_bCardOpen; //PIN code assigned(0), Awaiting pin assignment/Outstanding PUK(1)
[MarshalAs(UnmanagedType.I2)]
public short m_nBillingModel; //None(0), BillingDialog(1)
[MarshalAs(UnmanagedType.I2)]
public short m_nAccountingModel; //None(0), Tracking(1), Pay(2)
[MarshalAs(UnmanagedType.I4)]
public int m_nUserRights; // None(0)
[MarshalAs(UnmanagedType.I2)]
public short m_bAllowEncryption; // The user uses encryption YES(1) NO(0)
[MarshalAs(UnmanagedType.U1)]
bool m_bAllowCheckPrinting; // The user is allowed to receives checks YES(1) NO(0)
[MarshalAs(UnmanagedType.U1)]
bool m_bAllowPmail; // The user is allowed distribution YES(1) NO(0)
[MarshalAs(UnmanagedType.U1)]
bool m_bDenyRetain; // User allowed to retain his documents. New in SubVersion 3
public int m_lCreationDate;
public int m_lLastLogin;
[MarshalAs(UnmanagedType.I4)]
public int m_nServerId; // HomeServer of this user.
[MarshalAs(UnmanagedType.I4)]
public int m_nDomainId; // New in Subversion 1 - Reference to the windows domain the user are located in
[MarshalAs(UnmanagedType.I4)]
public int m_nTreeNodeId;
[MarshalAs(UnmanagedType.I4)]
public int m_nNid;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 51)]
public string m_wzCostCode; // Cost center, new in SubVersion 3
}
[StructLayout(LayoutKind.Sequential)]
public unsafe struct SCardInfoApiV4
{
[MarshalAs(UnmanagedType.I4)]
public Int32 m_nStructLength; // Length of entire struct
[MarshalAs(UnmanagedType.I2)]
public short m_nVersion; // Version (short)
[MarshalAs(UnmanagedType.I2)]
public short m_nSubVersion; // Subversion of reserved, set to 1 (short)
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
public byte[] m_achReserved; // Reserved for protocol expansion (fixed char)
[MarshalAs(UnmanagedType.I4)]
public int m_nCardId;
[MarshalAs(UnmanagedType.I4)]
public int m_nUserId;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 40)]
public string m_achCardNo; // originalt fixed char [40]
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 5)]
public string m_achReservedPinCode;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 9)]
public string m_achReservedPukCode;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 51)]
public string m_achDescription;
[MarshalAs(UnmanagedType.I4)]
int m_nCreatorId;
SYSTEMTIME m_sCreated;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1)]
public string m_nUseLifeTime; //originalt char
SYSTEMTIME m_sLifeStart;
SYSTEMTIME m_sLifeEnd;
[MarshalAs(UnmanagedType.I4)]
int m_nSourceId; // Sub version 1
}
And finally my methods:
public int LoginByLogon(string ipAddr, string userLogon, string password)
{
return sc_LoginByLogon(ipAddr, userLogon, password);
}
public int Logoff()
{
return sc_Logoff();
}
public sUserInfoApiV4 GetUser(string userLogon)
{
sUserInfoApiV4 tmpUserInfo = new sUserInfoApiV4();
IntPtr ptrTemp = Marshal.AllocHGlobal(Marshal.SizeOf(tmpUserInfo));
sc_GetUserInfoByUserLogon(userLogon, out ptrTemp);
Marshal.StructureToPtr(tmpUserInfo, ptrTemp, false);
sUserInfoApiV4 newStructure;
newStructure = (sUserInfoApiV4)Marshal.PtrToStructure(ptrTemp, typeof(sUserInfoApiV4));
return newStructure;
}
public unsafe int AddUser(string usercode, string email, string pinCode, string fullName)
{
sUserInfoApiV4 sUserstruct = new sUserInfoApiV4();
int sizeOfstruct = Marshal.SizeOf(typeof(sUserInfoApiV4));
IntPtr pSUserstruct = Marshal.AllocHGlobal(sizeOfstruct); //Make note of memory used
Marshal.StructureToPtr(sUserstruct, pSUserstruct, false);
sUserstruct.m_wzUserLogon = usercode;
sUserstruct.card.m_szCardNo = usercode; //Card number same as logon
sUserstruct.card.m_szPINCode = pinCode;
sUserstruct.m_wzFullName = fullName;
sUserstruct.m_wzEMail = email;
sUserstruct.m_nUserRights = 3; //Standard user rights
sUserstruct.m_nAccountingModel = 2; //Pay user
sUserstruct.m_nVersion = 4; //Safecom version
sUserstruct.m_nStructLength = sizeOfstruct;
sUserstruct.m_bAvoidPin = 1; // Disable PIN
int userId = 0; //Value of variable not used, just to initialize the variable. Used as pointer for return value. Index number for user in db
int* userIndex = &userId;
int nRes = sc_AddUser(ref sUserstruct, 0, 0, ref *userIndex);
Marshal.FreeHGlobal(pSUserstruct); // Release memory
pSUserstruct = IntPtr.Zero; // used by pointer.
return nRes;
}
Related
I am trying to convert c++ api example to c#. but I can not find the way of struct pointer in struct by the way struct has string types. Here is c++ structs and functions
struct AuthParam { char server_ip[32]; char username[50]; char password[50]; };
struct CameraInfo { int index; char devicename[100]; char smallrtsp[1000]; char bigrtsp[1000]; };
struct SingleDevice { char deviceid[50]; char devicename[100]; int flag_onuse; int cameralist_size; CameraInfo* cameralist; };
struct DeviceList { int listsize; SingleDevice* singledevicelist; };
typedef int (WINAPI capi_init)(void);
typedef int (WINAPI capi_disabled)(void);
typedef int (WINAPI capi_GetServerTimeCode)(char* server_ip, unsigned int* timecode);
typedef int (WINAPI GetDevicelist)(AuthParam auth_para, DeviceList* devicelist);
and this is my c# code but I can not find the way of defining struct pointer in struct I got "
Error CS0208 Cannot take the address of, get the size of, or declare a pointer to a managed type ('Form1.CameraInfo')" error.
public struct AuthParam
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string server_ip;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 50)]
public string username;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 50)]
public string password;
};
[StructLayout(LayoutKind.Sequential)]
public struct CameraInfo
{
public int index;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
public string devicename;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1000)]
public string smallrtsp;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1000)]
public string bigrtsp;
};
[StructLayout(LayoutKind.Sequential)]
public struct SingleDevice
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 50)]
public string deviceid;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
public string devicename;
public int flag_onuse;
public int cameralist_size;
public CameraInfo *cameralist;
};
[StructLayout(LayoutKind.Sequential)]
public unsafe struct DeviceList
{
public int listsize;
public SingleDevice *singledevicelist;
};
[DllImport("c:\\lib\\api_client.dll")] public static extern int capi_init();
[DllImport("c:\\lib\\api_client.dll")] public static extern int capi_disabled();
[DllImport("c:\\lib\\api_client.dll")] public static extern int capi_GetServerTimeCode(string ip, ref uint timecode);
[DllImport("c:\\lib\\api_client.dll")] public static extern int GetDevicelist (AuthParam auth_para,ref DeviceList devicelist);
is there any way to achieve this convertion?
i think this error because of the different nature of c++ (un-managed code) and c# (managed code), so maybe using System.IntPtr as a pointer to your camera struct.
please consider this question here, and you can find about P/Invoke Interop Assistant which is an open source tool to convert your code from the un-managed code to a managed C# code. with a small blog article about C++/C# interoperability
I might have 2 monitor/screens connected to my machine.
I want to know all Avaliable resolutions for a specific screen (I have an instance of type System.Windows.Forms.Screen).
I've seen the following:
How to list available video modes using C#?
List of valid resolutions for a given Screen?
but they all give results for all monitors and not just a specific one. Any suggestions? Thanks!!!
Edit 1:
This is the info about my 2 screens:
In the first of those links you're told about EnumDisplaySettings. Take a few seconds to lookup that function and the FIRST PARAMETER is the
string that specifies the display device about whose graphics mode the
function will obtain information.
Here's a sample class to fetch information about displays. I've deliberately omitted DEVMODE since you've already got it.
public class NativeMethods
{
[DllImport("user32.dll")]
public static extern bool EnumDisplaySettings(string deviceName, int modeNum, ref DEVMODE devMode);
[DllImport("user32.dll")]
public static extern bool EnumDisplayDevices(string deviceName, int modeNum, ref DISPLAY_DEVICE displayDevice, int flags);
}
[StructLayout(LayoutKind.Sequential)]
public struct DISPLAY_DEVICE
{
public int cb;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string DeviceName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string DeviceString;
public int StateFlags;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string DeviceID;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string DeviceKey;
}
static class Display
{
public static List<DISPLAY_DEVICE> GetGraphicsAdapters()
{
int i = 0;
DISPLAY_DEVICE displayDevice = new DISPLAY_DEVICE();
List<DISPLAY_DEVICE> result = new List<DISPLAY_DEVICE>();
displayDevice.cb = Marshal.SizeOf(displayDevice);
while (NativeMethods.EnumDisplayDevices(null, i, ref displayDevice, 1))
{
result.Add(displayDevice);
i++;
}
return result;
}
public static List<DISPLAY_DEVICE> GetMonitors(string graphicsAdapter)
{
DISPLAY_DEVICE displayDevice = new DISPLAY_DEVICE();
List<DISPLAY_DEVICE> result = new List<DISPLAY_DEVICE>();
int i = 0;
displayDevice.cb = Marshal.SizeOf(displayDevice);
while (NativeMethods.EnumDisplayDevices(graphicsAdapter, i, ref displayDevice, 0))
{
result.Add(displayDevice);
i++;
}
return result;
}
public static List<DEVMODE> GetDeviceModes(string graphicsAdapter)
{
int i = 0;
DEVMODE devMode = new DEVMODE();
List<DEVMODE> result = new List<DEVMODE>();
while (NativeMethods.EnumDisplaySettings(graphicsAdapter, i, ref devMode))
{
result.Add(devMode);
i++;
}
return result;
}
}
I tried this:
public struct SHFILEINFOW
{
public IntPtr hIcon;
public int iIcon;
public uint dwAttributes;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260 * 2)]
public string szDisplayName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80 * 2)]
public string szTypeName;
}
[DllImport("shell32.dll")]
public static extern IntPtr SHGetFileInfoW(IntPtr pIDL, uint dwFileAttributes, out SHFILEINFOW psfi, uint cbFileInfo, SHGFI uFlags);
String DisplayName = shInfoW.szDisplayName;
But DisplayName contain only the first char
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260 * 2)]
ByValTStr means "same as the class or structure". But you didn't specify the CharSet attribute for the structure. It defaults to CharSet.Ansi so the string is getting marshaled as though it was a 8-bit character string. Since the real string is Unicode, you'll indeed get very high odds for only getting the first character. Fix:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct SHFILEINFOW {
// etc...
}
I am trying to access information about drivers associated with devices in C# utilizing the win32 APIs.
I have managed to enable/disable devices (so the handles I am retrieving seem OK), however I have no luck when trying to call SetupDiEnumDriverInfo.
This is the code I am using:
private List<String> ListCompatibleDrivers(IntPtr hDevInfo, SP_DEVINFO_DATA devInfoData)
{
List<String> result = new List<String>();
try
{
SP_DRVINFO_DATA drvInfo = new SP_DRVINFO_DATA();
for (int i = 0; SetupDiEnumDriverInfo(hDevInfo, devInfoData, SPDIT_CLASSDRIVER, i, drvInfo); i++)
{
result.Add(drvInfo.Description);
}
if (result.Count < 1)
{
result.Add(Marshal.GetLastWin32Error().ToString());
}
return result;
}
catch
{
throw;
}
}
Where the parameters can be assumed to be okay (as I said, other methods from the setup API use them successfully).
These are the struct and the DllImport which might be corrupt:
[StructLayout(LayoutKind.Sequential)]
public class SP_DRVINFO_DATA
{
public Int32 cbSize;
public Int32 driverType;
public UIntPtr reserved;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)]
public String description;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)]
public String mfgName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)]
public String providerName;
public FILETIME driverDate;
public Int64 driverVersion;
};
[DllImport("setupapi.dll", SetLastError = true)]
public static extern bool SetupDiEnumDriverInfo(IntPtr lpInfoSet, SP_DEVINFO_DATA deviceInfoData, UInt32 driverType, Int32 memberIndex, SP_DRVINFO_DATA driverInfoData);
The API call returns with false immediately, the Marshal.GetLastWin32Error().ToString() returns 259, which is ERROR_NO_MORE_ITEMS.
I just don't get it, and my hopes are high I am just making some stupid mistake that I am not able to see because I have read hardly anything but msdn lately, and it gets incredibly tiring...
Any help is greatly appreciated, thanks a lot!
Well off the top I can tell you you don't match the function signature which should be:
[DllImport("setupapi.dll", SetLastError = true, charset=Charset.Unicode)]
[return:MarshalAs(UnmanagedType.Bool)]
private static extern bool SetupDiEnumDriverInfo(
[In] IntPtr lpInfoSet,
[In, Optional] SP_DEVINFO_DATA deviceInfoData,
[In] UInt32 driverType,
[In] Int32 memberIndex,
[Out] out SP_DRVINFO_DATA driverInfoData);
That out is important as it specifies that it needs to pull back out the data from the PInvoke.
There are several problems with the struct, the most annoying being that one has to specify pack=4 so the native code will find the correct entry points.
This works:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 4)]
public struct SP_DRVINFO_DATA
{
public int cbSize;
public int DriverType;
public UInt32 Reserved;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string Description;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string MfgName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string ProviderName;
public System.Runtime.InteropServices.ComTypes.FILETIME DriverDate;
public long DriverVersion;
}
Of course it is a god idea to actually prefix the P/Invokes with Charset=Charset.Unicode, too.
Here are the API and struct definitions that both worked on x64 and x86. I am adding also SetupDiGetDriverInfoDetail, good chance that you'll also need it.
API:
DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool SetupDiGetDriverInfoDetail(
IntPtr DeviceInfoSet,
ref SP_DEVINFO_DATA DeviceInfoData,
ref SP_DRVINFO_DATA DriverInfoData,
ref SP_DRVINFO_DETAIL_DATA DriverInfoDetailData,
Int32 DriverInfoDetailDataSize,
ref Int32 RequiredSize);
[DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool SetupDiEnumDriverInfo(
IntPtr DeviceInfoSet,
ref SP_DEVINFO_DATA DeviceInfoData,
int DriverType,
int MemberIndex,
ref SP_DRVINFO_DATA DriverInfoData);
structs:
#if !WIN64
[StructLayout(LayoutKind.Sequential, Pack = 2, CharSet = CharSet.Unicode)]
#else
[StructLayout(LayoutKind.Sequential, Pack = 8, CharSet = CharSet.Unicode)]
#endif
public struct SP_DRVINFO_DATA
{
public int cbSize;
public uint DriverType;
public UIntPtr Reserved;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string Description;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string MfgName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string ProviderName;
public System.Runtime.InteropServices.ComTypes.FILETIME DriverDate;
public ulong DriverVersion;
}
#if !WIN64
[StructLayout(LayoutKind.Sequential, Pack = 2, CharSet = CharSet.Unicode)]
#else
[StructLayout(LayoutKind.Sequential, Pack = 8, CharSet = CharSet.Unicode)]
#endif
public struct SP_DRVINFO_DETAIL_DATA
{
public Int32 cbSize;
public System.Runtime.InteropServices.ComTypes.FILETIME InfDate;
public Int32 CompatIDsOffset;
public Int32 CompatIDsLength;
public IntPtr Reserved;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public String SectionName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public String InfFileName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public String DrvDescription;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1)]
public String HardwareID;
};
my struct looks like this in c code:
typedef struct _REQUEST {
char D [_D_MAX+1];
char M [_M_MAX+1];
char T [_T_MAX+1];
char ClRef [_CL_REF_MAX+1];
char load [_LOAD_MAX];
ULONG loadLen;
} _REQUEST, *LP_REQUEST;
in c# like this:
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
public struct _REQUEST_STRUCT {
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string D;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string M;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string T;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
public string clRef;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1200)]
public string Load;
public UInt32 LoadLen;
}
the method I am calling is like this in c:
int
AJ_STDCALL
SimpTran (const char* svc_name,
const LP_REQUEST query,
LP_RESPONSE response)
{
//init stuff
//Validate input parameters
if ( query == NULL )
return(ERR_QUERY_NULL);
if (query->loadLen == 0)
return (ERR_QUERY_NULL);
}
in c#:
[DllImport(LINUXLIB, CallingConvention = CallingConvention.StdCall)]
public static extern int SimpTran(string serID, ref _REQUEST_STRUCT request, out IntPtr response);
and i am calling it like this:
p_request_struct = new _REQUEST_STRUCT();
// fill p_request_struct
// response
p_response_struct = new _RESPONSE_STRUCT();
// initialize unmanaged memory to hold return struct
IntPtr ptrRet = Marshal.AllocHGlobal(Marshal.SizeOf(p_response_struct));
Marshal.StructureToPtr(p_response_struct, ptrRet, false);
iRet = SimpTran(SerID, ref p_request_struct, out ptrRet);
I am getting null query! In C code query==null is true and it returns null. But I am populating the request struct?
Do I have to allocate memory for that as well?