OVH Cloud OVH Cloud

Clipboard windows

10 réponses
Avatar
lkm
Bonjour,

Désolé pour la duplication de ce message dans ce nouveau thread, mais
j'ai posté l'autre un peu trop haut ...

Je suis sur un problème qui me pose quelques soucis certainement dus à
mon manque d'expérience de l'API windows ...

J'ai la fonction suivante :

void InputClipboardData(char * Data)
{
DWORD DataLen ;
HGLOBAL hgbl ;
char * pnem ;
char * test = (char *)malloc(1024) ;
int i ;

DataLen = strlen(Data) ;
hgbl = GlobalAlloc(GHND, DataLen) ;
pnem = (char *)GlobalLock(hgbl) ;

strncpy(pnem, Data, DataLen) ;

GlobalUnlock(hgbl) ;
OpenClipboard(NULL) ;

EmptyClipboard() ;
//SetClipboardData(CF_TEXT, hgbl) ;

for(i=0; i<=3; i++){
sprintf(test, "ici %s=>%s=>%d=>%d", pnem, hgbl, DataLen, pnem) ;
MessageBox(NULL, test, "InputClipboardData", 1) ;
SetClipboardData(CF_TEXT, pnem) ;
}
CloseClipboard() ;
}

J'ai l'impression que la fonction SetClipboardData me supprime mon
dernier octet mais je ne comprend pas pourquoi ... L'execution de cette
fonction me sort :"test" "tes" "te" ... comme série de valeur pour pnem.
Le dernier caractère est donc supprimé à chaque appel de
SetClipboardData. Suis-je passé à coté de quelque chose ?

Merci, et bonnes fêtes à tous !

10 réponses

Avatar
Patrick Philippot
Bonjour,

Le dernier caractère est donc supprimé à chaque appel de
SetClipboardData. Suis-je passé à coté de quelque chose ?



Oui.

DataLen = strlen(Data) + 1;

Vous oubliez le 0 terminal de la chaîne qui n'est pas inclus dans la
valeur retournée par strlen. Le nombre d'octets occupés par la chaîne
est égale à la longeur + 1 (le 0). Enfin, quand je dis nombre d'octets,
c'est une bêtise puisque ça serait le double s'il s'agissait d'une
chaîne UNICODE. Mais ne chipotons pas...

--
Patrick Philippot - Microsoft MVP
MainSoft Consulting Services
www.mainsoft.fr
Avatar
Arnold McDonald \(AMcD\)
Patrick Philippot wrote:

Vous oubliez le 0 terminal de la chaîne qui n'est pas inclus dans la
valeur retournée par strlen. Le nombre d'octets occupés par la chaîne
est égale à la longeur + 1 (le 0). Enfin, quand je dis nombre
d'octets, c'est une bêtise puisque ça serait le double s'il
s'agissait d'une chaîne UNICODE. Mais ne chipotons pas...



Par forcémment le double d'ailleurs, patrick. Le plus sage est de faire
sizeof(sz)/sizeof(TCHAR). Enfin, / ou /, selon les usages. sz étant la
chaîne, genre TCHAR sz[] =TEXT("yo!"); ou TCHAR sz[256]; ou PTSR sz=
TEXT("yahoooo"); etc.

--
Arnold McDonald (AMcD)

http://arnold.mcdonald.free.fr/
Avatar
lkm
Patrick Philippot a écrit :


DataLen = strlen(Data) + 1;

Vous oubliez le 0 terminal de la chaîne qui n'est pas inclus dans la
valeur retournée par strlen. Le nombre d'octets occupés par la chaîne
est égale à la longeur + 1 (le 0). Enfin, quand je dis nombre d'octets,
c'est une bêtise puisque ça serait le double s'il s'agissait d'une
chaîne UNICODE. Mais ne chipotons pas...




Honte sur moi ... Merci, je cherchais beaucoup plus compliqué alors que
l'erreur était grosse comme un camion !

Merci encore ;)
Avatar
Patrick Philippot
Arnold McDonald (AMcD) wrote:
Par forcémment le double d'ailleurs, patrick. Le plus sage est de
faire sizeof(sz)/sizeof(TCHAR).



Absolument.

D'ailleurs, pour rebondir sur cette remarque, il serait temps que tous
les développeurs C/C++ utilisent systématiquement TCHGAR au lieu de
char. N'oublions pas qu'UNICODE est utilisé nativement par les OS
Windows et par .Net. L'utilisation de l'ASCII est pénalisante pour les
performances systèmes pour toutes les APIs utilisant des chaînes de
caractères. Il faut donc écrire son code en prévision d'un passage
inéluctable à UNICODE un de ces jours.

