CreateWindow in DLL



  • Hallo,

    mein Ziel ist es eine Eventhandler Callback Routine in einer DLL bekannt zu machen. Ich verwende hier die SAPI und möchte z.B. auf Synthesizer Events lauschen. Mein Programm wird als DLL in ein anderes Programm geladen. Das handle hInstance vom Laden der DLL bekomme ich als Parameter.
    Soweit ich das verstanden habe, brauche ich für die Benachrichtigungen ein WindowHandle.

    Nun rufe ich folgendes auf:

    WNDCLASSEX wcex;
      wcex.cbSize			= sizeof(WNDCLASSEX); 
      wcex.style			= CS_HREDRAW | CS_VREDRAW;
      wcex.lpfnWndProc		= (WNDPROC)MyWndProc;
      wcex.cbClsExtra		= 0;
      wcex.cbWndExtra		= 0;
      wcex.hInstance		= hInstance;
      wcex.hIcon			= 0; 
      wcex.hCursor			= LoadCursor(NULL, IDC_ARROW);
      wcex.hbrBackground	= 0;
      wcex.lpszMenuName		= NULL; 
      wcex.lpszClassName	= szWindowClass;
      wcex.hIconSm			= 0; (LPCTSTR)IDI_SMALL);
    
      HWND hwnd= CreateWindowEx(
          WS_EX_TOPMOST|WS_EX_LAYERED|WS_EX_TRANSPARENT,
          szWindowClass,
          szTitle,
          WS_POPUP|WS_SYSMENU,
          0, 0, 0, 0,
          NULL,
          NULL,
          hInstance,
          NULL);
    

    Leider ist das Window Handle, dass ich bekomme NULL. Ein Aufruf von GetLastError() liefert ebenfalls 0 zurück. Also keinerlei Hinweise auf einen Fehler.

    Für Hinweise auf die korrekten Parameter oder Tipps, die mir hier weiterhelfen, wäre ich dankbar.

    Dirk



  • Dieser Thread wurde von Moderator/in Martin Richter aus dem Forum MFC (Visual C++) in das Forum WinAPI verschoben.

    Im Zweifelsfall bitte auch folgende Hinweise beachten:
    C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?

    Dieses Posting wurde automatisch erzeugt.


  • Mod

    Und was für eine Fensterklasse benutzt Du?
    Was sagt GetLastError?



  • Habe vergessen zu sagen, dass das meine Fensterklasse natürlich noch mit

    RegisterClassEx(&wcex);
    

    registriert wird, bevor ich CreateWindow aufrufe. Oder was war mit der Frage nach der Fensterklasse gemeint?
    Wie ich schon oben gesagt habe, gibt mir GetLastError() leider keine Hinweise. Hier kommt 0 zurück.

    Dirk



  • Der mitgeteilte Code sieht sauber aus und läuft gewöhnlich so. Möglicherweise liegt das Problem im hInstance-Handle. Die DLL und WinMain haben unabhängig voneinander eigene hInstance-Handle. Poste mal etwas mehr Code. Kann so schwer nicht sein!



  • Die DLL wird etwa so geladen:

    const char *fn = com->filename.cstr();
        HINSTANCE hInst = LoadLibrary(fn);
    

    Dieses hInst bekomme ich dann in meine Methode:

    FARPROC pFn = GetProcAddress(com->hInstance, "RegisterServicesWin");
        if (pFn!=NULL)
        {
          com->loaded = (((windows_register_fn)pFn)(com->hInstance, hInstance, hWnd) != 0);
        }
    

    hInstance ist das HINSTANCE das in der WinMain ankommt und hWnd das Window Handle des Hauptprozesses.

    Verwende ich evtl. das falsche HINSTANCE?

    Dirk


  • Mod

    Also benutzt Du zum Registrieren, der Klasse das hInstance der EXE. Zum Errzeugen des Fensters aber das hInstance der DLL?

    Das geht nicht.
    Verwende einfach in der DLL immer das hInstance der DLL.

    Siehe auch:
    http://blog.m-ri.de/index.php/2007/12/12/die-unsitte-immer-getmodulehandlenull-fuer-hinstance-in-createwindow-und-registerclass-zu-verwenden/



  • Hallo,

    nein. Ich verwende für beides das hInstance der DLL. Vermutlich habe ich mich hier verwirrend ausgedrückt.

    Dirk



  • Das hInstance der DLL gilt allein für die DLL, das von WinMain allein für die EXE. Man kann die gegenseitig mitteilen, doch besser nur für Informationszwecke und Abfragefunktionen der WinApi. Betrachte DLL und EXE als quasi getrennte Prozesse. Es sind nur die Datenbereiche miteinander verknüpft. Verteile die Aufgaben der DLL eindeutig auf diese und regel alles weitere über DLL-Funktionen. Dann gibt es keine Komplikationen!



  • Danke erst einmal für die Hinweise. Leider bin ich damit immer noch nicht weiter.
    Mir ist allerdings aufgefallen, dass der Wert des handles für die DLL mit dem Handle der EXE übereinstimmt. Auch

    EXTERN_C IMAGE_DOS_HEADER __ImageBase;
    #define HINST_THISCOMPONENT ((HINSTANCE)&__ImageBase)
    

    liefert mir diesen Wert.

    Den Wert des Handles der EXE bekomme ich, wie gesagt, über die WinMain Methode. Etwas ratlos
    Dirk



  • Kann das nicht nachvollziehen, wie du das machst.
    Vorschlag: Richte für die EXE und die DLL jeweils eine Protokolldatei EXE.TXT und DLL.TXT ein und schreibe die hInstance-Handles hinein. Du wirst sehen, sie sind verschieden, weil quasi getrennte Prozesse. Wie man das mit solchen Protokolldateien machen kann, findest du auf meiner Homepage http://berniebutt.npage.de auf der Seite Protokolldatei. Solche Protokolldateien sind auch sonst nützlich.



  • Nach den handles habe ich schlichtweg im Debugger nach dem Wert geschaut.



  • Habe dann doch noch mal die Wert in eine Logdatei geschrieben. Die Werte sind unterschiedlich, werden vom Fuschel Studio Debugger aber als gleich angegeben.

    Bleibt dennoch das Problem, dass das WindowHandle NULL ist.

    Dirk



  • MrMagoo schrieb:

    Habe dann doch noch mal die Wert in eine Logdatei geschrieben. Die Werte sind unterschiedlich, werden vom Fuschel Studio Debugger aber als gleich angegeben.
    Bleibt dennoch das Problem, dass das WindowHandle NULL ist.
    Dirk

    Bist du dir sicher, dass hwnd NULL ist oder vertraust du da dem Debugger? Debugger können nicht alles und haben für das gemeinsame Debuggen von EXE und DLLs schon mal Schwierigkeiten oder erfordern besondere Massnahmen. Dies ist der Grund, warum ich lieber eigene Protokolldateien einsetze und den Debugger nur für Notfälle nehme. Wenn die Fensterklasse korrekt registriert ist, liefert ein CreateWindow auch ein gültiges hwnd-Handle zürück. Mache alles in der DLL und kontrolliere, was diese macht.



  • Die NULL stammt jetzt aus dem Protokoll.


  • Mod

    Wenn ein Windows Handle NULL ist nach CreateWindow, dann hat GetLastError einen Wert für die Fehlerursache...

    @berniebutt: Eine DLL in einem Prozess als eigenen Prozess zu beschreiben ist falsch. Einer DLL gehören keine Handles, kein dyamischer Speicher!

    Eine DLL ist nichts anderes als zusätzlicher Code und Daten, die man sich in den Speicher lädt.



  • Martin Richter schrieb:

    Eine DLL in einem Prozess als eigenen Prozess zu beschreiben ist falsch. Einer DLL gehören keine Handles, kein dyamischer Speicher!

    Eine DLL ist nichts anderes als zusätzlicher Code und Daten, die man sich in den Speicher lädt.

    --> Eine DLL wird nur tätig, wenn ein Prozess eine Funktion daraus aufruft, das ist unbestritten.
    --> Jede Instanz einer DLL besitzt sehr wohl eigene Handles, z.B. ihren InstanzHandle hInstance
    --> Jede Instanz einer DLL kann auch dynamischen Speicher anfordern und diesen wieder freigeben.
    --> Eine DLL kann unter Windows verschiebbar sein.
    --> Eine DLL ist mehr als nur die Bereitstellung von zusätzlichem Code und Daten.
    --> So betrachtet darf man jede DLL-Instanz schon als quasi eigenständigen Prozess ansehen.

    Aber das führt hier nicht viel weiter. Der Fragesteller erhält mit seinem CreateWindow ein hwnd = NULL und weiss nicht warum. Nur darum geht es!



  • Habe noch ein wenig weiter gebastelt, aber noch immer kein HWND erhalten. Mein aktuller Code sieht so aus:

    Instance handle erhalten über:

    EXTERN_C IMAGE_DOS_HEADER __ImageBase;
    #define HINST_THISCOMPONENT ((HINSTANCE)&__ImageBase)
    

    Versuchen, ein Window Handle zu erhalten mit:

    TCHAR *szWindowClass=L"TestSapiTtsWindowClass";
        TCHAR *szTitle=L"Test SAPITTS";
    
        LogWrite(LOG_I, "hinstance: %ld", HINST_THISCOMPONENT);
        WNDCLASS wndclass;
        wndclass.style         = CS_HREDRAW | CS_VREDRAW;
        wndclass.lpfnWndProc   = (WNDPROC) MyWndProc;
        wndclass.cbClsExtra    = 0;
        wndclass.cbWndExtra    = 0;
        wndclass.hInstance     = HINST_THISCOMPONENT;
        wndclass.hIcon         = NULL;// LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON));
        wndclass.hCursor       = 0;
        wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
        wndclass.lpszMenuName  = NULL;
        wndclass.lpszClassName = szWindowClass;
        ATOM atom = RegisterClass(&wndclass);
        if (atom == NULL)
    	{
    		LogWrite(LOG_E, "unable to register TTS window. Last Error: %ld",
    			GetLastError());
    	}
    
    	HWND hWnd = CreateWindow(
    	  szWindowClass,
    	  szTitle,
      	  WS_OVERLAPPEDWINDOW,
      	  CW_USEDEFAULT,
      	  0,
      	  CW_USEDEFAULT,
      	  0,
    	  HWND_MESSAGE,
    	  NULL,
    	  HINST_THISCOMPONENT,
    	  NULL);
    	if (hWnd==0)
    	{
    		LogWrite(LOG_E, "unable to create TTS window. Last Error: %ld",
    			GetLastError());
    	}
    

    Die Logausgabe ist folgende:
    `

    077367 I(sapitts.cpp:35) hinstance: 1433141248

    079286 E(sapitts.cpp:68) unable to create TTS window. Last Error: 0

    `

    Ein ATOM kann ich also erzeugen, ein Window nicht. GetLastError hilft mir hier leider auch nicht weiter.

    Ich verwende Windows 7, falls das weiter hilft.

    Dirk



  • Habe mal einen Breakpoint in meinen EventHandler gesetzt. Der wird tatsächlich mehrmals aufgerufen.

    Mein Handler sieht so aus:

    LRESULT CALLBACK MyWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    	switch (message)
    	{
    	case WM_CLOSE:
    		DestroyWindow(hWnd);
    		return 0;
    	case WM_DESTROY:
    		PostQuitMessage(0);
    		return 0;
    	}
    
    	return DefWindowProc(hWnd, message, lParam, wParam);
    }
    

    Messages sind 36, 129, 130

    Dirk



  • Das war wohl der Schlüssel dazu. Nach Änderung meines Codes zu:

    LRESULT CALLBACK MyWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    	switch (message)
    	{
    	case WM_NCCREATE:
    		return 1;
    	case WM_CLOSE:
    		DestroyWindow(hWnd);
    		return 0;
    	case WM_DESTROY:
    		PostQuitMessage(0);
    		return 0;
    	}
    
    	return DefWindowProc(hWnd, message, lParam, wParam);
    }
    

    Geht es weiter und ich bekomme tatsächlich ein Window Handle. Ich hoffe nur, dass diese Abwandlung so korrekt ist.

    Dirk


Log in to reply