开发者

passing float array from c# to ocx written in vc++6

I have an old ocx (spectrograph.ocx) written in VC++6. It contains a method called AppendDataX() that is defined as follows:

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

I am trying to write a new C#.NET win32 application using this old ocx control. I have used the following command,

AxImp spectrograph.ocx

to produce AxSPECTROGRAPHLib.dll. I can import the control (via the newly created .dll) into my IDE (SharpDevelop) where I can add it to a form like any other control. So far so good, until I try to pass a float[] to the ocx method 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();

This generates the following error during compile:

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

I have used the MSIL disassembler to generate the AxSPECTROGRAPHLib.il and I get this:

  .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]SPECTROGRA开发者_开发知识库PHLib._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

I have been searching and searching for a simple example showing marshalling from a float[] from c# to a vc6++ ocx but I haven't found an example yet that works for me. Can anyone help lead me in the right direction... I feel like I'm on the right track and that this really shouldn't be this hard to do but I feel like I'm stuck after looking at this for several days now.


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

That's a problem, that's not an Automation compatible function signature. Arrays must be passed as a SafeArray and the function must return an HRESULT. Right now, the type library importer has no way guess that the first argument is an array, it could just as easily be a pointer to a single float value. Which is what it guessed at, ref float.

If you cannot change the native code then you can technically edit the interop library that was generated and change the signature to use float[]. Your disassembly of it is very strange btw, never seen this before. The CLR normally generates the COM stubs dynamically from the declaration of the function in the interop library. No real clue how you got what you posted.

Technically it is possible to get module exports into a type library. That however is not an OCX. It does however explain the non-Automation compatible signature and the IL stub. In that case, it might be easier to create a small C++/CLI ref class wrapper that uses the exported function directly rather than using the type library. Converting an array to a float* is easy with pin_ptr<>.


Well if the control wants literally the address of the first element, you can always pin it and return the address:

var handle=GCHandle.Alloc( spectrum, GCHandleType.Pinned );
unsafe
{
    float *val=(float *)handle.AddrOfPinnedObject();
    // here's the val to send to your object
}
handle.Free();


I have encountered this problem recently. And I found a solution HERE. Making a helper dll to invoke the actual function with SAFEARRAY type.

Note that I didn't try the workaround, since I got access to the source of my ocx control, I just modify the pointer parameter to SAFEARRAY type. And to do that HERE is a detailed example.

I also tried to modify the IL of the InterOP Classes and recompile, as described HERE but that method not work for me. May be I do it wrong.

I had driven crazy by this issue just like you, so I hope you can get out of that.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