我的 c++ 和 c# 互操作在 64 位中崩溃,为什么?指针大小? [英] my c++ and c# interop crashes in 64 bit, why? pointer size?

查看:33
本文介绍了我的 c++ 和 c# 互操作在 64 位中崩溃,为什么?指针大小?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个本机 32 位 dll(无源),它在我使用的应用程序中作为插件运行.我自己做了另一个本机 dll,它将与该插件通信以创建和更新插件的控件.我从那个 dll 中导出了我需要的函数,以便从我的 c# 应用程序(使用 p/invoke)控制插件.

i got a native 32 bit dll (no source) which runs as a plugin in an application i use. I've done another native dll myself which will communicate with that plugin in order to create and update the plugin's controls. From that dll i've exported the functions I need in order to control the plugin from my c# application (with p/invoke).

代码如下:

h 文件:

#pragma once

#include "includeSpoutControls.h"

extern "C" { __declspec(dllexport) void InitializeControls(char *sendername, int *numControls, char** names, int *types, float* floats, float* toggles, float* press, char** text); }
extern "C" { __declspec(dllexport) bool UpdateControls(const char** text, float *floats, float *toggles, float *press, int *numControls); }
extern "C" { __declspec(dllexport) void CloseControls(); }
//
extern "C" __declspec(dllexport) int ReleaseMemory(float *pArray)
{
    delete[] pArray;
    //delete[] Usize;
    return 0;
};

cpp:

#include "SpoutControls4vvvv.h"

//SpoutControls and the functions
//CreateControl, OpenControls, CheckControls, CloseControls
//are declared in SpoutControls.h, which comes with the 32 bit plugin dll
SpoutControls spoutcontrols;

void InitializeControls(char *sendername, int *numControls, char** names, int *types, float* floats, float* toggles, float* press, char** text) {

    int Vcontrols = numControls[0];
    int Tcontrols = numControls[1];
    int Pcontrols = numControls[2];
    int Scontrols = numControls[3];

    int all = Vcontrols + Tcontrols + Pcontrols + Scontrols;
    int v=0, t=0, p=0, s = 0;

    for (int controlID = 0; controlID < all; controlID++) {

        if (types[controlID] == 0) {
            spoutcontrols.CreateControl(names[controlID], "float",0.0,1.0, floats[v]);
            v++;
        }
        if (types[controlID] == 1) {
            spoutcontrols.CreateControl(names[controlID], "bool", toggles[t]);
            t++;
        }
        if (types[controlID] == 2) {
            spoutcontrols.CreateControl(names[controlID], "event", press[p]);
            p++;
        }
        if (types[controlID] == 3) {
            spoutcontrols.CreateControl(names[controlID], "text", text[s]);
            s++;
        }

    }

    spoutcontrols.OpenControls(sendername);
}


bool UpdateControls(const char** text, float *floats, float *toggles, float *press, int *numControls) {
    int Vcontrols = numControls[0];
    int Tcontrols = numControls[1];
    int Pcontrols = numControls[2];
    int Scontrols = numControls[3];

    int all = Vcontrols + Tcontrols + Pcontrols + Scontrols;
    int v = 0, t = 0, p = 0, s = 0;



    if (spoutcontrols.CheckControls(myControls)) {

        for (int controlID = 0; controlID < all; controlID++) {

            if (myControls[controlID].type == 10) {
                floats[v] = myControls[controlID].value;
                v++;
            }
            if (myControls[controlID].type == 0) {
                toggles[t] = myControls[controlID].value;
                t++;
            }
            if (myControls[controlID].type == 1) {
                press[p] = myControls[controlID].value;
                p++;
            }
            if (myControls[controlID].type == 100) {
                text[s] = myControls[controlID].text.data();
                s++;
            }

        }
        return true;
    }
    return false;
}

void CloseControls() {
    spoutcontrols.CloseControls();
}

这里是 c# 代码:

