Probleme d'utilisation de DownloadToFile dans une DLL.

Résolu
xela138 Messages postés 10 Date d'inscription mardi 26 octobre 2004 Statut Membre Dernière intervention 22 avril 2010 - 20 avril 2009 à 14:03
cs_rt15 Messages postés 3874 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 7 novembre 2014 - 24 avril 2009 à 09:31
Bonjour à tous et merci à ceux qui pouront m'éclairer sur mon problème.
Mon client est un projet universitaire(il est sensé faire une mise à jour automatique et silencieuse d'ou la DLL)...sont role est d'interpréter un ordre sur une page web et de l'executer. Le projet tourne en version EXE sans AUCUN problèmes, j'ai récemment eu l'envie de le mettre sous forme de DLL mais je n'ai aucun bessoin de faire appel à ses fonctions par un programme extérieur donc je n'ai pas mis de .def je n'ai pas d'éclaré mes fonctions avec un extern "C" __cdecl void mafunc(){...}, je fais juste un apel à ma fonction d'initialisation au moment du chargement de la DLL avec:
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    init();   // ma fonction....
    break;
................
................
Tous se passe correctement, les MessageBox() sont affichés, je peut utiliser le registre, les socket marches.....
Maintenant le problème :)
--------> Au moment d'utiliser la fonction de l'API win32 DownloadToFile, la DLL se fige et ne fait plus rien.....Gros problème quand meme....
J'ai essayé avec les symbolles, sans les symbolles, j'ai essayé avec URLDownloadToFile(), on dirait que la DLL ne peut pas se servir de HRESULT ou HINSTANCE, je compile en "use MFC instatic lib", je n'ai jamais eu ce genre de problemes avant....Sa fait deja plus de 72h que je cherche le probleme, mais personne n'est capable de me répondre, le projet compile sans erreur juste quelques warnings....

J'ai inclus sa :
#include "stdafx.h"
#include
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <wininet.h>
#include <winsock2.h>
#pragma comment(lib,"Urlmon.lib")
#pragma comment(lib,"ole32.lib")
#pragma comment(lib,"kernel32.lib")
#pragma comment(lib,"user32.lib")
#pragma comment(lib,"advapi32.lib")
#pragma comment(lib,"shell32.lib")
#pragma comment(lib,"wininet.lib")
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "gdi32.lib")

