[Gdal-dev] C# Bindings

Simon Perkins sy at perkins.net
Fri Nov 3 21:19:05 EST 2006


Tamas Szekeres wrote:
>> >
>> > I'm afraid we will not be able to map pointers to the C# interface
>> > easily.
>>
>> Is this a SWIG limitation? Pointers are a valid C# type though, 
>> aren't they?
>
> I mean that the C style pointers has no exact mapping to C# we have to
> use the untyped IntPtr-s or HandleRef-s instead.

I don't know how SWIG works at all, but if we implement one low level 
function that, say, uses IntPtr and a GDALDataType flag, then we can add 
all the type safe versions as forwarding functions, e.g.:

private void ReadRasterImp(int xOff, int yOff, int xSize, int ySize, 
IntPtr buf,
                           int bufXsize, int bufYSize, GDALDataType type) {
  // Call GDAL external function directly
  ....
}

public void ReadRaster(int xOff, int yOff, int xSize, int ySize, byte* 
buf, int bufXSize, int bufYSize) {
  ReadRasterImp(xOff, yOff, xSize, ySize, new IntPtr(buf), bufXSize, 
bufYSize, GDALDataType.BYTE);
}

public void ReadRaster(int xOff, int yOff, int xSize, int ySize, byte[] 
buf, int bufXSize, int bufYSize) {
  fixed (byte* ptr = buf) {
    ReadRaster(xOff, yOff, xSize, ySize, ptr, bufXSize, bufYSize, 
GDALDataType.BYTE);
  }
}

I've omitted the pixelSpace and lineSpace args here.

Is that kind of thing doable with SWIG?


Couple of other questions / requests:

 - For any functions that use an array as a buffer, it would be 
convenient to add a bufferOffset int argument that says at what point in 
the buffer reading/writing should begin. This allows people to use GDAL 
to read into arrays that contain pixels in "packed" format. This only 
needs to appear in the overload of these functions that has the 
pixelSpace and lineSpace args, since packed format buffers require these 
to be specified as well.

- How are we dealing with errors? The original GDAL functions return 
CPLErr. Are we going to do the same? Or are we going to throw exceptions?



> Well, with the example above I am curious to know how if works in
> practice. So as to support this kind of usage we gonna have to
> establish a generic version of the ReadRaster/WriteRaster having
> IntPtr compatible argument holding the memory to be handled at the
> unmanaged part of the interface. It would be useful to know how
> LockBits and Scan0 works, will the managed memory segment be prevented
> from the relocation or GC collection during the unmanaged call. I will
> create a sample app. for testing this issue.
>
> BTW, I wonder how we can get the byte* notation work in general. Is it
> related to an unsafe code block specification?

The LockBits function must be called to prevent the GC moving the Bitmap 
buffer while you're working on it. See the MSDN docs on 
Bitmap.LockBits() for an example of usage.

Scan0 is simply an IntPtr that points to the start of the Bitmap data 
buffer.

Not sure I understand your last question. In general, you can only use 
pointers within a fixed() { } block, since that's the only safe way you 
can get a pointer to a managed object. The fixed() statement prevents 
the GC moving the object being pointed to. Needless to say, anything 
using pointers has to be declared unsafe. But I think it's hard to avoid 
that when interfaceing to unmanaged code that manipulates memory.


In case it helps, I've attached the hand-rolled GDAL C# interface that I 
worked on a while back, along with a simple image display program that 
uses that interface. You should just be able to unzip the file, load it 
into VS 2005, edit the file GDAL/Interop.cs to reflect the name of the 
GDAL DLL installed on your machine (make sure the DLL has the manifests 
embedded or you'll get DLL loading errors!), build the solution, ensure 
that the GDAL DLL is on your PATH, and then hit F5 to run the test 
program. Go to File->Open... and load any image...

This might clarify some of the locking / unlocking / Interop issues.

Note that this code implements RasterIO following the GDAL pattern very 
closely, so it's probably lower level than what you want to do.


> I think we should support the generic functions first. If it works, we
> will create the specializations using Marshal.Copy and calling the
> generic fn-s internally.

When you say "generic", I'm guessing you're not using it in the sense of 
"C# generics" (AKA C# templates)? That's the sense I've been using it in 
my e-mails... Not exactly sure what you have in mind here, but I'd 
prefer to avoid uncecessary copies of data if possible. I use GDAL to 
access some very large rasters, and so efficiency is important to me.


> I hope we shall not have to bring  GDALRWFlag and GDALDataType into
> the C# interface if it is possible.

Agreed.


> I would like to get something working this weekend.

Groovy.

> PS: Thanks, for your efforts about the manifest embedding stuff  :-)

No problem - the only tricky thing is finding decent documentation from 
Microsoft on any of this stuff...




Cheers,

Sy




More information about the Gdal-dev mailing list