2009-12-11 3 views
7

당분간 명령 줄 문자열과 현재 마우스 커서 좌표를 WPF 응용 프로그램에 보내야하는 네이티브 C++ 응용 프로그램이 있습니다. 메시지는 보내고받을 수 있습니다. 그러나 C#의 IntPtr 인스턴스를 구조체로 변환 할 수 없습니다.WM_COPYDATA를 사용하여 C++에서 WPF로 구조체 보내기

시도 할 때 응용 프로그램이 예외없이 중단되거나 변환하는 코드 줄이 건너 뛰고 루프의 다음 메시지가 수신됩니다. 이것은 아마도 네이티브 예외가 발생했음을 의미하지만 그 이유를 알지 못합니다.

다음은 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 문 안의 두 번째 줄은 건너 뛰었습니다. 모든 것이 충돌하지 않으면 끝납니다.

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; 
    } 
} 

아이디어가 있으십니까?

+0

이 동작은 동일) : 늦었 어. –

답변

7

설정에 대한 추가 정보가 없으면 무엇이 잘못되고 있는지 확실하지 않습니다. WPF 앱에서 WndProc을 사용하여 최선을 다해 코드를 복제했으며, 내 자신의 win32 앱에서 전송했다. 64 비트 응용 프로그램을 실행하는 경우 Packet = 1로 인해 COPYDATASTRUCT가 잘못 정렬되고 포인터에서 읽는 것이 고통에서 종료 될 가능성이있는 몇 가지 오류가 있습니다.

int를 전달하는 데 충돌이 있습니까? 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; 
} 
+0

"즉 Pack = 1이면 COPYDATASTRUCT가 잘못 정렬되고 포인터에서 읽기가 어려워 질 수 있습니다." 아, 이제 분명해. 나는 Pack = 1이 맞는 파일에서 구조체를 읽는 데 익숙하다. C++ 응용 프로그램은 32 비트이지만 64 비트 시스템이 있고 .NET 코드는 JITted 64 비트 코드입니다. 제거 팩 = 1 고정. 감사. "LPWSTR 또는 wstring을 전달하는 주석이 달린 코드를 보면 심각한 문제가 발생할 것입니다." 나는 그럴 것이라고 생각했습니다. 또한 성공하지 못한 것처럼 고정 된 wchar_t 문자열을 전달하려고 시도했지만 위의 문제로 인한 것입니다. –

3

나는 문제의 "삶은 다운"변형을 주소, (++ VC와 VC 번호, 각각) 응용 프로그램의 몇 가지를 구축했습니다 (즉 무능력 그 구조체를 얻을 수), 그들은 flawelessly 작동하는 것 , 그래서 그것은 실제로 당신의 셋업으로 뭔가있을 수 있습니다. tyranid이 말합니다.

어쨌든, 여기에 코드입니다 (그냥() VC++를 위해 새로 만든 Win32 응용 프로그램에 붙여 넣기에 충분해야하며 WINDOWS은 C 실행하기 # 테스트 신청을 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); 
     } 
    } 
} 

희망이 도움이됩니다.

P.나는 C#과 (특히) interop (주로 C++ 프로그래밍에 흥미를 가지고 있음)에 대한 지식이 많지 않지만 [몇 시간 전] 아무도 대답하지 않으면이 문제를 시도하는 것이 좋은 도전이라고 생각했습니다. 현상금 :

을 언급하지 * 그것은 AMN, 내가

나는 또한 윈폼 창에서의 WndProc을 무시하려
+0

아, 고마워. –

관련 문제