IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage C++ Discussion :

[DLL C++] Dependency Walker - Error: Modules with different CPU types were found.


Sujet :

Langage C++

  1. #1
    Futur Membre du Club
    Profil pro
    Inscrit en
    Août 2012
    Messages
    6
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2012
    Messages : 6
    Points : 6
    Points
    6
    Par défaut [DLL C++] Dependency Walker - Error: Modules with different CPU types were found.
    Bonjour,

    J'ai besoin d'aide... Voici un résumé de mon soucis
    • Je crée un programme Perl/Tk. Jusque là, je m'en sors. Cependant, pour certaines fonctions, j'ai décidé de passer par un fichier DLL appelé depuis Perl. Et c'est là que les ennuis commencent.
    • Je télécharge donc Code::Blocks que je sais être un bon éditeur C/C++, et je démarre un nouveau projet de DLL.
    • Afin de tester, je crée une fonction toute bête qui multiplie par 3 le nombre passé en paramètres et retourne le résultat et une autre qui retourne une simple chaine de caractères.
    • Je compile ma DLL avec Code::Blocks et le compilateur Gcc (j'ai mingw 64 bits d'installé).
    • Et là où ca déconne, c'est quand je tente d'utiliser ma DLL, l'appel à la fonction Win32::Api->new() de Perl retourne undef et Windows me retourne ce message d'erreur :
      Nom : erreur_dll_01.png
