7

ネイティブのC++アプリケーションがありますが、当面は、コマンドライン文字列と現在のマウスカーソルの座標をWPFアプリケーションに送信するだけで済みます。IntPtrメッセージは正常に送受信されますが、C#のインスタンスを構造体に変換できません。

これを行おうとすると、アプリケーションが例外なくクラッシュするか、アプリケーションを変換するコード行がスキップされ、ループ内の次のメッセージが受信されます。これはおそらくネイティブ例外が発生していることを意味しますが、理由はわかりません。

これがC++プログラムです。当面は、コマンドライン文字列を無視し、動作を確認するために偽のカーソル座標を使用します。

#include "stdafx.h"
#include "StackProxy.h"
#include "string"

typedef std::basic_string<WCHAR, std::char_traits<WCHAR>> wstring;

struct StackRecord
{
    //wchar_t CommandLine[128];
    //LPTSTR CommandLine;
    //wstring CommandLine;
    __int32 CursorX;
    __int32 CursorY;
};

int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
    COPYDATASTRUCT data;
    ZeroMemory(&data, sizeof(COPYDATASTRUCT));

    StackRecord* record = new StackRecord();

    wstring cmdLine(lpCmdLine);
    //record.CommandLine = cmdLine;
    record->CursorX = 5;
    record->CursorY = 16;
    data.dwData = 12;
    data.cbData = sizeof(StackRecord);
    data.lpData = record;

    HWND target = FindWindow(NULL, _T("Window1"));

    if(target != NULL)
    {
        SendMessage(target, WM_COPYDATA, (WPARAM)(HWND) target, (LPARAM)(LPVOID) &data);
    }
    return 0;
}

そして、これがメッセージを受信するWPFアプリケーションの一部です。全体がクラッシュしない場合は、IFステートメント内の2行目がスキップされます。

    public IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
    {
        if (msg == Interop.WM_COPYDATA)
        {
            var data = (Interop.CopyDataStruct)Marshal.PtrToStructure(lParam, typeof(Interop.CopyDataStruct));
            var record = (Interop.StackRecord)Marshal.PtrToStructure(data.lpData, typeof(Interop.StackRecord));
            MessageBox.Show(String.Format("X: {0}, Y: {1}", record.CursorX, record.CursorY));
        }
        return IntPtr.Zero;
    }

そして、これが構造体のC#定義です。私はマーシャリング属性を際限なくいじって、どこにも行きませんでした。

internal static class Interop
{
    public static readonly int WM_COPYDATA = 0x4A;

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct CopyDataStruct
    {
        public IntPtr dwData;
        public int cbData;
        public IntPtr lpData;
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 1)]
    public struct StackRecord
    {
        //[MarshalAs(UnmanagedType.ByValTStr)]
        //public String CommandLine;
        public Int32 CursorX;
        public Int32 CursorY;
    }
}

何か案は?

4

2 に答える 2

7

セットアップに関する詳細情報がなければ、必ずしも何が間違っているのかわかりません。コードを可能な限り複製し(WPFアプリでWndProcを使用し、自分のwin32アプリから送信)、正常に機能します。64ビットアプリケーションを実行している場合に明らかに発生するエラーがいくつかあります。つまり、Pack = 1の場合、COPYDATASTRUCTの位置がずれ、ポインタからの読み取りが困難になる可能性があります。

intsだけを通過してクラッシュしていますか?コメントされたコードを見てLPWSTRまたはwstringを渡すと、深刻な問題が発生しますが、送信されたデータをアンマーシャリングするまで、それは明らかにならないはずです。

価値があるのは、これは私のコードのスニペットであり、コマンドラインを横切ることを含めて私にとってはうまくいくようです。

/* C++ code */
struct StackRecord
{
    wchar_t cmdline[128];
    int CursorX;
    int CursorY;
};

