OVH Cloud OVH Cloud

Des char* en pagaille

4 réponses
Avatar
Fabien LE LEZ
Bonjour,

Une fonction de l'API Windows s'écrit à peu près ainsi :

size_t GetModuleFileName
(HMODULE hModule,
char* buffer_nom_fichier,
size_t taille_du_buffer);

La valeur de retour est le nombre d'octets copiés dans le buffer.
Je considère que si cette valeur de retour est égale à
taille_du_buffer, c'est que le buffer est trop petit, il faut
l'augmenter.

J'ai donc écrit :

std::string GetModuleFileName (HMODULE module)
{
size_t taille_buf= 256;
for(;;)
{
std::vector<char> buf (taille_buf);
DWORD resultat= GetModuleFileName (module, &buf[0], buf.size());
if (resultat < taille_buf)
{
return std::string (buf.begin(), buf.begin()+resultat);
}
taille_buf*=2;
}
}

Le style serait à améliorer, et je n'ai tenté aucune optimisation,
mais le principe est là : si le buffer est assez grand, je renvoie la
réponse ; sinon, je l'augmente et je réessaie.

Maintenant, j'aimerais savoir s'il est possible de rendre ce code plus
générique, afin de ne pas tout réécrire pour une fonction

size_t AutreFonction
(char* buffer_nom_fichier, size_t taille_du_buffer,
double machin, int truc);


Et j'avoue que je sèche un peu. Les seules solutions que j'entrevois
seraient nettement plus compliquées à utiliser que de tout réécrire à
chaque fois.

Donc, si quelqu'un a une solution simple et élégante...
Merci d'avance !

4 réponses

Avatar
Stan
"Fabien LE LEZ" a écrit dans le message de news:

Bonjour,

[...]



Et j'avoue que je sèche un peu. Les seules solutions que j'entrevois
seraient nettement plus compliquées à utiliser que de tout réécrire à
chaque fois.

Donc, si quelqu'un a une solution simple et élégante...
Merci d'avance !



As -tu jeté un coup d'oeil dans la bibliothèque Loki,
du côté des Typelists ?

Je pense que c'est juste ce qu'il te faut...

--
-Stan

Avatar
Loïc Joly
Bonjour,

Une fonction de l'API Windows s'écrit à peu près ainsi :

size_t GetModuleFileName
(HMODULE hModule,
char* buffer_nom_fichier,
size_t taille_du_buffer);

[snip pour rendre la chose utilisable]


Maintenant, j'aimerais savoir s'il est possible de rendre ce code plus
générique, afin de ne pas tout réécrire pour une fonction

size_t AutreFonction
(char* buffer_nom_fichier, size_t taille_du_buffer,
double machin, int truc);


J'envisage une possibilité à partir de boost::bind et boost::function
(tous deux en voie d'introduction dans le standard). Un truc du genre
(non testé) :

std::string callFctWithCheckedBuffer(
boost::function<size_t( char* buffer, size_t bufferSize)> fct)
{
size_t taille_buf= 256;
for(;;)
{
std::vector<char> buf (taille_buf);
size_t resultat= fct(&buf[0], buf.size());
if (resultat < taille_buf)
{
return std::string (buf.begin(), buf.begin()+resultat);
}
taille_buf*=2;
}
}

Que l'on pourrait appeler ainsi :

string str = callFctWithCheckedBuffer(
boost::bind(GetModuleFileName, module, _1, _2));
string str2 = callFctWithCheckedBuffer(
boost::bind(AutreFonction, _1, _2, machin, truc));

--
Loïc

Avatar
Sylvain Togni

std::string GetModuleFileName (HMODULE module)
{
size_t taille_buf= 256;
for(;;)
{
std::vector<char> buf (taille_buf);
DWORD resultat= GetModuleFileName (module, &buf[0], buf.size());
if (resultat < taille_buf)
{
return std::string (buf.begin(), buf.begin()+resultat);
}
taille_buf*=2;
}
}


Normalement on a pas à faire ce genre de choses, une api C sérieuse
va forcément prévoire une stratégie d'allocation des buffers pas
trop compliquée pour l'utilisateur.

En l'occurrence, puisque c'est un chemin de fichier qui est retourné,
ceci suffit :

std::string GetModuleFileName(HMODULE module)
{
char buffer[MAX_PATH + 1];
GetModuleFileName(module, buffer, sizeof(buffer));
return buffer;
}

D'autres fois, il faut s'y prendre en deux temps :

std::string RegQueryValue(HKEY key, std::string subKey)
{
// premier appel pour obtenir la taille
LONG size;
RegQueryValue(key, subKey.c_str(), NULL, &size);
std::vector<char> buffer(size);

// deuxième appel pour remplir le buffer
RegQueryValue(key, subKey.c_str(), &buffer[0], &size);
return std::string(&buffer[0], size);
}

--
Sylvain

Avatar
Fabien LE LEZ
On Fri, 09 Sep 2005 00:49:51 +0200, Sylvain Togni
:

En l'occurrence, puisque c'est un chemin de fichier qui est retourné,
ceci suffit :

std::string GetModuleFileName(HMODULE module)
{
char buffer[MAX_PATH + 1];
GetModuleFileName(module, buffer, sizeof(buffer));


Mon code me paraît nettement plus robuste.

<semi-HS>
Suivant le header, MAX_PATH vaut quelque chose comme 255 ou 260.
Or, avec la fonction CreateFile, il semble qu'on puisse créer des
fichiers au nom nettement plus long. Je préfère donc éviter de
présumer d'une taille maximale. Ou plutôt, je sais que le code que
j'ai proposé marche tout le temps, tandis qu'avec ta méthode, il faut
s'assurer que la limite qu'on met est bien valide.

<< CreateFile
[...]
Windows NT: You can use paths longer than MAX_PATH characters by
calling the wide (W) version of CreateFile and prepending "?" to
the path. The "?" tells the function to turn off path parsing. This
lets you use paths that are nearly 32,000 Unicode characters long. >>