[Gdal-dev] RE: GDAL, and C# Access

Paul, Michael michael.paul at tao.es
Thu Dec 22 06:21:24 EST 2005


Hi Frank,

referring to your mail below, effectively there is a way to use GDAL from
within C# without having to use SWIG. I have changed the code you posted to
this list so that it works absolutely stable, both on Windows and Linux with
Mono. You may find it below.

Two rules of thumb in order to make this code working:
1) never define a DLLImport statement with return type string, instead let
it return an IntPtr. Later, you can use the Marshal class to obtain the
string value. 
2) always pass a HandleRef to native code, not an IntPtr.

Some notes: 
at  http://cvs.sourceforge.net/viewcvs.py/mgis/driver/ogr.MGIS.Data.OGR/OGR/
you may see a more sophisticated wrapper that already permits read-only
access to the OGR C API. They are based upon the classes generated by the
SWIG interfaces of GDAL, but the DllImport statements (ogr_api.cs) have been
changed so that the GDAL library can be used directly. 

Last not least: a Managed C++ DLL that exposes the GDAL classes to .Net may
be another approach to solve the problem. An example may be seen in the
following article:
http://www.codeproject.com/csharp/GisMap.asp 


Any comments are welcome.

Have fun.

Changed code:
_____________________________
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace GoodleWrapper
{
        public class GoodleWrapper: Form
        {
            private Button button1;
        /// <summary>
		/// The main entry point for the application.
		/// </summary>
		[STAThread]
		static void Main()
		{
            Application.Run(new GoodleWrapper());
		}

		public enum GA_Access
		{			
            /// <summary>
            /// Read only (no update access
            /// </summary>
            GA_ReadOnly = 0,
            ///<summary>
            ///Read/write access. */
            ///</summary>
            GA_Update = 1
		}

		[DllImport("gdal13.dll")]
		public static extern IntPtr GDALOpen( [MarshalAs
(UnmanagedType.LPStr)]
                                                string pszFilename, 
                                                GA_Access eAccess );

		[DllImport("gdal13.dll")]
		public static extern IntPtr GDALGetDatasetDriver( HandleRef
GDALDatasetH );


		[DllImport("gdal13.dll")]
		public static extern void GDALAllRegister();

	
[DllImport("gdal13.dll",CharSet=CharSet.Ansi,EntryPoint="GDALGetDriverShortN
ame")]
		private static extern IntPtr GDALGetDriverShortName_api(
HandleRef GDALDriverH );

        public string GDALGetDriverShortName(HandleRef GDALDriverH)
        {
            return
Marshal.PtrToStringAnsi(GDALGetDriverShortName_api(GDALDriverH));
        }

		[DllImport("gdal13.dll",CharSet=CharSet.Ansi,
EntryPoint="GDALGetDriverLongName")]
        private static extern IntPtr GDALGetDriverLongName_api(HandleRef
GDALDriverH);

        public string GDALGetDriverLongName(HandleRef GDALDriverH)
        {
            return
Marshal.PtrToStringAnsi(GDALGetDriverLongName_api(GDALDriverH));
        }
		[DllImport("gdal13.dll")]
		public static extern int GDALGetRasterXSize( HandleRef
GDALDatasetH );

		[DllImport("gdal13.dll")]
            public static extern int GDALGetRasterYSize(HandleRef
GDALDatasetH);
		
		[DllImport("gdal13.dll")]
            public static extern int GDALGetRasterCount(HandleRef
GDALDatasetH);

		[DllImport("gdal13.dll",CharSet=CharSet.Ansi,
EntryPoint="GDALGetProjectionRef")]
            private static extern IntPtr GDALGetProjectionRef_api(HandleRef
GDALDatasetH);
            public string GDALGetProjectionRef(HandleRef GDALDatasetH)
            {
                return
Marshal.PtrToStringAnsi(GDALGetProjectionRef_api(GDALDatasetH));
            }

		public enum CPLErr
		{
			CE_None = 0,
			CE_Debug = 1,
			CE_Warning = 2,
			CE_Failure = 3,
			CE_Fatal = 4

		}

		[DllImport("gdal13.dll")]
		public static extern CPLErr GDALGetGeoTransform( HandleRef
GDALDatasetH, [In,Out] double [] Transform );

		[DllImport("gdal13.dll")]
		public static extern IntPtr GDALGetDriverByName(
[MarshalAs(UnmanagedType.LPStr)]string s );

		[DllImport("gdal13.dll")]
		public static extern IntPtr
        GDALCreateCopy(HandleRef GDALDriverH,
[MarshalAs(UnmanagedType.LPStr)] string s, HandleRef GDALDatasetH, int i,
HandleRef j, HandleRef k, HandleRef l);


		[DllImport("gdal13.dll")]
		public static extern void GDALClose(HandleRef GDALDriverH);


		[DllImport("gdal13.dll")]
		public static extern void GDALDestroyDriverManager();

		private void button1_Click(object sender, System.EventArgs
e)
		{
			GDALAllRegister();
			
            	//first rule of thumb: pass a HandleRef to native code, not
an IntPtr.
            	//1. wrap dataset handle return by GDAL into a HandleRef
			HandleRef hDataset = new HandleRef (this, GDALOpen(
"C:\\myimage.tif", GA_Access.GA_ReadOnly));
			if( hDataset.Handle == IntPtr.Zero )
			{
				MessageBox.Show("Could not open Raster
File.");
			}

            	//1. wrap dataset handle return by GDAL into a HandleRef
			HandleRef   hDriver;
			hDriver = new HandleRef (this, GDALGetDatasetDriver(
hDataset ));

			//FW:This seems to wig out .NET...Looks to me GDAL
has become unstable due to this call.
            	
			//second rule of thumb: use Marshal.PtrToStringAnsi
in order to handle strings returned by native code           
			MessageBox.Show("Driver: " + GDALGetDriverShortName(
hDriver ) + " " + GDALGetDriverLongName( hDriver ) );

			MessageBox.Show("Size is " + GDALGetRasterXSize(
hDataset ) + " " + GDALGetRasterYSize( hDataset ) + " " + 
            GDALGetRasterCount( hDataset ) );

			string ProjectionRef = null;

			//FW:Also this call destabilized the stack. Looks to
me like strings are not handled
			//the way they should be by .NET.
            
			//Note: applied the rule stated above and code
works:
			ProjectionRef = GDALGetProjectionRef( hDataset );

			if( ProjectionRef != null )
				MessageBox.Show("Projection is " +
ProjectionRef );

			double [] adfGeoTransform = new double[6];
			if( GDALGetGeoTransform( hDataset, adfGeoTransform )
== CPLErr.CE_None )
			{
				MessageBox.Show( "Origin = " +
adfGeoTransform[0] + " " + adfGeoTransform[3] );

				MessageBox.Show( "Pixel Size = " +
adfGeoTransform[1] + " " + adfGeoTransform[5] );
			}


			//Convert to some other format (JPG for example)
			hDriver = new HandleRef (this, GDALGetDriverByName(
"JPEG" ));

			//Do a straight copy.
			HandleRef  hOutDS = new HandleRef (this,
GDALCreateCopy( hDriver, "C:\\myimage.jpg", hDataset,
				0, new HandleRef (null, IntPtr.Zero), new
HandleRef(null, IntPtr.Zero), new HandleRef (null, IntPtr.Zero)));

			if(hOutDS.Handle != IntPtr.Zero)
                GDALClose( hOutDS );

			//Shut everything down.
			GDALClose( hDataset );
			GDALDestroyDriverManager();

			MessageBox.Show("Export to JPEG complete.");
		}
            public GoodleWrapper()
            {
                InitializeComponent();
            }

            private void InitializeComponent()
            {
                this.button1 = new System.Windows.Forms.Button();
                this.SuspendLayout();
                // 
                // button1
                // 
                this.button1.Location = new System.Drawing.Point(113, 99);
                this.button1.Name = "button1";
                this.button1.Size = new System.Drawing.Size(75, 23);
                this.button1.TabIndex = 0;
                this.button1.Text = "I love &.Net";
                this.button1.UseVisualStyleBackColor = true;
                this.button1.Click += new
System.EventHandler(this.button1_Click);
                // 
                // GoodleWrapper
                // 
                this.ClientSize = new System.Drawing.Size(292, 266);
                this.Controls.Add(this.button1);
                this.Name = "GoodleWrapper";
                this.ResumeLayout(false);

            }
	}
}



 
Regards,
 
Michael

_____________________________________________ 

From: Frank Warmerdam 
Sent: Thu Nov 4 11:55:45 EST 2004
To: [Gdal-dev]
Subject: GDAL, and C# Access

Folks,

There has been talk from time to time about using GDAL from C# or as a .NET
assemblage.  I can't say I grok all the issues in this area, but I thought
I should pass on something Roger Bedell sent me over a year ago.  He sent
a whole project showing how GDAL could be called from C#, which I am finally
looking at briefly.  I couldn't actually run the project, but I did dig
through the code, and found the following was the core of the GDAL
interaction.

The point is that it is fairly easy to call out to C entry points from C#.
At some point I might well try and maintain an appropriate set of C#
declarations for the GDAL C API though I am not ready to do that just yet.


		/// <summary>
		/// The main entry point for the application.
		/// </summary>
		[STAThread]
		static void Main()
		{
			Application.Run(new Form1());
		}

		public enum GA_Access
		{
			/*! Read only (no update) access */ GA_ReadOnly = 0,
			/*! Read/write access. */           GA_Update = 1
		}

		[DllImport("gdal11.dll")]
		public static extern IntPtr
			GDALOpen( string pszFilename, GA_Access eAccess );

		[DllImport("gdal11.dll")]
		public static extern IntPtr
			GDALGetDatasetDriver( IntPtr GDALDatasetH );


		[DllImport("gdal11.dll")]
		public static extern void
			GDALAllRegister();

		[DllImport("gdal11.dll",CharSet=CharSet.Ansi)]
		public static extern string
			GDALGetDriverShortName( IntPtr GDALDriverH );

		[DllImport("gdal11.dll",CharSet=CharSet.Ansi)]
		public static extern string
			GDALGetDriverLongName( IntPtr GDALDriverH );

		[DllImport("gdal11.dll")]
		public static extern int GDALGetRasterXSize( IntPtr
GDALDatasetH );

		[DllImport("gdal11.dll")]
		public static extern int GDALGetRasterYSize( IntPtr
GDALDatasetH );
		
		[DllImport("gdal11.dll")]
		public static extern int GDALGetRasterCount( IntPtr
GDALDatasetH );

		[DllImport("gdal11.dll",CharSet=CharSet.Ansi)]
		public static extern string GDALGetProjectionRef( IntPtr
GDALDatasetH );


		public enum CPLErr
		{
			CE_None = 0,
			CE_Debug = 1,
			CE_Warning = 2,
			CE_Failure = 3,
			CE_Fatal = 4

		}

		[DllImport("gdal11.dll")]
		public static extern CPLErr GDALGetGeoTransform( IntPtr
GDALDatasetH, [In,Out] double [] Transform );

		[DllImport("gdal11.dll")]
		public static extern IntPtr
		GDALGetDriverByName( string s );

		[DllImport("gdal11.dll")]
		public static extern IntPtr
		GDALCreateCopy( IntPtr GDALDriverH, string s, IntPtr
GDALDatasetH,
						int i, IntPtr j, IntPtr k,
IntPtr l);


		[DllImport("gdal11.dll")]
		public static extern void
			GDALClose( IntPtr GDALDriverH );


		[DllImport("gdal11.dll")]
		public static extern void
			GDALDestroyDriverManager();

		private void button1_Click(object sender, System.EventArgs
e)
		{
			GDALAllRegister();
			
			IntPtr hDataset = GDALOpen( Application.StartupPath
+ "\\..\\..\\SampleData\\SARA_IRS.TIF", GA_Access.GA_ReadOnly);
			if( hDataset == (IntPtr)null )
			{
				MessageBox.Show("Could not open Raster
File.");
			}

			IntPtr   hDriver;
	
			hDriver = GDALGetDatasetDriver( hDataset );

			//This seems to wig out .NET...Looks to me GDAL has
become unstable due to this call.
//			MessageBox.Show("Driver: " + GDALGetDriverShortName(
hDriver ) + " " + GDALGetDriverLongName( hDriver ) );

			MessageBox.Show("Size is " + GDALGetRasterXSize(
hDataset ) + " " + GDALGetRasterYSize( hDataset ) + " " + 
GDALGetRasterCount( hDataset ) );

//			string ProjectionRef = null;

			//Also this call destabilized the stack. Looks to me
like strings are not handled
			//the way they should be by .NET.
//			ProjectionRef = GDALGetProjectionRef( hDataset );

//			if( ProjectionRef != null )
//				MessageBox.Show("Projection is " +
ProjectionRef );

			double [] adfGeoTransform = new double[6];
			if( GDALGetGeoTransform( hDataset, adfGeoTransform )
== CPLErr.CE_None )
			{
				MessageBox.Show( "Origin = " +
adfGeoTransform[0] + " " + adfGeoTransform[3] );

				MessageBox.Show( "Pixel Size = " +
adfGeoTransform[1] + " " + adfGeoTransform[5] );
			}


			//Convert to some other format (JPG for example)
			hDriver = GDALGetDriverByName( "JPEG" );

			//Do a straight copy.
			IntPtr hOutDS = GDALCreateCopy( hDriver,
Application.StartupPath + "\\..\\..\\SampleData\\SARA_IRS.JPG", hDataset,
				0, (IntPtr)null,
				(IntPtr)null, (IntPtr)null);

			if(hOutDS != (IntPtr)null)
				GDALClose( hOutDS );

			//Shut everything down.
			GDALClose( hDataset );
			GDALDestroyDriverManager();

			MessageBox.Show("Export to JPEG complete.");
		}
	}

Best regards,

-- 
---------------------------------------+------------------------------------
--
I set the clouds in motion - turn up   | Frank Warmerdam, warmerdam at
pobox.com
light and sound - activate the windows | http://pobox.com/~warmerdam
and watch the world go round - Rush    | Geospatial Programmer for Rent



More information about the Gdal-dev mailing list