J'en profite pour recaser un post déjà ancien mais toujours d'actualité:

L'écriture d'un code compilé en ASCII et "migrable" vers Unicode ne
représente pas un effort particulier. On utilise TCHAR.H au lieu de
string.h, on utilise les fonctions _tcsxxx au lieu des fonctions strxxx,
on ne confond pas char et octet, on fait attention à la taille des
buffers (sizeof (TCHAR)) et c'est tout.

Ensuite on #define UNICODE ou pas selon que l'on veut de l'Ascii ou de
l'Unicode. C'est incroyablement simple.

Allez tenez, je suis généreux aujourd'hui, voilà un extrait d'un de mes
cours sur ce sujet:

----------------------------------
(tous droits de reproduction réservés à MainSoft - www.mainsoft.fr)

Coder UNICODE

La première constatation du développeur mettant en oeuvre UNICODE est
qu'il va être nécessaire de travailler avec des buffers dont la taille
sera double des buffers habituels (les char étant codés sur un seul
octet). Dans certains cas extrêmes, cela peut poser quelques problèmes
(de pile par exemple).

Le type standard représentant les caractères en UNICODE est wchar_t.

Pour chaque fonction strxxxx de la bibliothèque standard C, on va donc
trouver un équivalent UNICODE. Par exemple:
char* strcat(char*, const char*);

va devenir

wchar_t* wcscat(wchar_t*, const wchar_t*);

On notera donc que toute librairie développée à partir de ces fonctions
de base de la C Runtime Library est à revoir (ou au minimum à recompiler
mais bien souvent cela ne suffira pas).

Il est bien évident que l'on a besoin ici d'une interface un peu plus
transparente qui s'adaptera automatiquement selon que l'on décide de
supporter UNICODE ou non. Les fichiers .H de Win32 mettent en oeuvre un
jeu de macros adapté. Pour rendre son code le plus possible indépendant
du choix UNICODE ou non, on procédera comme suit:

· Au lieu d'inclure STRING.H on inclura TCHAR.H.
· Au lieu d'utiliser char ou wchar_t, on utilisera le type TCHAR.
· Tout codage de texte " en dur " dans le code (à éviter), sera
fait par le biais de la macro __TEXT ou _T (identiques). Exemple:

TCHAR* szText = _T("Mon_Texte");

· On utilisera des types normalisés comme LPTSTR et LPCTSTR au lieu
de type spécifiques comme char* et const char*.
· On évitera les confusions entre tableaux de caractères et
tableaux d'octets.
· Au lieu d'utiliser des noms de fonctions standard, on utilisera
les alias définis dans TCHAR.H. Par exemple, _tcscpy deviendra strcpy si
_UNICODE n'est pas défini et wcscpy dans le cas contraire.
· Si l'on désire supporter UNICODE on fera un #define de _UNICODE.

On se rend compte dans la pratique que ces changements ne sont pas très
complexes. Le seul vrai problème est le code dérivé des fonctions
standard et encapsulé dans des classes ou des bibliothèques. La classe
CString des MFC supporte les 2 alternatives.

Certaines fonctions de l'API Win32 ont des prototypes différents selon
que UNICODE est actif ou non. De cette manière, NT sait toujours s'il
doit effectuer une conversion ou pas. Ces différences n'apparaissent pas
au développeur s'il applique les règles citées plus haut. Mises à part
quelques fonctions de la RTL C qui ne peuvent pas être converties et ont
donc des équivalents en Win32 (par ex. tolower et toupper), le passage à
un support transparent d'UNICODE se fera sans difficultés.
En cas de besoin on pourra toujours convertir des chaînes ANSI en
UNICODE et inversement à l'aide de MultiByteToWideChar et
WideCharToMultiByte. Attention aux tailles des buffers!!!

Ressources

Une remarque finale concernant les ressources. Toute chaîne de
caractères déclarée dans vos ressources est automatiquement et
obligatoirement transformée par le compilateur de ressources en chaîne
UNICODE. Selon que vous définissez _UNICODE ou non, la fonction
LoadString sera convertie dans le prototype adéquat (LoadStringW ou
LoadStringW - la fonction LoadString n'existant pas en réalité, c'est
simplement une macro).

----------------------------------

--
Patrick Philippot - Microsoft MVP
MainSoft Consulting Services
www.mainsoft.fr
Avatar
Bertrand Lenoir-Welter
Patrick Philippot :