public unsafe class SystemSpoutSenderNode: IDisposable
    {

        [System.Runtime.InteropServices.DllImport("SpoutControls4vvvv.dll")]
        private static extern void InitializeControls(IntPtr sendername, IntPtr numControls,String[] names, IntPtr types, IntPtr floats, IntPtr toggles, IntPtr press, String[] text);
        [System.Runtime.InteropServices.DllImport("SpoutControls4vvvv.dll")]
        private static extern int CloseControls();
        [System.Runtime.InteropServices.DllImport("SpoutControls4vvvv.dll", CallingConvention = CallingConvention.Cdecl)]
        private static extern bool UpdateControls([In, Out] String[] text, [In, Out] float[] floats,  [In, Out] float[] toggles, [In, Out] float[] press, IntPtr numControls);
        [System.Runtime.InteropServices.DllImport("SpoutControls4vvvv.dll")]
        private static extern int ReleaseMemory(IntPtr ptr);


    public void Evaluate(int SpreadMax)
            {           
                        //countControls determines number of controls per type (string,float,toggle,click)                                  
                        int[] controls = countControls(FType);
                        //sumControls will just add up all elements in controls
                        int all = sumControls(controls);

                        //in my code these arrays will get filled with values, deleted here for readability         
                        String[] names = new String[all];   
                        int[] types = new int[all]; 
                        float[] floats = new float[controls[0]];
                        float[] toggles = new float[controls[1]];
                        float[] press = new float[controls[2]];

                        String[] text = new String[controls[3]];

                        //initialze return arrays
                        String[] Rtext = new String[controls[3]];
                        float[] Rfloats = new float[controls[0]];
                        float[] Rtoggles = new float[controls[1]];
                        float[] Rpress = new float[controls[2]];

                        //allocate pointers
                        IntPtr SndrNamePtr = NativeUtf8FromString(FSenderName);
                        IntPtr BinPtr = Marshal.AllocHGlobal(4*sizeof(int));                
                        IntPtr TypePtr = Marshal.AllocHGlobal(all*sizeof(int));
                        IntPtr FloatPtr = Marshal.AllocHGlobal(controls[0]*sizeof(float));
                        IntPtr TogglePtr = Marshal.AllocHGlobal(controls[1]*sizeof(float));
                        IntPtr PressPtr = Marshal.AllocHGlobal(controls[2]*sizeof(float));

                        try
                            {           
                            //copy control info + defaults to pointer   
                            Marshal.Copy(controls, 0, BinPtr, 4);
                            Marshal.Copy(types, 0, TypePtr, all);
                            Marshal.Copy(floats, 0, FloatPtr, controls[0]);
                            Marshal.Copy(toggles, 0, TogglePtr, controls[1]);
                            Marshal.Copy(press, 0, PressPtr, controls[2]);

                            //initialize controls   
                            if (FWrite) InitializeControls(SndrNamePtr,BinPtr,names,TypePtr,FloatPtr,TogglePtr,PressPtr,text);

                            //update controls
                            bool changed = UpdateControls(Rtext,Rfloats,Rtoggles,Rpress,BinPtr);


                            //FF, FT, FS and FP are the outputs in my c# host
                            if (changed){

                                for(int j=0; j<controls[0];j++){
                                FF[j]=Rfloats[j];
                                }           
                                for(int j=0; j<controls[1];j++){
                                FT[j]=FloatToBool(Rtoggles[j]);
                                }
                                for(int j=0; j<controls[3];j++){
                                FS[j]=Rtext[j];
                                }
                            }

                            for(int j=0; j<controls[2];j++){
                                FP[j]=FloatToBool(Rpress[j]);
                                }

                            }

                        finally
                        {
                            Marshal.FreeHGlobal(SndrNamePtr);
                            Marshal.FreeHGlobal(BinPtr);
                            Marshal.FreeHGlobal(FloatPtr);
                            Marshal.FreeHGlobal(TogglePtr);
                            Marshal.FreeHGlobal(PressPtr);  
                        }
                    }
                }   
            }

            public void Dispose()
            {
                CleanUp();
                CloseControls();
            }
}

注意:c# 代码无需预编译即可在基于框架的 c# 主机环境中运行以进行图形编程 (vvvv),因此,我删除了主机特定的输入(FType、FSenderName)和输出(FF、FS、FP、FT)的声明以避免混淆.这些将用于将此代码与其他功能连接".主机会在每一帧调用 Evaluate.

