A helloworld example of marshalling an array to C# created in C.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <errno.h> | |
#include "hello.h" | |
static const char* get_field(char *line, int num) | |
{ | |
const char *tok; | |
for (tok = strtok(line, ","); tok && *tok; tok = strtok(NULL, ",\n")) { | |
if (!--num) | |
return tok; | |
} | |
return NULL; | |
} | |
static int parse_human(char *line, struct human *human) | |
{ | |
char *tmp = strdup(line); | |
const char *f; | |
f = get_field(tmp, 1); | |
//printf("field 1='%s'\n", f); | |
memset(human->first, 0, sizeof(human->first)); | |
strcpy(human->first, f); | |
free(tmp); | |
tmp = strdup(line); | |
f = get_field(tmp, 2); | |
//printf("field 2='%s'\n", f); | |
memset(human->last, 0, sizeof(human->last)); | |
strcpy(human->last, f); | |
free(tmp); | |
tmp = strdup(line); | |
f = get_field(tmp, 3); | |
//printf("field 3='%s'\n", f); | |
memset(human->contact->cell, 0, sizeof(human->contact->cell)); | |
strcpy(human->contact->cell, f); | |
free(tmp); | |
tmp = strdup(line); | |
f = get_field(tmp, 4); | |
//printf("field 4='%s'\n", f); | |
memset(human->contact->home, 0, sizeof(human->contact->home)); | |
strcpy(human->contact->home, f); | |
free(tmp); | |
return 0; | |
} | |
HELLOAPI int HELLOCALL say_hello(struct human *person) | |
{ | |
if (person->contact) { | |
if (person->contact && person->contact->cell) | |
printf("Calling %s to say hello to %s %s\n", | |
person->contact->cell, person->first, person->last); | |
if (person->contact && person->contact->home) | |
printf("Calling %s to say hello to %s %s\n", | |
person->contact->home, person->first, person->last); | |
} else { | |
printf("Hello, %s %s\n", person->first, person->last); | |
} | |
return 0; | |
} | |
HELLOAPI int HELLOCALL import_csv(char *path, struct human ***persons, int *numPersons) | |
{ | |
int res; | |
FILE *csv; | |
char line[1024]; | |
struct human **humans; | |
csv = fopen(path, "r"); | |
if (csv == NULL) { | |
return errno; | |
} | |
humans = calloc(2, sizeof(struct human *)); | |
*numPersons = 0; // init to sane value | |
if (humans == NULL) | |
return ENOMEM; | |
while (fgets(line, 1024, csv)) { | |
char *tmp = strdup(line); | |
struct human *person; | |
humans[*numPersons] = calloc(1, sizeof(*person)); | |
person = humans[*numPersons]; // easier to work with | |
if (person == NULL) { | |
return ENOMEM; | |
} | |
person->contact = calloc(1, sizeof(*(person->contact))); | |
if (person->contact == NULL) { | |
return ENOMEM; | |
} | |
printf("parsing: '%s'\n", line); | |
res = parse_human(line, person); | |
if (res != 0) { | |
return res; | |
} | |
(*numPersons)++; | |
} | |
(*persons) = humans; | |
fclose(csv); | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef ___HELLO_H | |
#define ___HELLO_H | |
#ifdef _WIN32 | |
//#ifdef par_EXPORTS | |
#define HELLOAPI __declspec(dllexport) | |
//#else | |
// #define HELLOAPI __declspec(dllimport) | |
//#endif | |
#define HELLOCALL __cdecl | |
#else | |
#define HELLOAPI | |
#define HELLOCALL | |
#endif | |
#ifdef __cplusplus | |
extern "C" { | |
#endif | |
struct contact_info { | |
char cell[32]; | |
char home[32]; | |
}; | |
struct human { | |
char first[32]; | |
char last[32]; | |
struct contact_info *contact; | |
}; | |
HELLOAPI int HELLOCALL say_hello(struct human *person); | |
HELLOAPI int HELLOCALL import_csv(char *path, struct human ***persons, int *numPersons); | |
#ifdef __cplusplus | |
} | |
#endif | |
#endif /* ___HELLO_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
using System.Runtime.InteropServices; | |
namespace HelloApp | |
{ | |
class HelloLibrary | |
{ | |
//[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] | |
[StructLayout(LayoutKind.Sequential)] | |
public struct contact_info | |
{ | |
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] | |
public String cell; | |
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] | |
public String home; | |
} | |
//[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] | |
[StructLayout(LayoutKind.Sequential)] | |
public struct human | |
{ | |
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] | |
public String first; | |
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] | |
public String last; | |
public IntPtr contact; | |
} | |
[DllImport("HelloLibrary.dll", CallingConvention = CallingConvention.Cdecl)] | |
public static extern int say_hello(ref human person); | |
[DllImport("HelloLibrary.dll", CallingConvention = CallingConvention.Cdecl)] | |
public static extern int import_csv([MarshalAs(UnmanagedType.LPStr)]String path, | |
ref IntPtr persons, ref int numPersons); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Joe | Schmoe | 1234567890 | 0987654321 | |
---|---|---|---|---|
Bob | Smith | 18001237654 | 0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
using System.Runtime.InteropServices; | |
namespace HelloApp | |
{ | |
class Program | |
{ | |
static HelloLibrary.human createHuman(string first, string last, string cell, string home) | |
{ | |
HelloLibrary.human person = new HelloLibrary.human(); | |
person.first = first; | |
person.last = last; | |
if (cell != null && home != null) | |
{ | |
HelloLibrary.contact_info info = new HelloLibrary.contact_info(); | |
info.cell = cell; | |
info.home = home; | |
IntPtr ptr1 = Marshal.AllocHGlobal(Marshal.SizeOf(info)); | |
Marshal.StructureToPtr(info, ptr1, true); | |
person.contact = ptr1; | |
} | |
return person; | |
} | |
static void Main(string[] args) | |
{ | |
#region Say Hello to single person | |
//HelloLibrary.human person = new HelloLibrary.human(); | |
//person.first = "Joe"; | |
//person.last = "Schmoe"; | |
//HelloLibrary.contact_info info = new HelloLibrary.contact_info(); | |
//info.cell = "1234567890"; | |
//info.home = ""; | |
//IntPtr ptr1 = Marshal.AllocHGlobal(Marshal.SizeOf(info)); | |
//Marshal.StructureToPtr(info, ptr1, true); | |
//person.contact = ptr1; | |
//HelloLibrary.say_hello(ref person); | |
#endregion Say Hello to single person | |
#region Say Hello to array | |
//HelloLibrary.human[] humans = new HelloLibrary.human[5]; | |
//humans[0] = createHuman("Erich", "Schroeter", "7156142117", ""); | |
//humans[1] = createHuman("Matt", "McAnelly", "1234567790", "82776568829"); | |
//humans[2] = createHuman("Moe", "Curly", null, null); | |
//humans[3] = createHuman("Guy", "Moore", "1833332889", "000100248858"); | |
//humans[4] = createHuman("Joe", "Schmoe", "19191931884848248", "103381111"); | |
//foreach (HelloLibrary.human human in humans) | |
//{ | |
// HelloLibrary.human person = human; | |
// HelloLibrary.say_hello(ref person); | |
//} | |
#endregion Say Hello to array | |
#region Read CSV of humans | |
if (args.Length < 1) | |
{ | |
Console.WriteLine("Specify a CSV file."); | |
Environment.Exit(1); | |
} | |
IntPtr humansPtr = IntPtr.Zero; | |
int numHumans = 0; | |
HelloLibrary.import_csv(args[0], ref humansPtr, ref numHumans); | |
HelloLibrary.human[] humans = new HelloLibrary.human[numHumans]; | |
IntPtr[] ptrs = new IntPtr[numHumans]; | |
IntPtr aIndex = (IntPtr)Marshal.PtrToStructure(humansPtr, typeof(IntPtr)); | |
// Populate the array of IntPtr | |
for (int i = 0; i < numHumans; i++) | |
{ | |
ptrs[i] = new IntPtr(aIndex.ToInt64() + | |
(Marshal.SizeOf(typeof(IntPtr)) * i)); | |
Console.WriteLine("ptrs[{0}]={1}", i, ptrs[i]); | |
} | |
// Marshal the array of human structs | |
for (int i = 0; i < numHumans; i++) | |
{ | |
humans[i] = (HelloLibrary.human)Marshal.PtrToStructure( | |
ptrs[i], | |
typeof(HelloLibrary.human)); | |
} | |
// Use the marshalled data | |
foreach (HelloLibrary.human human in humans) | |
{ | |
Console.WriteLine("first:'{0}'", human.first); | |
Console.WriteLine("last:'{0}'", human.last); | |
HelloLibrary.contact_info contact = (HelloLibrary.contact_info)Marshal. | |
PtrToStructure(human.contact, typeof(HelloLibrary.contact_info)); | |
Console.WriteLine("cell:'{0}'", contact.cell); | |
Console.WriteLine("home:'{0}'", contact.home); | |
} | |
#endregion Read CSV of humans | |
Console.Read(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment