我正在尝试公开我需要从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#class中进行了以下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 ++专家,我不确定问题是什么......
请帮助!!
答案 0 :(得分:2)
我建议您调试代码。您可以在C#项目的设置(调试选项卡)中启用调试非托管代码。
请同时发布主叫代码。
备注:p / invoke的字符串输出参数通常使用StringBuilder类完成。
[编辑]字符串输出有问题 - 谁为字符串提供存储空间以及谁将其释放(如果需要)?唯一有用的解决方案是将存储(作为char *)及其长度传递给C ++函数。如上所述,在C#端使用StringBuilder。
答案 1 :(得分:1)
我使用了你发布的代码和最新版本的库,它对我来说很好用。您可以考虑的一件事是包装为C ++ / CLI而不是使用P / Invoke,但这是另一个主题。
我正在假设你使用的是Visual Studio 2010(哦,一个人必须从某个地方开始:-))。
显然不好的一件事是:
<强>本地强>
extern“C”__ declspec(dllexport)void __stdcall convertGeocentricToMGRS(const double x,const double y,const double z,char *&amp; mgrsString,Precision :: Enum&amp; precision)
和C#:
[的DllImport( “CoordinateConversionWrapper.dll”)] private static extern void convertGeocentricToMGRS(double x,double y,double 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(包括用于CoTaskMemAlloc的Objbase.h)
在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
}
可能存在其他可能性......
其他一些有用的东西:
为了能够调试,请确保:
在工具&gt;选项&gt;调试&gt;一般情况下,“启用我的代码”未选中。
在项目&gt;属性&gt;选中“调试”选项卡“启用非托管代码调试”。
在C#方法中放置一个断点,当到达断点时,您可以进入F11并到达C ++代码......
我通过选择“使用多字节字符集”(配置属性\常规\字符集)编译了C ++ Dll
如果CoordinateConversionService构造函数无法加载配置文件(它会搜索它们看起来似乎在可以通过名为MSPCCS_DATA的环境变量配置的路径中并且未定义环境变量),它似乎会抛出一个CoordinateConversionException。它在相对于exe路径的../../data/中查找它们。
可能在C ++包装器方法中,您可能希望捕获被调用方法可能引发的任何异常并返回错误代码... I.e。触发异常的其他情况是由于输入坐标无效等原因造成的。
正如我所说,我有一个有效的例子,如果你愿意,我可以发给你......