NOTE: the c# code runs without precompiling in a frame-based, c# host environment for graphical programming (vvvv), therefore i've deleted host specific decalarations of inputs (FType,FSenderName) and outputs (FF,FS,FP,FT) to avoid confusion. These will be used to "connect" this code with other functionality. Evaluate will be called every frame by the host.

现在进入实际问题:

到目前为止,它在 32 位中运行良好,但在 64 位中,我的 c# 主机在没有任何消息的情况下崩溃.经过一些阅读,我相信这是由于 32/64 位系统中的指针大小不同,但我不确定该怎么做/如果这真的适用于这里.如果可以,我将不胜感激

it's working fine so far in 32 bit, but in 64 bit my c# host crashes without any message. after some reading i believe this is due to pointer sizes being different in 32/64bit systems, but i'm not exactly sure what to do/if this actually applies here. I would be very thankful if you could

  • 解释如何(以及为什么)让这段代码在 64 位中运行
  • 指出您在此过程中可能发现的任何其他错误 - 我对 C++ 完全陌生,并且仍然是 C# 的初学者,所以我非常有信心这里有很多需要改进的地方;特别是:内存泄漏并将值从 c++ 传递到 c#,反之亦然......uiuiui.

我知道我不应该将指针转换为 64 位的 int,所以我尝试的最后一件事是从

I've understood that I shouldn't cast a pointer to an int in 64 bit, so the last thing I've tried is to change from

int Vcontrols = numControls[0];
int Tcontrols = numControls[1];
int Pcontrols = numControls[2];
int Scontrols = numControls[3];

int Vcontrols = (INT_PTR)numControls[0];
int Tcontrols = (INT_PTR)numControls[1];
int Pcontrols = (INT_PTR)numControls[2];
int Scontrols = (INT_PTR)numControls[3];

但没有运气,因此我发布了我原来的问题,即使这是一个正确的改进(?).

but with no luck, therefore I'm posting my original problem, even if this is a correct improvement(?).

感谢@dkackman 指出一个不明确的点:我的 cpp 代码调用作为源代码 (SpoutControls.h) 和本机 32 位 dll 提供的函数.它不是 32 位 dll 本身的来源,但声明了用于(据我所知)访问与 32 位 dll 相同的共享内存的函数.如果这可能是问题所在,我也可以将代码复制粘贴到此处?也可以在此处

thanks to @dkackman for pointing out one unclear point: my cpp code calls functions which come as source code (SpoutControls.h) with the native 32 bit dll. It's not the source for the 32 bit dll itself but declares the functions used to (as far as i can tell) access the same shared memory as the 32 bit dll. I can also copy paste the code here if this might be the problem? Also can be found here

谢谢.

推荐答案

恐怕你不走运了.如果您的进程是 64 位,则无论您尝试多少次都无法加载该 32 位 dll.

I am afraid you are out of luck. If your process is 64bit, you won't be able to load that 32bit dll, no matter how much you try.

可以我在 Windows 上将 32 位 DLL 加载到 64 位进程中吗?

来自 https:///msdn.microsoft.com/en-us/library/windows/desktop/aa384231(v=vs.85).aspx

在 64 位 Windows 上,64 位进程无法加载 32 位动态链接库 (DLL).

On 64-bit Windows, a 64-bit process cannot load a 32-bit dynamic-link library (DLL).

在无法访问其源代码的情况下,您唯一的选择是将主机转换为 32 位,或者找出如何在 32 位进程中托管 32 位插件并使用某种 IPC 从 64 位主机进程与其通信.

Without access to its source, your only option would be to convert your host to 32bit or otherwise figure out how to host the 32bit plugin in a 32bit process and use some sort of IPC to communicate with it from a 64bit host process.

所以我的猜测是,这与您的包装器、数组传递或互操作代码无关.

So my guess is that this has nothing to do with your wrapper, array passing or interop code.

这篇关于我的 c++ 和 c# 互操作在 64 位中崩溃,为什么?指针大小?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