# [C++] Meine DLL will nicht funktionieren.



## Aziz (24. Dezember 2003)

Ich versuche momentan einen Keyboard Hook zu programmieren, aber selbst nach viel Mühsal will es einfach nicht funktionieren. Ich habe mindestens 4 Beispiel-Projekte angesehen (Spy++..), ich habe in diesem Forum gesucht und alles gelesen was gefunden wurde, ich habe bei experts-exchange.com gesucht und beinahe alle Fragen angesehen, die etwas direkt oder indirekt mit systemweiten Hooks zu tun haben, ich habe auch auf codeproject.com Artikel über Dll's durchgelesen, ABER ich hab immer noch keinen systemweiten Hook zusammengebracht, geschweige denn das importieren von Funkionen aus meiner selbsterstellten Dll. Ich verliere bald meinen Verstand und driffte langsam in den Wahnsinn!

Hier ist der Code meiner Dll. Was mache ich falsch

KeyboardHook.h

```
#ifndef _DEFINED_KEYBOARDHOOK
#define _DEFINED_KEYBOARDHOOK

#if _MSC_VER > 1000
  #pragma once
#endif

#ifdef _COMPILING_KEYBOARDHOOK
  #define KEYBOARDHOOK_API __declspec(dllexport)
#else
  #define KEYBOARDHOOK_API __declspec(dllimport)
#endif // _COMPILING_KEYBOARDHOOK

KEYBOARDHOOK_API BOOL InstallHook(void);
KEYBOARDHOOK_API BOOL UnInstallHook(void);

#endif // _DEFINED_Dlltest
```

KeyboardHook.cpp

```
#define WIN32_LEAN_AND_MEAN		// Exclude rarely-used stuff from Windows headers
#include <windows.h>

#define _COMPILING_KEYBOARDHOOK
#include "KeyboardHook.h"

static LRESULT CALLBACK KeyboardHookProc(int, WPARAM, LPARAM); 
 
 
HINSTANCE   hDllInstance; 
HHOOK       hKeyboardHook; 
 
BOOL APIENTRY DllMain(HINSTANCE hInstance, DWORD fdwReason, PVOID pvReserved) 
{
  // Perform actions based on the reason for calling.
	switch(fdwReason) { 
	case DLL_PROCESS_ATTACH:
		// Initialize once for each new process.
		// Return FALSE to fail DLL load
		hDllInstance = hInstance;
		break;

	case DLL_THREAD_ATTACH:
		// Do thread-specific initialization.
		break;

	case DLL_THREAD_DETACH:
		// Do thread-specific cleanup.
		break;

	case DLL_PROCESS_DETACH:
		// Perform any necessary cleanup.
		break;
	}
  MessageBox(0, "Dll loaded.", "Dll entry", 0);
	return TRUE;  // Successful DLL_PROCESS_ATTACH.
}
 
__declspec(dllexport) BOOL InstallHook(void)
{ 
    hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD, KeyboardHookProc, hDllInstance, NULL); 
 
    if (hKeyboardHook == NULL) 
    {
      MessageBox(0,"The keyboard hook could not be installed.", "Fehler",MB_OK);
      return FALSE;
    }
 
    return TRUE; 
} 
 
__declspec(dllexport) BOOL UnInstallHook(void) 
{
    return UnhookWindowsHookEx(hKeyboardHook);
} 
 
static LRESULT CALLBACK KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam) 
{
    return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam); 
}
```

Die folgenden Zeilen füge ich in die OnCreate(..)-Methode meiner Dialogfensterklasse ein (ist ein getrenntes MFC Projekt).


```
typedef BOOL (*PINSTALLHOOK)(void);

  m_hDLL = LoadLibrary("KeyboardHook.dll"); 
  if(m_hDLL)
  {
    PINSTALLHOOK pInstallHook = (PINSTALLHOOK) GetProcAddress(m_hDLL, "InstallHook");
    pInstallHook();
  }
```

