2

他のプログラムにメッセージを送信するために共有メモリを利用するc++アプリからのもののように見えるc++コードのブロックが与えられました。

C++コードにはまだ#includeなどがありません。C#アプリケーションで使用するコードが与えられましたが、かなり行き詰まっています。コードの機能はある程度理解していますが、コーディングに慣れていないため、C#に変換するのに十分な知識がありません。

私の質問は、私のプロジェクトでコードの機能を使用できるようにする最も簡単な方法は何ですか?最終的な結果は、別のプログラムにメッセージを送信することです。これにより、私が心配していないことを実行できます。

ソリューションでさまざまなc++プロジェクトとファイルタイプを作成して、後で参照を使用してそれらをリンクしようとしましたが、正しくコンパイルできません。

アドバイスや見どころがあれば教えてください。私はいつでもより多くの情報を提供することができます。

コード(コメントを削除する必要がありました、申し訳ありません)

UINT WM_HELO_ZOOM_XYZ = RegisterWindowMessage("WM_HELO_ZOOM_XYZ");


int HELO_Broadcast_Zoom_Message(
  double dbX,
  double dbY,
  double dbZ,
  UINT uMessage=WM_HELO_ZOOM_XYZ) {

  #ifndef HELO_ 
    typedef struct { 
      UINT uMajVersion; 
      UINT uMinVersion; 
      DWORD dwReserved;
      double dbX;  
      double dbY;
      double dbZ;
    } HELOCoordsStruct;
  #endif


  char *szSharedMemory = "HELO-_Coords"; 
  char szErr[_MAX_PATH*3];
  HANDLE hMem = OpenFileMapping(FILE_MAP_WRITE, FALSE, szSharedMemory); 
  if (NULL == hMem) {
    return(0);
  }

  void *pvHead = MapViewOfFile(hMem, FILE_MAP_WRITE, 0,0,0);
  if (NULL == pvHead)  {
    CloseHandle(hMem);
    sprintf(szErr, "Unable to view", szSharedMemory);
    AfxMessageBox(szErr, MB_OK|MB_ICONSTOP);
    return(0);
  }

  HELOCoordsStruct *pHELOCoords = (HELOCoordsStruct *)pvHead;

  BOOL bVersionOk=FALSE; 

  if (1 == pHELOCoords->uMajorVersion) {

    if (WM_HELO_ZOOM_XYZ==uMessage) { 
      pHELOCoords->dbX = dbX;
      pHELOCoords->dbY = dbY;
      pHELOCoords->dbZ = dbZ;
    }
    bVersionOk=TRUE;
  }
  else {

    sprintf(szErr, "Unrecognized HELO- shared memory version: %d.%d", pHELOCoords->uMajVersion, pHELOCoords->uMinVersion);
    AfxMessageBox(szErr, MB_OK);
  }

  if (NULL != hMem) CloseHandle(hMem);
  UnmapViewOfFile(pvHead);

  if (bVersionOk) {
    PostMessage(HWND_BROADCAST,uMessage,0,0); 
    return(1); 
  }
  else return(0);
}

編集:フィードバックは完全に非現実的です。コミュニティは確かにこのあたりの人々を台無しにしていると言わなければなりません。

ありがとう、ケビン

4

4 に答える 4

4

3つの選択肢があると思います。

  1. クラスライブラリタイプのマネージC++プロジェクトを作成し、その中にコードを配置して、メインアプリからこのプロジェクトへの参照を作成します。
  2. アンマネージC++DLLプロジェクトを作成し、コードを1つまたは複数の関数に配置し、関数をエクスポートして(.defファイルを使用)、プロジェクトをビルドします。属性を使用して、そのdllの関数を使用し[DllImport]ます。(ここここを参照)
  3. コードをC#に変換します。これには、アンマネージコード、Win32およびP / Invokeに関するある程度の知識が必要です(ここここを参照)。そして、私があなたのコードを見ると、それは少し時間がかかります!

