对 DLL 进行两次相同的调用,使用 pinvoke,得到不同的结果
Same call on DLL twice, with pinvoke, getting different results
我在 C# 应用程序(net45、VS2013、windows 7 64)上使用我无法控制的 fort运行 DLL(用 mingw 编译),通过Pinvoke。但是,它具有从绝对相等调用中产生不同结果的 st运行ge 行为。它比这稍微复杂一点,查看示例(假设 'get' 是 ddl 方法):
第一个 C# 运行
- 'get' 调用产生“200”
- 'get' 调用产生'-100'
第二个 C# 运行
- get 调用产生“200”
- get 调用产生“-100”
正确的结果总是第一个 运行。我相信存在某种糟糕的内存使用情况,因为我实际上遇到了类似的问题,其中 'get' 无法被第二次调用(它会崩溃)。最初我尝试为所有调用加载一次 DLL,然后在每次调用之前重新加载,但两者的行为完全相同。在下面查看它们:
为所有调用加载一次dll
[DllImport(@"gamma.dll", CallingConvention = CallingConvention.Cdecl)]
static extern void get_(ref GammaInputStruct inputParams, ref int nobs, float[] utmx, float[] utmy, float[] dobi, float[] embi, float[] sobi, float[] tci, float[] gamma, float[] matrixOut);
每次调用前重新加载 dll(参见 http://blogs.msdn.com/b/jmstall/archive/2007/01/06/typesafe-getprocaddress.aspx)
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate void GetDelegate(ref GammaInputStruct inputParams, ref int nobs, float[] utmx, float[] utmy, float[] dobi, float[] embi, float[] sobi, float[] tci, float[] gamma, float[] matrixOut);
using (var lib = new UnmanagedLibrary("gamma.dll"))
{
var func = lib.GetUnmanagedFunction<GetDelegate>("get_");
func(ref input.InputParams, ref input.Nobs, input.Utmx, input.Utmy, input.Dobi, input.Embi, input.Sobi.ToArray(), input.Tci, input.Gamma, matrixOut);
}
最后,下面是"gamma.dll"的编译过程以及方法签名的源代码。
堡运行编译:
gfortran.exe -Jobj\Debug\ -ffree-line-length-none -ffixed-line-length-none -Wall -g -DBUILD_DLL -fPIC -ffixed-form -ffree-form -c "Gamma14.f90" -o obj\Debug\Gamma14.o
要塞运行 获取签名:
!DEC$ ATTRIBUTES DLLEXPORT::get
subroutine get(inputParams,nobsIn,utmx,utmy,dobi,embi,sobi,tci,gammaArray,matrixOut)
最后但同样重要的是,此代码 运行 在 WPF GUI 上,用户选择输入,因此它可以 运行 无限次,相同或不同输入。
我运行没主意了。拿到一些?
谢谢!
更新----------------
还尝试在调用之间复制(不同的名称)和删除 DLL,但没有成功。
我对 DLL's/memory 用法的了解非常基础,但我希望有一种方法可以使每次调用都是全新的,这将使代码能够抵抗某些堡垒运行 代码有味道。考虑到我的时间限制,尝试并修复堡垒运行 代码并不是一个很好的选择。
更新2-------------
我找到了关于这个问题的更多信息,并设法解决了它。我在两个不同的 DLL 上进行了两次 pinvoke 调用,两者都是 fort运行,具有不同且不相关的源代码。它们是管道的一部分,但在下面的示例中,为了测试,调用彼此完全无关。让我们称它们为 'DLL1' 和 'DLL2':
- 情况 1:运行'DLL1' 多次 -> OK
- 情况 2:运行'DLL2' 多次 -> OK
- 情况三:运行'DLL1'一次,然后'DLL2'多次->
不好
请参阅下面的答案。
我尝试在每次调用前重新加载 'DLL1',它成功了。我做了一些更多的测试,发现除非我对其中的 both 都这样做,否则它不会起作用。
我仍然不能真正理解所有这一切的原因,但无论如何,这是有效的。
我在 C# 应用程序(net45、VS2013、windows 7 64)上使用我无法控制的 fort运行 DLL(用 mingw 编译),通过Pinvoke。但是,它具有从绝对相等调用中产生不同结果的 st运行ge 行为。它比这稍微复杂一点,查看示例(假设 'get' 是 ddl 方法):
第一个 C# 运行
- 'get' 调用产生“200”
- 'get' 调用产生'-100'
第二个 C# 运行
- get 调用产生“200”
- get 调用产生“-100”
正确的结果总是第一个 运行。我相信存在某种糟糕的内存使用情况,因为我实际上遇到了类似的问题,其中 'get' 无法被第二次调用(它会崩溃)。最初我尝试为所有调用加载一次 DLL,然后在每次调用之前重新加载,但两者的行为完全相同。在下面查看它们:
为所有调用加载一次dll
[DllImport(@"gamma.dll", CallingConvention = CallingConvention.Cdecl)]
static extern void get_(ref GammaInputStruct inputParams, ref int nobs, float[] utmx, float[] utmy, float[] dobi, float[] embi, float[] sobi, float[] tci, float[] gamma, float[] matrixOut);
每次调用前重新加载 dll(参见 http://blogs.msdn.com/b/jmstall/archive/2007/01/06/typesafe-getprocaddress.aspx)
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate void GetDelegate(ref GammaInputStruct inputParams, ref int nobs, float[] utmx, float[] utmy, float[] dobi, float[] embi, float[] sobi, float[] tci, float[] gamma, float[] matrixOut);
using (var lib = new UnmanagedLibrary("gamma.dll"))
{
var func = lib.GetUnmanagedFunction<GetDelegate>("get_");
func(ref input.InputParams, ref input.Nobs, input.Utmx, input.Utmy, input.Dobi, input.Embi, input.Sobi.ToArray(), input.Tci, input.Gamma, matrixOut);
}
最后,下面是"gamma.dll"的编译过程以及方法签名的源代码。
堡运行编译:
gfortran.exe -Jobj\Debug\ -ffree-line-length-none -ffixed-line-length-none -Wall -g -DBUILD_DLL -fPIC -ffixed-form -ffree-form -c "Gamma14.f90" -o obj\Debug\Gamma14.o
要塞运行 获取签名:
!DEC$ ATTRIBUTES DLLEXPORT::get
subroutine get(inputParams,nobsIn,utmx,utmy,dobi,embi,sobi,tci,gammaArray,matrixOut)
最后但同样重要的是,此代码 运行 在 WPF GUI 上,用户选择输入,因此它可以 运行 无限次,相同或不同输入。
我运行没主意了。拿到一些?
谢谢!
更新----------------
还尝试在调用之间复制(不同的名称)和删除 DLL,但没有成功。
我对 DLL's/memory 用法的了解非常基础,但我希望有一种方法可以使每次调用都是全新的,这将使代码能够抵抗某些堡垒运行 代码有味道。考虑到我的时间限制,尝试并修复堡垒运行 代码并不是一个很好的选择。
更新2-------------
我找到了关于这个问题的更多信息,并设法解决了它。我在两个不同的 DLL 上进行了两次 pinvoke 调用,两者都是 fort运行,具有不同且不相关的源代码。它们是管道的一部分,但在下面的示例中,为了测试,调用彼此完全无关。让我们称它们为 'DLL1' 和 'DLL2':
- 情况 1:运行'DLL1' 多次 -> OK
- 情况 2:运行'DLL2' 多次 -> OK
- 情况三:运行'DLL1'一次,然后'DLL2'多次-> 不好
请参阅下面的答案。
我尝试在每次调用前重新加载 'DLL1',它成功了。我做了一些更多的测试,发现除非我对其中的 both 都这样做,否则它不会起作用。
我仍然不能真正理解所有这一切的原因,但无论如何,这是有效的。