Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Arrays 从C#到F#:从F调用的外部函数中的固定数组和Stringbuilder#_Arrays_F#_Pinvoke_External_Pass By Reference - Fatal编程技术网

Arrays 从C#到F#:从F调用的外部函数中的固定数组和Stringbuilder#

Arrays 从C#到F#:从F调用的外部函数中的固定数组和Stringbuilder#,arrays,f#,pinvoke,external,pass-by-reference,Arrays,F#,Pinvoke,External,Pass By Reference,我正在尝试从F#访问外部DLL函数。 这一次我真是汗流浃背 C标题是: ext_def(int32) swe_calc_ut(double tjd_ut, int32 ipl, int32 iflag, double *xx, char *serr); 我在F#中相应地导入了: extern int32 ext_swe_calc_ut(double tjd_ut, int32 ipl, int32 iflag, double *xx, StringBuilder serr); 问题是数组部

我正在尝试从F#访问外部DLL函数。 这一次我真是汗流浃背

C标题是:

ext_def(int32) swe_calc_ut(double tjd_ut, int32 ipl, int32 iflag, 
double *xx, char *serr);
我在F#中相应地导入了:

extern int32 ext_swe_calc_ut(double tjd_ut, int32 ipl, int32 iflag, double *xx, StringBuilder serr);
问题是数组部分。我从F#Powerpack尝试了Pinnedaray,但呼叫仍然失败。char数组可能还可以,尽管我无法检查,因为调用失败

到目前为止:

open System
open System.Runtime.InteropServices
open System.Text
open Microsoft.FSharp.NativeInterop

#r "FSharp.PowerPack.dll" 
#nowarn "51"

module Sweph =

    [<DllImport(@"swedll32.dll", CharSet = CharSet.Ansi, EntryPoint = "swe_calc_ut")>]
    extern int32 ext_swe_calc_ut(double tjd_ut, int32 ipl, int32 iflag, double *xx, StringBuilder serr);
    /// <param name="jdnr">Julian day</param>
    /// <returns>Array with 6 doubles: 0:longitude, 1:latitude, 2:distance,3:speel in longitude, 
    ///          4: speed in latitude, 5: speed in distance </returns>


let ar: double array = Array.zeroCreate 6
let argx = PinnedArray.of_array ar

printfn "  ar: %A" ar

// This fails with a "FileLoadException"
printfn "ar: %A" argx

// Details of FileLoadException:
(*
程序在这一点上崩溃(控制台窗口消失,在调试过程中,它只是跳回第一行)

我知道我可以使用“use”而不是“let”加上“let argx=pinnedaray.of_array ar”,但是编译器不允许我使用它,因为顶部有一个模块声明

在C#中有这样一个实现:

    public static double[] getPlanet(int ipl, double jdnr) {
        //   String ephePath = "Q:\\sweph\\";
        //   Sweph.setEphePath(ephePath);
        double[] xx2 = new double[8];
        double[] xx = new double[6];
        String serr = "";
        int iflag = Constants.SEFLG_SPEED;
        long iflgret = ext_swe_calc_ut(jdnr, ipl, iflag, xx, serr);
        for (int i = 0; i < 6; i++) { 
            xx2[i] = xx[i]; 
        }
        iflag = Constants.SEFLG_SWIEPH | Constants.SEFLG_SPEED | Constants.SEFLG_EQUATORIAL;
        iflgret = ext_swe_calc_ut(jdnr, ipl, iflag, xx, serr);
        xx2[6] = xx[0];
        xx2[7] = xx[1];

        return xx2;
    }
publicstaticdouble[]getPlanet(intipl,doublejdnr){
//字符串ephePath=“Q:\\sweph\\”;
//斯威夫.塞特弗帕斯(以弗帕斯);
double[]xx2=新的double[8];
double[]xx=新的double[6];
字符串serr=“”;
int iflag=常数。SEFLG_速度;
长iflgret=外部计算(jdnr、ipl、iflag、xx、serr);
对于(int i=0;i<6;i++){
xx2[i]=xx[i];
}
iflag=Constants.SEFLG_SWIEPH | Constants.SEFLG_SPEED | Constants.SEFLG_赤道;
iflgret=外部计算(jdnr、ipl、iflag、xx、serr);
xx2[6]=xx[0];
xx2[7]=xx[1];
返回xx2;
}
也许整个问题都要追溯到FileLoad异常(即使在dll调用中没有显示)——可能是因为FSharp Powerpack


非常感谢您的帮助。

您可以尝试使用
System.Runtime.Interop
命名空间中的功能,而不是依赖F#PowerPack。我想您应该尝试以下方法:

let hndl = GCHandle.Alloc(ar, GCHandleType.Pinned)
let ptr : double nativeptr = 
    hndl.AddrOfPinnedObject() 
    |> NativePtr.ofNativeInt

let ret_calc = Sweph.ext_swe_calc_ut(4700.0,1,1,ptr,sb)

hndl.Free()

但是,看起来C代码使用了不同的互操作签名—它将
xx
封送为
double[]
,将
serr
封送为
字符串
(看起来它可能返回
int64
)。如果该代码有效,您可能希望在F#…

中执行相同的操作。根据C类型签名和我找到的。它可以编译,但您必须告诉我它是否有效,因为我没有
swedll32.dll
程序集。此外,我的代码不需要F#Powerpack程序集

编辑:只需阅读@kvb答案下的注释——他建议我在代码中包含相同的内容,即带有
SizeConst
属性集的
[]
属性。我还添加了
[]
,因为最后两个参数用作返回值;IIRC,它还影响编组行为

编辑2:根据@wolfgang的报告,从
Marshallas
属性中删除了
ExactSpelling=true

[<DllImport(@"swedll32.dll",
    CharSet = CharSet.Ansi,
    EntryPoint = "swe_calc_ut")>]
extern int32 swe_calc_ut (
    float tjd_ut,
    int32 ipl,
    int32 flag,
    [<Out; MarshalAs(UnmanagedType.LPArray, SizeConst = 6)>]
    float[] xx,
    [<Out; MarshalAs(UnmanagedType.LPStr, SizeConst = 256)>]
    System.Text.StringBuilder serr)

// Wrapper function for swe_calc_ut
let swe_calc_ut_wrapper (tjd_ut, ipl, flag) =
    let positions = Array.zeroCreate 6
    let errorSB = System.Text.StringBuilder (256)
    let result = swe_calc_ut (tjd_ut, ipl, flag, positions, errorSB)
    if result < 0 then
        // Error
        Choice2Of2 (result, errorSB.ToString ())
    else
        Choice1Of2 positions
[]
外部int32软件计算(
浮动tjd_ut,
int32 ipl,
int32标志,
[]
浮动[]xx,
[]
System.Text.StringBuilder(serr)
//swe_calc_ut的包装函数
让swe_calc_ut_包装(tjd_ut,ipl,标志)=
让positions=Array.zeroCreate 6
设errorSB=System.Text.StringBuilder(256)
let result=swe_calc_ut(tjd_ut,ipl,标志,位置,错误b)
如果结果<0,则
//错误
选择2of2(结果,errorSB.ToString())
其他的
选择1of2位置

也许可以在没有pinnedaray的情况下完成?这可能会完全避免问题-但内存分配仍然有效吗?非常感谢,我会尝试一下。关于int64:我也这么认为,但它说的是“ext_def(int32)”在C标题中。当我意识到FSharpPowerpack提供了两种下载后,FileLoadException消失了:旧的带有直接链接,新的(用于FS 3.0)通过NuGet。对不起,但我是新手-你的封送解决方案看起来怎么样?没有尝试过。不熟悉F#。@Wolfgang-你说什么“句柄构造不起作用”?与以前相同的错误?编译时错误?不同的运行时错误?@Wolfgang-至于签名,我的建议是将
double*xx
更改为
double[]xx
StringBuilder-serr
string-serr
,然后直接传递数组,而不是处理指针。看起来像是巫术。凌晨4点。将尝试。Wohoo!Yahoo!它编译了!你们太棒了!有“给你们买啤酒”按钮吗?:-)(只需删除“精确拼写”选项。)将把这封信寄给瑞士星历的制作者,以避免后世的烦恼;-)来自瑞士的快乐神学家,为他的康复论文寻找“伯利恒之星”的组合
[<DllImport(@"swedll32.dll",
    CharSet = CharSet.Ansi,
    EntryPoint = "swe_calc_ut")>]
extern int32 swe_calc_ut (
    float tjd_ut,
    int32 ipl,
    int32 flag,
    [<Out; MarshalAs(UnmanagedType.LPArray, SizeConst = 6)>]
    float[] xx,
    [<Out; MarshalAs(UnmanagedType.LPStr, SizeConst = 256)>]
    System.Text.StringBuilder serr)

// Wrapper function for swe_calc_ut
let swe_calc_ut_wrapper (tjd_ut, ipl, flag) =
    let positions = Array.zeroCreate 6
    let errorSB = System.Text.StringBuilder (256)
    let result = swe_calc_ut (tjd_ut, ipl, flag, positions, errorSB)
    if result < 0 then
        // Error
        Choice2Of2 (result, errorSB.ToString ())
    else
        Choice1Of2 positions