(...) Il faut donc écrire son code en prévision d'un passage
inéluctable à UNICODE un de ces jours.



Je voudrais pas polémiquer sur un sujet avec lequel je suis plutôt
d'accord, mais... j'avoue que je vois pas forcément l'intérêt de passer
à UNICODE pour un programme destiné à tourner exclusivement sur une API
Windows de base (sans .NET et autres de même métal) et dans une langue
que l'ASCII contente très bien. J'ai un peu de mal à imaginer que les
gens de Microsoft seraient couillons au point de laisser tomber la
compatibilité ASCII d'une future API Windows.

La portabilité, c'est bien, mais c'est quand même pas une fin en soi.
Avatar
Arnold McDonald \(AMcD\)
Je suis d'accord avec toi, mais bon, également avec philippe.

Par défaut, les nouveaux OS de Kro bossent en UNICODE. C'est clair que les
avantages semblent assez flous pour l'instant, mais puisque c'est "natif",
autant faire comme l'OS. C'est plus logique non ?

Et puis c'est juste une question d'include ou de réglage du compilo. Après,
tout en TCHAR ou PTCHAR et ça y est. Pas de quoi se suicider quand même...

--
Arnold McDonald (AMcD)

http://arnold.mcdonald.free.fr/
Avatar
Patrick Philippot
Bonjour,

Je voudrais pas polémiquer sur un sujet avec lequel je suis plutôt
d'accord, mais... j'avoue que je vois pas forcément l'intérêt de
passer à UNICODE pour un programme destiné à tourner exclusivement
sur une API Windows de base (sans .NET et autres de même métal) et
dans une langue que l'ASCII contente très bien. J'ai un peu de mal à
imaginer que les gens de Microsoft seraient couillons au point de
laisser tomber la compatibilité ASCII d'une future API Windows.



Puisque l'OS travaille de toutes façons en UNICODE et ignore superbement
l'existence même de l'ASCII, à chaque fois que l'on utilise une API qui
prend en argument au moins une chaîne de caractères (et il y en a un
nombre certain), cette chaîne de caractères est nécessairement convertie
en UNICODE avant d'être passée au système. De même, si l'API retourne
une chaîne de caractères (ou transforme la ou les chaîne(s) passée(s) en
argument) et que le programme utilise ASCII, les chaînes en retour sont
converties d'UNICODE en ASCII. Selon les cas, l'impact en performances
sera négligeable ou massif.

Les gens de MS ne sont pas des couillons, c'est un fait certain mais ils
ne sont pas masochistes non plus. Le support de l'ASCII présente un
inconvénient majeur: pour chaque API manipulant des chaînes de
caractères, il leur faut maintenir 2 versions du code (ASCII et
UNICODE). Par exemple, l'API LoadString n'existe pas, c'est une macro.
Selon qu'UNICODE est défini ou non, elle va se résoudre en LoadStringW
ou LoadStringA. Il en va de même pour toutes les APIs prenant une chaîne
en argument ou retournant une chaîne.

Je ne dis pas que la compatibilité ASCII va être abandonnée mais
j'observe que de manière fort cohérente, MS ne propose plus aucun outil
de développement qui ne soit pas compatible .Net, donc UNICODE. Dans
cette panoplie, seul le C++ fait exception. Les spécifications des
futures versions de Windows sont extrêmement riches et ne vont pas
s'accommoder longtemps de cette "double vie".

La conclusion est qu'il faut dès aujourd'hui écrire son code de manière
compatible avec UNICODE sans se poser de questions. Ce n'est pas
compliqué, il faut 2 heures pour comprendre ce qu'il y a à faire. Ceux
qui ignorent ce point aujourd'hui le regretteront plus tard quand il
faudra retravailler des kilotonnes de code dans cette optique. Autant le
faire dès maintenant quand il est temps.

--
Patrick Philippot - Microsoft MVP
MainSoft Consulting Services
www.mainsoft.fr
Avatar
Bertrand Lenoir-Welter
AMcD:

Pas de quoi se suicider quand même...



D'ac. Ce qui m'a fait tiquer, c'est le mot "inéluctable" dans le post de
Patrick. J'ai quelques doutes sur cette inéluctabilité.

