1. 程式人生 > >VS2017編譯GDAL(64bit)+解決C#讀取Shp資料中文路徑的問題

VS2017編譯GDAL(64bit)+解決C#讀取Shp資料中文路徑的問題

編譯GDAL過程比較繁瑣,查閱了網上相關資料,同時通過實踐,完成GDAL的編譯,同時解決了SHP資料中文路徑及中文欄位亂碼的問題,本文以“gdal-2.3.2”版本為例闡述整個編譯過程。

一、編譯準備

1、編譯工具是VS2017,編譯前需要下載“gdal-2.3.2”和“swigwin-3.0.12”,下載連結如下:

  • GDAL:http://trac.osgeo.org/gdal/wiki/DownloadSource
  • swigwin:https://sourceforge.net/projects/swig/files/swigwin/

2、在“D盤”新建目錄“GDAL”,將兩個壓縮包解壓到該目錄中,同時新建一個資料夾用於存放編譯結果(如“D:\GDAL\GDAL\GDAL232“”),如圖所示:

3、修改“D:\GDAL\gdal-2.3.2\nmake.opt”檔案,如下圖:

檔案“nmake.opt”修改如下:

修改57行,GDAL_HOME = "D:\GDAL\GDAL\GDAL232"(編譯後文件的生成目錄)

修改86行,SWIG = D:\GDAL\swigwin-3.0.12\swig.exe(這個必須是完全路徑)

修改184行,去掉“#”,效果為WIN64=YES

修改960行,去掉後邊的下劃線,效果為SYM_PREFIX=

二、編譯C++

以管理員執行【開始】-【所有程式】-【Visual Studio 2017】-【Visual Studio Tools】-【VC】-【適用於 VS 2017 的 x64 本機工具命令提示】選單,彈出命令框如圖所示:

輸入cd D:\GDAL\gdal-2.3.2 切換至gdal-2.3.2目錄,如圖所示:

然後輸入: nmake /f makefile.vc

                   nmake /f makefile.vc install

                   nmake /f makefile.vc devinstall

C++編譯時間較長,需要耐心等待……

三、編譯C#

1、修改C#原始碼檔案

    開啟“D:\GDAL\gdal-2.3.2\swig\csharp\AssemblyInfo.cs”,註釋掉【[assembly: AllowPartiallyTrustedCallers]】,如下圖所示:

   開啟“D:\GDAL\gdal-2.3.2\swig\csharp\gdal\GdalPINVOKE.cs”

          “D:\GDAL\gdal-2.3.2\swig\csharp\ogr\OgrPINVOKE.cs”

          “D:\GDAL\gdal-2.3.2\swig\csharp\osr\OsrPINVOKE.cs”

          三個檔案,分別註釋掉重複的建構函式,如圖所示:

         

       開啟“D:\GDAL\gdal-2.3.2\swig\csharp\gdal\Band.cs”

              “D:\GDAL\gdal-2.3.2\swig\csharp\gdal\Dataset.cs”

              “D:\GDAL\gdal-2.3.2\swig\csharp\gdal\Driver.cs”

              檔案,修改介面成員(大概17行),如下:

              public Band(IntPtr cPtr, bool cMemoryOwn, object parent): base(GdalPINVOKE.Band_SWIGUpcast(cPtr), cMemoryOwn, parent){swigCPtr = new HandleRef(this, cPtr);}

              public Dataset(IntPtr cPtr, bool cMemoryOwn, object parent): base(GdalPINVOKE.Band_SWIGUpcast(cPtr), cMemoryOwn, parent){swigCPtr = new HandleRef(this, cPtr);}

              public Driver(IntPtr cPtr, bool cMemoryOwn, object parent): base(GdalPINVOKE.Band_SWIGUpcast(cPtr), cMemoryOwn, parent){swigCPtr = new HandleRef(this, cPtr);}

        接下來解決讀取中文路徑及屬性亂碼 :

        開啟“D:\GDAL\gdal-2.3.2\swig\csharp\const\GdalConstPINVOKE.cs”

               “D:\GDAL\gdal-2.3.2\swig\csharp\gdal\GdalPINVOKE.cs”

               “D:\GDAL\gdal-2.3.2\swig\csharp\ogr\OgrPINVOKE.cs”

               “D:\GDAL\gdal-2.3.2\swig\csharp\osr\OsrPINVOKE.cs”

                4個檔案,分別修改類“SWIGStringHelper”(大概168行),具體程式碼(紅色為修改過得程式碼)如下:

