EXTENSION DU SHELL : MENU CONTEXTUEL (WIN32 API)

julienbj Messages postés 452 Date d'inscription jeudi 4 décembre 2003 Statut Membre Dernière intervention 19 décembre 2008 - 2 nov. 2008 à 23:29
UndeadG Messages postés 1 Date d'inscription lundi 16 octobre 2006 Statut Membre Dernière intervention 13 avril 2011 - 13 avril 2011 à 15:45
Cette discussion concerne un article du site. Pour la consulter dans son contexte d'origine, cliquez sur le lien ci-dessous.

https://codes-sources.commentcamarche.net/source/48345-extension-du-shell-menu-contextuel-win32-api

UndeadG Messages postés 1 Date d'inscription lundi 16 octobre 2006 Statut Membre Dernière intervention 13 avril 2011
13 avril 2011 à 15:45
Enfin,je trouve du code correspondant à cette question que je me posais (la msdn est bien gentille,mais manquait d'exemple,j'avais même pas compris où intervenait IClassFactory ),merci beaucoup Racpp.
ciberrique Messages postés 589 Date d'inscription lundi 25 août 2003 Statut Membre Dernière intervention 18 juillet 2010 1
16 févr. 2011 à 16:33
Bonjour,
Impossible à faire fonctionner sous Seven.
Des idées ?

Merci.
Utilisateur anonyme
24 avril 2010 à 22:34
LeFauve42 : Désolé pour le retard.
Je parlais de la version inclus dans le zip.
LeFauve42 Messages postés 239 Date d'inscription vendredi 20 octobre 2006 Statut Membre Dernière intervention 20 avril 2009
11 mars 2010 à 18:05
Roro7302: Tu parles de la DLL incluse dans le zip, ou bien d'une version que tu as recompilee en 64 bits ?
Utilisateur anonyme
11 mars 2010 à 15:43
Très bonne extension :)
Dommage que ça ne marche pas sur du 64 Bits :(
racpp Messages postés 1909 Date d'inscription vendredi 18 juin 2004 Statut Modérateur Dernière intervention 14 novembre 2014 17
4 oct. 2009 à 13:30
Merci COLARGOL7.
Désolé je ne travaille pas en .NET
Voici un article, en anglais, qui pourrait t'être utile:
http://www.theserverside.net/tt/articles/showarticle.tss'id=ShellExtensions
colargol7 Messages postés 2 Date d'inscription mardi 22 septembre 2009 Statut Membre Dernière intervention 4 octobre 2009
4 oct. 2009 à 10:19
Bonjour,
Bravo pour le code, c'est exactement ce que je cherche à faire.
- mais peut on transposer facilement ce code en C# qui est beaucoup plus à ma porté? (j'ai du mal à trouver l'équivalent en C#)
- J'ai une application qui dois mettre à jour le menu contextuel à chaque exécution, comment dois je m'organiser?
Ce sont des questions de débutant, vous n'êtes pas obligé de répondre, en tout cas merci pour les sources!!!
racpp Messages postés 1909 Date d'inscription vendredi 18 juin 2004 Statut Modérateur Dernière intervention 14 novembre 2014 17
3 oct. 2009 à 03:14
Là, je viens de remarquer un truc un peu grave. La documentation MSDN change et on ne sait plus à quoi se référer. En effet, j'utilise la documentation MSDN hors-ligne livrée avec Visual Studio 2005 qui, au sujet de SetClipboardData(), dit:
"After SetClipboardData is called, the system owns the object identified by the hMem parameter. The application can read the data, but must not free the handle or leave it locked until the CloseClipboard function is called. (The application can access the data after calling CloseClipboard). If the hMem parameter identifies a memory object, the object must have been allocated using the function with the GMEM_MOVEABLE flag."
En comparant ce paragraphe avec celui de la page du lien que tu as fourni, on se rend-compte qu'il y'a bien une différence. Pourtant cette fonction est supportée depuis Windows 95 et NT 3.51 et il ne devrait y avoir aucune raison de modifier sa documentation.
D'habitude je fais toujours très attention aux opérations d'allocation de mémoire et de sa libération. Je connais des cas où il ne faut pas libérer la mémoire allouée pour laisser le système (ou autre) l'utiliser puis la libérer. La documentation de SetClipboardData() ne précise pas qui est responsable de la libération de cette mémoire. Il existe EmptyClipboard(), ultilisée par l'application, qui ordonne au système de libérer l'objet mémoire du clipboard mais, même en le libérant avec GlobalFree() après CloseClipBoard() tout continue de fonctionner normalement. A noter que la valeur retournée par GlobalFree() est bien 0 prouvant que la libération a réussi. Ce qui laisse penser que le clipboard ne fait que copier le contenu de notre objet mémoire dans un autre objet mémoire lui appartenant.
As-tu remarqué la même anomalie en utilisant la Dll fournie dans le zip du code source?
Merci pour la contribution.
cs_Xaviou Messages postés 154 Date d'inscription dimanche 1 avril 2001 Statut Membre Dernière intervention 2 octobre 2009
2 oct. 2009 à 08:38
J'ai oublié un truc dans mon post précédent.

J'ai en effet constaté que pour un raccourci (sur le bureau, dans le menu démarrer), DragQueryFile retourne la cible de ce raccourci, et non le fichier lui-même (le ".lnk").

J'aurai besoin de détecter ce genre de chose (par exemple, pour proposer la possibilité d'ouvrir une fenêtre explorateur dans le dossier de la cible du raccourci).