Ich kopiere die Dll in den Debug-Ordner, also sollte die Frage "Findet er die Dll überhaupt?" garnicht erst aufkommen 
Beim Debuggen finde ich heraus, dass die Funktion "LoadLibrary" die Dll erfolgreich lädt aber der Funktionszeiger pInstallHook kriegt einfach keine Adresse ;(


----------



## Daniel Toplak (24. Dezember 2003)

Die Frage ist, ob deine DLL auch wirklich die entsprechende Funktion exportiert.
Mit dem Dependency Walker vom VS kannst du das herausfinden. Er liegt normalerweise unter "C:\Programme\Microsoft Visual Studio\Common\Tools"
Ansonsten solltest du eine export.def mit in deine DLL linken.

Gruß Homer


----------



## Aziz (24. Dezember 2003)

Ich habe bereits versucht die Dll mit dem Dependency Walker zu laden, und die Funktionen, die ich exportieren will werden auch korrekt als exportierte Funktionen angezeigt...

Eine export.def muss ich nicht schreiben, da in der MSDN steht, dass die Schlüsselworte __declspec(dllexport) dies für mich übernehmen.

Achja ich verwende Microsoft Visual Studio C++ 6.0 + ServicePack5, falls das von Wichtigkeit ist...


----------



## Aziz (24. Dezember 2003)

Hmm es scheint zu funktionieren wenn ich den dekorierten Funktionsnamen der Funktion GetProcAddress( ) übergebe. Das finde ich ziemlich unpraktisch. Wo anders hab ich gelesen, dass man "hübschere" Namen nur mit einer .DEF Datei festlegen kann. Stimmt das?


----------



## chibisuke (24. Dezember 2003)

ersetz mal das 
__declspec(dllexport)

durch

extern "C" __declspec(dllexport)

das verhindert das C++ die funktionsnamen erweitert.


----------



## Aziz (24. Dezember 2003)

Ich denke auch das habe ich schon probiert. Aber das Problem habe ich Gott sei Dank endlich gelöst. Zuerst habe ich eine .DEF File geschrieben und dort die undekorierten Funktionsnamen definiert. Somit konnte ich der GetProcAddress( ) Funktion ordentliche Funktionsnamen übergeben. Später jedoch, habe ich herausgefunden, dass wenn man die Dateiendung der Quelldatei der DLL auf *.c umändert, die *.DEF überflüssig wird! Ich habe mir stundenlang ein Beispiel-Projekt angesehen, welches systemweit verhindert, dass die Tastenkombination CTRL+C verarbeitet wird. Und ich hab mir ständig die Frage gestellt was ich denn anders mache. Es war alles gleich! Tausendmal habe ich Alt+Tab gedrückt um herauszufinden ob sich da vielleicht doch die Project-Settings unterscheiden. Dabei lag der einzige, aber wesentliche,Unterschied darin, dass der Sourcecode meiner DLL in einer *.cpp Datei gelagert war; beim anderen Projekt wars aber eine *.c Datei.

Einfach unglaublich. Ich war schon richtig am Verzweifeln  

Trotzdem Danke an jene, die bereit waren sich den Sourcecode anzusehen...


----------



## chibisuke (24. Dezember 2003)

Ja .c dateien is die alternative zu extern "c"

es gibt 3 möglichkeiten von den C++ namen zurück auf "normale" namen zu kommen..

entweder .def dateien

oder die dateien erhalten die endung .c wodurch die wie C dateien verarbeitet werden. nachteil dabei ist allerding das du dann nicht mit klassen arbeiten kannst, und auch die DCOM schnittstelle nicht unbedingt konfortabel zu benutzen ist wenn man jedesmal den this pointer extra übertagen muss.

und die 3. möglichkeit ist das man extern "c" vor den funktionsprototyp setzt und so ganz einfach den C++ kompiler zwingt die namensrichtlinien eines C kompilers anzuwenden.


----------



## Aziz (25. Dezember 2003)

Vielen Dank für diese Information. Als Anfänger ist es unglaublich schwierig soetwas in Erfahrung zu bekommen...


----------



## fld (26. Dezember 2003)

Und da Du noch Neuling bist, solltest Du Dir eine Unart direkt wieder abgewöhnen. Ich weiß, den alten C++-Dinosauriern kann man das nicht mehr austreiben, und mindestens 90% aller OpenSource-Projekte sind überschwemmt damit. Auch wenn's nur eine minimale Kleinigkeit ist: Symbolnamen, die mit einem doppelten Underscore (_ _) beginnen, und solche, die mit einem Underscore gefolgt von einem Großbuchstaben beginnen sind für die Implementierung der Sprache C++ reserviert.

Konkret: 
	
	
	



```
#ifndef _DEFINED_KEYBOARDHOOK
```
 ist streng genommen kein gültiger C++-Code. Richtig wäre z.B.: 
	
	
	



```
#if !defined( INC_KEYBOARDHOOK )
  #define INC_KEYBOARDHOOK
...
#endif  // !defined( INC_KEYBOARDHOOK )
```
 Dabei habe ich den Präfix INC_ gewählt, um die Information in den Namen aufzunehmen, daß das Symbol aufgrund eines #include definiert wurde. Nimm's mir nicht übel, ich bin nun mal der Ansicht, daß der Schutz der Sprache nicht alleine für natürliche Sprachen gelten sollte.

.f


----------