void SendCopyData(HWND hFind)
{
    COPYDATASTRUCT cp;
    StackRecord record;

    record.CursorX = 1;
    record.CursorY = -1;

    _tcscpy(record.cmdline, L"Hello World!");
    cp.cbData = sizeof(record);
    cp.lpData = &record;
    cp.dwData = 12;
    SendMessage(hFind, WM_COPYDATA, NULL, (LPARAM)&cp);
}

/* C# code */
public static readonly int WM_COPYDATA = 0x4A;

[StructLayout(LayoutKind.Sequential)]
public struct CopyDataStruct
{
    public IntPtr dwData;
    public int cbData;
    public IntPtr lpData;
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct StackRecord
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=128)]
    public string CommandLine;
    public Int32 CursorX;
    public Int32 CursorY;
}

protected override IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
    if (msg == WM_COPYDATA)
    {
        StackRecord record = new StackRecord();
        try
        {
            CopyDataStruct cp = (CopyDataStruct)Marshal.PtrToStructure(lParam, typeof(CopyDataStruct));
            if (cp.cbData == Marshal.SizeOf(record))
            {
                record = (StackRecord)Marshal.PtrToStructure(cp.lpData, typeof(StackRecord));
            }
        }
        catch (Exception e)
        {
            System.Diagnostics.Debug.WriteLine(e.ToString());
        }
        handled = true;
    }
    else
    {
        handled = false;
    }
    return IntPtr.Zero;
}
于 2009-12-14T22:32:08.007 に答える
3

私はいくつかのアプリケーション(それぞれVC ++とVC#を使用)を構築し、問題の「煮詰められた」バリアント(つまり、その構造体を取得できない)に対処しましたが、それらはスムーズに機能しているように見えるので、実際には何かかもしれませんtyranidが言うように、セットアップで。

とにかく、ここにコードがあります(新しく作成されたWIN32アプリケーション(VC ++の場合)およびC#のWINDOWS FORMSアプリケーションに貼り付けて実行およびテストするだけで十分です):

StackProxy.cpp

#include "stdafx.h"
#include "StackProxy.h"
#include <string>


struct StackRecord {
    __int32 CursorX;
    __int32 CursorY;
};


int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) {
    StackRecord record;

    record.CursorX = 5;
    record.CursorY = 16;

    COPYDATASTRUCT data;

    data.dwData = 12;
    data.cbData = sizeof(StackRecord);
    data.lpData = &record;

    HWND target = FindWindow(NULL, _T("Window1"));

    if(target != NULL)
        SendMessage(target, WM_COPYDATA, (WPARAM)(HWND) target, (LPARAM)(LPVOID) &data);

    return 0;
}

Form1.cs

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

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public struct COPYDATASTRUCT
        {
            public System.Int32 dwData;
            public System.Int32 cbData;
            public System.IntPtr lpData;
        }

        int WM_COPYDATA = 0x4A;

        [StructLayout(LayoutKind.Sequential)]
        public struct StackRecord
        {
            public Int32 CursorX;
            public Int32 CursorY;
        }

        public Form1()
        {
            InitializeComponent();
            Text = "Window1";
        }

        protected override void WndProc(ref Message msg)
        {
            if (msg.Msg == WM_COPYDATA) {
                COPYDATASTRUCT cp = (COPYDATASTRUCT)Marshal.PtrToStructure(msg.LParam, typeof(COPYDATASTRUCT));
                StackRecord record = (StackRecord)Marshal.PtrToStructure(cp.lpData, typeof(StackRecord));
                MessageBox.Show(String.Format("X: {0}, Y: {1}, Data: {2}", record.CursorX, record.CursorY, cp.dwData));
            } 
            base.WndProc(ref msg);
        }
    }
}

お役に立てれば。

PS私はC#と(特に)相互運用機能(主にC ++プログラミングに興味を持っています)についてあまり知識がありませんが、[数時間前]誰も答えを見ていないので、この問題を試すのはいい挑戦だと思いました。賞金は言うまでもありません:)

*午前、私は遅れています:))

于 2009-12-15T00:37:19.710 に答える