Et puis aussi peut-être une tendance générale comme quoi, avant même de
savoir ce que va faire un programme, le catéchisme officiel veut qu'on
soit bien sûr qu'il sera Portable (avé la majuscule hein) sur toutes les
plateformes passées, présentes et à venir. C'est comme ça qu'on voit
parfois un bidule mal fichu, buggué, voire inachevé, mais capable de
sévir sur plein de machines différentes, même si de toute façon il ne
tournera jamais que sur une seule - et encore, quand il tourne. Et quand
tu demandes à celui qui a commis la chose s'il est fier de son bébé, il
te sort que oui parce que son truc est Portable. Ca finit par agacer un
poil.
Avatar
Arnold McDonald \(AMcD\)
Oui, là, je suis absolument en phase avec toi. De comprends tout à fait les
gars que ça emmerde de refouiller 250.000 ou 500.000 lignes de code pour en
reécrire une partie lors d'un portage. D'un autre côté, si le code est bien
écrit/documenté... Et puis dans les cas où le portage est une question si
primordiale, alors passer à du Java ou quelque chose du même tonneau et le
problème est réglé.

Mais pour des appli standards, inférieur à 100k ligne de C quoi, faire du
multi-plateforme c'est amha ridicule. Tu perds un temps fou et ce n'est que
très rarement rentable. C'est parfois bien plus rapide d'écrire une version
par OS que de passer des semaines à tester que ça marche de W95 à W2003 !

Le code portable, c'est une utopie. À pleins de points de vue. Mais bon, on
va pas digresser :-).

Mais pour l'UNICODE, je suis d'accord avec l'ami Philippot. Moi, ça ne me
sert vraiment à rien dans mes applis. Mais bon, l'OS bosse en UNICODE,
alors... En plus, limite c'est une faute d'optimisation vu que, si tu reste
en 8 bits ASCII ou équivalent, l'OS va devoir allouer des buffers, traduire,
etc., pour interpréter ton ASCII. Donc, je suis passé à l'UNICODE. Un
include (ou un réglage du VS), usage de TCHAR et PTCHAR pour les types et
toutes les fonctions de chaînes t'ajoute un l, genre strlen() -> lstrlen().
Après, si tu codes en C pur, faut faire gaffe à pas oublier les * ou
/sizeof(TCHAR) dans certaines manipulations de buffer.

Sérieux, ça m'a pris 1h à piger il y a 5 ou 6 ans (ou les docs étaient moins
"évidentes" qu'aujourd'hui), depuis, j'y fais même plus gaffe. Et puis ça
fait un argument publicitaire de plus pour ton code.

Pour le code portable par contre, c'est niet. C'est d'ailleurs bizarre
l'informatique, il faudrait que ce soit parfait. Libre, gratuit, portable,
etc. Rien au monde n'est ainsi. J'ai du mal à comprendre ceux qui
s'obstinent à vouloir l'informatique comme telle. Ils feraient mieux de
peser de tout leur poids pour obtenir des OS stables, des UI simples et
ergonomiques, une informatique de "service" quoi, pas une informatique ou
l'apprentissage est inévitable. Mince, je digresse...

--
Arnold McDonald (AMcD)

http://arnold.mcdonald.free.fr/
Avatar
Patrick Philippot
Bonsoir,

D'ac. Ce qui m'a fait tiquer, c'est le mot "inéluctable" dans le post
de Patrick. J'ai quelques doutes sur cette inéluctabilité.

Et puis aussi peut-être une tendance générale comme quoi, avant même
de savoir ce que va faire un programme, le catéchisme officiel veut
qu'on soit bien sûr qu'il sera Portable



Ce n'est absolument pas un problème de portabilité (un mythe dont je
suis également revenu) mais un problème de compatibilité et de
performances. Rien à voir. C'est une précaution élémentaire à prendre
dès aujourd'hui pour éviter d'avoir à le regretter plus tard, pour les
raisons expliquées plus haut.

Le mot inéluctable vient de l'idée qui me semble évidente qu'à terme
(indéterminé), personne ne souhaitera maintenir la redondance
ASCII/UNICODE alors que tous les OS et les outils de développement
utiliseront UNICODE nativement. Plus tôt on s'en préoccupe, moins ça
fera mal (à soi même ou au repreneur de notre code).

Il ne s'agit pas nécessairement de produire des programmes UNICODE dès
aujourd'hui (bien que je ne voie pas en quoi ça gêne sauf pour la
manipulation des fichiers texte - et encore) mais d'écrire proprement
pour que le basculement se fasse en un tournemain (l'activation d'un
#define). Comme le dit Arnold, ça prend une petite heure à comprendre
(c'est pourquoi j'ai posté cet extrait de mon cours) et après on n'y
pense plus. Quand je développe en C/C++, je ne livre rien à mes clients
qui ne soit conforme à ces quelques règles simples.

--
Patrick Philippot - Microsoft MVP
MainSoft Consulting Services
www.mainsoft.fr