2011-02-22 165 views
10

我正在創建一個應用程序,該應用程序使用連接到幾個不同的DLL的主項目。從一個DLL窗口中,我需要能夠在另一個窗口中打開一個窗口,但DLL不能相互引用。用C發送消息#

有人建議我在第一個DLL中使用sendmessage函數,並在主程序中有一個偵聽器,該偵聽器將該消息引導到相應的DLL以打開它的窗口。

但是我對sendmessage函數並不熟悉,並且在我在網上找到的信息中有很多不同的東西拼湊在一起。

如果有人可以請讓我看看使用sendmessage函數的正確方法(如果有的話)以及聽衆如何捕獲那個令人驚訝的消息。以下是我目前獲得的一些代碼,我不確定是否正朝着正確的方向前進。

[DllImport("user32.dll")] 
    public static extern int FindWindow(string lpClassName, String lpWindowName); 
    [DllImport("user32.dll")] 
    public static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam); 

    public void button1_Click(object sender, EventArgs e) 
    { 
     int WindowToFind = FindWindow(null, "Form1"); 
    } 
+0

嗨尼科爾,SendMessage「可以」在這種情況下有所幫助是的,但我擔心這不是您實現目標的最簡單方法。你能描述一下你的整個場景是什麼?你有1個WindowsForms應用程序和一些包含你想要顯示的額外表單的類庫,如果沒有,你到底想要做什麼?提供更多細節,我們將看到哪條路。 – 2011-02-22 21:09:09

+0

如果您對這兩個應用程序都有控制權,請使用其他一些IPC策略(命名爲管道/套接字) – 2011-02-22 21:09:22

回答

6

你不需要發送消息。

event添加到另一個窗體和一個事件處理程序。然後,您可以使用第三個項目來引用其他兩個將事件處理程序附加到事件。這兩個DLL不需要相互引用就可以工作。

0

這聽起來不像是一個好主意,使用發送消息。我認爲你應該嘗試解決這個DLL不能互相引用的問題......

0

其他一些選項:

常見大會

創建一個具有可以由組件來實現一些常用的接口,另一組裝。

反思

這有各種警告和缺點,但是你可以使用反射來實例化/與形式溝通。這是慢速和運行時動態的(在編譯時沒有對此代碼進行靜態檢查)。

0

建立在馬克·拜爾斯的答案。

第三個項目可能是一個WCF項目,作爲Windows服務託管。如果所有程序都監聽該服務,則一個應用程序可以調用該服務。該服務將消息傳遞給所有正在監聽的客戶端,並且他們可以在適當的情況下執行操作。這裏

良好的WCF視頻 - http://msdn.microsoft.com/en-us/netframework/dd728059

8
public static extern int FindWindow(string lpClassName, String lpWindowName); 

爲了找到窗口,你需要窗口類名。下面是一些例子:

C#:

hParent = FindWindow("TfrmMain", vbNullString) 

爲了得到一個窗口的類名,你用」:

const string lpClassName = "Winamp v1.x"; 
IntPtr hwnd = FindWindow(lpClassName, null); 

從一個程序,我做了,用VB編寫的示例你需要一個叫Win Spy

一旦你有窗口的句柄,你可以使用SendMessage(IntPtr hWnd,int wMsg,IntPtr wParam,IntPtr lParam)函數發送消息給它。

hWnd在這裏是FindWindow函數的結果。在上面的例子中,這將是hwnd和hParent。它告訴SendMessage函數將消息發送到哪個窗口。

第二個參數wMsg是一個常量,表示您要發送的消息的類型。該消息可能是一個按鍵(例如,將「輸入鍵」或「空格鍵」發送到窗口),但它也可能是一個關閉窗口的命令(WM_CLOSE),一個用於更改窗口的命令(隱藏它,顯示它,最小化它,改變它的標題等),窗口內的信息請求(獲得標題,在文本框內獲取文本等)等等。一些常見的例子包括以下內容:

