2016-08-28 11 views
3

私は使用しているアプリケーションでプラグインとして動作するネイティブの32ビットdll(ソースなし)を取得しました。私はプラグインのコントロールを作成して更新するために、プラグインと通信する別のネイティブDLLを自分で実行しました。 そのDLLから、私のC#アプリケーション(p/invoke)からプラグインを制御するために必要な機能をエクスポートしました。私のC++とC#のinteropが64ビットでクラッシュするのはなぜですか?ポインタサイズ?

ここのコードです:

Hファイル:

#pragma once 

#include "include\SpoutControls.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:

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#コード

#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#のコードですが、フレーム内でプリコンパイルせずに実行される(vvvv)、私は入力(FType、FSenderName)と出力(FF、FS、FP、FT)のホスト固有のデカルタレーションを削除して、混乱を避けました。これらは、このコードを他の機能と「接続」するために使用されます。評価はホストによってすべてのフレームと呼ばれます。

は、今、実際の質問(複数可)に:

それは32ビットで、これまで正常に動作していますが、64に任意のメッセージを表示せずに私のC#のホストがクラッシュビット。いくつかの読書の後私は32/64bitシステムでは異なるポインタサイズが原因だと信じていますが、実際にここに当てはまる場合はどうすればよいか正確にはわかりません。あなたは

  • は、このコードは64ビット
  • ポイントにあなたは私は完全に新たなんだway-に沿って見つけるかもしれない他の過ちを実行するために取得する方法(と理由)私を説明することができる場合、私は非常に感謝するでしょうC++の初心者でもありますので、ここで改善すべき点はかなりあると確信しています。特に:メモリリークとC++からc#への値の受け渡し、またはその逆... uiuiui。私は私が試した最後のものは

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

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

    から変更することがあるので、私は、64ビットのintへのポインタをキャストしてはならないことを理解しました

しかし運がないので、これが正しい改善(?)であっても、私は元の問題を投稿しています。

EDIT:1つの不明な点を指摘するための@dkackmanのおかげです。私のcppコードは、ネイティブの32ビットDLLをソースコード(SpoutControls.h)として使用する関数を呼び出します。これは32ビットdll自体のソースではありませんが、(私が知る限り)32ビットdllと同じ共有メモリにアクセスするために使用される関数を宣言します。 これが問題の可能性がある場合は、ここにコードをコピーしてコピーすることもできます。 もhere

はあなたに感謝しています。

+2

なぜポインタを渡す必要がありますか?それだけで面倒な、エラーが発生しやすいコードがたくさんあります。 –

+0

これは、管理対象コードと非管理対象コードの間でfloat/double/stringsの配列を渡すことがわかった(唯一の)方法です。私は正しい方向に私を案内してくれますか、何が欠けていますか? – digitalWannabe

+0

をdkackmanとして以下に示すように、32ビットDLLを64ビットプロセスにロードすることはできません。 32ビットDLLを読み込み、2つのプロセス間でipcを実行するか、C#コードを32ビットのみにコンパイルして64ビットOS上でも32ビットを実行できるように、64ビットで別の32プロセスを作成する必要があります。 – GreatAndPowerfulOz

答えて

6

あなたは運が悪いと思います。あなたのプロセスが64ビットであれば、どれくらい試しても、その32ビットのdllをロードすることはできません。https://msdn.microsoft.com/en-us/library/windows/desktop/aa384231(v=vs.85).aspx 64ビットWindowsで

から

Can I load a 32 bit DLL into a 64 bit process on Windows?

、64ビットプロセスは、32ビットのダイナミックリンク ライブラリ(DLL)をロードすることができません。

ホストを32ビットに変換するか、32ビットプロセスで32ビットプラグインをホストする方法と、64ビットから何らかの種類のIPCを使用して通信する方法がありますホストプロセス。

私の推測では、これはあなたのラッパー、配列渡しまたはinteropコードとは関係がないということです。

+0

これが不明な場合はごめんなさい:ネイティブ32ビットDLLはプラグインとしてホストアプリケーションに正常にロードされますが、私はC#64ビットアプリケーションでロードする必要はありません。私は、C#64ビットコードがC++ 64ビットdllへのポインタを介して値を渡すときに問題が発生したと考えています。それ自体は(afaik)32ビットdllの共有メモリに値を書き込みます。私の質問が更新され、これが明確になります。ありがとう – digitalWannabe

+1

明らかにすることができます:あなたのホストプロセスは64または32ビットですか?もしそうなら、その32ビットdllをロードする方法はありません。そうでない場合は、64ビットへの参照がどこから来ているのかはわかりません。 32ビットプロセスは、64ビットOSで動作していても、依然として32ビットプロセスです。コンパイルされたバイナリのビット数を同じプロセスで混在させることはできません。 – dkackman

+0

私は32ビットアプリケーションで32ビットDLLを実行しています。常に。 32ビットまたは64ビットのどちらでも実行できる別の(C#)アプリケーションと通信したい。このアプリケーションは上記のC#コードを実行し、私が行ったdllを呼び出します(上記のC++、32ビットまたは64ビットのいずれかにコンパイルされます)。 64ビットバージョンではC#ホストがクラッシュします。 私は理論的にはこれがうまくいくことを知っています。値の代わりにテクスチャを共有する私のC#ホスト用の同様のプラグインがあり、C#側の32/64bitと受信側の32ビットの両方で動作します。 – digitalWannabe

関連する問題