web-dev-qa-db-fra.com

Envoyer un message en C #

Je crée une application qui utilise un projet principal connecté à plusieurs DLL différentes. Depuis une fenêtre DLL, je dois pouvoir ouvrir une fenêtre dans une autre mais les DLL ne peuvent pas se référencer.

Il m'a été suggéré d'utiliser la fonction sendmessage dans le premier DLL et d'avoir un écouteur dans le programme principal qui dirige ce message vers le DLL pour l'ouvrir) c'est la fenêtre.

Cependant, je ne connais pas du tout la fonction sendmessage et j'ai beaucoup de difficultés à reconstituer les choses à partir des informations que je trouve en ligne.

Si quelqu'un pouvait me montrer la bonne façon (s'il y en a) d'utiliser la fonction sendmessage et peut-être comment un auditeur capte ce message qui serait incroyable. Voici une partie du code que j'ai jusqu'à présent, je ne sais pas si je vais dans la bonne direction.

    [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");
    }
14
Nicole

Vous n'avez pas besoin d'envoyer de messages.

Ajoutez un événement à l'un des formulaires et un gestionnaire d'événements à l'autre. Ensuite, vous pouvez utiliser un troisième projet qui référence les deux autres pour attacher le gestionnaire d'événements à l'événement. Les deux DLL n'ont pas besoin de se référencer pour que cela fonctionne.

6
Mark Byers
public static extern int FindWindow(string lpClassName, String lpWindowName);

Pour trouver la fenêtre, vous avez besoin du nom de classe de la fenêtre. Voici quelques exemples:

C #:

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

Exemple d'un programme que j'ai fait, écrit en VB:

hParent = FindWindow("TfrmMain", vbNullString)

Pour obtenir le nom de classe d'une fenêtre, vous aurez besoin de quelque chose appelé Win Spy

Une fois que vous avez le handle de la fenêtre, vous pouvez lui envoyer des messages à l'aide de la fonction SendMessage (IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam).

hWnd, ici, est le résultat de la fonction FindWindow. Dans les exemples ci-dessus, ce sera hwnd et hParent. Il indique à la fonction SendMessage à quelle fenêtre envoyer le message.

Le deuxième paramètre, wMsg, est une constante qui signifie le [~ # ~] type [~ # ~] du message que vous envoyez. Le message peut être une frappe (par exemple envoyer "la touche Entrée" ou "la barre d'espace" à une fenêtre), mais il peut également s'agir d'une commande pour fermer la fenêtre (WM_CLOSE), une commande pour modifier la fenêtre (la cacher, affichez-le, minimisez-le, modifiez son titre, etc.), une demande d'informations dans la fenêtre (obtention du titre, obtention de texte dans une zone de texte, etc.), etc. Voici quelques exemples courants:

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

Ceux-ci peuvent être trouvés avec une visionneuse d'API (ou un simple éditeur de texte, tel que le bloc-notes) en ouvrant (Microsoft Visual Studio Directory) /Common/Tools/WINAPI/winapi32.txt.

Les deux paramètres suivants sont certains détails, s'ils sont nécessaires. En termes de pression sur certaines touches, ils spécifieront exactement quelle touche spécifique doit être pressée.

Exemple C #, définition du texte de "windowHandle" avec WM_SETTEXT:

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

Plus d'exemples d'un programme que j'ai fait, écrit en VB, définissant l'icône d'un programme (ICONBIG est une constante qui peut être trouvée dans winapi32.txt):

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

Un autre exemple de VB, en appuyant sur la touche espace (VK_SPACE est une constante qui peut être trouvée dans winapi32.txt):

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

VB envoyant un clic de bouton (un bouton gauche vers le bas, puis vers le haut):

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

Aucune idée de la façon de configurer l'écouteur dans un .DLL, mais ces exemples devraient aider à comprendre comment envoyer le message.

11
TimFoolery

Tu es presque là. (notez la modification de la valeur de retour de la déclaration FindWindow). Je recommanderais d'utiliser RegisterWindowMessage dans ce cas afin que vous n'ayez pas à vous soucier des tenants et aboutissants de 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);
}

Et puis dans votre classe 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);
    }
}

Gardez à l'esprit que je n'ai compilé aucun des éléments ci-dessus, donc quelques ajustements peuvent être nécessaires. Gardez également à l'esprit que d'autres réponses vous avertissant de SendMessage sont parfaites. Ce n'est pas le moyen préféré de communication inter-modules de nos jours et de manière générale, remplacer le WndProc et utiliser SendMessage/PostMessage implique une bonne compréhension du fonctionnement de infrastructure de messages Win32 .

Mais si vous voulez/devez emprunter cette voie, je pense que ce qui précède vous fera avancer dans la bonne direction.

3
dkackman

Cela ne semble pas être une bonne idée d'utiliser l'envoi d'un message. Je pense que vous devriez essayer de contourner le problème que les DLL ne peuvent pas se référencer ...

0
Daniel Hilgarth

Quelques autres options:

Assemblée commune

Créez un autre assembly qui possède des interfaces communes pouvant être implémentées par les assemblys.

Réflexion

Cela a toutes sortes d'avertissements et d'inconvénients, mais vous pouvez utiliser la réflexion pour instancier/communiquer avec les formulaires. C'est à la fois lent et dynamique d'exécution (pas de vérification statique de ce code au moment de la compilation).

0
RQDQ

S'appuyant sur la réponse de Mark Byers.

Le 3ème projet pourrait être un projet WCF, hébergé en tant que service Windows. Si tous les programmes écoutaient ce service, une application pouvait appeler le service. Le service transmet le message à tous les clients en écoute et ils peuvent effectuer une action si cela est approprié.

Bonnes vidéos WCF ici - http://msdn.Microsoft.com/en-us/netframework/dd728059

0
JonWillis