2010-02-01 7 views
0

J'ai besoin de sous-classer un contrôle richedit dans un programme de chat (j'essaie de faire un musicbot). Je ne sais pas comment coder en c/C++ mais j'ai été capable d'utiliser C++ pour injecter un code managé dans le programme de chat en utilisant CLR Hosting. Mais des problèmes de couple se produisent. J'espère pouvoir obtenir de l'aide d'ici.Injecter DLL géré dans le problème de processus natif

  1. Mon code managé se fermerait une fois le thread terminé. Je dois le faire tourner
  2. Lorsque j'ai essayé de sous-classer le contrôle richedit en utilisant SetWindowLong api et GWL_WNDPROC, le programme de discussion a été gelé.

Quelqu'un pourrait-il me diriger vers une bonne façon de faire cela? Ou est-il même possible de le faire en code managé?

Merci

Répondre

1

Ce genre de choses dépendent de beaucoup de facteurs et peuvent être difficiles à aller. Pouvez-vous fournir plus de détails?

Au niveau général, pour 1: Si vous utilisez ICLRRuntimeHost::ExecuteInDefaultAppDomain(pwzAssemblyPath, pwzTypeName, pwzMethodName, pwzArgument) pour exécuter votre code managé, l'exécution gérée s'arrêtera dès que la méthode désignée par pwzMethodName sera terminée. Si vous avez d'autres tâches que vous voulez faire avec persistance, et que vous ne voulez pas que cet appel se bloque entre-temps, votre meilleur pari est d'avoir pwzMethodName démarrer une fonction de boucle de programme sur un autre thread.

Comme pour 2, si vous injectez du code dans un processus cible et interagissez avec des contrôles, la sécurité des threads peut être un gros problème. Personnellement, je n'ai pas utilisé SetWindowLong API, mais cela pourrait être quelque chose à faire avec la modification des contrôles d'un thread non-Dispatcher.

+0

Voici mon code C++ hr = pClrHost-> ExecuteInDefaultAppDomain (L "ClassLibrary2.dll", L "ClassLibrary2.Class1", L "Test", L "MyParameter", & dwRet); – Tri

+0

Voici mon code C# public static void Sous-classe (IntPtr hWnd) { _WndProc = new WndProcDelegate (WndProc); _OldWndProc = SetWindowLongPtr (hWnd, GWL_WNDPROC, Marshal.GetFunctionPointerForDelegate (_WndProc)); } statique statique IntPtr WndProc (intPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam) { System.Diagnostics.Debug.WriteLine (msg); Montrer (msg.ToString()); Renvoie CallWindowProc (_OldWndProc, hWnd, msg, wParam, lParam); } – Tri

+1

Comme je l'ai dit dans ma réponse, ExecuteInDefaultAppDomain quittera une fois ClassLibrary2.Class1.Test exit. Si cette méthode est une boucle infinie, ExecuteInDefaultAppDomain sera une boucle infinie trop essentiellement. Si vous voulez que votre ExecuteInDefaultAppDomain retourne immédiatement, mais que le code .NET continue à s'exécuter, vous devez démarrer un thread 'principal' à partir de la fonction que vous appelez dans ExecuteInDefaultAppDomain – jeffora

0

Voici mon C#

public class Class1 
{ 

    [DllImport("kernel32", SetLastError = true)] 
    public static extern IntPtr LoadLibrary(string lpFileName); 

    [DllImport("user32.dll", SetLastError = true)] 
    public static extern IntPtr CallWindowProc(IntPtr lpPrevWndFunc,IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam); 

    [DllImport("user32.dll", EntryPoint = "GetWindowLong", SetLastError = true)] 
    public static extern IntPtr GetWindowLongPtr32(IntPtr hWnd, int nIndex); 

    [DllImport("user32.dll", EntryPoint = "GetWindowLongPtr", SetLastError = true)] 
    public static extern IntPtr GetWindowLongPtr64(IntPtr hWnd, int nIndex); 

    [DllImport("user32.dll", EntryPoint = "SetWindowLong", SetLastError = true)] 
    public static extern int SetWindowLong32(IntPtr hWnd, int nIndex, IntPtr dwNewLong); 

    [DllImport("user32.dll", EntryPoint = "SetWindowLongPtr", SetLastError = true)] 
    public static extern IntPtr SetWindowLongPtr64(IntPtr hWnd, int nIndex, IntPtr dwNewLong); 

