Skip to content

Instantly share code, notes, and snippets.

@erichschroeter
Last active August 21, 2021 10:33
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save erichschroeter/df895f2855af0fc89dd5 to your computer and use it in GitHub Desktop.
Save erichschroeter/df895f2855af0fc89dd5 to your computer and use it in GitHub Desktop.
A helloworld example of marshalling an array to C# created in C.
#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;
}
#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 */
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);
}
}
Joe Schmoe 1234567890 0987654321
Bob Smith 18001237654 0
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