GeoTrans p/invoke wrapper NullReferenceException

GeoTrans p/invoke wrapper NullReferenceException

本文关键字:wrapper NullReferenceException invoke GeoTrans      更新时间:2023-10-16

我试图暴露我需要从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++包装器方法中,您可能想要捕获被调用方法抛出的任何异常并返回错误代码…也就是说,触发异常的其他情况是由于无效的输入坐标等。

就像我说的,我有一个可行的例子所以如果你想的话,我可以把它发给你。