    public static IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex) 
    { 
     if (IntPtr.Size == 8) 
      return GetWindowLongPtr64(hWnd, nIndex); 
     else 
      return GetWindowLongPtr32(hWnd, nIndex); 
    } 

    public static IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr dwNewLong) 
    { 
     if (IntPtr.Size == 8) 
      return SetWindowLongPtr64(hWnd, nIndex, dwNewLong); 
     else 
      return new IntPtr(SetWindowLong32(hWnd, nIndex, dwNewLong)); 
    } 


    public delegate IntPtr WndProcDelegate(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam); 


    public const int GWL_WNDPROC = -4; 
    public const int HWND_MESSAGE = -3; 
    public const int WM_LBUTTONDOWN = 513; 


    public static int Test(String pwzArgument) 
    { 

     f = new Form1(); 
     f.Show(); 

     Process p = Process.GetCurrentProcess(); 

     string s = "Name: " + p.ProcessName + "\nTitle: " + p.MainWindowTitle + "\nHandle: " + p.MainWindowHandle.ToString(); 


     Show(s); 

     Show("Started"); 
     Subclasshwnd(p.MainWindowHandle); 
     //For i = 0 To 100000000 
     //' Show("Loop", "") 
     //Threading.Thread.CurrentThread.Sleep("10000") 
     //Next 
     return 1; 
    } 



    public static void Show(string input) 
    { 
     MessageBox.Show(input); 
     f.Settext(input + "\n"); 
    } 



    public static WndProcDelegate _WndProc; 
    public static IntPtr _OldWndProc; 
    public static IntPtr _hWnd; 
    public static Form1 f; 


    public static void Subclasshwnd(IntPtr hWnd) 
    { 

     _WndProc = new WndProcDelegate(WndProc); 
     // _OldWndProc = GetWindowLongPtr(hWnd, GWL_WNDPROC); 

     _OldWndProc= SetWindowLongPtr(hWnd, GWL_WNDPROC,Marshal.GetFunctionPointerForDelegate(_WndProc)); 

     // Show(_OldWndProc.ToString()); 
    } 

    // this is the new wndproc, just show a messagebox on left button down: 
    public static IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam,IntPtr lParam) 
    { 
     System.Diagnostics.Debug.WriteLine(msg); 
     Show(msg.ToString()); 

     return CallWindowProc(_OldWndProc, hWnd, msg, wParam, lParam); 
    } 


} 

Et voici mon code C++

BOOL APIENTRY DllMain(HANDLE hModule,DWORD ul_reason_for_call,LPVOID lpReserved) 
{ 

    switch (ul_reason_for_call) 
    { 
    case DLL_PROCESS_ATTACH: 
     MessageBox(0, L"Dll Injection Successful! ", L"Dll Injector", MB_ICONEXCLAMATION | MB_OK);  
     CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&StartTheDotNetRuntime, 0, 0, NULL); 
     break; 

    case DLL_THREAD_ATTACH: break; 
    case DLL_THREAD_DETACH: break; 
    case DLL_PROCESS_DETACH: 

     break; 
    } 

    return TRUE; 







void StartTheDotNetRuntime() 

{ 

    ICLRRuntimeHost *pClrHost = NULL; 
    HRESULT hr = CorBindToRuntimeEx(NULL, L"wks", 0, CLSID_CLRRuntimeHost,IID_ICLRRuntimeHost, (PVOID*)&pClrHost); 
    hr = pClrHost->Start(); 

    DWORD dwRet = 0; 
    hr = pClrHost->ExecuteInDefaultAppDomain(L"ClassLibrary2.dll",L"ClassLibrary2.Class1", L"Test", L"MyParameter", &dwRet); 
    hr = pClrHost->Stop();  
    pClrHost->Release(); 
} 
+0

Vous ne devez pas appeler CreateThread dans DllMain. Avoir une lecture de la documentation msdn - il y a beaucoup de choses que vous ne devriez pas faire dans DllMain qui peuvent causer l'échec du programme: http://msdn.microsoft.com/en-us/library/ms682583%28VS.85%29.aspx – jeffora

0

Un autre "plus dynamique" façon est d'écrire une bibliothèque C++ géré qui peut être injecté.

Une bibliothèque C++ gérée peut exporter des fonctions natives à utiliser pour le charger dans un autre processus. N'écrivez que du code dans cette bibliothèque C++ managée qui vous permet de charger des bibliothèques supplémentaires.

Cette bibliothèque peut être réutilisée pour injecter des objets futurs ...

Voir: http://www.vbib.be/index.php?name=PNphpBB2&file=viewtopic&p=38982

Questions connexes