AttachConsole in DLL



  • Hallo,

    ich schreibe gerade eine DLL, die ich mit RunDll32.exe (über Batch) aufrufen kann.

    Ich möchte allerdings in der gleichen Console bleiben (Console des Parent Process erben)

    [cmd.exe] (Batch-Programm) <-- In die Console möchte ich...
    v
    [rundll32.exe]
    v
    [xxx.dll] <-- ...von dieser DLL aus schreiben
    

    Wenn ich jetzt in der DLL AttachConsole(ATTACH_PARENT_PROCESS) aufrufe, dann wird der Fehler ERROR_INVALID_HANDLE (6) erzeugt.

    void DLL_EXPORT Init(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
    {
        AttachConsole(ATTACH_PARENT_PROCESS)
    
        freopen("conin$",  "r", stdin);
        freopen("conout$", "w", stdout);
        freopen("conout$", "w", stderr);
    
        cout << "Hello World";
    }
    

    AllocConsole() funktioniert natürlich, weil das in dem RunDll32.exe-Prozess eine neue Console erstellt, aber das möchte ich ja nicht...

    Wie kann ich das Problem lösen?

    Vielen Dank schonmal 🙂

    Gruß
    Fabian



  • Ich habe herausgefunden, wie es geht:

    DWORD GetParentProcessID(DWORD ProcessID)
    {
        DWORD result = 0;
        HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
        if (INVALID_HANDLE_VALUE != snap)
        {
            PROCESSENTRY32 entry = {sizeof(entry)};
            if (Process32First(snap, &entry))
            {
                DWORD pid = ProcessID;
                do
                {
                    if (pid == entry.th32ProcessID)
                    {
                        result = entry.th32ParentProcessID;
                        break;
                    }
                }
                while (Process32Next(snap, &entry));
            }
            CloseHandle(snap);
        }
        return result;
    }
    
    void InitializeConsole()
    {
        if (!AttachConsole(GetParentProcessID/*cmd.exe*/((DWORD)GetParentProcessID/*rundll32.exe *32*/((DWORD)GetCurrentProcessId()/*rundll32.exe*/))))
        {
            //Fehler
        }
    
        freopen("conin$",  "r", stdin);
        freopen("conout$", "w", stdout);
        freopen("conout$", "w", stderr);
    }
    
    void DLL_EXPORT EntryPoint(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
    {
        InitializeConsole();
    
        cout << "Hello World!";
    }
    

    Allerdings sieht die Prozess-Struktur bei meinem x64-Vista so aus:

    [cmd.exe]
    v
    [rundll.exe]
    v
    [rundll.exe *32]
    v
    [xxx.dll]
    

    Und bei meinem x84-XP wie im ersten Posting.

    Wie kann ich herausfinden, ob ein Prozess ein 64 Bit oder 32 Bit-Prozess ist?
    Oder hat jmd. vllt. eine andere Lösung?

    Gruß
    Fabian



  • Falls es jmd. interressiert, ich habe es hingekommen.

    Die Dll muss eine x86-Dll sein.

    Aufrufen kann man es so:

    rundll32 xxx.dll,EntryPoint Hello World
    
    #define _WIN32_WINNT 0x0501
    
    #include <windows.h>
    #include <tlhelp32.h>
    
    #include <stdio.h>
    
    #include <iostream>
    using namespace std;
    
    #include "main.h"
    
    DWORD GetParentProcessID(DWORD ProcessID)
    {
        DWORD result = 0;
        HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
        if (INVALID_HANDLE_VALUE != snap)
        {
            PROCESSENTRY32 entry = {sizeof(entry)};
            if (Process32First(snap, &entry))
            {
                DWORD pid = ProcessID;
                do
                {
                    if (pid == entry.th32ProcessID)
                    {
                        result = entry.th32ParentProcessID;
                        break;
                    }
                }
                while (Process32Next(snap, &entry));
            }
            CloseHandle(snap);
        }
        return result;
    }
    
    typedef UINT (WINAPI* GETSYSTEMWOW64DIRECTORY)(LPTSTR, UINT);
    
    bool IsWow64(void)
    {
        GETSYSTEMWOW64DIRECTORY getSystemWow64Directory;
        HMODULE hKernel32;
        TCHAR Wow64Directory[MAX_PATH];
    
        hKernel32 = GetModuleHandle(TEXT("kernel32.dll"));
        if (hKernel32 == NULL)
        {
            return false;
        }
    
        getSystemWow64Directory = (GETSYSTEMWOW64DIRECTORY) GetProcAddress(hKernel32, "GetSystemWow64DirectoryW");
    
        if (getSystemWow64Directory == NULL)
        {
            return false;
        }
    
        if ((getSystemWow64Directory(Wow64Directory, sizeof(Wow64Directory)/sizeof(TCHAR)) == 0) && (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED))
        {
            return false;
        }
    
        return true;
    }
    
    void InitializeConsole()
    {
        if (IsWow64())
        {
            if (!AttachConsole(GetParentProcessID((DWORD)GetParentProcessID((DWORD)GetCurrentProcessId()))))
            {
                //Fehler
            }
        }
        else
        {
            if (!AttachConsole((DWORD)GetParentProcessID((DWORD)GetCurrentProcessId())))
            {
                //Fehler
            }
        }
    
        freopen("conin$",  "r", stdin);
        freopen("conout$", "w", stdout);
        freopen("conout$", "w", stderr);
    }
    
    void DLL_EXPORT EntryPoint(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
    {
        InitializeConsole();
    
        cout << lpszCmdLine << endl;
    }
    

    Ich glaube das ist aber ziemlich unperformant, also sollte ich wohl einfach eine exe erstellen, die man dann aufruft 😃


Anmelden zum Antworten