DBO Geschrieben 15. Oktober 2001 Teilen Geschrieben 15. Oktober 2001 Hi, mein Ausbildungsbeautragter hat mich heute mit meinem neuen Projekt konfrontriert. Dabei soll mit Hilfe von Shell Erweiterungen es möglich werden das man über das Kontextmenu einer Datei einen von uns Definierten Befehl aus führt, das ganze soll nur bei einem bestimmten Dateityp überhaupt in Kontextmenu anwendbar sein. Zwar hat er mir auch ein Buch da gelassen welches ziemlich informativ ist allerdings fehlt mir irgendwie der Background dazu. Deswegen hier meine Frage: Was ruft wen auf, und wer registriert sich wo(in Bezug auf Shell-erweiterungs-Dll)? Ok ich weis das hört sich bescheuert an... aber es ist einfach so das dieses Buch fast zu spezifisch ist, und ich einfach ne erklärung der groben zusammenhänge und funktionsweise der Shell Erweiterung Thx für alle Post Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
Crush Geschrieben 15. Oktober 2001 Teilen Geschrieben 15. Oktober 2001 Wenn ich mich nicht täusche ist das fast alles in der Registry zu erledigen. Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
Magoo Geschrieben 16. Oktober 2001 Teilen Geschrieben 16. Oktober 2001 Ich meine auch, das das alles in der Registry erledigt wird. Ich habe mal sowas ähnliches gemacht. Ist aber schon eine Weile her und weiss nicht mehr, wie ich das gemacht hab. Aber heute Abend kann ich das gerne mal nachgucken... CU Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
DBO Geschrieben 16. Oktober 2001 Autor Teilen Geschrieben 16. Oktober 2001 @Magoo wer echt nett von dir!! Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
Crush Geschrieben 16. Oktober 2001 Teilen Geschrieben 16. Oktober 2001 Also im Registy-Editor schau Dir mal HKEY_CLASSES_ROOT an. Im gleichen Ordner kann man anscheinend Zusatz-Informationen in der CLSID (Class-ID) hinterlegen, die Reihenfolge ist einfach ersichtlich (einfach um 1 hochzählen=nächster Eintrag). CLSID merken! Jetzt gehst Du nach MIME\Database\Content Type\application\irgendeinname, setzt dort einen Key Extension mit der Endung und die CLSID von Deinem neu angelegten Programmaufruf. Es könnte sein, daß die CLSID nicht mehr benötigt wird und schon von oben die richtige Class aufgerufen wird ... probier´s halt aus. Notwendig ist es an sich nicht, außer für den File-Kontext, aber Du kannst noch eine detailliertere Beschreibung der Extension in Arbeitsplatz\HKEY_LOCAL_MACHINE\Software\CLASSES\ hinterlegen. Die obigen Keys müssen eventuell auch noch in der lokalen Maschine angelegt werden (wahrscheinlich nicht unbedingt) bei: Arbeitsplatz\HKEY_LOCAL_MACHINE\Software\CLASSES\CLSID\(obige ID-Nr.) und Arbeitsplatz\HKEY_LOCAL_MACHINE\Software\CLASSES\MIME\Database\Content Type\ Ein Doppelklick sollte dann den richtigen Typen aufrufen mit dem zugehörigen Programm. Es gibt noch Möglichkeiten Variable Parameter mit zu übergeben beim Programmaufruf und zwar mit %1 oder ein ähnliches Steuerzeichen wenn ich mich nicht täusche, dann wird der Name des geklickten Files als Parameter direkt übergeben - such halt ein wenig rum, dann findest Du´s schon. Im Programm mußt Du diesen halt abfangen bei: int main(int argc, char* argv[]) wenn Du was eigenes schreibst (weißt ja, Argument-Anzahl, Argumente). Rein theoretisch müßte es schon vollkommen ausreichend sein, wenn die ganzen Keys nur in der LOCALE_MACHINE eingetragen sind, das ist jedoch dann nur für Single-User-Workstations! Getestet habe ich das ganze jetzt auch gerade nicht, aber bestimmt wird das so ungefähr ablaufen. Das ist ohnehin nirgendwo richtig erklärt. Bei den Keys muß man halt drauf aufpassen, daß ein Neuer nur 1 mal existieren darf, da sonst die Registry nicht weiß, welcher Teil zu welcher ID gehört und somit Fehlaufrufe starten könnten, bzw. beim nächsten Registry-Defrag nur ein fataler Fehler angezeigt wird. <FONT COLOR="#a62a2a" SIZE="1">[ 16. Oktober 2001 08:50: Beitrag 1 mal editiert, zuletzt von Crush ]</font> Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
DBO Geschrieben 16. Oktober 2001 Autor Teilen Geschrieben 16. Oktober 2001 Danke das hat zumindest einige meiner Fragen beantwortet. Wenn sich jetzt noch jemand finden würde der mir erklärt wie die Shell-Erweiterungs-DLL's funktionieren wärs super Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
Crush Geschrieben 16. Oktober 2001 Teilen Geschrieben 16. Oktober 2001 Anstatt der DLLs kannst Du auch einfach eine Exe reinsetzen! Eine DLL wird nur dann verwendet, wenn mehrere Programme einfach dieselben Funktionen für bestimmte Dinge benötigen, so spart man sich Speicher und Versions-Updates benötigen nur 1 neues File, der Verlust eines solchen Files betrifft aber deshalb leider auch alle damit verknüpften Programme und kann einer der Hauptgründe für ein unstabiles System. Du kannst ja mal den DLL-Explorer http://www.realsol.com.au/DLL.htm benutzen um zu schauen was für Programme welche DLL verwenden. Eigentlich hat das nur Sinn, wenn Du etwas Eigenes schreibst, was als mehrfache Instanz im Speicher lauffähig sein soll, andererseits kannst Du ja auch mehrere Exe Dateien starten und die Funktionen direkt beim Compilen fest einlinken. Das ist einfach eine Frage des persönlichen Geschmacks. Wenn eine DLL mit einer Extension verknüpft ist, dann muß entweder ein Programm dafür mitverknüpft sein oder die Schnittstelle zwischen Programmen und der DLL c:\Windows\RUNDLL (meistens auch im Task-Menü sichtbar) entscheidet wohl irgendwie, wer damit gestartet wird. Früher bei entsprechend kleinen Speichern war das DLL-System bestimmt vorteilhaft und sinnvoll, aber heute gibt es wohl nur noch das Argument, daß Updates einfacher auszuführen sind, bzw. sogar zur Laufzeit möglich sind. Das hat aber noch den Nachteil, daß bei Deinstallationen von Programmen der User hoffnungslos überfragt ist, ob eine DLL beibehalten oder entfernt werden soll, da dieser meist eh nicht weiß, wer, wo wann diese DLL tatsächlich benutzt und ein Löschen fatale Folgen haben kann. Viren hängen sich ja auch deshalb gerne an DLLs, da diese "extern" gestartet werden - wieder ein Argument gegen DLLs. Da kann man noch viel drüber streiten. Wo sollen eigentlich die Shellextension-DLLs sein, denn ich habe da nix entsprechendes finden können? <FONT COLOR="#a62a2a" SIZE="1">[ 16. Oktober 2001 09:16: Beitrag 2 mal editiert, zuletzt von Crush ]</font> Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
DBO Geschrieben 16. Oktober 2001 Autor Teilen Geschrieben 16. Oktober 2001 An der Sache einfach noch ne Exe mit reinzuhängen hab ich auch schon gedacht..nur das wollte mein Chef nicht(zwecks lernzwecken)..also muss ichs woll so angehen! Die Shell-Extensions-Dll(bez. hat mein Chef gsacht in Buch heist allerdings Shell-Erweiterungs-Dll) funktioniert im Prinzip wie eine OLE-In-Prozess-Server-DLL Das ganze Beruht auf den Component Object Model(COM) von OLE. Wobei sich die Shell eine Objektes über dessen Schittstellen bedient.Die Anwendung implementiert diese Schnittstellen in ein Shell-Erweiterungs-DLL. Danke für deine Hilfe Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
Crush Geschrieben 19. Oktober 2001 Teilen Geschrieben 19. Oktober 2001 Also mal sehn: Über den Registryeintrag "Defaulticon" kann man ein Icon an ein Objekt setzen. Eine aktualisierung des Icons auf dem System läuft über SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH, TEXT("C:\"), NULL); Ein Default-Icon für File Classes geht so z.B.: HKEY_CLASSES_ROOT .doc=AWordProcessor DefaultIcon=C:\MYDIR\MYAPP.EXE,1 Einen Context Menüeintrag erzeugt man für eine File-Extension so: HKEY_CLASSES_ROOT <applicationID> = <"description"> shell <verb> = <"menu-item text"> command = <"command string"> Command-Strings werden dann so gesetzt: HKEY_CLASSES_ROOT wrifile = Write Document shell open command = C:\Progra~1\Access~1\WORDPAD.EXE %1 print command = C:\Progra~1\Access~1\WORDPAD.EXE /p "%1" printto command = C:\Progra~1\Access~1\WORDPAD.EXE /pt "%1" "%2" "%3" "%4" der %1 parameter ist der Filename, %2 Printername, $3 Treibername und %4 Portname Das auslösen von Shell-Extension per Doppelclick (oder halt Einfachklick - je nach Einstellung) geht so: HKEY_CLASSES_ROOT .xyz="xyzfile" ShellNew NullFile="" . . . xyzfile="XYZ Picture" shell open command="C:\XYZ\XYZAPP.EXE %1 Die ClsID sollte auch mit einer GUID auf *.* erfaßt sein: HKEY_CLASSES_ROOT * = * shellex ContextMenuHandlers <name> = {00000000-1111-2222-3333-00000000000001} PropertySheetHandlers <name> = {00000000-1111-2222-3333-00000000000002} Oder auf einzelne Folders: Folder = Folder shellex DragDropHandlers <name> = {00000000-1111-2222-3333-00000000000004} CopyHookHandlers <name> = {00000000-1111-2222-3333-00000000000005} Um jetzt im Programm das ganze zu registrieren hier ein kleines Beispiel: #include <windows.h> #include <string.h> void main(void) { // // First, attempt to open the registry key where approved extensions are // listed. Note the extra slashes within the second parameter (the // registry path string). // long err; HKEY hkApproved; err = RegOpenKeyEx( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved", 0, KEY_SET_VALUE, &hkApproved); if (err == ERROR_ACCESS_DENIED) { // // The user does not have permission to add a new value to this key. In this // case, a reasonable action would be to warn the user that some // application features will not be available unless an administrator // installs the application. If the shell extension is central to the // functioning of the application, tell the user that the install // can only be performed by an administrator, and stop the install. // } else if (err == ERROR_FILE_NOT_FOUND) { // // The key does not exist. This should only happen if setup is running // on Windows 95 instead of Windows NT, or if you are installing on an older // version of either operating system that does not have the new shell. // } else if (err != ERROR_SUCCESS) { // // Some other problem... // } else { // // The open of the key succeeded. Now register the new shell extension // under this key. This requires having the ProgID and string form of the // CLSID handy. // // // Assume that lpstrProgID contains our ProgID string. // LPSTR lpstrProgID = "My Bogus Class"; // // Assume that clsidExtension contains the CLSID struct. The code below // creates a string form this CLSID. If a string version of // the CLSID is already handy, skip this code. // CLSID clsidExtension = {0x11111111, 0x1111, 0x1111, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}; HRESULT hr; LPOLESTR lpolestrCLSID; CHAR rgchCLSID[40]; CoInitialize(NULL); hr = StringFromCLSID(clsidExtension, &lpolestrCLSID); // // StringFromCLSID returns a Unicode string, so convert to ANSI for // calling the registry. Note that on Windows NT you can call the Unicode // version of the registry API instead. // WideCharToMultiByte(CP_ACP, 0, lpolestrCLSID, -1, rgchCLSID, 40, NULL, NULL); CoTaskMemFree(lpolestrCLSID); CoUninitialize(); // // Now add the new value to the registry. // Note that each new shell extension CLSID must be registered here. // err = RegSetValueEx( hkApproved, rgchCLSID, 0, REG_SZ, (const BYTE *)lpstrProgID, strlen(lpstrProgID)); // // Finally, close the key. // err = RegCloseKey(hkApproved); } } Der Zugriff verläuft so: STDMETHODIMP CShellExt::Initialize( LPCITEMIDLIST pIDFolder, LPDATAOBJECT pDataObj, HKEY hRegKey) { // Initialize can be called more than once. if (m_pDataObj) m_pDataObj->Release(); // Save the object pointer. if (pDataObj) { m_pDataObj = pDataObj; pDataObj->AddRef(); // Get the file associated with this object, if applicable. STGMEDIUM medium; FORMATETC fe = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; UINT uCount; if(SUCCEEDED(m_pDataObj->GetData(&fe, &medium))) { // Get the file name from the HDROP. uCount = DragQueryFile((HDROP)medium.hGlobal, (UINT)-1, NULL, 0); if(uCount) DragQueryFile((HDROP)medium.hGlobal, 0, m_szFile, sizeof(m_szFile)); ReleaseStgMedium(&medium); } } // Duplicate the registry handle. if (hRegKey) RegOpenKeyEx( hRegKey, NULL, 0L, MAXIMUM_ALLOWED, &m_hRegKey); return NOERROR; } Hier sind die wichtigsten Funktionen kurz angesprochen: A shell extension handler must implement three functions: an entry point function (often called DllMain or LibMain), DllCanUnloadNow, and DllGetClassObject. DllCanUnloadNow and DllGetClassObject are essentially the same as they would be for any OLE in-process server DLL. The use of DllCanUnloadNow is shown in the following example: STDAPI DllCanUnloadNow(void) { // g_cRefThisDll must be placed in the instance-specific // data section. return ResultFromScode((g_cRefThisDll==0) ? S_OK : S_FALSE); } DllGetClassObject needs to expose the class factory for the object in the DLL. For more information about exposing the class factory, see the OLE documentation included in the Microsoft Platform Software Development Kit (SDK). The following example shows how to expose the class factory. // DllGetClassObject - a DLL entry point function used by // most in-process server DLLs. STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppvOut) { *ppvOut = NULL; // assume failure if (IsEqualIID(rclsid, CLSID_ShellExtension)) { return CShellExtSample_Create(riid, ppvOut); } else { return CLASS_E_CLASSNOTAVAILABLE; } } Und hier wie´s im Programm dann aussehen könnte: STDMETHODIMP CShellExt::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags) { UINT idCmd = idCmdFirst; char szMenuText1[64]; char szMenuText2[64]; char szMenuText3[64]; char szMenuText4[64]; BOOL bAppendItems=TRUE; if ((uFlags & 0x000F) == CMF_NORMAL) { lstrcpy(szMenuText1, "New menu item 1, Normal File"); lstrcpy(szMenuText2, "New menu item 2, Normal File"); lstrcpy(szMenuText3, "New menu item 3, Normal File"); lstrcpy(szMenuText4, "New menu item 4, Normal File"); } else if (uFlags & CMF_VERBSONLY) { lstrcpy(szMenuText1, "New menu item 1, Shortcut File"); lstrcpy(szMenuText2, "New menu item 2, Shortcut File"); lstrcpy(szMenuText3, "New menu item 3, Shortcut File"); lstrcpy(szMenuText4, "New menu item 4, Shortcut File"); } else if (uFlags & CMF_EXPLORE) { lstrcpy(szMenuText1, "New menu item 1, Normal File right click in Explorer"); lstrcpy(szMenuText2, "New menu item 2, Normal File right click in Explorer"); lstrcpy(szMenuText3, "New menu item 3, Normal File right click in Explorer"); lstrcpy(szMenuText4, "New menu item 4, Normal File right click in Explorer"); } else { bAppendItems = FALSE; } if (bAppendItems) { // Insert a separator InsertMenu(hMenu, indexMenu++, MF_SEPARATOR | MF_BYPOSITION, 0, NULL); // Insert the menu items InsertMenu(hMenu, indexMenu++, MF_STRING | MF_BYPOSITION, idCmd++, szMenuText1); InsertMenu(hMenu, indexMenu++, MF_STRING | MF_BYPOSITION, idCmd++, szMenuText2); InsertMenu(hMenu, indexMenu++, MF_STRING | MF_BYPOSITION, idCmd++, szMenuText3); InsertMenu(hMenu, indexMenu++, MF_STRING | MF_BYPOSITION, idCmd++, szMenuText4); // Must return the greatest menu item identifier plus one. return MAKE_HRESULT(SEVERITY_SUCCESS, 0, idCmd); } return NOERROR; } When the user selects one of the menu items added by a context menu handler, the shell calls the handler's InvokeCommand method to let the handler process the command. If multiple context menu handlers are registered for a file type, the value of the ContextMenuHandlers key determines the order of the commands. The InvokeCommand function in the following example handles the commands associated with the menu items added by the previous example. STDMETHODIMP CShellExt::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi) { HRESULT hr = E_INVALIDARG; // If the high-order word of lpcmi->lpVerb is not NULL, this // function was called by an application and lpVerb is a command // that should be activated. Otherwise, the shell has called this // function, and the low-order word of lpcmi->lpVerb is the // identifier of the menu item that the user selected. if (!HIWORD(lpcmi->lpVerb)) { switch (LOWORD(lpcmi->lpVerb)) { case 0: hr = DoMenu1(lpcmi->hwnd, lpcmi->lpDirectory, lpcmi->lpVerb, lpcmi->lpParameters, lpcmi->nShow); break; case 1: hr = DoMenu2(lpcmi->hwnd, lpcmi->lpDirectory, lpcmi->lpVerb, lpcmi->lpParameters, lpcmi->nShow); break; case 2: hr = DoMenu3(lpcmi->hwnd, lpcmi->lpDirectory, lpcmi->lpVerb, lpcmi->lpParameters, lpcmi->nShow); break; case 3: hr = DoMenu4(lpcmi->hwnd, lpcmi->lpDirectory, lpcmi->lpVerb, lpcmi->lpParameters, lpcmi->nShow); break; } } return hr; } Also ich halte das auch für etwas aufwendig, aber so wird´s halt scheinbar gemacht. Die Auszüge sind alle aus der M$ MSDN! Also frage mich nicht, was was genau bedeuten soll. Vielleicht bringt Dich aber das weiter. Du mußt hat alles über DLLMain oder DLLLibmain integrieren - das ist wohl die Absicht Deines "Chefs". Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
Empfohlene Beiträge
Dein Kommentar
Du kannst jetzt schreiben und Dich später registrieren. Wenn Du ein Konto hast, melde Dich jetzt an, um unter Deinem Benutzernamen zu schreiben.