2009-12-11 9 views
7

kullanarak gönderme Yerel bir C++ uygulamasına sahip olmak için, zamanının bir komut satırı dizesini ve geçerli fare imleci koordinatlarını bir WPF uygulamasına göndermesi yeterlidir. İleti gönderilir ve yalnızca iyi alınır, ancak C# 'da IntPtr örneğini bir yapıya dönüştüremiyorum.C++ ile WPF arasındaki bir yapılandırmayı WM_COPYDATA

Bunu yapmaya çalıştığımda, uygulama ya istisnasız çökecek ya da dönüştüren kod satırı atlanacak ve döngüdeki bir sonraki ileti alındı. Bu muhtemelen ortaya çıkan yerel bir istisna olduğu anlamına gelir, ancak nedenini bilmiyorum.

İşte C++ programı. Şu an için komut satırı dizesini görmezden geliyorum ve şeylerin çalıştığından emin olmak için sahte imleç koordinatlarını kullanıyorum.

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

Ve bu iletiyi alan WPF uygulamasının bir parçasıdır. IF ifadesinin içindeki ikinci satır, tüm şey çökmezse, atlanır.

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

Burada C# yapıları için tanımları bulabilirsiniz. Sürekli olarak marshalling özellikleriyle oynamış ve hiçbir yere ulaşamamıştım.

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

Herhangi bir fikir?

+0

, davranış aynıdır) :) geciktim. –

cevap

7

Kurulumunuz hakkında daha fazla bilgi edinmeden, yanlış bir şekilde ne yaptığınızdan emin değilim. En iyi şekilde kodu kopyaladım (WPPro uygulamasında bir WPF uygulaması kullanarak kendi win32 uygulamasından gönderiyorum) ve benim için iyi çalışıyor. 64 bit uygulamaları çalıştırıyorsanız kesin olarak kırpılacak birkaç hata vardır, yani Pack = 1, COPYDATASTRUCT'un yanlış hizalanmasına neden olacak ve işaretçiden okuma ağrının sona ermesine neden olacaktır.

Sadece ints geçişi mi oluyor? Yorumlanan kodunuza bir LPWSTR veya wstring geçirerek bakmak ciddi sorunlara yol açacaktır, ancak gönderilen verileri serbest bırakana kadar bu durum belirgin olmamalıdır.

Buna değer bir şey varsa, bu benim komut satırını almam dahil olmak üzere benim için çalışacak şekilde görünen kod snippet'leri.

/* 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

"yani Pack = 1, COPYDATASTRUCT'un yanlış hizalanmasına neden olacak ve işaretçiden okuyacağınız acıya son vermeyecektir." Ah, şimdi çok açık. Pack = 1'in anlamlı olduğu dosyalardan yapıları okumak için kullanıyorum. C++ uygulaması 32-bittir, ancak 64-bit bir sistemim var ve .NET kodu 64-bit kodu JITted. Pack = 1 kaldırılıyor. Teşekkürler. "Yorumlanan kodunuza baktığımızda bir LPWSTR veya wstring geçmesi ciddi sorunlara neden olacaktır" diye düşündüm olabilir . Başarısız olarak yaptığınız gibi sabit bir wchar_t dizesini geçirmeyi denedim, ancak yukarıdaki sorun nedeniyle oldu. –

3

Sorunun "Haşlanmış aşağıya" varyantını adresleme, (++ VC ile ve VC#, sırasıyla) uygulamalar bir çift oluşturmak ettik (yani yetersizlikleri bu yapı almak için), bunlar flawelessly çalışmıyor gibi görünüyor tyranid'un dediği gibi, kurulumunuzda gerçekten bir şey olabilir.

Neyse, işte kod (sadece() ++ VC için yeni oluşturulan Win32 uygulaması yapıştırın için yeterli olmalı ve WINDOWS C çalıştırmak için # ve test için BAŞVURU FORMLARI):

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

Bu yardımcı olur umarım.

P.S.C# ve (özellikle) interop hakkında çok fazla bilgiye sahip değilim (öncelikle C++ programlamada ilgi alanına sahip), fakat hiç kimsenin [birkaç saat önce] yanıt vermediğini görmek, bu sorunu denemek için iyi bir meydan okuma olacağını düşündü. ödül :)

cabası * bunun amn i

Ben de bir Win penceresinde WndProc geçersiz kılma çalıştı
+0

Ah, yine de teşekkürler! –