Ma fonction de download (j'ai meme foutu les symboles, pas moyen d'utiliser l'API) :

HRESULT xURLDownloadToFile(char *szURL, char *szFileName)
{
   HMODULE urlmon_dll;
   HRESULT hRet;
   typedef HRESULT (__stdcall *UDTF)(DWORD, LPCSTR, LPCSTR, DWORD, DWORD);
   UDTF fURLDownloadToFile;
   urlmon_dll = LoadLibrary("urlmon.dll");
   fURLDownloadToFile = (UDTF)GetProcAddress(urlmon_dll, "URLDownloadToFileA")
   hRet = fURLDownloadToFile(0, szURL, szFileName, 0, 0);
   FreeLibrary(urlmon_dll);
   return hRet;
}

Et je l'apelle comme sa :

int traitement(char * recvbuf)
{
...........etc..........
xURLDownloadToFile("http://www.videolan.org/mirror-geo.php?file=vlc/0.9.9/win32/vlc-0.9.9-win32.exe", sTemp);
.........etc.......
}

Et tous se fige pile au moment ou j'appel xURLDownloadToFile()
Le problème vient à priori des HRESULT et HINSTANCE, mais je ne voit pas comment les déclarer différements.
Je suis perdu help me !!!!
J'espere que brunews pourra apporter sa contribution héhé car je pense qu'il est l'homme de la situation(MVP).

12 réponses

BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
20 avril 2009 à 21:58
Inutile d'aller chercher ailleurs, la raison précise a bien été indiquée par rt15:
Pas de loadLibrary ni FreeLibrary depuis DLL_PROCESS_ATTACH sinon réentrance de code donc boucle sans fin.


Il faut exporter ta fonction ou te lier en static à urlmon, exporter serait le mieux.
J'insiste malgré tout sur le fait que DLL_PROCESS_ATTACH n'est pas du tout le moment de longs traitements tels que téléchargement de fichiers car ça devrait se faire dans un thread.


Azer33:
Il est clair qu'un MVP n'a pas science infuse sur tous produits MS.
Mon cas:
- Je n'utilise quasi rien de VC++ hors l'éditeur et bouton compiler.
- Je me sers de très peu de fonctions Win32 (je ne fais pas d'interfaces graphiques dans mon taf).
- Je ne fais jamais de C++ (C et ASM only).
C'est connu depuis des années de la direction du prog MVP et je suis pourtant MVP VC++, simplement parce que c'est la categ la plus voisine de ce que je fais.
Par contre comme newbie t'ira chercher ailleurs, suis dispo pour te filer cahier des charges d'un calculateur statistique et on comparera les perfs.
Tu es dans quelle catégorie avec quel ID MVP ???
Je te signale aussi que les NON réponses sur le forum ont fini par me burner, telles celles de jeffy131 (surement un autre de tes pseudos). Les comptes CS ne faisant que cela sont dorénavant supprimés. Soit on vient aider, soit on passe son chemin.

ciao...
BruNews, MVP VC++
3
cs_rt15 Messages postés 3874 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 7 novembre 2014 13
21 avril 2009 à 11:15
Azer33 -> Ah ok. En fait, quand je poste sur usenet, je suis pro. Mais quand je poste sur cppfrance je le suis pas. Logique.

xela138 -> Effectivement, charger (Dans le .exe) toutes les dlls nécessaires à URLDownloadToFile avant d'appeler le point d'entrée de la dll ne corrige pas. Effectivement, le problème est ailleurs. Breum, pas facile de faire bosser un débogueur sur le sujet... Mais un petit coup de process monitor donne un résultat très intéressant :

Dernier appel : CreateThread. Un petit coup de google pour avoir la
confirmation... CreateThread dans un dllmain, ça peut générer des
DeadLock. Ca semble être le cas ici.

Explications ici ou par exemple.

Bilan, seule solution, l'export d'un symbole, comme dans le source de BruNews. Pourquoi ça te traumatise tellement d'en exporter un ???
3
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
20 avril 2009 à 14:20
On ne fait pas de longs traitements dans DLL_PROCESS_ATTACH, c'est juste l'endroit de qlqs initialisations rapides mais pas plus.

ciao...
BruNews, MVP VC++
0
xela138 Messages postés 10 Date d'inscription mardi 26 octobre 2004 Statut Membre Dernière intervention 22 avril 2010
20 avril 2009 à 14:31
Tous d'abord merci pour ta rapidité^^.
Mais alors comment faire pour utiliser cette API dans la DLL sans programme externe...Si MessageBox() passe, le reste devrait passer sans problème vu que c'est un PE. Et qu'est ce qui limite DLL_PROCESS_ATTACH.
Désolé sa fait que deux jours que j'utilise les DLL....et meme dans les nombreux tutos que j'ai lu ce n'ai pas définit clairement vus que la DLL ne sert pas à sa.
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
xela138 Messages postés 10 Date d'inscription mardi 26 octobre 2004 Statut Membre Dernière intervention 22 avril 2010
20 avril 2009 à 14:42
En gros la question c'est : Doit-je réecrire DownloadToFile moi meme pour que sa marche?... Aparement toutes les manipulations standard marchent meme à travers de nombreuses fonctions et sans problèmes.
0
cs_rt15 Messages postés 3874 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 7 novembre 2014 13
20 avril 2009 à 19:19
Salut,

[quote=msdn]
The entry-point function should perform only simple initialization or termination tasks. It must not call the LoadLibrary or LoadLibraryEx function (or a function that calls these functions), because this may create dependency loops in the DLL load order. This can result in a DLL being used before the system has executed its initialization code.
/quote

Te lier statiquement à urlmon peut régler le problème, via un .lib (Tu peux te faire ton .lib)... Mais bon exporter une bête fonction serait certainement beaucoup plus propre et moins risqué.
0
xela138 Messages postés 10 Date d'inscription mardi 26 octobre 2004 Statut Membre Dernière intervention 22 avril 2010
20 avril 2009 à 19:37
Oui j'ai remarqué que chargé une DLL depuis une autre DLL été pas trés malin, du coup j'ai fait un loader qui charge les DLLs nécéssaires au préalable. Cependant le probleme reste entier, j'ai fait apel à un viel ami à moi qui a une grande expérience en la matière, il a débugué le soft et n'a trouvé aucune erreurs, il a qualifié sa de "strange",....!@##!? l'API windows ne renvoi rien sur HRESULT. Je suis actuellement en train de coder une fonction de substitution pour DownloadToFileA. Si quelqu'un sait comment faire pour utiliser sa dans une DLL je suis preneur!!!
PS: je n'exporte pas de fonction donc il me semble difficile de lié mon .lib à urlmon.dll
je pense pouvoir faire que sa #pragma comment(lib,"Urlmon.lib").
Et encore merci pour la rapidité et la qualité des réponses :)
0
Azer33 Messages postés 6 Date d'inscription dimanche 4 janvier 2009 Statut Membre Dernière intervention 25 mai 2009
20 avril 2009 à 19:50
Tu peux essayer de demander chez les réseaux pros (les vrais), BBS et Usenet (Win32, winapi)
(rappel : le programme MVP n'a rien à voir avec un quelconque professionnalisme,
puisque le but est de réduire le budget support technique en ramassant un maximum de newbies :
aucun des 7 experts Win32 français n'est MVP par exemple...)
(étant MVP moi-même, j'ai vite compris...)
0
xela138 Messages postés 10 Date d'inscription mardi 26 octobre 2004 Statut Membre Dernière intervention 22 avril 2010
20 avril 2009 à 20:08
Ok merci je vais aller faire un tour de ce coté, et continuer mon downloader, car je pense qu'il n'y as pas de sollution as ce problème. Si quelqu'un est intéressé je peut lui envoyer le project^^ mais faudrait t'il encore savoir quelles sont les limitations de la DLL. (On ne fait pas de longs traitements dans DLL_PROCESS_ATTACH, c'est
juste l'endroit de qlqs initialisations rapides mais pas plus.)
0
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
20 avril 2009 à 22:13
et aussi Azer33:
je prends le temps de faire des tests pour voir ce qui se passe:
http://brunews.com/tstDownl.zip
Si on recompile la DLL en décommentant la ligne:
call    Download
on peut monitorer la récursion du code.


Répéter toujours 'aller voir newsgroup trucbidule et autre usenet' n'apporte rien, c'est de la pollution.

ciao...
BruNews, MVP VC++
0
xela138 Messages postés 10 Date d'inscription mardi 26 octobre 2004 Statut Membre Dernière intervention 22 avril 2010
23 avril 2009 à 18:30
Voila j'ai fini par trouver un remède à mon problème en téléchargeant moi meme le fichié je poste donc le code qui m'as permis de remplacer DownloadToFileA. Cela dit cette methode n'est pas du tous approprié comme l'on démontré brunews et rt15, le seul intéret est d'avoir une DLL qui peut fonctionner sans EXE, regsvr32.exe suffit pour charger la DLL...

int downloadurl (VOID)
{
 SOCKET sockfd;
 WSADATA wsaData;
 struct hostent *host;
 struct sockaddr_in dest_addr;
 if (WSAStartup(0x202,&wsaData) == SOCKET_ERROR) {
 WSACleanup();
 return -1;
 }
 if ( (host=gethostbyname("127.0.0.1")) == NULL) {  /* Put your server here */
 perror("gethostbyname");
  return 1;
 }
 memset(&dest_addr,0,sizeof(dest_addr));
 memcpy(&(dest_addr.sin_addr),host->h_addr,host->h_length);
 /* Prepare dest_addr */
 dest_addr.sin_family= host->h_addrtype;
dest_addr.sin_port= htons(80); /* PORT */
 if ((sockfd=socket(AF_INET,SOCK_STREAM,0)) < 0) {
 perror("socket");
  return 1;
 }
 /* Connect*/
 if (connect(sockfd, (struct sockaddr *)&dest_addr,sizeof(dest_addr)) == -1){
 perror("connect");
 return 1;
 }   
 char req[1024]="0";
 const char requete[]=
     "GET /hello_prog.exe HTTP/1.0\r\n"       
     "User-Agent: Mozilla/5.0 (Windows NT 6.0; fr; rv:1.9.0.4) Firevox/3.0.4\r\n"
     "\r\n";
 printf(requete);
 send(sockfd,requete,sizeof(requete),0); /* send GET header */
/*  Receive until the peer closes the connection */
 FILE *zfile;
 zfile=fopen("temp.exe","ab+");
 int iResult;
 char recvbuf[DEFAULT_BUFLEN]="\0";
 char exebuf[DEFAULT_BUFLEN]="\0";
 int recvbuflen = DEFAULT_BUFLEN;
         int x=0;
        int y=0;
        int i=0;
        int b=0;
 do
 {
     iResult = recv(sockfd, recvbuf, sizeof(recvbuf), 0);
     if ( iResult > 0 )
     {
         if(b==0)/* parse the first packet! */
         {
             b=1;
             /* This is totally bullshit you know that */
             while(!(recvbuf[x] == 'M' && recvbuf[x+1] == 'Z')) // Some bug with "!="
             {                 
                 x++;
             }
                for(i=x;i<=512;i++)
                 {
                 exebuf[y]=recvbuf[i];
                 y++;
                 }
                b=1;
         fwrite (exebuf, sizeof(char), y-1, zfile);
         printf("Bytes received: %d\n", iResult);
         }
         else
         fwrite (recvbuf, sizeof(char), iResult, zfile);
     }
     else if ( iResult == 0 )
         printf("Connection closed\n");
     else
         printf("recv failed: %d\n", WSAGetLastError());
 } while( iResult > 0 );
 fclose(zfile);
 #ifdef WIN32
 closesocket(sockfd);
 WSACleanup();
 #else
 close(sockfd);
 #endif
 }

Et encore merci à tous ceux qui m'ont apportés leur aide.   :)
0
cs_rt15 Messages postés 3874 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 7 novembre 2014 13
24 avril 2009 à 09:31
C'était donc ça !
Ca me fait penser à rundll32, qui permet d'exécuter une fonction exportée d'une dll, à condition que son prototype suive une convention qui va bien.
0
Rejoignez-nous