Hi,
Can someone please help me convert my C structure/function into C#? I really need this badly...
I believe I can call the DLL properly if I have able to correctly convert the function and marshal properly my structure.
Here is my struct and the function that uses it:
[CODE]
typedef struct UIclient_info {
char name[50];
int age;
SECONDUSER *stParent;
} FIRSTUSER;
typedef struct ui_product_form {
char m_sCoupon;
double amountTotal;
char m_sErrorCode[50];
SUBPRODUCT *pstSubProduct;
} PRODUCT;
typedef struct tagReport
{
REPORTSUMMARY *pstRepsum;
char errorMsg[100];
}FINAL_REPORT;
int Save(FIRSTUSER *myUser, PRODUCT *uiStructure)
FINAL_REPORT GenerateReport(FIRSTUSER *myUser, PRODUCT *uiStructure)
[/CODE]
PLEASE HELP.
Thanks in advance.
-dantz
VulpesPosted Oct 22, 2011, 9:21 AM
Are you getting any output at all, even if it's wrong?
dantzPosted Oct 22, 2011, 7:06 AM
I'd have thought that, if there were any SECONDUSER or SUBPRODUCT info, you'd fill that in yourself. You would then need to use AllocHGlobal to allocate memory for that.
However, if there's an error, then the error code string will be filled in by the DLL using the pointer to the structure (i.e. the class reference) you're passing to it.
Just noticed though that the errorCode field should be defined as string not char. Sorry missed that in my first response:
The DLL will fill in the correct amountTotal base on the coupon that I send.
And also the errorCOde why it change the amountTotal.
Is it correct to convert my save method to accept IntPtr parameter like this:
I will initialize my values then convert to IntPtr, is that the correct way?
I have done the above but I still can't get my output to the DLL.
What I am missing?
Appreciate your help on this.
VulpesPosted Oct 21, 2011, 11:01 AM
I'd have thought that, if there were any SECONDUSER or SUBPRODUCT info, you'd fill that in yourself. You would then need to use AllocHGlobal to allocate memory for that.
However, if there's an error, then the error code string will be filled in by the DLL using the pointer to the structure (i.e. the class reference) you're passing to it.
Just noticed though that the errorCode field should be defined as string not char. Sorry missed that in my first response:
dantzPosted Oct 21, 2011, 7:52 AM
My DLL still not able to get it.
My struct will be read and the DLL will fill-in data inside.
Is there no need for AllocHGlobal ?
Thanks for the reply
VulpesPosted Oct 21, 2011, 5:56 AM
FIRSTUSER firstUser = new FIRSTUSER();
dantzPosted Oct 21, 2011, 5:44 AM
However, my DLL is not able to read the data that I have initialized.
Am I missing something?
Please help me here.
I think I am almost near to my solution.
Thanks in advance.
dantzPosted Oct 20, 2011, 8:33 PM
With regards to this:
"4. If the unmanaged code (or your code) is going to fill a memory block with SECONDUSER, SUBPRODUCT and REPORTSUMMARY details, then you will need to use Marshal.AllocHGlobal to allocate memory on the unmanaged heap and return an IntPtr to it for embedding in the class."
Fill a memory block means there was a malloc instantiated inside the DLL?
I guess I really need these because when I call the DLL functions, my data was NOT received by the DLL.
When I search on Marshal.AllocHGlobal it returns an IntPtr.
I am not too sure how can I transfer this to my function call?
Can please guide me on this?
thanks.
VulpesPosted Oct 20, 2011, 9:06 AM
5. In the case of FINAL_REPORT, I think you'll have to declare it as a struct rather than a class as the GenerateReport function is returning it by value. Return values which are structs can be a troublesome area when using P/Invoke and I think you'll just have to try it and see.
[return:MarshalAs(UnmanagedType.Struct)]
dantzPosted Oct 20, 2011, 12:28 AM
I was actually thinking of doing DLLImport on the DLL
then create a structure/class that would represent (I don't know it is called) its structure C#
This is what I created, Please correct me if I am wrong:
[StructLayout(LayoutKind.Sequential)]
public class FIRSTUSER
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=50)]
string name;
int age;
IntPtr stParent;
};
[StructLayout(LayoutKind.Sequential)]
public class PRODUCT
{
char coupon;
double amountTotal;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=50)]
char errorCode;
IntPtr pstSubProduct;
};
[StructLayout(LayoutKind.Sequential)]
public class FINAL_REPORT
{
IntPtr pstRepsum;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=100)]
string errorMsg;
};
[DllImport("SQSCode.dll")]
public static extern int Save(ref FIRSTUSER myUser, ref PRODUCT uiStructure);
[DllImport("SQSCode.dll")]
public static extern FINAL_REPORT GenerateReport(ref FIRSTUSER myUser, ref PRODUCT uiStructure);
Is this correct?
Do I need some AllocHGlobal(IntPtr) with this?
dantzPosted Oct 20, 2011, 12:26 AM
Thanks for the immediate reply.
I cannot easily recompile with /CLR
I am not sure why.
Below are the switch I am using.
/Zi /clr /nologo /W3 /WX- /Od /Oy- /D "_MBCS" /EHa /GS /fp:precise /Zc:wchar_t /Zc:forScope /Fp"Debug\SQSLibraryTest.pch" /Fa"Debug\" /Fo"Debug\" /Fd"Debug\vc100.pdb" /analyze- /errorReport:queue
Just a follow up question, If the creators of the library can compile it in Visual Studio 2010 C++ Project.
Does it mean I can use it in C#?
Is it possible to call those C functions in my C# codes?
Javeed M ShaikhPosted Oct 19, 2011, 8:28 PM
What I would suggest is to compile your C code in a Visual Studio.NET C++ project
with the /CLR switch and it will be compiled into a .NET managed assembly. You can than use that in your C# code. I am not sure of any direct converter from C to C#.
Please do not forget to mark "Accepted Answer".