@+
Xav'
cs_Xaviou Messages postés 154 Date d'inscription dimanche 1 avril 2001 Statut Membre Dernière intervention 2 octobre 2009
2 oct. 2009 à 08:25
Hello
Moi, ça merdouille un coup sur deux si je remets le GlobalFree
Pour le GlobalUnlock avant le SetClipboardData, il y est déjà (vu qu'il y était dans ta source).

Et concernant l'article MSDN, il y est bien dit que si SetClipboardData est appelée avec succès, le système prend possession de l'objet identifié par le paramètre hMem, et que l'application ne doit ni écrire dans, ni libérer la mémoire de cet objet après que la possession ait été prise par le système.
Il est par contre possible de lire le contenu de cet objet après avoir appelé SetClipboardData, en faisant un GlobalLock, mais il faut penser à faire un GlobalUnlock avant d'appeler CloseClipboard. :

Citation MSDN : If SetClipboardData succeeds, the system owns the object identified by the hMem parameter. The application may not write to or free the data once ownership has been transferred to the system, but it can lock and read from the data until the CloseClipboard function is called. (The memory must be unlocked before the Clipboard is closed.) If the hMem parameter identifies a memory object, the object must have been allocated using the function with the GMEM_MOVEABLE flag.

Sinon, j'ai un peu amélioré le truc, en utilisant l'interface IContextMenu3 à la place de IContextMenu, afin de pouvoir ajouter des icônes à mes entrées de menu contextuel.
Et autant dire, j'ai mis un moment avant de trouver pourquoi la fonction HandleMenuMsg2 n'était jamais appelée.

Pour ceux que ça intéresse, il faut penser à modifier la fonction QueryInterface :
Pour un simple IContextMenu, on a (code ci-dessus) :
if (IsEqualGUID(riid, IID_IShellExtInit) || IsEqualGUID(riid, IID_IUnknown))*ppv = (LPSHELLEXTINIT)this;
else if (IsEqualGUID(riid, IID_IContextMenu))*ppv = (LPCONTEXTMENU)this;

Pour prendre en compte IContextMenu3, il faut mettre :
if (IsEqualGUID(riid, IID_IShellExtInit) || IsEqualGUID(riid, IID_IUnknown))*ppv = (LPSHELLEXTINIT)this;
else if (IsEqualGUID(riid, IID_IContextMenu3))*ppv = (LPCONTEXTMENU3)this;
else if (IsEqualGUID(riid, IID_IContextMenu))*ppv = (LPCONTEXTMENU)this;

Et ça marche tip-top.

@+
Xav'
racpp Messages postés 1909 Date d'inscription vendredi 18 juin 2004 Statut Modérateur Dernière intervention 14 novembre 2014 17
2 oct. 2009 à 02:39
DARUNIA >> Comme précisé dans la présentation du code, la gestion des erreurs est minimale pour ne pas affecter la lisibilité du code. Pourtant, et après de nombreux tests, tout marche exactement comme prévu sans la moindre erreur avec le flag DELETE pour OpenKeyEx().
XAVIOU >> Chez moi, avec Visual C++, je n'ai remarqué aucune anomalie et cela marche à tous les coups. MSDN précise que tant que CloseClipboard() n'a pas été appelée la mémoire ne doit pas être libérée. Comme tu l'as remarqué dans le code GlobalFree() vient après CloseClipboard(). Essaie de mettre un GlobalUnlock() juste avant SetClipboardData() peut être que ça résoudrait le problème.
cs_Xaviou Messages postés 154 Date d'inscription dimanche 1 avril 2001 Statut Membre Dernière intervention 2 octobre 2009
24 sept. 2009 à 16:31
Hello
Excellente source !

Malgré tout, il y a (à mon avis) un petit soucis.
Je m'explique :
Je suis parti de cette source pour faire ma propre extension (j'utilise Code::Blocks / MinGW).
Je me suis aperçu que la fonction "Copier le chemin" ne marchait qu'un fois sur deux.
Après quelques tests, il s'avère que c'est "SetClipboardData" qui foire.

Et après consultation de la doc sur MSDN ( http://msdn.microsoft.com/en-us/library/ms649051%28VS.85%29.aspx ) il apparaît que le système prend possession de l'objet que l'on met dans le clipboard, et qu'il ne faut surtout pas libérer la mémoire correspondante.

Et effectivement, en supprimant le "GlobalFree" ça marche à tous les coups.
J'aimerais quand même avoir confirmation du fait qu'il faille bien le supprimer.

En tout cas, merci Racpp pour cette source (et pour toutes les autres).

@+
Xav'
cs_darunia Messages postés 354 Date d'inscription mercredi 18 décembre 2002 Statut Membre Dernière intervention 24 mars 2011 2
6 août 2009 à 13:17
Il y a une erreur dans le DllUnregister.

Il faut utiliser le regsam REG_SET_VALUE pour le OpenKeyEx au lieu de DELETE, sinon on se paye un bô Access Denied sur le RegDeleteKey.

Sinon, excellente source
racpp Messages postés 1909 Date d'inscription vendredi 18 juin 2004 Statut Modérateur Dernière intervention 14 novembre 2014 17
9 nov. 2008 à 16:14
racpp Messages postés 1909 Date d'inscription vendredi 18 juin 2004 Statut Modérateur Dernière intervention 14 novembre 2014 17
9 nov. 2008 à 15:25
Le code en C est presque prêt. Il faudra juste y ajouter quelques commentaires avant de le poster.
Pour unionx >> :
1- Ce sera long d'aborder les notions de base des interfaces COM. Il est possible de trouver des tutoriaux en Anglais. Si j'ai le temps d'en trouver je posterai les liens.
2- J'ai créé le projet en Dll car selon Microsoft une extension du Shell doit être implémentée dans une Dll Objet COM. C'est à dire qui exporte des interfaces avec lesquelles le Shell peut communiquer. Pour que cela fonctionne, on est donc obligés de respecter les normes définies.
3- Quand un menu contextuel est sur le point de s'ouvrir par le Shell, ce dernier cherche, dans la base de registres, les extensions voulant ajouter des éléments à ce menu. Il appelle ensuite la méthode QueryContextMenu() de l'inerface IContextMenu exportée par l'extension. Dans cette méthode, il suffit d'utiliser InsertMenu() pour ajouter un élément en lui assignant un identificateur. Pour le sous-menu on utilise InsertMenuItem() avec la strucure MENUITEMINFO péalablement initialisée. Quand un élément a été choisi, le Shell appelle la méthode InvokeCommand() en lui passant l'identificateur de l'élément. C'est donc dans cette méthode que se fait le traitement des commandes.
4- Pour que notre extension soit reconnue par le Shell, il faut l'enregistrer dans la base de registres en lui assignant un identificateur unique avec le chemin de la Dll.
5- Un compteur de référence d'une Dll permet d'empêcher cette dernière d'être déchargée par le système tant que ce compteur n'est pas nul. S'il n'est pas nul, ça veut dire qu'il y'a des objets instanciés par la Dll et ne sont pas encore détruits.
unionx Messages postés 190 Date d'inscription dimanche 17 avril 2005 Statut Membre Dernière intervention 18 mars 2009
9 nov. 2008 à 02:16
re-salut
racpp si tu veux refaire ta source en C n'oublie pas d'expliquer ou bien de nous donne un lien qui explique ce que c'est "la manipulation des interfaces COM" j'ai bien cherche dans le web et j'ai rien trouve et je veux savoir pourquoi tu as creer ton projet en dll ?
sérieusement, j'ai bien aimé ta source mais j'ai rien compris.
merci d'avoir nous explique les etapes pour insérer un element dans "IContextMenu"
et puis comment tu as fais pour ajoute des sous menu.

autre chose, la partie registre c'est quoi les lignes de :

// Ajouter le CLSID de notre DLL COM à la base de registres:
RegCreateKeyEx(HKEY_CLASSES_ROOT,"CLSID\\{DCD2E883-A2E4-11DD-B747-000D9D95332B}",0,0,0, KEY_WRITE, 0, &hKey,0);

j'aimerai savoir la partie importante de ton code, avec le minimum de code pour qu'il soit clair et après on peut ajoute les autres trucs.

au debut , j'avais pense que tout sa passe dans le registre mais dans ton code je vois pas et en plus c'est long et j'ai rien compris.
c'est pas ton defaut sert, ton code il est bien mais le probleme c'est que j'ai rien compris de ce que tu as fais.
exemple :
pourquoi le Compteur de référence de DLL ?
c'est quoi QueryContextMenu ? ne me dis pas que c'est le PHP

bon je parle trop mais je compte sur toi, si tu as le temps libre explique moi "s'il te plait" ton code et merci avance.
draluorg Messages postés 625 Date d'inscription vendredi 23 avril 2004 Statut Membre Dernière intervention 25 novembre 2010
7 nov. 2008 à 23:49
re,

bon j'avais écris tout une réponse mais bon c'est pas le lieu pour débattre de ça ça ne ferait que polluer ce post.
Par contre je serais très intéressé par un exemple en C.
Une autre chose, j'avais il y a quelques temps fait une extension Shell pour convertir des images, je m'étais basé sur un exemple en C++, tout fonctionnait, sauf que j'étais obligé de garder le gui de l'exemple sinon ça ne marchait plus.

Je n'ai jamais trouvé de documentation digeste sur le sujet, comment générer son gui ? car si j'en générait un moi même ou avec le générateur de vs le tool ne fonctionnait plus.
racpp Messages postés 1909 Date d'inscription vendredi 18 juin 2004 Statut Modérateur Dernière intervention 14 novembre 2014 17
7 nov. 2008 à 22:18
Si j'ai le temps je ferai un exemple, plus simple, mais entièrement en C.
Je n'ai pas dit "déclarer les variables n'imoporte où" mais plutôt "là où on veut". J'ai vu des codes source de pilotes en Kernel-Mode qui devraient normalement être en C mais leurs auteurs les ont écrits en C++ juste pour avoir ce petit confort dans les déclarations. Ils utilisent quelques outils faits spécialement pour cela. Quand on sait bien coder on fait du code propre que ce soit en C ou en C++.
Pour moi il y'a du natif et de l'interprété. Le C++ fait bien du natif aussi et en orienté objet.
draluorg Messages postés 625 Date d'inscription vendredi 23 avril 2004 Statut Membre Dernière intervention 25 novembre 2010
7 nov. 2008 à 21:02
Salut a tous,

Dommage que ce soit en cpp je cherche une implémentation en C depuis un ptit temps déjà...
Quelqu'un aurait-il un exemple d'implémentation ?

Pour le fait de déclarer des variables n'importe ou dans le code, je ne vois pas ça comme un avantage et ce n'est surement pas plus clair!!! c'est source de source a la noix! lol
On fini par ne plus réutiliser la moindre variable et en créer une a chaque fois!

Bon on va pas refaire le débat c/c++ mais bon, pour moi il y a le C et les interprétés. Le C++ n'a pour moi aucun intérêt! (mais ça n'engage que moi)
unionx Messages postés 190 Date d'inscription dimanche 17 avril 2005 Statut Membre Dernière intervention 18 mars 2009
7 nov. 2008 à 00:55
dernière chose, ou je peux trouver un tuto qui exprime
la manipulation des interfaces COM c'est surment ce qui j'ai pas compris dans ta source.
merci pour tout.
racpp Messages postés 1909 Date d'inscription vendredi 18 juin 2004 Statut Modérateur Dernière intervention 14 novembre 2014 17
6 nov. 2008 à 18:47
J'ai oublié d'ajouter que pour bien comprendre ce code il faut avoir le minimum de notions de base sur la manipulation des interfaces COM.
racpp Messages postés 1909 Date d'inscription vendredi 18 juin 2004 Statut Modérateur Dernière intervention 14 novembre 2014 17
6 nov. 2008 à 18:36
unionx >> Pour réaliser une extension du shell, il faut la mettre dans une DLL Objet COM. Cette dernière contient des inetrfaces COM qui sont en fait des classes. Le choix du C++ s'impose ici donc. Il est bien sûr possible de la coder entièrement en C mais ce sera beaucoup plus long et nettement plus compliqué. Il faudra en effet abondonner le confort apporté par le C++ et devoir notamment créer la VTable de chaque interface et la remplir manuellement avec les pointeurs de toutes les méthodes.
La structure MENUITEMINFO n'est utilisée ici que pour pouvoir donner un identificateur au sous-menu grâce à la fonction InsertMenuItem(). Cet identificateur est indispensable pour que le Shell puisse supprimer le sous-menu après utilisation. Pour les éléments normaux du menu contextuel cette structure est inutile.
Comme précisé par lefauve42 le C n'est pas toujours plus facile que le C++. Quand il n'y a pas d'objets C++ le C suffirait. La raison d'être du C++ est justement l'utilisation de ces objets avec toutes les notions qui vont avec. Personnellement, je n'utilise le C que pour pouvoir optimiser au maximum un programme. Une raison qui me fait adopter le C++, même sans objets, est le fait de pouvoir déclarer les variables là où on veut dans le code. C'est plus pratique à lire et surtout à maintenir. En C on est contraint de les déclarer toujours en début de bloc.
Pour une lecture plus confortable d'un long code, il est préférable de l'imprimer sur papier.
unionx Messages postés 190 Date d'inscription dimanche 17 avril 2005 Statut Membre Dernière intervention 18 mars 2009
6 nov. 2008 à 16:01
peut n'import c'est pas un probleme.
je veux creer ça dans un excutable.
je vois que la structure MENUITEMINFO est la structure qui fait tout, enfin je pense.
si c'est oui ? et apres avoir remplire cette structure comment je vais l'enregistrer pour qu'il marche ?

la source est bien clair mais il est long , je veux juste l'essenciel.

merci avance
LeFauve42 Messages postés 239 Date d'inscription vendredi 20 octobre 2006 Statut Membre Dernière intervention 20 avril 2009
6 nov. 2008 à 10:18
:o)

Unionx, je suis navre de te l'apprendre, mais en C comme en C++, il y a des fichiers d'entete (.h) et de code (.cpp ou .c).

Si regarder dans 2 fichiers est au dessus de tes forces, regarde dans le .cpp (ou .c) uniquement, tu y trouveras pratiquement tout ce qui est utile a la comprehension du source.

Ce genre de source n'est pas evident a comprendre, surtout a cause des appels systemes, et ca, tu peux les coder en ce que tu veux, ca restera aussi complique (peut-etre meme plus en C car tu ne peux pas les planquer dans une classe et les oublier (enfin, beaucoup moins facilement)).

Eric

NB: Et contrairement a certaines superstitions, le C n'est pas plus simple que le C++ (Que ce soit a ecrire ou a comprendre) :o).
unionx Messages postés 190 Date d'inscription dimanche 17 avril 2005 Statut Membre Dernière intervention 18 mars 2009
5 nov. 2008 à 23:37
trop beau ce que tu as fait, et sincerement il est trop dur a comprend, j'aime pas c++ car il faut pent de voir le type de retour dans .h et d'autre truc et regarde dans le fichier cpp ce qui me asse la tete et c'est pour ca pourquoi j'aime c et pas c++

très bonne travail 10/10

la prochaine fois s'il vous plait fait tes sources en c simple si c'est possible c'est tout.

merci encore
racpp Messages postés 1909 Date d'inscription vendredi 18 juin 2004 Statut Modérateur Dernière intervention 14 novembre 2014 17
4 nov. 2008 à 19:35
Merci julienbj et lefauve42.
julienbj >> Pour les informations, c'est essentiellement la MSDN. Comme cette page pour commencer:
http://msdn.microsoft.com/en-us/library/cc144067(VS.85).aspx

lefauve42 >> Comme tu l'as compris, j'ai inventé le type de fichiers .FCH juste pour illustrer le fonctionnement de cette extension du shell et notamment l'ajout d'un élément au menu contextuel pour un type de fichier précis.
LeFauve42 Messages postés 239 Date d'inscription vendredi 20 octobre 2006 Statut Membre Dernière intervention 20 avril 2009
4 nov. 2008 à 11:45
Merci pour ce code tres utile, que je prendrais le temps de regarder en details, mais je n'ai pas bien compris le but des fichiers .FCH.
Est-ce que c'est juste pour illustrer l'ajout de menus associes a un type personalise ou bien est-ce qu'ils ont une utilite qui m'a echapee ?

Eric

NB: Ca fait plaisir de trouver encore quelques codes qui fonctionnent sans l'usine a gaz .net :o)
julienbj Messages postés 452 Date d'inscription jeudi 4 décembre 2003 Statut Membre Dernière intervention 19 décembre 2008 15
2 nov. 2008 à 23:29
Impressionnant...
Ou trouves-tu donc toutes ces informations?

Je suis assez surpris, cela fait déjà plusieurs fois que j'effectue des recherches (code/messages sur le forum) sans avoir réellement trouvé mon bonheur, et ... Racpp poste 2 à 3 jours plus tard exactement ce que je recherche... Bravo en tout cas pour cette source.
Rejoignez-nous