protected class SWIGStringHelper {

public delegate string SWIGStringDelegate(IntPtr message); static SWIGStringDelegate stringDelegate = new SWIGStringDelegate(CreateString);

[global::System.Runtime.InteropServices.DllImport("ogr_wrap", EntryPoint="SWIGRegisterStringCallback_Ogr")] public static extern void SWIGRegisterStringCallback_Ogr(SWIGStringDelegate stringDelegate);

static string CreateString(IntPtr pNativeData) { if (pNativeData == IntPtr.Zero) return "";

int i = 0; byte[] strbuf1 = new byte[1]; Marshal.Copy(pNativeData + i, strbuf1, 0, 1); while (strbuf1[0] != 0) { i++; strbuf1 = new byte[1]; Marshal.Copy(pNativeData + i, strbuf1, 0, 1); } int length = i;//迴圈查詢字串的長度

byte[] strbuf = new byte[length]; Marshal.Copy(pNativeData, strbuf, 0, length); return System.Text.Encoding.UTF8.GetString(strbuf); }

static SWIGStringHelper() { SWIGRegisterStringCallback_Ogr(stringDelegate); } }

          開啟“D:\GDAL\gdal-2.3.2\swig\csharp\gdal\Gdal.cs”

                 “D:\GDAL\gdal-2.3.2\swig\csharp\ogr\Ogr.cs”

                 “D:\GDAL\gdal-2.3.2\swig\csharp\osr\Osr.cs”

                 三個檔案,分別修改函式“Utf8BytesToString”,程式碼如下:

internal static string Utf8BytesToString(IntPtr pNativeData) { if (pNativeData == IntPtr.Zero) return null; int i = 0; byte[] strbuf1 = new byte[1]; Marshal.Copy(pNativeData + i, strbuf1, 0, 1); while (strbuf1[0] != 0) { i++; strbuf1 = new byte[1]; Marshal.Copy(pNativeData + i, strbuf1, 0, 1); } int length = i;//迴圈查詢字串的長度

byte[] strbuf = new byte[length]; Marshal.Copy(pNativeData, strbuf, 0, length); //int length = Marshal.PtrToStringAnsi(pNativeData).Length; //byte[] strbuf = new byte[length]; //Marshal.Copy(pNativeData, strbuf, 0, length); return System.Text.Encoding.UTF8.GetString(strbuf); }

2、編譯

     輸入cd swig\csharp ,切換到csharp目錄,

     輸入nmake /f makefile.vc(執行這一步有問題的話,加以下兩句:namke /f makefile.vc clear 、nmake /f makefile.vc interface)

     輸入nmake /f makefile.vc install 

編譯完成後,在目錄“D:\GDAL\GDAL\GDAL232\csharp”會生成8個檔案,如圖所示:

注:C#編譯過程中,如果出現HandleRef和IntPtr沒有引用的錯誤,只需要在相應檔案中新增名稱空間

using System;using System.Runtime.InteropServices;即可解決該問題

四、測試DLL

新建一個Winform應用程式,修改執行配置為x64,如圖所示:

把“D:\GDAL\GDAL\GDAL232\csharp”中的8gedll和“D:\GDAL\GDAL\GDAL232\bin”中的一個dll複製到“x64/Release”目錄下,新增引用

讀取Shp資料的程式碼如下:

OSGeo.GDAL.Gdal.AllRegister(); OSGeo.OGR.Ogr.RegisterAll(); OSGeo.OGR.Driver dr = OSGeo.OGR.Ogr.GetDriverByName("ESRI shapefile"); OSGeo.OGR.DataSource ds = dr.Open(path, 0); if (ds == null) { MessageBox.Show("檔案不能開啟,請檢查!"); return; }

效果如圖所示: