1

我有一个用 VC++6 编写的旧 ocx (spectrograph.ocx)。它包含一个名为 AppendDataX() 的方法,定义如下:

afx_msg void AppendDataX(float FAR* data, long n, float xpos);

我正在尝试使用这个旧的 ocx 控件编写一个新的 C#.NET win32 应用程序。我使用了以下命令,

AxImp spectrograph.ocx

生成 AxSPECTROGRAPHLib.dll。我可以将控件(通过新创建的 .dll)导入到我的 IDE (SharpDevelop) 中,在那里我可以像任何其他控件一样将其添加到表单中。到目前为止一切顺利,直到我尝试将 float[] 传递给 ocx 方法 AppendDataX():

        FileStream tw = new FileStream("XX-YY-ZZZZ.2011.01.10.15.52.00.spec", FileMode.Open);
        BinaryReader br = new BinaryReader(tw);
        int pixelCnt = br.ReadInt32();
        float[] wavelength = new float[pixelCnt];
        for (int i=0; i<pixelCnt; i++)
            wavelength[i] = br.ReadSingle();

        bool eof = false;
        float temp;
        float[] spectrum = new float[pixelCnt];
        while(!eof)
        {
            try
            {
                temp = br.ReadSingle();
                for (int i=0; i<pixelCnt; i++)
                    spectrum[i] = br.ReadSingle();

                spec.AppendDataX(spectrum, pixelCnt, temp);
            }
            catch(EndOfStreamException)
            {
                eof = true;
            }
        }
        tw.Close();

这会在编译期间生成以下错误:

Argument '1': cannot convert from 'float[]' to 'ref float' (CS1503)

我使用了 MSIL 反汇编程序来生成 AxSPECTROGRAPHLib.il,我得到了这个:

  .method public hidebysig newslot virtual 
      instance void  AppendDataX(float32& data,
                                 int32 n,
                                 float32 xPos) cil managed
{
// Code size       35 (0x23)
.maxstack  8
IL_0000:  ldarg.0
IL_0001:  ldfld      class [SPECTROGRAPHLib]SPECTROGRAPHLib._DSpectrograph AxSPECTROGRAPHLib.AxSpectrograph::ocx
IL_0006:  brtrue.s   IL_0014

IL_0008:  ldstr      "AppendDataX"
IL_000d:  ldc.i4.0
IL_000e:  newobj     instance void [System.Windows.Forms]System.Windows.Forms.AxHost/InvalidActiveXStateException::.ctor(string,
                                                                                                                         valuetype [System.Windows.Forms]System.Windows.Forms.AxHost/ActiveXInvokeKind)
IL_0013:  throw

IL_0014:  ldarg.0
IL_0015:  ldfld      class [SPECTROGRAPHLib]SPECTROGRAPHLib._DSpectrograph AxSPECTROGRAPHLib.AxSpectrograph::ocx
IL_001a:  ldarg.1
IL_001b:  ldarg.2
IL_001c:  ldarg.3
IL_001d:  callvirt   instance void [SPECTROGRAPHLib]SPECTROGRAPHLib._DSpectrograph::AppendDataX(float32&,
                                                                                                int32,
                                                                                                float32)
IL_0022:  ret
} // end of method AxSpectrograph::AppendDataX

我一直在搜索和搜索一个简单的示例,该示例显示从 c# 的 float[] 编组到 vc6++ ocx,但我还没有找到适合我的示例。任何人都可以帮助我朝着正确的方向前进......我觉得我在正确的轨道上,这真的不应该这么难,但我觉得我看了几天后就被困住了.

4

3 回答 3

1
afx_msg void AppendDataX(float FAR* data, long n, float xpos);

这是一个问题,这不是自动化兼容的函数签名。数组必须作为 SafeArray 传递,并且函数必须返回 HRESULT。现在,类型库导入器无法猜测第一个参数是一个数组,它可以很容易地成为一个指向单个浮点值的指针。这是它的猜测,参考浮动。

如果您无法更改本机代码,那么您可以从技术上编辑生成的互操作库并将签名更改为使用 float[]。顺便说一句,您对它的拆卸奇怪,以前从未见过。CLR 通常从互操作库中的函数声明动态生成 COM 存根。不知道你是如何得到你发布的内容的。

从技术上讲,可以将模块导出到类型库中。然而,这不是OCX。然而,它确实解释了非自动化兼容的签名和 IL 存根。在这种情况下,创建一个直接使用导出函数而不是使用类型库的小型 C++/CLI 引用类包装器可能更容易。使用 pin_ptr<> 可以轻松将数组转换为 float*。

于 2011-01-17T21:46:03.047 回答
0

好吧,如果控件确实想要第一个元素的地址,您可以随时固定它并返回地址:

var handle=GCHandle.Alloc( spectrum, GCHandleType.Pinned );
unsafe
{
    float *val=(float *)handle.AddrOfPinnedObject();
    // here's the val to send to your object
}
handle.Free();
于 2011-01-17T21:09:42.180 回答
0

我最近遇到了这个问题。我在这里找到了解决方案。制作一个辅助 dll 来调用具有 SAFEARRAY 类型的实际函数。

请注意,我没有尝试解决方法,因为我可以访问我的 ocx 控件的源,我只是将指针参数修改为 SAFEARRAY 类型。为此,这里有一个详细的示例。

我还尝试修改 InterOP 类的 IL 并重新编译,如此处所述,该方法对我不起作用。可能是我做错了。

我和你一样被这个问题逼疯了,所以我希望你能摆脱它。

于 2014-07-01T16:59:08.127 回答