変換されたコードは次のとおりです(オプション3)。

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace UnmanagedBlock
{
    public class ConvertedClass
    {
        public uint WM_HELO_ZOOM_XYZ = RegisterWindowMessageA("WM_HELO_ZOOM_XYZ"); // Your code uses the ANSI string

        int HELO_Broadcast_Zoom_Message(
            double dbX, double dbY, double dbZ, uint uMessage) // Porting the default value for 'uMessage' is not possible
        {
            string szSharedMemory = "HELO-_Coords";
            IntPtr hMem = OpenFileMapping(FileMapAccessRights.Write, FALSE, szSharedMemory);
            if (IntPtr.Zero == hMem)
                return 0;
            IntPtr pvHead = MapViewOfFile(hMem, FileMapAccessRights.Write, 0, 0, UIntPtr.Zero);
            if (IntPtr.Zero == pvHead)
            {
                CloseHandle(hMem);
                MessageBox.Show(
                    "Unable to view " + szSharedMemory, // Your code does not concat these two strings.
                    "Error", MessageBoxButtons.OK, MessageBoxIcon.Stop);
                return 0;
            }

            HELOCoordsStruct pHELOCoords = new HELOCoordsStruct();
            Marshal.PtrToStructure(pvHead, pHELOCoords);

            int bVersionOk = FALSE;

            if (1 == pHELOCoords.uMajVersion) // I think it had a typo (it was uMajorVersion)
            {
                if (WM_HELO_ZOOM_XYZ == uMessage)
                {
                    pHELOCoords.dbX = dbX;
                    pHELOCoords.dbY = dbY;
                    pHELOCoords.dbZ = dbZ;
                }
                Marshal.StructureToPtr(pHELOCoords, pvHead, false);
                bVersionOk = TRUE;
            }
            else
            {
                MessageBox.Show(
                    "Unrecognized HELO- shared memory version: " +
                    pHELOCoords.uMajVersion.ToString() + "." + pHELOCoords.uMinVersion.ToString());
            }

            if (IntPtr.Zero != hMem)
                CloseHandle(hMem);
            UnmapViewOfFile(pvHead);

            if (bVersionOk == TRUE)
            {
                PostMessage(HWND_BROADCAST, uMessage, 0, 0);
                return 1;
            }
            else
                return 0;
        }

        [StructLayout(LayoutKind.Sequential)]
        private class HELOCoordsStruct
        {
            public uint uMajVersion;
            public uint uMinVersion;
            public uint dwReserved;
            public double dbX;
            public double dbY;
            public double dbZ;
        }

        [DllImport("user32", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode)]
        public static extern uint RegisterWindowMessageW([In]string lpString);

        [DllImport("user32", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
        public static extern uint RegisterWindowMessageA([In]string lpString);

        [DllImport("kernel32", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Auto)]
        public static extern IntPtr OpenFileMapping(FileMapAccessRights dwDesiredAccess, int bInheritHandle, [In]String lpName);

        [DllImport("kernel32", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Auto)]
        public static extern IntPtr MapViewOfFile(IntPtr hFileMappingObject, FileMapAccessRights dwDesiredAccess, uint dwFileOffsetHigh, uint dwFileOffsetLow, UIntPtr dwNumberOfBytesToMap);

        [DllImport("kernel32", CallingConvention = CallingConvention.StdCall)]
        public static extern int UnmapViewOfFile(IntPtr lpBaseAddress);

        [DllImport("kernel32", CallingConvention = CallingConvention.StdCall)]
        public static extern int CloseHandle(IntPtr hObject);

        [DllImport("user32.dll")]
        public static extern IntPtr PostMessage(IntPtr hWnd, uint msg, int wParam, int lParam);

        public const int FALSE = 0, TRUE = 1;

        public enum FileMapAccessRights : uint
        {
            Write = 0x2,
            Read = 0x4,
            Execute = 0x20,
        }

        public const IntPtr HWND_BROADCAST = (IntPtr)0xffff;
    }
}

私は正確な変換を行い、それはうまくいくはずだと思いますが、私はそれをテストしていません。

動作するかどうか教えてください。

于 2012-05-22T16:22:46.683 に答える
1

C++コードをVisualC++プロジェクトにダンプしてビルドできます。ビルドするときは、プロジェクト設定に移動し、tlbファイルを生成するオプションを選択します(これはc ++ /。net相互運用機能のプロキシクラスであり、オプションの名前を思い出せません)。

これを取得したら、C#プロジェクトからtlb相互運用機能アセンブリへの参照を追加できます。

また、Microsoftの例http://msdn.microsoft.com/en-us/library/fx82zhxa.aspxをここで探してください

于 2012-05-22T16:05:47.547 に答える
1

ここにコードを投稿すると、誰かがコードをC ++からC#に移植してくれる可能性があります。ただし、.NETアプリケーション内からネイティブC ++コードを使用する場合の将来の参照のために、.NET FrameworkのInteropServicesを使用して、ネイティブdllのネイティブ関数を参照できます。

これを行うには、C ++側とC#側の両方でいくつかの手順が必要です。まず、C++でエクスポートされた関数としてエントリポイントを構築する必要があります。

たとえば、2つの数値を足し合わせてC#アプリから呼び出す、簡単なC ++関数を作成したい場合は、次のようにする必要があります。

ステップ1:C++関数を記述します。外部ソースが関数を見つけるためには、関数が「エクスポート」されることをコンパイラに通知する必要があります。注意すべき点は、エクスポートされた関数内から他の関数​​を呼び出す場合、それらすべてをエクスポート済みとしてマークする必要はないということです。

それでは、C++で「add」関数を書いてみましょう。

#define DLLEXPORT extern "C" declspec(dllexport) 

DLLEXPORT int __cdecl add(int x, int y)
{
    return (x + y);
}

最初の行は、エクスポートされたメソッドをマークするために使用するマクロを定義します。このextern "C"部分は、エクスポートされた関数の名前を操作しないようにコンパイラーに指示します(したがって、@ YZadd_のようなものではなく、常に'add'になります)。次に、DLLEXPORTとしてマークされた関数定義が表示されます。続行する前に、エクスポートされた関数の「名前マングリング」についてもう1つポイントがあります。これは、宣言された関数__stdcallまたはそのバリエーション(WINAPI..etc)のいずれかです。エクスポート用にマークされextern "C"、呼び出し規約__stdcallで宣言された関数には、常に関数パラメーターのバイト数が追加され@XますX(したがって、上記の例では、add宣言された__stdcall場合、エクスポートされた関数名は次のようになります。add@8。C#で関数の検索に問題が発生した場合は、この点に注意してください。

これで、C ++側が完了し、それをDLLとしてコンパイルして、C#に移動します。

C#では、外部関数をインポートするのはかなり簡単です。InteropServicesまず、名前空間を参照する必要があります。

using System.Runtime.InteropServices;

[DllImport]次に、宣言を行う必要があります。

[DllImport(@"path to your C++ dll here")]
public static extern int add(int x, int y) //make sure the function definition matches.

関数名が一致していれば、関数をインポートするために必要なのはそれだけです。addこれで、C#の通常の関数と同じように呼び出すことができます。

int x = 5;
int y = 10;
int z = add(x, y); //z should be 10

これで、C ++関数を単純にエクスポートし、C#アプリケーションから呼び出す方法は終わりです。

于 2012-05-22T16:22:08.277 に答える
0

C ++コードをそのまま動作させることができない場合は、C#アプリに移植しようとしても意味がありません。

最初にC++コードを理解します(使用されているAPIのMSDNドキュメントを読み、コードを提供した人に質問し、特定の質問を投稿します)。それをよりよく理解し、それを機能させることができれば、C#で必要なことを行うための最良の方法を見つける可能性が高くなります。

于 2012-05-22T16:07:25.453 に答える