Platform invoke: referencing parameters as structures

R

russb_69

Russ here. I'm new to this forum. I need help in understanding why
the following code does not work. Basically, I'm defining a
structure in a c# application, and using a c++ dll to modify it.

Here's the c++ .dll file:

// DemoAccountDLLTest.cpp : Defines the entry point for the DLL
application.
//

#include "stdafx.h"
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
return TRUE;
}

struct DemoAccountInfo
{
int login;
char password[16];
char phonepassword[16];
char name[64];
char group[16];
char country[32];
char city[32];
char state[32];
char zipcode[16];
char address[32];
char phone[32];
char email[32];
char unused[72];
int leverage;
double balance;
char reserved[20];
};

extern "C" __declspec(dllexport) void __stdcall
OpenDemoAccount(DemoAccountInfo *info)
{
info->login = 123456;
strcpy(info->password, "a1b2c3d4");
}

Here's the c# console application:

using System;
using System.Runtime.InteropServices;

namespace ConsoleApplication2
{
/// <summary>
/// Summary description for Class1.
/// </summary>
class Class1
{
[DllImport("DemoAccountDLLTest.dll")]
public static extern void OpenDemoAccount(out DemoAccountInfo
info);

[StructLayout(LayoutKind.Sequential)]
public struct DemoAccountInfo
{
public int login;
public char[] password;
public char[] phonepassword;
public char[] name;
public char[] group;
public char[] country;
public char[] city;
public char[] state;
public char[] zipcode;
public char[] address;
public char[] phone;
public char[] email;
public char[] unused;
public int leverage;
public double balance;
public char[] reserved;
};


/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
//
// TODO: Add code to start application here
//

DemoAccountInfo acc = new DemoAccountInfo();
acc.name = "John Smith".ToCharArray();
acc.email = "(e-mail address removed)".ToCharArray();
acc.address = "some address".ToCharArray();
acc.city = "Toronto".ToCharArray();
acc.country = "Canada".ToCharArray();
acc.state = "Ontario".ToCharArray();
acc.phone = "777777777".ToCharArray();
acc.zipcode = "123456".ToCharArray();
acc.group = "demo".ToCharArray();
acc.balance = 100;
acc.leverage = 10;


OpenDemoAccount(out acc);

Console.WriteLine(acc.name);
Console.WriteLine(acc.login);
Console.WriteLine(acc.password);
Console.WriteLine("Finished.");

Console.ReadLine();

}
}
}

I think it may have something to do with the fact that I'm passing the
DemoAccountInfo parameter as a pointer in the .dll file and I'm
declaring it incorectly in c#. I may also have to implement somekind
of marshaling as well, but I'm just not sure. Keep in mind that the
code in the .dll file is programmed correctly and fallows design
specs, therefore it cannot be changed.
 
T

Tom Shelton

Russ here. I'm new to this forum. I need help in understanding why
the following code does not work. Basically, I'm defining a
structure in a c# application, and using a c++ dll to modify it.

Here's the c++ .dll file:

struct DemoAccountInfo
{
int login;
char password[16];
char phonepassword[16];
char name[64];
char group[16];
char country[32];
char city[32];
char state[32];
char zipcode[16];
char address[32];
char phone[32];
char email[32];
char unused[72];
int leverage;
double balance;
char reserved[20];
};

<snip>

Try changing this to:
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
public struct DemoAccountInfo
{
public int login;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=16)]
public string password;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=16)]
public string phonepassword;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=64)]
public string name;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=16)]
public string group;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=32)]
public string country;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=32)]
public string city;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=32)]
public string state;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=16)]
public string zipcode;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=32)]
public string address;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=32)]
public string phone;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=32)]
public string email;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=72)]
public string unused;
public int leverage;
public double balance;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=20)]
public string reserved;
};

[DllImport("DemoAccountDLLTest.dll", CharSet=CharSet.Ansi)]
public static extern void OpenDemoAccount(
out DemoAccountInfo info);
 
G

Guest

just considering your "password" member for a moment, if you changed it from:
public char[] password;
to
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=16)]
public string password;
Your code will work just fine. You can change the other char[] fields to string as well.
And BTW you can also use "ref" instead of "out" and your code will work.

Hope that helps.
Abubakar.
http://joehacker.blogspot.com/


russb_69 said:
Russ here. I'm new to this forum. I need help in understanding why
the following code does not work. Basically, I'm defining a
structure in a c# application, and using a c++ dll to modify it.

Here's the c++ .dll file:

// DemoAccountDLLTest.cpp : Defines the entry point for the DLL
application.
//

#include "stdafx.h"
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
return TRUE;
}

struct DemoAccountInfo
{
int login;
char password[16];
char phonepassword[16];
char name[64];
char group[16];
char country[32];
char city[32];
char state[32];
char zipcode[16];
char address[32];
char phone[32];
char email[32];
char unused[72];
int leverage;
double balance;
char reserved[20];
};

extern "C" __declspec(dllexport) void __stdcall
OpenDemoAccount(DemoAccountInfo *info)
{
info->login = 123456;
strcpy(info->password, "a1b2c3d4");
}

Here's the c# console application:

using System;
using System.Runtime.InteropServices;

namespace ConsoleApplication2
{
/// <summary>
/// Summary description for Class1.
/// </summary>
class Class1
{
[DllImport("DemoAccountDLLTest.dll")]
public static extern void OpenDemoAccount(out DemoAccountInfo
info);

[StructLayout(LayoutKind.Sequential)]
public struct DemoAccountInfo
{
public int login;
public char[] password;
public char[] phonepassword;
public char[] name;
public char[] group;
public char[] country;
public char[] city;
public char[] state;
public char[] zipcode;
public char[] address;
public char[] phone;
public char[] email;
public char[] unused;
public int leverage;
public double balance;
public char[] reserved;
};


/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
//
// TODO: Add code to start application here
//

DemoAccountInfo acc = new DemoAccountInfo();
acc.name = "John Smith".ToCharArray();
acc.email = "(e-mail address removed)".ToCharArray();
acc.address = "some address".ToCharArray();
acc.city = "Toronto".ToCharArray();
acc.country = "Canada".ToCharArray();
acc.state = "Ontario".ToCharArray();
acc.phone = "777777777".ToCharArray();
acc.zipcode = "123456".ToCharArray();
acc.group = "demo".ToCharArray();
acc.balance = 100;
acc.leverage = 10;


OpenDemoAccount(out acc);

Console.WriteLine(acc.name);
Console.WriteLine(acc.login);
Console.WriteLine(acc.password);
Console.WriteLine("Finished.");

Console.ReadLine();

}
}
}

I think it may have something to do with the fact that I'm passing the
DemoAccountInfo parameter as a pointer in the .dll file and I'm
declaring it incorectly in c#. I may also have to implement somekind
of marshaling as well, but I'm just not sure. Keep in mind that the
code in the .dll file is programmed correctly and fallows design
specs, therefore it cannot be changed.
 

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