GeoTrans p/invoke wrapper NullReferenceException
GeoTrans p/invoke wrapper NullReferenceException
我试图暴露我需要从GeoTrans c++库调用的方法,但是,我遇到了问题。任何帮助都太好了!
我有下面的c++文件,我正在运行nmake来编译成一个dll。
#include <iostream>
#include "CoordinateConversionService.h"
#include "CoordinateSystemParameters.h"
#include "GeodeticParameters.h"
#include "CoordinateTuple.h"
#include "GeodeticCoordinates.h"
#include "CartesianCoordinates.h"
#include "Accuracy.h"
#include "MGRSorUSNGCoordinates.h"
#include "UTMParameters.h"
#include "UTMCoordinates.h"
#include "CoordinateType.h"
#include "HeightType.h"
#include "CoordinateConversionException.h"
using MSP::CCS::Precision;
int main(int argc, char **argv){}
extern "C"__declspec(dllexport) void __stdcall convertGeodeticToGeocentric(const double lat,const double lon, const double height, double& x, double& y, double& z)
{
MSP::CCS::CoordinateSystemParameters geocentricParameters(MSP::CCS::CoordinateType::geocentric);
MSP::CCS::CoordinateConversionService ccs( "WGE", &geodeticParameters, "WGE", &geocentricParameters );
MSP::CCS::Accuracy sourceAccuracy;
MSP::CCS::Accuracy targetAccuracy;
MSP::CCS::GeodeticCoordinates sourceCoordinates(MSP::CCS::CoordinateType::geodetic, lon, lat, height);
MSP::CCS::CartesianCoordinates targetCoordinates(MSP::CCS::CoordinateType::geocentric);
ccs.convertSourceToTarget( &sourceCoordinates, &sourceAccuracy, targetCoordinates, targetAccuracy );
x = targetCoordinates.x();
y = targetCoordinates.y();
z = targetCoordinates.z();
}
extern "C"__declspec(dllexport) void __stdcall convertGeocentricToGeodetic(const double x, const double y, const double z, double& lat,double& lon, double& height)
{
MSP::CCS::CoordinateSystemParameters geocentricParameters(MSP::CCS::CoordinateType::geocentric);
MSP::CCS::GeodeticParameters geodeticParameters(MSP::CCS::CoordinateType::geodetic, MSP::CCS::HeightType::ellipsoidHeight);
MSP::CCS::CoordinateConversionService ccs( "WGE", &geocentricParameters, "WGE", &geodeticParameters );
MSP::CCS::Accuracy sourceAccuracy;
MSP::CCS::Accuracy targetAccuracy;
MSP::CCS::CartesianCoordinates sourceCoordinates(MSP::CCS::CoordinateType::geocentric, x, y, z);
MSP::CCS::GeodeticCoordinates targetCoordinates;
ccs.convertSourceToTarget( &sourceCoordinates, &sourceAccuracy, targetCoordinates, targetAccuracy );
lat = targetCoordinates.latitude();
lon = targetCoordinates.longitude();
height = targetCoordinates.height();
}
extern "C"__declspec(dllexport) void __stdcall convertGeocentricToUTM(const double x, const double y, const double z, long& zone, char& hemisphere, double& easting, double& northing)
{
MSP::CCS::CoordinateSystemParameters geocentricParameters(MSP::CCS::CoordinateType::geocentric);
MSP::CCS::UTMParameters utmParameters(MSP::CCS::CoordinateType::universalTransverseMercator, 1, 0);
MSP::CCS::CoordinateConversionService ccs( "WGE", &geocentricParameters, "WGE", &utmParameters );
MSP::CCS::Accuracy sourceAccuracy;
MSP::CCS::Accuracy targetAccuracy;
MSP::CCS::CartesianCoordinates sourceCoordinates(MSP::CCS::CoordinateType::geocentric, x, y, z);
MSP::CCS::UTMCoordinates targetCoordinates;
ccs.convertSourceToTarget( &sourceCoordinates, &sourceAccuracy, targetCoordinates, targetAccuracy );
zone = targetCoordinates.zone();
hemisphere = targetCoordinates.hemisphere();
easting = targetCoordinates.easting();
northing = targetCoordinates.northing();
}
extern "C"__declspec(dllexport) void __stdcall convertGeocentricToMGRS(const double x, const double y, const double z, char*& mgrsString, Precision::Enum& precision)
{
MSP::CCS::CoordinateSystemParameters geocentricParameters(MSP::CCS::CoordinateType::geocentric);
MSP::CCS::CoordinateSystemParameters mgrsParameters(MSP::CCS::CoordinateType::militaryGridReferenceSystem);
MSP::CCS::CoordinateConversionService ccs( "WGE", &geocentricParameters, "WGE", &mgrsParameters );
MSP::CCS::Accuracy sourceAccuracy;
MSP::CCS::Accuracy targetAccuracy;
MSP::CCS::CartesianCoordinates sourceCoordinates(MSP::CCS::CoordinateType::geocentric, x, y, z);
MSP::CCS::MGRSorUSNGCoordinates targetCoordinates;
ccs.convertSourceToTarget( &sourceCoordinates, &sourceAccuracy, targetCoordinates, targetAccuracy );
mgrsString = targetCoordinates.MGRSString();
precision = targetCoordinates.precision();
}
然后在我的c#类中有以下p/invoke调用。
[DllImport("CoordinateConversionWrapper.dll")]
private static extern void convertGeodeticToGeocentric(double lat, double lon, double height, ref double x, ref double y, ref double z);
[DllImport("CoordinateConversionWrapper.dll")]
private static extern void convertGeocentricToMGRS(double x, double y, double z, ref char[] mgrsString, Precision precision);
调用上述任何p/invoke方法都会导致NullReferenceException。似乎问题是在c++代码本身,但不是一个c++专家,我不确定问题是什么…
请帮助! !
我建议调试你的代码。您可以在c#项目的设置(Debug选项卡)中启用调试非托管代码。
请同时写上电话号码。
注意:p/invoke的字符串输出参数通常使用StringBuilder类完成。
[EDIT]字符串输出有问题-谁为字符串提供存储,谁正在释放它(如果需要)?唯一有用的解决方案是将存储空间(以char*的形式)及其长度传递给c++函数。如前所述,在c#端使用StringBuilder
我使用了您与最新版本的库一起发布的代码,它对我来说很好。你可以考虑的一件事是用c++/CLI包装而不是用P/Invoke,但这是另一个主题。
我在假设你正在使用Visual Studio 2010的情况下工作(哦,好吧,必须从某个地方开始:-))。
有一件事显然是不行的:
本地:
extern "C"__declspec(dllexport) void __stdcall convertGeocentricToMGRS(const double x, const double y, const double z, char*&mgrsString、精密:Enum&精密)
和c#:
[DllImport("CoordinateConversionWrapper.dll")]private static extern void convertGeocentricToMGRS(双x,双y,双z, ref char[] mgrsString, Precision Precision);
:
extern "C"__declspec(dllexport) void __stdcall convertGeocentricToMGRS(const double x, const double y, const double z, char** mgrsString, Precision::Enum& precision)
{
MSP::CCS::CoordinateSystemParameters geocentricParameters(MSP::CCS::CoordinateType::geocentric);
MSP::CCS::CoordinateSystemParameters mgrsParameters(MSP::CCS::CoordinateType::militaryGridReferenceSystem);
MSP::CCS::CoordinateConversionService ccs( "WGE", &geocentricParameters, "WGE", &mgrsParameters );
MSP::CCS::Accuracy sourceAccuracy;
MSP::CCS::Accuracy targetAccuracy;
MSP::CCS::CartesianCoordinates sourceCoordinates(MSP::CCS::CoordinateType::geocentric, x, y, z);
MSP::CCS::MGRSorUSNGCoordinates targetCoordinates;
ccs.convertSourceToTarget( &sourceCoordinates, &sourceAccuracy, targetCoordinates, targetAccuracy );
int nMGRSLen = strlen( targetCoordinates.MGRSString() );
::CoTaskMemFree(*mgrsString);
*mgrsString = (char *)::CoTaskMemAlloc(nMGRSLen + 1);
strcpy( *mgrsString, targetCoordinates.MGRSString() );
precision = targetCoordinates.precision();
}
注意char是作为指针到指针的方式传入的,并且使用了CoTaskMemFree/CoTaskMemAlloc/strcpy(包括Objbase.h for CoTaskMemAlloc)
在c#代码中你可以:
[DllImport("MSPGeotransTest.dll", CharSet= CharSet.Ansi))]
public static extern void convertGeocentricToMGRS(double x, double y, double z, ref string mgrsString, ref PrecisionEnum precision);
地点:
public enum PrecisionEnum : uint
{
degree = 0,
tenMinute = 1,
minute = 2,
tenSecond = 3,
second = 4,
tenthOfSecond = 5,
hundrethOfSecond = 6,
thousandthOfSecond = 7,
tenThousandthOfSecond = 8
}
可能存在其他的可能性…
其他一些有用的东西:
为了能够调试,请确保:
在"工具>选项>调试>常规"中,"只启用我的代码"未选中。
在Project> Properties> Debug选项卡中,选中"Enable unmanaged code debugging"。
在c#方法中放置一个断点,当到达断点时,您可以进入F11并到达c++代码…
我通过选择"使用多字节字符集"(配置属性通用字符集)编译c++ Dll
也似乎CoordinateConversionService构造函数抛出一个CoordinateConversionException,如果它无法加载配置文件(它搜索它们,它似乎在一个路径中,可以通过一个名为MSPCCS_DATA的环境变量配置,如果环境变量没有定义,它寻找它们在../../data/相对于exe路径)。
可能在c++包装器方法中,您可能想要捕获被调用方法抛出的任何异常并返回错误代码…也就是说,触发异常的其他情况是由于无效的输入坐标等。
就像我说的,我有一个可行的例子所以如果你想的话,我可以把它发给你。
- consteval wrapper vs. source_location
- OpenSSL fips in C++ wrapper Library 如何?错误:指纹不匹配
- C++ :: 安全地使用 reinterpret_cast 生成"wrapper"迭代器
- Java SWIG wrapper vs direct function calling
- C++ Wrapper for threadx RTOS?
- 传递对variadic-templates的引用使用std ::参考 - wrapper
- C++ Firebase wrapper?
- Sonarqube build wrapper for distutils
- Bizzare nullref in C++
- Boost Python wrapper 和 OpenCv 参数错误与 cv::Mat.
- 如何使用"wrapper function"调用没有参数的递归函数 n 次?
- libev c++ wrapper function_thunk
- SOCI (SQL C++ wrapper) - PostgreSQL 不执行命令 (?)
- C++智能指针和指针到指针输出 API。模板化"wrapper"
- C++98 Wrapper for std::map::at()
- C# wrapper class for c++ lib dll
- Libragnar(Libtorrent Wrapper)LocalTorrent文件,而不是URL?C#/C++
- c++, Win32 LoadString wrapper
- SWIG生成的Lua<-->C++ Wrapper错误地处理了typedef重命名的基元类型
- 提交c++回调到.net c++ /CLI Wrapper