Public Const WM_CHAR = &H102 
Public Const WM_SETTEXT = &HC 
Public Const WM_KEYDOWN = &H100 
Public Const WM_KEYUP = &H101 
Public Const WM_LBUTTONDOWN = &H201 
Public Const WM_LBUTTONUP = &H202 
Public Const WM_CLOSE = &H10 
Public Const WM_COMMAND = &H111 
Public Const WM_CLEAR = &H303 
Public Const WM_DESTROY = &H2 
Public Const WM_GETTEXT = &HD 
Public Const WM_GETTEXTLENGTH = &HE 
Public Const WM_LBUTTONDBLCLK = &H203 

這些可以用API瀏覽器(或一個簡單的文本編輯器,如記事本)打開(微軟的Visual Studio目錄)/普通/工具/ WINAPI/winapi32找到。文本。

接下來的兩個參數是某些細節,如果它們是必要的。就按某些鍵而言,他們將確切指定要按下哪個特定鍵。

C#例如,設置「windowHandle」的文本與WM_SETTEXT:從程序,我提出,寫在VB

x = SendMessage(windowHandle, WM_SETTEXT, new IntPtr(0), 
m_strURL); 

更多的例子,設定的程序的圖標(ICONBIG是一個常數,其可以發現在winapi32.txt):

Call SendMessage(hParent, WM_SETICON, ICON_BIG, ByVal hIcon) 

從VB又如,按下空格鍵(VK_SPACE是一個常數可以在winapi32.txt找到):

Call SendMessage(button%, WM_KEYDOWN, VK_SPACE, 0) 
Call SendMessage(button%, WM_KEYUP, VK_SPACE, 0) 

VB發送點擊一個按鈕(左按鈕下來,然後向上):

Call SendMessage(button%, WM_LBUTTONDOWN, 0, 0&) 
Call SendMessage(button%, WM_LBUTTONUP, 0, 0&) 

不知道如何設置監聽一個.DLL內,但這些例子應該瞭解如何發送幫助信息。

2

你快到了。 (注意FindWindow聲明的返回值的更改)。在這種情況下,我建議使用RegisterWindowMessage,這樣您就不必擔心WM_USER的來龍去脈。

[DllImport("user32.dll")]  
public static extern IntPtr FindWindow(string lpClassName, String lpWindowName);  
[DllImport("user32.dll")]  
public static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam);  
[DllImport("user32.dll", SetLastError=true, CharSet=CharSet.Auto)] 
static extern uint RegisterWindowMessage(string lpString); 

public void button1_Click(object sender, EventArgs e) 
{   
    // this would likely go in a constructor because you only need to call it 
    // once per process to get the id - multiple calls in the same instance 
    // of a windows session return the same value for a given string 
    uint id = RegisterWindowMessage("MyUniqueMessageIdentifier"); 
    IntPtr WindowToFind = FindWindow(null, "Form1");  
    Debug.Assert(WindowToFind != IntPtr.Zero); 
    SendMessage(WindowToFind, id, IntPtr.Zero, IntPtr.Zero); 
} 

,然後在Form1類:

class Form1 : Form 
{ 
    [DllImport("user32.dll", SetLastError=true, CharSet=CharSet.Auto)] 
    static extern uint RegisterWindowMessage(string lpString); 

    private uint _messageId = RegisterWindowMessage("MyUniqueMessageIdentifier"); 

    protected override void WndProc(ref Message m) 
    { 
     if (m.Msg == _messageId) 
     { 
      // do stuff 

     } 
     base.WndProc(ref m); 
    } 
} 

請記住我沒有編譯的任何上述的這樣一些調整,可能是必要的。 另外請記住,其他答案警告你遠離SendMessage是現貨。這不是當今模塊間通信的首選方式,通俗地說覆蓋了WndProc,並且使用SendMessage/PostMessage意味着很好地理解Win32 message infrastructure的工作原理。

但是,如果你想/需要走這條路線,我認爲上述會讓你朝着正確的方向前進。