[Mono-list] interop problem
Lloyd Dupont
lloyd@galador.net
Wed, 7 Nov 2001 17:15:47 +0100
i have a strange interop bug.
just after coming back from a C# delegate into a C (interop function)
in fact the callback was passed to C previously.
i wonder if the delegate could be "managed" and see some of its intern data moving....
and how could i prevent this ?
or pass stable data to long living interop code ?
here my failing interop code: (i remove the println code...)
(one other bug is that i allways get tab.Lenght = 1 if i use SAFE_DELEGATE)
could anyone advice me, please ?
___ makefile ___
run: all
tdelegate
all: tdelegate.dll tdelegate.exe
tdelegate.dll: tdelegate.c
gcc -shared -o tdelegate.dll tdelegate.c
tdelegate.exe: tdelegate.cs
csc /unsafe tdelegate.cs
___ tdelegate.c _
// csc /unsafe tdelegate.cs && tdelegate
//#define SAFE_DELEGATE
using System;
using System.Collections;
using System.IO;
using System.Runtime.InteropServices;
public class Test
{
[DllImport("tdelegate")]
static extern void DMreadAll(SDL_RWops ctxt);
public static void Main(string[] arg)
{
Stream s = new FileStream("tdelegate.cs", FileMode.Open);
SDL_RWops io = new SDL_RWops(s);
DMreadAll(io);
}
}
[StructLayout(LayoutKind.Sequential)]
public unsafe struct SDL_RWops : IDisposable
{
IntPtr handle;
// a table holding all currently opened & used stream
static Hashtable streams = new Hashtable();
[DllImport("tdelegate")]
static extern IntPtr DMRWopsFromStream(s_seek s, s_read r, s_write w, s_close c);
[DllImport("tdelegate")]
static extern void DMRWopsFree(IntPtr io);
public SDL_RWops(Stream s)
{
handle = DMRWopsFromStream(seeker, reader, writer, closer);
if(handle == IntPtr.Zero)
throw new SystemException("not enough memory");
streams[handle] = s;
}
public void Dispose()
{
Stream s = (Stream) streams[handle];
if(s != null) {
DMRWopsFree(handle);
streams.Remove(handle);
}
handle = IntPtr.Zero;
}
const int SEEK_SET = 0;
const int SEEK_CUR = 1;
const int SEEK_END = 2;
delegate int s_seek(IntPtr ctxt, int offset, int whence);
static int seek(IntPtr ctxt, int offset, int whence)
{
Stream s = (Stream) streams[ctxt];
if(s == null)
return -1;
switch(whence) {
case SEEK_SET:
s.Seek(offset, SeekOrigin.Begin);
break;
case SEEK_CUR:
s.Seek(offset, SeekOrigin.Current);
break;
case SEEK_END:
s.Seek(offset, SeekOrigin.End);
break;
}
return (int) s.Position;
}
#if SAFE_DELEGATE
delegate int s_read(IntPtr ctxt, int len, byte[] ptr);
static int read(IntPtr ctxt, int len, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)] byte[] tab)
{
Stream s = (Stream) streams[ctxt];
if(s == null)
return -1;
System.Console.WriteLine("tab.Length = " + tab.Length);
return s.Read(tab, 0, tab.Length);
}
delegate int s_write(IntPtr ctxt, int len, byte[] ptr);
static int write(IntPtr ctxt, int len, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)] byte[] tab)
{
Stream s = (Stream) streams[ctxt];
if(s == null)
return -1;
System.Console.WriteLine("tab.Length = " + tab.Length);
s.Write(tab, 0, len);
return tab.Length;
}
#else
delegate int s_read(IntPtr ctxt, int len, byte *ptr);
static int read(IntPtr ctxt, int len, byte *ptr)
{
Stream s = (Stream) streams[ctxt];
if(s == null)
return -1;
byte[] buf = new byte[len];
int ret = s.Read(buf, 0, len);
fixed(byte * bufp = &buf[0])
Pointer.memcpy(ptr, bufp, ret);
System.Console.WriteLine("ptr = "+((int) ptr));
return ret;
}
delegate int s_write(IntPtr ctxt, int len, byte * ptr);
static int write(IntPtr ctxt, int len, byte *ptr)
{
Stream s = (Stream) streams[ctxt];
if(s == null)
return -1;
byte[] buf = new byte[len];
fixed(byte * bufp = &buf[0])
Pointer.memcpy(bufp, ptr, len);
s.Write(buf, 0, len);
return len;
}
#endif
delegate int s_close(IntPtr ctxt);
static int close(IntPtr ctxt)
{
Stream s = (Stream) streams[ctxt];
if(s != null) {
s.Close();
DMRWopsFree(ctxt);
streams.Remove(ctxt);
}
return 1;
}
static s_seek seeker = new s_seek(seek);
static s_read reader = new s_read(read);
static s_write writer = new s_write(write);
static s_close closer = new s_close(close);
}
public unsafe class Pointer
{
public static void memcpy(void * dst, void * src, int size)
{
byte * bdst = (byte *) dst;
byte * bsrc = (byte *) src;
for(int i=0; i<size; i++)
* bdst ++ = * bsrc ++;
}
}
___ tdelegate.cs _
// gcc -shared -o tdelegate.dll tdelegate.c
#include <stdlib.h>
#include <stdio.h>
#define DLLOBJ __declspec(dllexport)
typedef struct SDL_RWops {
int (*seek)(struct SDL_RWops *context, int offset, int whence);
int (*read)(struct SDL_RWops *context, int len, void *ptr);
int (*write)(struct SDL_RWops *context, int len, void *ptr);
int (*close)(struct SDL_RWops *context);
} SDL_RWops;
// ---------------------------------------
DLLOBJ SDL_RWops * DMRWopsFromStream(
int (* fseek) (struct SDL_RWops *context, int offset, int whence),
int (* fread) (struct SDL_RWops *context, int len, void * ptr),
int (* fwrite)(struct SDL_RWops *context, int len, void * ptr),
int (* fclose)(struct SDL_RWops *context))
{
struct SDL_RWops * io = (struct SDL_RWops *) malloc(sizeof(SDL_RWops));
if(!io)
return NULL;
io->seek = fseek;
io->read = fread;
io->write = fwrite;
io->close = fclose;
return io;
}
DLLOBJ void DMRWopsFree(SDL_RWops * io)
{
if(!io)
return;
free(io);
}
#define BUF_SIZE 50
DLLOBJ void DMreadAll(SDL_RWops * io)
{
char buf[BUF_SIZE+1];
int n;
buf[BUF_SIZE] = 0;
while((n = io->read(io, BUF_SIZE, buf)) == BUF_SIZE)
printf("%d : %s", buf, buf);
buf[n] = 0;
printf("%s\n", buf);
io->close(io);
}