Affichages : 766
Taille : 27,3 Ko
    • Alors je creuse un peu, et je vois sur des forums qu'on recommande le logiciel Dependency Walker pour identifier les erreurs d'une DLL. J'installe donc ce logiciel, et analyse ma DLL avec
    • La seule erreur que remonte DW, c'est "Error: Modules with different CPU types were found."


    Voici maintenant les sources que j'utilise :
    Code perl : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    #!C:/Strawberry/bin/perl.exe
    use warnings;
    use strict;
     
    use Win32::API;
    my $function = new Win32::API(
        "genPasswd.dll", "test", "I", "I"
    );
    print $function->Call(4);
    et l'erreur retournée par mon programme Perl :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Can't call method "Call" on an undefined value at GestionnairePasswd.pl line 15.
    Et maintenant voici les sources de ma DLL. main.h :
    Code CPP : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    #ifndef __MAIN_H__
    #define __MAIN_H__
     
    #include <windows.h>
    #include <string>
     
    using namespace std;
     
    /*  To use this exported function of dll, include this header
     *  in your project.
     */
     
    #ifdef BUILD_*DLL
        #define DLL_EXPORT __declspec(dllexport)
    #else
        #define DLL_EXPORT __declspec(dllimport)
    #endif
     
     
    #ifdef __cplusplus
    extern "C"
    {
    #endif
     
    DLL_EXPORT string __stdcall getId();
    DLL_EXPORT int test(int t);
     
    #ifdef __cplusplus
    }
    #endif
     
    #endif // __MAIN_H__

    et main.cpp :
    Code CPP : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    #include "main.h"
     
    // a sample exported function
    DLL_EXPORT string __stdcall getId()
    {
        return "Test";
    }
     
    DLL_EXPORT int test(int t) {
        return t * 2;
    }
     
    extern "C" DLL_EXPORT BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
    {
        switch (fdwReason)
        {
            case DLL_PROCESS_ATTACH:
                // attach to process
                // return FALSE to fail DLL load
                break;
     
            case DLL_PROCESS_DETACH:
                // detach from process
                break;
     
            case DLL_THREAD_ATTACH:
                // attach to thread
                break;
     
            case DLL_THREAD_DETACH:
                // detach from thread
                break;
        }
        return TRUE; // succesful
    }

    Compilateur sélectionné dans Code::Blocks : GNU GCC Compiler

    Options du linker (j'ai trouvé ces lignes sur internet pour résoudre une précédente erreur) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    -static-libgcc
    -static-libstdc++
    Je remercie par avance toutes les personnes qui pourront m'aider

    EDIT :
    Voici le log de compilation (sans erreur) de ma DLL
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    -------------- Build: Release in genPasswd (compiler: GNU GCC Compiler)---------------
     
    mingw32-g++.exe -O2 -Wall -DBUILD_DLL  -c D:\Users\Sphinx\Documents\CodeBlocksProjects\genPasswd\main.cpp -o obj\Release\main.o
    mingw32-g++.exe -shared -Wl,--output-def=bin\Release\libgenPasswd.def -Wl,--out-implib=bin\Release\libgenPasswd.a -Wl,--dll  obj\Release\main.o  -o bin\Release\genPasswd.dll -s -static-libgcc -static-libstdc++  -luser32
    Output file is bin\Release\genPasswd.dll with size 9.50 KB
    Process terminated with status 0 (0 minute(s), 0 second(s))
    0 error(s), 0 warning(s) (0 minute(s), 0 second(s))

  2. #2
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 518
    Points
    41 518
    Par défaut
    Je ne vois rien qui précise la bitness dans les lignes de commande passées à gcc.

    Pour bien faire, il faudrait de quoi connaître la bitness de perl.exe et trouver comment passer la même valeur en option à gcc...

    Edit: J'ai retrouvé un vieux code en C pour obtenir la bitness d'un fichier EXE ou DLL, et je l'ai converti pour qu'il marche sous Code::Blocks:
    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    /*
    Note: GetBinaryType() and SHGetFileInfo(SHGFI_EXETYPE) always fail on DLLs.
    ImageLoad() and the artisanal code work on both EXEs and DLLs,
    and bitness of the program or examined module doesn't influence this part.
    */
    #define UNICODE
    #define _UNICODE
    #include <windows.h>
    #include <stdio.h>
    #include <limits.h>
    #include <errno.h>
    #include <tchar.h>
     
    /*
    A PE file contains an IMAGE_DOS_HEADER that contains the offset of an IMAGE_NT_HEADERS(32/64) structure.
    The IMAGE_NT_HEADERS(32/64) structure, in turn, contains:
    	A 4-byte signature "PE\0\0"
    	A bitness-independent IMAGE_FILE_HEADER structure that contains the "machine" field we want,
    		as well as the linker timestamp (which we want in another code).
    	An IMAGE_OPTIONAL_HEADER(32/64) structure.
     
    This function returns 0 if successful and -1  if it fails.
    */
    static int ReadPEFileMachine(FILE *pfIn, WORD *pMachine, BOOL bVerbose)
    {
    	IMAGE_DOS_HEADER imageDosHeader = {0};
    	size_t nRead = 0;
     
    	if(pfIn == NULL || pMachine==NULL)
    	{
    		errno = EINVAL;
    		return -1;
    	}
     
     
    	nRead = fread(&imageDosHeader, sizeof(imageDosHeader), 1, pfIn);
    	if(nRead != 1)
    	{
    		if(bVerbose)
    			_ftprintf(stderr, _T("fread(IMAGE_DOS_HEADER) returned %d (Error: C %d)\n"), nRead, errno);
    		return -1;
    	}
     
    	{
    		LONG offsetPE = imageDosHeader.e_lfanew;
    		DWORD signaturePE = 0;
    		IMAGE_FILE_HEADER imageFileHeaderPE = {0};
    		int seeked;
     
    		/*if(bVerbose)
    			_ftprintf(stderr, _T("IMAGE_DOS_HEADER contains offset %ld to the PE header\n"), offsetPE);*/
    		seeked = fseek(pfIn, offsetPE, SEEK_SET);
    		if(seeked != 0)
    		{
    			if(bVerbose)
    				_ftprintf(stderr, _T("fseek returned %d (Error: C %d)\n"), seeked, errno);
    			return -1;
    		}
     
    		nRead = fread(&signaturePE, sizeof(signaturePE), 1, pfIn);
    		if(nRead != 1)
    		{
    			if(bVerbose)
    				_ftprintf(stderr, _T("fread(signature) returned %d (Error: C %d)\n"), nRead, errno);
    			return -1;
    		}
     
    		nRead = fread(&imageFileHeaderPE, sizeof(imageFileHeaderPE), 1, pfIn);
    		if(nRead != 1)
    		{
    			if(bVerbose)
    				_ftprintf(stderr, _T("fread(IMAGE_FILE_HEADER) returned %d (Error: C %d)\n"), nRead, errno);
    			return -1;
    		}
     
    		/*_ftprintf(stderr, _T("fread(IMAGE_FILE_HEADER) succeeded (Machine: 0x%04X)\n"), imageFileHeaderPE.Machine);*/
    		*pMachine = imageFileHeaderPE.Machine;
    		return 0;
    	}
    }
     
    static int GetPEFileMachine(LPCTSTR filePath, WORD *pMachine, BOOL bVerbose)
    {
    	FILE* pfIn = _tfopen(filePath, _T("rb"));
    	int ret = -1;
    	if(pfIn == NULL)
    	{
    		if(bVerbose)
    			_ftprintf(stderr, _T("fopen_s failed (Error: C %d)\n"), errno);
    		return -1;
    	}
     
    	ret = ReadPEFileMachine(pfIn, pMachine, bVerbose);
    	fclose(pfIn);
    	return ret;
    }
     
    int ReadAndPrintBitness(LPCTSTR filePath)
    {
    	/*Note: From winnt.h:
    		#define IMAGE_FILE_MACHINE_I386              0x014c  // Intel 386.
    		#define IMAGE_FILE_MACHINE_AMD64             0x8664  // AMD64 (K8)
    	*/
     
    	WORD machine = (WORD)-1;
     
    	_tprintf(_T("ThisProcesBitness: %d - FileToTest: %s\n"), (int)(sizeof(void*)*CHAR_BIT), filePath);
     
    	if(GetPEFileMachine(filePath, &machine, TRUE) == 0)
    	{
    		_tprintf(_T("GetPEFileMachine succeeded (Type: 0x%04X)\n"), machine);
    		switch(machine)
    		{
    		case IMAGE_FILE_MACHINE_I386: _tprintf(_T("%s is a 32-bit executable."), filePath); break;
    		case IMAGE_FILE_MACHINE_AMD64: _tprintf(_T("%s is a 64-bit executable."), filePath); break;
    		default: _putts(_T("Unknown executable type.")); break;
    		}
    		return 0;
    	}
    	else
    		return -1;
    }
     
    int _tmain(int argc, _TCHAR *argv[])
    {
    	if(argc < 2)
    	{
    		_putts(_T("Usage: GetBitness <filePath>"));
    		return EXIT_FAILURE;
    	}
     
    	if(ReadAndPrintBitness(argv[1]))
    		return EXIT_FAILURE;
    	return EXIT_SUCCESS;
    }
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  3. #3
    Futur Membre du Club
    Profil pro
    Inscrit en
    Août 2012
    Messages
    6
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2012
    Messages : 6
    Points : 6
    Points
    6
    Par défaut
    Je ne comprends pas ce qu'est le bitness ? Une DLL n'est donc pas utilisable par n'importe quel langage disposant des modules complémentaires ?

  4. #4
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Une DLL 32 bit ne peut être appelée que depuis un programme 32 bits lui aussi. Idem en 64 bits.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  5. #5
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 518
    Points
    41 518
    Par défaut
    L'exception étant certaines DLLs .Net (Celles en C# ou VB.Net, celles en C++/CLI compilées avec /clr:safe, et encore d'autres), qui s'adaptent aux deux parce qu'elles sont en bytecode au lieu d'être en langage machine.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  6. #6
    Expert éminent sénior

    Homme Profil pro
    pdg
    Inscrit en
    Juin 2003
    Messages
    5 749
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : pdg

    Informations forums :
    Inscription : Juin 2003
    Messages : 5 749
    Points : 10 666
    Points
    10 666
    Billets dans le blog
    3
    Par défaut
    Citation Envoyé par Iaret Voir le message
    Je ne comprends pas ce qu'est le bitness ? Une DLL n'est donc pas utilisable par n'importe quel langage disposant des modules complémentaires ?
    Nope, ça serait trop simple sinon

    Une DLL écrite prudemment avec une (vraie) interface C (pas C++) sera en effet utilisable dans beaucoup de langages (modulo l'histoire des 32/64 bits). Mais dans ton cas, tu auras un problème à l'appel de cette fonction:

    Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    DLL_EXPORT string __stdcall getId();

    Tu exportes un types C++ std::string. Et pour info, c'est même pas compatibles d'un compilo C++ vers un autre, ni même souvent d'une version (majeure) à l'autre d'un même compilo

    Tu dois adapter ton API pour exporter ta chaîne de caractère façon C, pas C++. C'est à dire via un tableau de char. L'option courante est d'accepter un buffer en entrée (donné par ton script Perl au moment de l'appel). Regarde donc comment ils font en perl pour wrapper des fonction Win32 telles que GetWindowText pour te faire une idée. C'est une façon robuste et propre.

    Après y'a une autre façon qui peut créer des surprises mais qui suffit peut-être dans ton cas (mono-thread + copie immédiate du résultat) : allouer un buffer permanent (statique) en C++, y mettre le résultat dedans, et renvoyer un pointeur brut sur ce buffer...

Discussions similaires

  1. Copy des DLL de dependances de sous projet
    Par Timidei dans le forum Visual C++
    Réponses: 3
    Dernier message: 21/05/2008, 17h30
  2. Using DLL Import lib in C code with GCC
    Par Hibou57 dans le forum C
    Réponses: 7
    Dernier message: 23/03/2006, 22h38
  3. [Forms10g (9.0.4)] error 310 with %ROWTYPE
    Par star dans le forum Oracle
    Réponses: 14
    Dernier message: 16/01/2006, 22h48
  4. Trouver les dll dont depend un programme
    Par baert dans le forum Shell et commandes GNU
    Réponses: 3
    Dernier message: 17/10/2005, 14h41
  5. dependency walker
    Par benoit70 dans le forum MFC
    Réponses: 6
    Dernier message: 13/05/2005, 14h46

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo