HILFE! DLL einbinden klappt, GetProcAddress() jedoch nicht! (VC++ 6.0)
-
Moin!
Ich verzweifle am korrekten Einbinden einer DLL. Obwohl ich mich, denke ich, an die zahlreichen Beispiele im Internet gehalten habe, klappt es einfach nicht. Wäre nett, wenn mal jemand drüber gucken könnte.
Und bitte nicht auf Google verweisen, da habe ich nun schon etliche Stunden erfolglos investiert...
Das Einbinden per LoadLibrary() klappt, jedoch liefert GetProcAddress() kein gültiges Handle. GetLastError() liefert 127 (The specified procedure could not be found) zurück.
myDLL.h :
#ifdef MYDLL_EXPORTS #define MYDLL_API __declspec(dllexport) #else #define MYDLL_API __declspec(dllimport) #endif MYDLL_API void ScreenShotWholeDesktop(void);myDLL.cpp :
#include "stdafx.h" #include "myDLL.h" BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; } MYDLL_API void ScreenShotWholeDesktop(void) { //-------------------------------------------------------------------------------------------------------------------------- //__declspec(dllexport) void _cdecl ScreenShotWholeDesktop(void) { //-------------------------------------------------------------------------------------------------------------------------- int nWidth = GetSystemMetrics(SM_CXSCREEN); int nHeight = GetSystemMetrics(SM_CYSCREEN); HWND hWnd = ::GetDesktopWindow(); HDC hdc = ::GetDC(hWnd); HDC memDC = ::CreateCompatibleDC(hdc); HBITMAP hbm = ::CreateCompatibleBitmap(hdc, nWidth, nHeight); HBITMAP hbmOld = (HBITMAP)::SelectObject(memDC, hbm); ::BitBlt(memDC, 0, 0, nWidth, nHeight, hdc, 0, 0, SRCCOPY); BITMAPINFO bmi; ZeroMemory(&bmi, sizeof(bmi)); bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmi.bmiHeader.biWidth = nWidth; bmi.bmiHeader.biHeight = nHeight; bmi.bmiHeader.biBitCount = 24; bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biCompression = BI_RGB; bmi.bmiHeader.biSizeImage = 32 * nWidth * nHeight / 8; BYTE *pbBits = new BYTE[bmi.bmiHeader.biSizeImage]; ::GetDIBits( memDC, hbm, 0, bmi.bmiHeader.biHeight, pbBits, &bmi, DIB_RGB_COLORS ); BITMAPFILEHEADER bfh; bfh.bfType = ('M' << 8) + 'B'; bfh.bfSize = sizeof(BITMAPFILEHEADER) + bmi.bmiHeader.biSizeImage + sizeof(BITMAPINFOHEADER); bfh.bfReserved1 = 0; bfh.bfReserved2 = 0; bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); SetDIBits(memDC,hbm,0,bmi.bmiHeader.biHeight,pbBits,&bmi,DIB_RGB_COLORS); // StretchBlt(*hDC, 0, 0, WinSizeX,WinSizeY,memDC, 0, 0,WinSizeX/2,WinSizeY/2,SRCCOPY); // BitBlt(*hDC, 0, 0, GetSystemMetrics(SM_CXSCREEN)-1,GetSystemMetrics(SM_CYSCREEN)-1,memDC, 0, 0, SRCCOPY); HANDLE hfile = CreateFile( "__TMP__SCRNSHOT__2357__.BMP", GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0 ); if(hfile==INVALID_HANDLE_VALUE) { MessageBox(NULL,"Datei konnte nicht erzeugt werden!",NULL,MB_OK); } DWORD dwWritten; WriteFile(hfile,&bfh, sizeof(bfh), &dwWritten, NULL); WriteFile(hfile,&bmi.bmiHeader, sizeof(BITMAPINFOHEADER), &dwWritten, NULL); WriteFile(hfile,pbBits, bmi.bmiHeader.biSizeImage, &dwWritten, NULL); CloseHandle(hfile); ::SelectObject(memDC, hbmOld); ::DeleteDC(memDC); ::ReleaseDC(hWnd,hdc); ::DeleteObject(hbm); delete[] pbBits; return; }testDLL.cpp :
#include "stdafx.h" #include "..\\myDLL.h" typedef void (*DLLFUNC)(void); int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow) { // HMODULE hDLL = LoadLibrary("..\\debug\\myDLL.dll"); DLLFUNC pfnDllScreenShotWholeDesktop = NULL; if(hDLL==NULL) { MessageBox(NULL,"LoadLibrary NICHT erfolgreich!",NULL,MB_OK); } pfnDllScreenShotWholeDesktop = (DLLFUNC)GetProcAddress((HINSTANCE)hDLL,"ScreenShotWholeDesktop"); if(pfnDllScreenShotWholeDesktop==NULL) { MessageBox(NULL,"GetProcAddress NICHT erfolgreich!",NULL,MB_OK); char sTmp[10]={0}; wsprintf(sTmp,"Error: %i",GetLastError()); MessageBox(NULL,sTmp,NULL,MB_OK); } //pfnDllScreenShotWholeDesktop(); FreeLibrary(hDLL); return 0; }Im Voraus schonmal vielen Dank!
Gruß Matze
-
Schau mal mit "depends.exe" nach wie die Funktion in der DLL wirklich heisst... die heisst nämlich nicht so wie Du denkst...
Siehe:
http://www.dependencywalker.com/
-
Danke, so klappt es! Auf den Funktionsnamen "?ScreenShotWholeDesktop@@YAXXZ" wäre ich ja nie gekommen...
Gerade ist auch (endlich!) ein Arbeitskollege gekommen, der auch prompt einen Tipp hatte:
In der myDLL.h muss dem Prototyp ein 'extern "C"' vorangestellt werden, und (der Knackpunkt:) der Prototyp muss von geschweiften Klammern umschlossen sein. Also so:
extern "C" { MYDLL_API void ScreenShotWholeDesktop(void); }'extern "C"' hatte ich auch vorher drinnen, hat allerdings nie geklappt. Somit sind die geschweiften Klammern wohl Pflicht, zumindest beim VC++ 6.0. Ich kann mir gut vorstellen, dass das bei anderen Compilern auch ohne Klammern geht, schließlich finden sich unzählige Beispiele im Internet, die keine Klammern verwenden.
Laut meines Kollegen ist die Methode mit 'extern "C"' der vorigen vorzuziehen, da sich ein Funktionsname wie "?ScreenShotWholeDesktop@@YAXXZ" ändert, sobald man die Parameter der Funktion umstellt bzw. erweitert.
Gruß Matze
-
Wenn Du einen "schönen" und "eindeutigen" Namen haben willst, dann verwende eine def-Datei...
PS: Wenn Du Parameter änderst, dann hast Du sowieso verloren! Du solltest Dir mal Gedanken über Versionierung machen!
MS ändert z.B. *nie* Parameter, so das es inkompatibel wird...
Entweder enthält die übergebene Struktur ein "dwSize" oder es wird eine neue Funktion angelegt (...Ex).
-
def-Dateien werd' ich mir mal ansehen, sobald ich Zeit dafür finde.
Versionierung ist momentan noch kein Thema, da die DLL ja gerade erst am Anfang der Entwicklung steht. Ist sie einmal fertig, wird sie auch nicht mehr geändert. Versprochen!
Da MS für die ganze (Win-)Welt entwickelt, kann eine einmal veröffentlichte Funktion natürlich nicht mehr geändert werden. Da hängt zuviel dran. Da es bei meinem Projekt aber um eine rein firmeninterne Geschichte geht, würde ich sagen, im Notfall kann man sowas tolerieren, da schließlich alle notwendigen Änderungen ohne Probleme vollzogen werden können (ist aber in den wenigen Monaten, in denen ich nun hier arbeite, noch nicht vorgekommen).
Nochmals Danke für die prompte Hilfe!
Gruß Matze