您的位置:首页 > 移动开发

在.NET 4中调用GDAL库时遇到的问题及解决方法

2010-07-31 16:22 471 查看
 

最近需要在.NET 4的环境中调用GDAL库。GDAL本身是一套非托管类库,不过还好提供了托管的Wrapper。
这些托管的程序集被包含在了FWTools的安装包中,FWTools中带的版本依赖于gdal_fw.dll,gdal_fw.dll是GDAL核心类库的修改版,而它依赖的其他非托管程序集太多了,加起来有18M左右。所以还是自己下载代码编译的好。

这篇文章介绍了1.4版本的编译方法,该方法同样适用于现在的1.7版本。

编译好之后引用、调用、Debug都没问题,一切正常,但是如果用Release编译并在VS之外运行的话则会报出AccessViolationException,异常信息提示说访问了受保护的内存。我的第一反应就是托管的Wrapper中用P/Invoke调用了非托管程序集,而非托管程序集导致了这个问题。但是这个猜测并不能解释为什么只有在.NET 4+Release+IDE外运行的情况下才会出错的现象。
猜来猜去,找来找去找到了问题的所在:
GDAL的托管Wrapper中有一个叫做SWIGStringHelper的类型,该类型的静态构造方法中执行了一些比较重要的初始化操作。另外一个叫做OsrPINVOKE的类中声明了一个SWIGStringHelper类型的私有静态字段,并在声明时就初始化了该字段,而且OsrPINVOKE中没有显式声明的静态构造。
把代码简化一下的话,大概是这样的:
class OsrPINVOKE
{
private static SWIGStringHelper helper = new SWIGStringHelper();

public static void DoSomething()
{
Console.WriteLine("static method of OsrPINVOKE");
}
}

class SWIGStringHelper
{
static SWIGStringHelper()
{
//这里做了一些重要的初始化
Console.WriteLine("SWIGStringHelper static constructor");
}
}

如果有代码调用DoSomething,我对这段代码执行顺序的估计是这样的:
OsrPINVOKE的静态构造方法(里面初始化helper这个静态字段);
SWIGStringHelper的静态构造方法(输出字符串);
SWIGStringHelper的实例构造方法(里面啥也没有做);
DoSomething方法(输出字符串)。
所以应该是先输出SWIGStringHelper
static constructor而后输出static method of
OsrPINVOKE。
试着这样调用一下:
static void Main(string[] args)
{
OsrPINVOKE.DoSomething();
Console.ReadLine();
}
 
却发现如果用的target framework是.net
4,用release编译并且在VS外运行的话,就会只输出static method of OsrPINVOKE,感觉好像SWIGStringHelper的静态构造方法没有执行。而如果用的是.net 2.0、3.5,或者是用Debug编译或是在VS里面运行的话都不会有问题。
难道是静态字段的初始化在.NET 4中变成Lazy的了?
事实证明真的是这样。所以要解决这个问题的话只要在OsrPINVOKE里面显示声明一个静态构造方法,把new SWIGStringHelper();这一句放到里执行就OK了。
如果您在.NET 4中调用GDAL时遇到了类似的问题,不妨试一下。
 
参考:
http://social.microsoft.com/Forums/zh-CN/visualcshartzhchs/thread/2106ea8e-4889-45bf-82fd-55ab4b3e9aad
http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/d3fb3454-b982-4357-bb6b-63f7eceee69b/#96f5cc6b-a31b-4ae2-b2f4-40a99e7581af
 
感谢:
韦恩卑鄙、Nishant
Sivakumar
 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