DLLs und Pointer
-
Hallo,
ich benutze seit Kurzem die CURL-Dll und bin da auf etwas gestossen, das ich gar nicht kannte, hat aber nichts mit CURL selbst zu tun sondern mit DLLs.Bei den Beispielcodes gibt es immer wieder den Hinweis, eine eigene CallBack-Methode zu implementieren:
/* NOTE: if you want this example to work on Windows with libcurl as a
DLL, you MUST also provide a read callback with CURLOPT_READFUNCTION.
Failing to do so will give you a crash since a DLL may not use the
variable's memory when passed in to it from an app like this. */Warum ist das so? Kann die DLL nicht auf Daten des Aufrufers zugreifen? Ich dachte die DLL wird in den Adressraum der App gemappt?
-
dadidag schrieb:
Ich dachte die DLL wird in den Adressraum der App gemappt?
Genau so ist es auch, das Kommentar ist äußerst merkwürdig...
-
"when passed in to it from an app like this" - like what?
Ohne den Code zu sehen hab ich jetzt keine Ahnung auf was die sich da beziehen.
Und daher kann ich auch net sagen ob das Unsinn ist oder nicht.
-
Warum ist das so? Kann die DLL nicht auf Daten des Aufrufers zugreifen?
der code der dll wird in den Prozess gemappt, richtig ....
Die dll weiss aber nicht an welche adresse (loadlibrary / dlopen handle)
alle Adressen innerhalb der Dll sind relativ zueinanderfür funktionspointer auf die dll von der App aus bekommt man dann wie folgt:
fix zur startadresse des dll codes liegt die exporttabelle, dort schaut man dann über namen oder index wie der offset ist und kann sich den pointer errechnen.
macht die funktion GetProcAdress() oder dlsym()für einen ...
Nicht exportierte symbole/funktionen/daten kann die App auch nicht wissen, das nuss die dll tun, bzw der app helfender code der dll kommt damit nicht auf Symbole /daten des Prozesses der die dll läd drauf. Datenaustausch muss immer von der Anwendung initiert werden ...
Ciao ...
-
Hier das Beispiel (man beachte den Kommentar innerhalb read_callback):
#include <stdio.h> #include <string.h> #include <curl/curl.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <errno.h> #ifdef WIN32 #include <io.h> #else #include <unistd.h> #endif /* * This example shows an FTP upload, with a rename of the file just after * a successful upload. * * Example based on source code provided by Erick Nuwendam. Thanks! */ #define LOCAL_FILE "/tmp/uploadthis.txt" #define UPLOAD_FILE_AS "while-uploading.txt" #define REMOTE_URL "ftp://example.com/" UPLOAD_FILE_AS #define RENAME_FILE_TO "renamed-and-fine.txt" /* NOTE: if you want this example to work on Windows with libcurl as a DLL, you MUST also provide a read callback with CURLOPT_READFUNCTION. Failing to do so will give you a crash since a DLL may not use the variable's memory when passed in to it from an app like this. */ static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *stream) { curl_off_t nread; /* in real-world cases, this would probably get this data differently as this fread() stuff is exactly what the library already would do by default internally */ size_t retcode = fread(ptr, size, nmemb, stream); nread = (curl_off_t)retcode; fprintf(stderr, "*** We read %" CURL_FORMAT_CURL_OFF_T " bytes from file\n", nread); return retcode; } int main(void) { CURL *curl; CURLcode res; FILE *hd_src; struct stat file_info; curl_off_t fsize; struct curl_slist *headerlist=NULL; static const char buf_1 [] = "RNFR " UPLOAD_FILE_AS; static const char buf_2 [] = "RNTO " RENAME_FILE_TO; /* get the file size of the local file */ if(stat(LOCAL_FILE, &file_info)) { printf("Couldnt open '%s': %s\n", LOCAL_FILE, strerror(errno)); return 1; } fsize = (curl_off_t)file_info.st_size; printf("Local file size: %" CURL_FORMAT_CURL_OFF_T " bytes.\n", fsize); /* get a FILE * of the same file */ hd_src = fopen(LOCAL_FILE, "rb"); /* In windows, this will init the winsock stuff */ curl_global_init(CURL_GLOBAL_ALL); /* get a curl handle */ curl = curl_easy_init(); if(curl) { /* build a list of commands to pass to libcurl */ headerlist = curl_slist_append(headerlist, buf_1); headerlist = curl_slist_append(headerlist, buf_2); /* we want to use our own read function */ curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback); /* enable uploading */ curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); /* specify target */ curl_easy_setopt(curl,CURLOPT_URL, REMOTE_URL); /* pass in that last of FTP commands to run after the transfer */ curl_easy_setopt(curl, CURLOPT_POSTQUOTE, headerlist); /* now specify which file to upload */ curl_easy_setopt(curl, CURLOPT_READDATA, hd_src); /* Set the size of the file to upload (optional). If you give a *_LARGE option you MUST make sure that the type of the passed-in argument is a curl_off_t. If you use CURLOPT_INFILESIZE (without _LARGE) you must make sure that to pass in a type 'long' argument. */ curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)fsize); /* Now run off and do what you've been told! */ res = curl_easy_perform(curl); /* Check for errors */ if(res != CURLE_OK) fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); /* clean up the FTP commands list */ curl_slist_free_all (headerlist); /* always cleanup */ curl_easy_cleanup(curl); } fclose(hd_src); /* close the local file */ curl_global_cleanup(); return 0; }
Eine DLL (in dem Fall CURL) kann nicht auf einen Buffer oder Filepointer von mir zugreifen?
So gaaaanz hab ich die Erklärung von RHBaum nicht verstanden - sorry.
-
Wenn du
CURLOPT_READFUNCTION
nicht verwendest, dann musst du statt dessen mitCURLOPT_READDATA
einenFILE*
setzen, den libcurl dann anfread()
übergibt.Die
FILE
Strukturen werden nun aber von der CRT (C-Runtime Library) verwaltet. Und diese kann je nach Compiler gänzlich unterschiedlich sein. Und vor allem: sie kann statisch zum Programm oder zur DLL dazugelinkt sein. D.h. die libcurl DLL hat "ihre" CRT mir "ihren" CRT Datenstrukturen und Funktionen, und dein Programm hat "seine" CRT mit "seinen" Datenstrukturen und Funktionen. Die existieren schön nebeneinander, und beide haben ihre eigenen, vermutlich ganz unterschiedlichen Vorstellungen darüber was einFILE
ist und wie man damit umzugehen hat.Und selbst wenn es die selbe CRT wäre: so lange sie zu einem der beiden Spieler statisch dazugelinkt ist gibt es zwei verschiedene Sets an globalen CRT Variablen. Das kann dann nicht funktionieren.
Wie es doch funktioniert, ist, wenn beide Teilnehmer mit dem selben Compiler, der selben CRT und vor allem auch beide mit der DLL Version der CRT compiliert/gelinkt wurden. (Dann geht es zumindest wenn man Visual C++ als Compiler und die Visual C++ CRT DLL verwendet.)
Um zu so einer libcurl DLL zu kommen müsstest du sie allerdings selbst bauen (und davor vermutlich noch die Projekteinstellungen anpassen damit die CRT DLL und nicht die statische Lib verwendet wird). Oder eine passend compilierte DLL für genau deine Visual Studio Version finden die auch die CRT DLL verwendet.Bei auf Windows portierten C (ohne ++) Libraries wie libcurl ist es allerdings sehr unüblich fertige DLLs für alle möglichen Visual Studio Versionen zu finden. D.h. einen
FILE*
vom Programm an die DLL zu übergeben, und die DLL macht dann was damit, geht einfach nicht. Crash-and-Burn. Daher das Kommentar mit der Warnung. Wobei die Formulierung "a DLL may not use the variable's memory when passed in to it from an app like this" mehr als nur ein wenig unglücklich ausgefallen ist. Ich hatte auf Anhieb auch keine Ahnung was damit gemeint ist.Der Zugriff auf den Speicher der
Variabe
(Struktur) ist dabei nämlich nicht das Problem. Das Problem ist dass Unsinn passiert wenn der eine ganz andere Vorstellungen darüber hat wie die Werte in diesem Speicher organisiert sind, und wo/wie ggf. weitere Datenstrukturen abzufragen/anzupassen sind wenn etwas mit dem "Objekt" das sich "in" diesem Speicher befindet gemacht werden soll.
-
Hallo hustbaer,
vielen Dank für Deine Erklärung!!!!
Das leuchtet absolut ein - *jetzt* hab auch ich das "Problem" verstanden.Grüße!