cs_Cako19
Messages postés56Date d'inscriptionmardi 4 février 2003StatutMembreDernière intervention 5 décembre 2005
-
13 avril 2004 à 16:04
cs_fabrice91
Messages postés27Date d'inscriptionjeudi 13 avril 2006StatutMembreDernière intervention28 janvier 2009
-
16 janv. 2009 à 09:49
Bonjour,
Après avoir défini une fonction appartenant à une dll externe à mon projet, à l'aide de typedef, LoadLibrary, GetProcAdress et etc..., à l'exécution, la fonction que j'utilise renvoie le bon resultat mais donne l'erreur suivante:
"The value of ESP was not properly saved across a fonction call. This is usually a result of calling a fonction declared with one calling convention with a fonction pointer declared with a different calling convention."
Pourtant je suis sure d'avoir bien défini le pointeur de fonction avec les mêmes type de paramètres que la fonction de la dll.
Quelqu'un a t il déjà rencontré cette erreur ou aurait il une idée pour la résoudre ?
cs_fabrice91
Messages postés27Date d'inscriptionjeudi 13 avril 2006StatutMembreDernière intervention28 janvier 2009 15 janv. 2009 à 10:56
Salut,
J'ai un problème qui ressemble à celui de ce sujet : j'ai créé une dll (à partir de fonction qui marchent sans problème) qui compile sans aucune erreur, et lorsque je l'utilise elle fait planter mon .exe. Je suis sur de mon .exe, et les fonctions marche parfaitement (je les ai essayé avant dans un projet sans dll). La dll exporte en __declspec , j'ai essayé avec __cdecl, mais lors de la compilation j'ai eu : error: expected initializer before "OpenCOM" j'ai essayé __cdeclspec, mais làerror: `dllimport' was not declared in this scope. (je suis sous code::block)
Que faire...
Merci d'avance pour l'aide que vous pourrez (j'espère) m'apporter.
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include "dllFAB_pointeur.h"
/* Définition de constantes*/
#define RX_SIZE 4096 /* taille tampon d'entrée */
#define TX_SIZE 4096 /* taille tampon de sortie */
#define MAX_WAIT_READ 5000 /* temps max d'attente pour lecture (en ms) */
#define DllExport __declspec(dllexport)
/******************************************************************************
OpenCOM : ouverture et configuration du port COM.
entrée : nId : Id du port COM à ouvrir.
retour : vrai si l'opération a réussi, faux sinon.
******************************************************************************/
BOOL DllExport OpenCOM(HANDLE *g_hCOM, int nId)
{
/* variables locales */
char szCOM[16];
/* Délais d'attente sur le port COM */
COMMTIMEOUTS g_cto =
{
MAX_WAIT_READ, /* ReadIntervalTimeOut */
0, /* ReadTotalTimeOutMultiplier */
MAX_WAIT_READ, /* ReadTotalTimeOutConstant */
0, /* WriteTotalTimeOutMultiplier */
0 /* WriteTotalTimeOutConstant */
};
/* construction du nom du port, tentative d'ouverture */
sprintf(szCOM, "COM%d", nId);
*g_hCOM = (HANDLE)CreateFile(szCOM, GENERIC_READ|GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, NULL);
if(*g_hCOM == INVALID_HANDLE_VALUE)
{
printf("Erreur lors de l'ouverture du port COM%d", nId);
return FALSE;
}
/* affectation taille des tampons d'émission et de réception */
SetupComm(*g_hCOM, RX_SIZE, TX_SIZE);
/* configuration du port COM */
if(!SetCommTimeouts(*g_hCOM, &g_cto) || !SetCommState(*g_hCOM, &g_dcb))
{
printf("Erreur lors de la configuration du port COM%d", nId);
CloseHandle(*g_hCOM);
return FALSE;
}
/* on vide les tampons d'émission et de réception, mise à 1 DTR */
PurgeComm(*g_hCOM, PURGE_TXCLEAR|PURGE_RXCLEAR|PURGE_TXABORT|PURGE_RXABORT);
EscapeCommFunction(*g_hCOM, SETDTR);
return TRUE;
}
/******************************************************************************
CloseCOM : fermeture du port COM.
retour : vrai si l'opération a réussi, faux sinon.
******************************************************************************/
BOOL DllExport CloseCOM(HANDLE *g_hCOM)
{
/* fermeture du port COM */
CloseHandle(*g_hCOM);
return TRUE;
}
/******************************************************************************
ReadCOM : lecture de données sur le port COM.
entrée : buffer : buffer où mettre les données lues.
nBytesToRead : nombre max d'octets à lire.
pBytesRead : variable qui va recevoir le nombre d'octets lus.
retour : vrai si l'opération a réussi, faux sinon.
-------------------------------------------------------------------------------
Remarques : - la constante MAX_WAIT_READ utilisée dans la structure
COMMTIMEOUTS permet de limiter le temps d'attente si aucun
caractères n'est présent dans le tampon d'entrée.
- la fonction peut donc retourner vrai sans avoir lu de données.
******************************************************************************/
BOOL DllExport ReadCOM(HANDLE *g_hCOM, void* buffer, int nBytesToRead, int* pBytesRead)
{
return ReadFile(*g_hCOM, buffer, nBytesToRead, (DWORD*)pBytesRead, NULL);
}
/******************************************************************************
WriteCOM : envoi de données sur le port COM.
entrée : buffer : buffer avec les données à envoyer.
nBytesToWrite : nombre d'octets à envoyer.
pBytesWritten : variable qui va recevoir le nombre d'octets
envoyés.
retour : vrai si l'opération a réussi, faux sinon.
******************************************************************************/
BOOL DllExport WriteCOM(HANDLE *g_hCOM, void* buffer, int nBytesToWrite, int* pBytesWritten)
{
/* écriture sur le port */
return WriteFile(*g_hCOM, buffer, nBytesToWrite, (DWORD*)pBytesWritten, NULL);
}
BOOL APIENTRY DllMain (HINSTANCE hInst /* Library instance handle. */ ,
DWORD reason /* Reason this function is being called. */ ,
LPVOID reserved /* Not used. */ )
{
switch (reason)
{
case DLL_PROCESS_ATTACH:
break;
case DLL_PROCESS_DETACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
}
/* Returns TRUE on success, FALSE on failure */
return TRUE;
}
PS: les fonctions doivent permettre de dialoguer avec un port COM (l'ouvrir, ecrire dessus, le lire et le fermer)
BruNews
Messages postés21040Date d'inscriptionjeudi 23 janvier 2003StatutModérateurDernière intervention21 août 2019 15 janv. 2009 à 15:08
Prenez l'habitude de TOUJOURS compiler en stdcall (à régler dans les options du proj sur VS), que soit pour DLL ou EXE et vous n'aurez jamais de problème, c'est le standard sous Windows 32 bits. Ainsi il n'y aura plus à préciser le modèle devant les fonctions.
Pour Windows 64, c'est fastcall le standard.
cs_fabrice91
Messages postés27Date d'inscriptionjeudi 13 avril 2006StatutMembreDernière intervention28 janvier 2009 15 janv. 2009 à 18:11
Merci BruNews pour ta réponse, cependant je suis sous code::block et je n'ai pas trouvé cette option dans les propriétés de mon projet...Connais-tu code::block?
Peut-on simplement dans le code modifier cela (j'ai essayé de remplacer #define DllExport __declspec(dllexport) par #define DllExport __stdcall(dllexport) ou encore #define DllExport __cdecl(dllexport)) mais j'ai erreur sur erreur)?
Sais tu ce que je pourrai essayer d'autre, et comment expliquer qu'une dll que j'ai fait précedement (exporté en __declspec) fonctionne correctement et celle la compile bien mais ne fonctionne pas ?!
cs_fabrice91
Messages postés27Date d'inscriptionjeudi 13 avril 2006StatutMembreDernière intervention28 janvier 2009 16 janv. 2009 à 09:49
J'ai essayé ton modèle SAKingdom et malheureusement, tjs le mm problème, la librairie compile bien mais lors de l'exécution j'ai tjs la mm erreur windows.. j'ai mm essayé le modèle sur une librairie quasi identique, et cette erreur que je n'avais pas est apparue...:( Je vous met le code de la librairie qui fonctionne, cela vous permettra peut etre de voir ou est l'erreur qui m'echappe... d'ailleur celle-ci n'est finalement peut etre pas sur l'exportation (et donc l'importation...)
/******************************************************************************
OpenCOM : ouverture et configuration du port COM.
entrée : nId : Id du port COM à ouvrir.
retour : vrai si l'opération a réussi, faux sinon.
******************************************************************************/
/* construction du nom du port, tentative d'ouverture */
sprintf(szCOM, "COM%d", nId);
g_hCOM = CreateFile(szCOM, GENERIC_READ|GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, NULL);
if(g_hCOM == INVALID_HANDLE_VALUE)
{
printf("Erreur lors de l'ouverture du port COM%d", nId);
return FALSE;
}
/* affectation taille des tampons d'émission et de réception */
SetupComm(g_hCOM, RX_SIZE, TX_SIZE);
/* configuration du port COM */
if(!SetCommTimeouts(g_hCOM, &g_cto) || !SetCommState(g_hCOM, &g_dcb))
{
printf("Erreur lors de la configuration du port COM%d", nId);
CloseHandle(g_hCOM);
return FALSE;
}
/* on vide les tampons d'émission et de réception, mise à 1 DTR */
PurgeComm(g_hCOM, PURGE_TXCLEAR|PURGE_RXCLEAR|PURGE_TXABORT|PURGE_RXABORT);
EscapeCommFunction(g_hCOM, SETDTR);
return TRUE;
}
/******************************************************************************
CloseCOM : fermeture du port COM.
retour : vrai si l'opération a réussi, faux sinon.
******************************************************************************/
BOOL DllExport CloseCOM()
{
/* fermeture du port COM */
CloseHandle(g_hCOM);
return TRUE;
}
/******************************************************************************
ReadCOM : lecture de données sur le port COM.
entrée : buffer : buffer où mettre les données lues.
nBytesToRead : nombre max d'octets à lire.
pBytesRead : variable qui va recevoir le nombre d'octets lus.
retour : vrai si l'opération a réussi, faux sinon.
-------------------------------------------------------------------------------
Remarques : - la constante MAX_WAIT_READ utilisée dans la structure
COMMTIMEOUTS permet de limiter le temps d'attente si aucun
caractères n'est présent dans le tampon d'entrée.
- la fonction peut donc retourner vrai sans avoir lu de données.
******************************************************************************/
BOOL DllExport ReadCOM(void* buffer, int nBytesToRead, int* pBytesRead)
{
/*return ReadFile(g_hCOM, buffer, nBytesToRead, pBytesRead, NULL);*/
return ReadFile(g_hCOM, buffer, nBytesToRead, (DWORD*)pBytesRead, NULL);/*ajout d'un cast*/
}
/******************************************************************************
WriteCOM : envoi de données sur le port COM.
entrée : buffer : buffer avec les données à envoyer.
nBytesToWrite : nombre d'octets à envoyer.
pBytesWritten : variable qui va recevoir le nombre d'octets
envoyés.
retour : vrai si l'opération a réussi, faux sinon.
******************************************************************************/
BOOL DllExport WriteCOM(void* buffer, int nBytesToWrite, int* pBytesWritten)
{
/* écriture sur le port */
/*return WriteFile(g_hCOM, buffer, nBytesToWrite, pBytesWritten, NULL);*/
return WriteFile(g_hCOM, buffer, nBytesToWrite, (DWORD*)pBytesWritten, NULL);
}
BOOL APIENTRY DllMain (HINSTANCE hInst /* Library instance handle. */ ,
DWORD reason /* Reason this function is being called. */ ,
LPVOID reserved /* Not used. */ )
{
switch (reason)
{
case DLL_PROCESS_ATTACH:
break;
case DLL_PROCESS_DETACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
}
/* Returns TRUE on success, FALSE on failure */
return TRUE;
}
Vous l'aurez compris, la différence entre les 2 est que le handle du port série avec lequel je eveux dialoguer est placé en argument dans chacune des 4 fonctions.
En tout cas merci de m'aider!