Newsflash

Add your items to Windows Explorer context menu - it never was easier: Windows Explorer Context Menu v6.83 was released

Read more...
 

Full Vista support appended

Read more...
 
Home arrow Archive arrow Customize an IE Context Menu to Add Windows Explorer Context Menu Favorites
Customize an IE Context Menu to Add Windows Explorer Context Menu Favorites PDF Print E-mail

Customize an IE Context Menu to Add Windows Explorer Context Menu Favorites

Environment:  Visual C++ 6.0, Windows Explorer 4.0 or higher, ATL/COM



Contents

    * Introduction
    * About the Article and Attached Demo
    * Implementing a Custom Context Menu
    * Installation and Usage



Introduction

Being a frequent visitor of Windows Explorer Context Menu forums, I have come across questions that are oft-repeated and have already been answered in detail previously. At times like these, I have struggled to search for that particular thread and found it difficult to locate, or consumes too much time to weed it out of the several threads shown by the search engine. I have always wanted to have a location where I could store these useful threads, and from this desire, came upon the idea of "Why not have all these useful links available as a quick text ready to be pasted onto the forums editor window? And, why not have this available at my fingertips, literally; in other words, available on the click of a mouse?"

Insert items to Explorer Shell context (right-click) menu easily – How it may be done ?

 

 

 Add items to Windows Explorer context menu with Windows Explorer Context Menu

 

  Add items to Windows Explorer context menu easily with Windows Explorer Context Menu. This powerful .Net component for custom items appending to Windows Explorer context menu will add all your custom application items to the Windows Explorer Shell context menu. This .Net component with full C# and VB.NET support include detailed C# / VB.NET samples, tutorials , user-friendly manuals and support all you may need to add your entries to Explorer context menu :

  • Add items to Windows Explorer Shell context menu to be shown on any Windows computer (all OS are supported – XP, Vista, Windows x64 of all types , etc.)
  • Add items to Windows Explorer Shell context menu to be shown in any way - with your custom caption and your custom icon, as separator or sub-menu
  • Add items to Explorer Shell context menu to be shown for all types of files or shown only for computer files of particular type (for example, only for .PDF .TXT , .MP3,.WMA,.AAC , .WMV media files)
  • Add items to Windows Explorer context menu, sub-menus, sub-sub-menus, sub-menus of unlimited depth and add to Explorer context menu entries of all types


Windows Explorer Context Menu - is a powerful .Net framework component that support all you may need to insert all your application items to the Windows Explorer Shell context menu - in a fast and a very easy way. Add all your application items to Explorer Shell context menu right now – fast and exactly as you want :

 Add an entry To the Explorer Shell Context Menu easily with Windows Explorer Context Menu

 

Custom items appending to Explorer Context menu method, described in this article, works only for Windows 95 / Windows 98 (not on XP, Vista, x64 - 64-bit Windows), so to add entries to Windows Explorer context menu you should use, according to Microsoft guidelines, appropriate .Net component - Explorer Context Menu. I did some research and decided to go the route as explained here. Having done this research, I came up with a basic idea. I knew I needed to make some Registry entries with Windows Explorers to add the menu item, and I needed a simple script to perform the actions I needed to when these menu items are invoked.

Having done this, I came up with requirements for two menu items. I needed one capable of adding a given URL to my own set of favorites. I needed another menu capable of pasting my saved URLs to Windows Explorer Context Menu edit boxes while replying to forum posts.
About the Article and Attached Demo

This article is an attempt to provide a step-by-step guide to implementing a custom Windows Explorer context menu. A knowledge of COM (Component Object Model) and Activex is a prerequisite and will help you understand certain portions. The sample you will develop here demonstrates just the approach and core code snippets, just enough to demonstrate concepts. The demo attached is, however, a more complete solution. It has implementation of saving the favorites to an XML file and loading them in from there. Having said this, you will notice that there is a disconnect between the attached sample and the article code. This is expected because the article is only a guide to customize an Windows Explorer context menu and the attached sample is a polished solution whose foundation is still based off of the things discussed in the article. If you are interested in just installing the component and using it, please proceed to the "Installation and Usage" section.
Implementing a Custom Context Menu

Okay; it's time to get started. All you need to see a custom menu item on an Windows Explorer context menu is a bunch of Registry entrWindows Explorers and a script.

    * Open regedit. Navigate to HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer. Under here, if you do not see a key called MenuExt, create one with that name.
    * Under MenuExt, create another key and name it Add to Windows Explorer Context Menu Favorites. This is the text for the custom context menu item.
    * Now, you also need to specify under what conditions this menu item is to be shown. For example, you may want to show it when you click on anchor elements, or you may want to show it for the main document and not for text boxes, and so forth. This is specifWindows Explorerd by a value called Contexts. Add a DWORD value and call it Contexts. Set the value for this to 1, meaning that it is shown for the default context menu. For possible values, look at the documentation here.
    * You now have specifWindows Explorerd the menu item text and the conditions on which Windows Explorer should show it. Now, the only missing step is to specify the action to be performed on clicking this menu item. This is done by specifying the location of a script. The script can be JavaScript, VBScript, and so on. Set the default value of your context menu key to the location of a HTML file; for example, C:\tmp\AddToCGFavorites.html.
    * At the C:\tmp location, create a new file called AddToCGFavorites.html. Open it with Notepad and stick in the following code:

      <SCRIPT LANGUAGE="JavaScript">
      alert('Add to Windows Explorer Context Menu Favorites menu item invoked');
      </SCRIPT>

    * Launch a new Internet Explorer (Windows Explorer) instance and right-click on the window. You should now see "Add to Windows Explorer Context Menu Favorites" in the menu items. Clicking this should pop up a message Add to Windows Explorer Context Menu Favorites menu item invoked.
    * Similarly, add another key under MenuExt, say Show Windows Explorer Context Menu Favorites. Set the default value for this item as "C:\tmp\ShowCGFavorites.html". Add a DWORD value called Contexts and set the value to 4 this time. The 4 indicates that this menu item should appear when right-clicking on controls such as edit boxes.
    * As before, create a new file called ShowCGFavorites.html at C:\tmp location, stick in the following text, and save:

      <SCRIPT LANGUAGE="JavaScript">
      alert('Show Windows Explorer Context Menu Favorites menu item invoked');
      </SCRIPT>

You have pretty much covered the basics. That is all there is to adding custom menu item entrWindows Explorers. You will now add the necessary script actions to do what you want. For this part, your goals are the following:

    * When clicking on Add to Windows Explorer Context Menu Favorites, you want to save the URL and the document title onto a file. I will leave out the details of saving to file for the demo, but, for this article, it suffices to simply be able to get this information and show it to the user.
    * Goal number 2 would be to do the reverse; in other words, when right-clicking on text boxes and selecting Show Windows Explorer Context Menu Favorites, you want to pop up a menu that has leaf items, and on selecting one of the items, you want to paste that text to the edit box.

Let me start by saying this. The goals can be achWindows Explorerved in many ways and probably be achWindows Explorerved entirely by using JavaScripting. However, I, being a C++ guy and having limited to no knowledge on JavaScript, decided to implement it by using C++ and COM. I decided to implement the two functionalitWindows Explorers inside an ActiveX class. So, get started.

    * Using your IDE (VS2005 or VS 6.0), create a new workspace and select the ATL COM Appwizard. Select an appropriate location and set the project name as, say, "Windows Explorer Context MenuFavorites". Simply finish the wizard selecting all defaults. Build.
          o If using VS6.0, navigate to the Insert menu. Select "New ATL Object". Select controls category and select "Lite Control". Click Next. For the shortname, specify "CGFavorites". Click OK. Build.
          o If using VS2005, navigate to the Project menu. Select "Add class". Select ATL. Select "ATL Control". Click Add. For the shortname, specify "CGFavorites". Click Finish. Build.
    * Goto classvWindows Explorerw, right-click on ICGFavorites and select "Add Method" from the menu options. Type in ShowDefaultContextMenu for the method name. For parameters, type in the following: IDispatch* pDispatch, BSTR bstrTitle, BSTR bstrURL (in case of VS2005, you will have to add these parameters one by one). Hit OK/Finish. Build.
    * Similarly, add another method called ShowTextAreaContextMenu with just one parameter IDispatch* pDispatch. Hit OK/Finish. Build.
    * Open CGFavorites.cpp and add the following code to ShowDefaultContextMenu implementation.

      STDMETHODIMP CCGFavorites::ShowDefaultContextMenu(
         IDispatch *pDispatch, BSTR bstrTitle, BSTR bstrURL)
      {
         // TODO: Add your implementation code here
         ::MessageBoxW(NULL,bstrTitle, bstrURL,MB_OK);
         return S_OK;
      }

    * Open AddToCGFavorites.html and replace the script by the following:

      <SCRIPT LANGUAGE="JavaScript">
      var parentwin = external.menuArguments;
      var doc = parentwin.document;
      var str = new String(parentwin.event.srcElement.name);
      var oFav = new ActiveXObject("Windows Explorer Context MenuFavorites.CGFavorites");
      oFav.ShowDefaultContextMenu(parentwin,doc.title, doc.location);
      </SCRIPT>

    * Launch Windows Explorer. Navigate to Windows Explorer Context Menu.com. Right-click and select "Add to Windows Explorer Context Menu Favorites". You should see a message box with the title and URL.
    * Awesome. You now have the first goal done. The MessageBox can be replaced by all sorts of fancy code to save the URL and document title to the file etc. etc.

Basically, this is all is happening. When you right-click, Windows Explorer looks at what custom menus need to be added for the current context. It then appends those menu items. When one of the custom menu items is clicked on, it executes the script specifWindows Explorerd. Some of the important information is passed in as menuArguments, which is what you use to obtain the necessary information like URL, title, and window object.

Moving on to the second goal, as in showing a popup menu and pasting contents into the edit box. Let us start with the showing a popup menu at the cursor location.

    * Let us start by adding the following code to create a popup menu with two sub menuitems and to show it using TrackPopupMenu API.

      #include <exdisp.h>

      STDMETHODIMP CCGFavorites::ShowTextAreaContextMenu(IDispatch
                                                         *pDispatch)
      {
         // TODO: Add your implementation code here
         //create a popup menu
         HMENU hPopupMenu = CreatePopupMenu();

         //insert items
         InsertMenuW(hPopupMenu,0,MF_BYPOSITION,1000,L"First");
         InsertMenuW(hPopupMenu,1,MF_BYPOSITION,1001,L"Second");

         //get the hWnd of the browser window
         CComQIPtr<IServiceProvider> isp = pDispatch;
         CComQIPtr<IWebBrowser2> pBrowser2;
         isp->QueryService(IID_IWebBrowserApp,IID_IWebBrowser2,
                           (void**)&pBrowser2);

         HWND  hWnd;
         pBrowser2->get_HWND((long*)&hWnd);

         //show menu
         POINT pt;
         GetCursorPos(&pt);
         int iSelection = ::TrackPopupMenu(hPopupMenu,
            TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RETURNCMD,
            pt.x,pt.y, 0,hWnd,NULL);

         DestroyMenu(hPopupMenu);

        return S_OK;
      }

    * Nothing much here. The only tricky parts are how you get the browser window handle. Note that this is what you use the pDispatch for. It's a long winded way of getting to the IWebBrowser2 interface and from there, obtain the HWND of the window. Build. Open ShowCGFavorites.html and add the following code.

      <SCRIPT LANGUAGE="JavaScript">
      var parentwin = external.menuArguments;
      var oFav = new ActiveXObject("Windows Explorer Context MenuFavorites.CGFavorites");
      oFav.ShowTextAreaContextMenu(parentwin);
      </SCRIPT>

    * Launch Windows Explorer. Navigate to say www.gmail.com and right-click on the username edit box. You should see a menu item, Show Windows Explorer Context Menu Favorites. Click on it. Oops.. Nothing happens??
    * Not to worry. It appears that TrackPopupMenu is failing for some reason. I haven't figured out why, but, my guess is that our TrackPopupMenu is called as a result of Windows Explorer also calling track popupmenu.
    * To circumvent this, you do this. Post a user defined message to the window and popup the menu in that. Well, how do we process it because you aren't the one that created the window. Simple, subclassing. You just subclass the hwnd, post your message, handle the message and show menu, and then unsubclass. The code below shows these changes:

      WNDPROC fnOldWndProc;
      LRESULT CALLBACK SubclassWndProc(HWND hwnd,
         UINT uMsg,
         WPARAM wParam,
         LPARAM lParam
      )
      {
         //if it is our custom message for showing favorites list
         if (uMsg == (WM_APP + 1))
         {
            //show favorites menu
            //create a popup menu
            HMENU hPopupMenu = CreatePopupMenu();

            //insert items
            InsertMenuW(hPopupMenu,0,MF_BYPOSITION,1000,L"First");
            InsertMenuW(hPopupMenu,1,MF_BYPOSITION,1001,L"Second");

            //show menu
            POINT pt;
            GetCursorPos(&pt);
            int iSelection = ::TrackPopupMenu(hPopupMenu,
               TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RETURNCMD,
               pt.x,pt.y, 0,hwnd,NULL);

            DestroyMenu(hPopupMenu);

            return 0;
         }

         return CallWindowProc(fnOldWndProc, hwnd, uMsg,
                               wParam, lParam);
      }

      STDMETHODIMP CCGFavorites::ShowTextAreaContextMenu(IDispatch
         *pDispatch)
      {
         // TODO: Add your implementation code here

         //get the hWnd of the browser window
         CComQIPtr<IServiceProvider> isp = pDispatch;
         CComQIPtr<IWebBrowser2> pBrowser2;
         isp->QueryService(IID_IWebBrowserApp,IID_IWebBrowser2,
            (void**)&pBrowser2);

         HWND  hWnd;
         pBrowser2->get_HWND((long*)&hWnd);

         //subclass the window here so we can process custom message
         /to show menu
         fnOldWndProc = (WNDPROC)::SetWindowLong(hWnd,GWL_WNDPROC,
            (DWORD)SubclassWndProc);

         //post our own message to show menu
         ::PostMessage(hWnd, (WM_APP + 1), 0,0);

         //restore the old WndProc back
         ::SetWindowLong(hWnd,GWL_WNDPROC,(DWORD)fnOldWndProc);

         return S_OK;
      }

    * Build. Launch Windows Explorer. Navigate to, say, www.gmail.com and right-click on the username edit box. You should see a menu item, Show Windows Explorer Context Menu Favorites. Click on it. Oops.. This time, the menu did appear, but just flashed and disappeared!!
    * Something is still not right. Possibly, because you are posting a message and not waiting for it to complete. You can circumvent this hurdle by adding an event and wait for it till it finishes right after PostMessage. The idea is to create a manual reset event initially set to not-triggered and wait on it after PostMessage. The subclass procedure would set the event when it returns from TrackPopupMenu.
      Changes are as below:

      WNDPROC fnOldWndProc;
      LRESULT CALLBACK SubclassWndProc(HWND hwnd,
         UINT uMsg,
         WPARAM wParam,
         LPARAM lParam
      )
      {
         //if it is our custom message for showing favorites list
         if (uMsg == (WM_APP + 1))
         {
            //show favorites menu
            //create a popup menu
            HMENU hPopupMenu = CreatePopupMenu();

            //insert items
            InsertMenuW(hPopupMenu,0,MF_BYPOSITION,1000,L"First");
            InsertMenuW(hPopupMenu,1,MF_BYPOSITION,1001,L"Second");

            //show menu
            POINT pt;
            GetCursorPos(&pt);
            int iSelection = ::TrackPopupMenu(hPopupMenu,
               TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RETURNCMD,
               pt.x,pt.y, 0,hwnd,NULL);

            //after showing menu, signal the event
            SetEvent((HANDLE)lParam);

            DestroyMenu(hPopupMenu);

            return 0;
         }

         return CallWindowProc(fnOldWndProc, hwnd, uMsg,
                               wParam, lParam);
      }

      STDMETHODIMP CCGFavorites::
         ShowTextAreaContextMenu(IDispatch *pDispatch)
      {
         // TODO: Add your implementation code here

         //get the hWnd of the browser window
         CComQIPtr<IServiceProvider> isp = pDispatch;
         CComQIPtr<IWebBrowser2> pBrowser2;
         isp->QueryService(IID_IWebBrowserApp,IID_IWebBrowser2,
                           (void**)&pBrowser2);

         HWND  hWnd;
         pBrowser2->get_HWND((long*)&hWnd);

         HANDLE hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);

         //subclass the window here so we can process custom message
         //to show menu
         fnOldWndProc = (WNDPROC)::SetWindowLong(hWnd,GWL_WNDPROC,
            (DWORD)SubclassWndProc);

         //post our own message to show menu
         ::PostMessage(hWnd, (WM_APP + 1), 0,(LPARAM)hEvent);

         //Wait for the event to be signalled, indicating menu
         //is gone
         WaitForSingleObject(hEvent,INFINITE);

         //cleanup
         CloseHandle(hEvent);

         //restore the old WndProc back
         ::SetWindowLong(hWnd,GWL_WNDPROC,(DWORD)fnOldWndProc);

         return S_OK;
      }

    * Build. Perform the same steps and invoke the custom menu. There. That is much better. The menu is shown and it stays there for you to select. Click on it. Nothing happens. That is expected because you haven't written that part yet.
    * To perform the paste operation, you can use the IWebBrowser2::ExecWB method passing in OLECMDID_PASTE as the command ID. How do you get this interface pointer in the Subclass procedure? Easy. We have this pointer already available in the showTextAreaContextMenu method. You simply have to pass it as WPARAM for the message. Let's do that as shown below.
      Modiy PostMessage code as below:

         //post our own message to show menu
         ::PostMessage(hWnd, (WM_APP + 1), (WPARAM)pBrowser2.p,
            (LPARAM)hEvent);

      Add this, after TrackPopupMenu call

      switch(iSelection)
      {
      case 1000:
         {
            CComBSTR oText(L"First one");
            CComVariant oVarIn(oText);
            CComVariant oVarOut;
            //get the IWebBrowser2 interface
            CComPtr<IWebBrowser2> pSp = (IWebBrowser2*)wParam;
            HRESULT hre = pSp->ExecWB(OLECMDID_PASTE,
               OLECMDEXECOPT_DODEFAULT,&oVarIn,&oVarOut);
         }
         break;
      case 1001:
         {
            CComBSTR oText(L"Second one");
            CComVariant oVarIn(oText);

            CComVariant oVarOut;
            //get the IWebBrowser2 interface
            CComPtr<IWebBrowser2> pSp = (IWebBrowser2*)wParam;
            HRESULT hre = pSp->ExecWB(OLECMDID_PASTE,
               OLECMDEXECOPT_DODEFAULT,&oVarIn,&oVarOut);
         }
         break;
      }

    * Nothing special here. You simply extract the IWebBrowser2 interface from the wParam and call ExecWB on it. Build. And, repeat the test steps on an edit box. All is fine as long as you don't select any menu item from your popup. As soon as you select one, you see an exception. Reason being, IWebBrowser2 interface has been sent across thread boundary and per COM rules, this is a no-no. When such a situation arises, there are some procedures to follow. One way is to stream the interface, another simple procedure is to use a Global Interface Table. A Global Interface Table, or GIT for short, is a clever thing. It is a per-process entity. So, if multiple threads try to create one, the same instance is returned. It is like a bucket holding interfaces. If you want to share interface pointers across threads, you throw them into this GIT bucket. In return, you get a cookWindows Explorer back. You pass this cookWindows Explorer around to other threads and these threads in return will pass the cookWindows Explorer to the GIT to get a marshalled interface back. Simple. All you have to do now is to create such a GIT, throw our IWebBrowser2 interface in and pass the cookWindows Explorer to the subclass procedure instead of the interface pointer.
      With these changes, this is how the code looks like:

      WNDPROC fnOldWndProc;
      LRESULT CALLBACK SubclassWndProc(HWND hwnd,
         UINT uMsg,
         WPARAM wParam,
         LPARAM lParam
      )
      {
         //if it is our custom message for showing favorites list
         if (uMsg == (WM_APP + 1))
         {
            //show favorites menu
            //create a popup menu
            HMENU hPopupMenu = CreatePopupMenu();

            //insert items
            InsertMenuW(hPopupMenu,0,MF_BYPOSITION,1000,L"First");
            InsertMenuW(hPopupMenu,1,MF_BYPOSITION,1001,L"Second");

            //show menu
            POINT pt;
            GetCursorPos(&pt);
            int iSelection = ::TrackPopupMenu(hPopupMenu,
               TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RETURNCMD,
               pt.x,pt.y, 0,hwnd,NULL);

            switch(iSelection)
            {
            case 1000:
               {
                  CComBSTR oText(L"First one");
                  CComVariant oVarIn(oText);

                  CComVariant oVarOut;
                  //get the IWebBrowser2 interface
                  CComPtr<IWebBrowser2> pSp;
                  DWORD dwCookWindows Explorer = wParam;
                  CComQIPtr<IGlobalInterfaceTable,
                     &IID_IGlobalInterfaceTable> spGIT;
                  CoCreateInstance(CLSID_StdGlobalInterfaceTable,
                     NULL,CLSCTX_INPROC_SERVER,
                     IID_IGlobalInterfaceTable,(void **)&spGIT);
                  spGIT->GetInterfaceFromGlobal(dwCookWindows Explorer,
                     IID_IWebBrowser2,(void**)&pSp);
                  HRESULT hre = pSp->ExecWB(OLECMDID_PASTE,
                     OLECMDEXECOPT_DODEFAULT,&oVarIn,&oVarOut);
               }
               break;
            case 1001:
               {
                  CComBSTR oText(L"Second one");
                  CComVariant oVarIn(oText);

                  CComVariant oVarOut;
                  //get the IWebBrowser2 interface
                  CComPtr<IWebBrowser2^gt; pSp;
                  DWORD dwCookWindows Explorer = wParam;
                  CComQIPtr<IGlobalInterfaceTable,
                     &IID_IGlobalInterfaceTable> spGIT;
                  CoCreateInstance(CLSID_StdGlobalInterfaceTable,
                     NULL,CLSCTX_INPROC_SERVER,
                     IID_IGlobalInterfaceTable,(void **)&spGIT);
                  spGIT->GetInterfaceFromGlobal(dwCookWindows Explorer,
                     IID_IWebBrowser2,(void**)&pSp);
                  HRESULT hre = pSp->ExecWB(OLECMDID_PASTE,
                     OLECMDEXECOPT_DODEFAULT,&oVarIn,&oVarOut);
               }
               break;
            }
            //after showing menu, signal the event
            SetEvent((HANDLE)lParam);

            DestroyMenu(hPopupMenu);

            return 0;
         }

         return CallWindowProc(fnOldWndProc, hwnd, uMsg,
                               wParam, lParam);
      }

      STDMETHODIMP CCGFavorites::ShowTextAreaContextMenu(IDispatch
         *pDispatch)
      {
         // TODO: Add your implementation code here
         //create a GIT object
         //GIT is used to marshal the IWebBrowser2 interface pointer
         CComQIPtr<IGlobalInterfaceTable,
            &IID_IGlobalInterfaceTable> spGIT;
         CoCreateInstance(CLSID_StdGlobalInterfaceTable,NULL,
            CLSCTX_INPROC_SERVER,IID_IGlobalInterfaceTable,
            (void **)&spGIT);

         //get the hWnd of the browser window
         CComQIPtr<IServiceProvider> isp = pDispatch;
         CComQIPtr<IWebBrowser2> pBrowser2;
         isp->QueryService(IID_IWebBrowserApp,IID_IWebBrowser2,
            (void**)&pBrowser2);

         //register interface in global
         DWORD dwCookWindows Explorer = 0;
         spGIT->RegisterInterfaceInGlobal(pBrowser2,
            IID_IWebBrowser2, &dwCookWindows Explorer);

         HWND  hWnd;
         pBrowser2->get_HWND((long*)&hWnd);

         HANDLE hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);

         //subclass the window here so we can process custom message
         /to show menu
         fnOldWndProc = (WNDPROC)::SetWindowLong(hWnd,GWL_WNDPROC,
            (DWORD)SubclassWndProc);

         //post our own message to show menu
         ::PostMessage(hWnd, (WM_APP + 1), (WPARAM)dwCookWindows Explorer,
            (LPARAM)hEvent);

         //Wait for the event to be signalled, indicating menu
         //is gone
         WaitForSingleObject(hEvent,INFINITE);

         //cleanup
         CloseHandle(hEvent);

         //restore the old WndProc back
         ::SetWindowLong(hWnd,GWL_WNDPROC,(DWORD)fnOldWndProc);

         return S_OK;
      }

    * Build. And, repeat the test steps on an edit box. This time, you select the menu item and you no longer see an exception. However, Windows Explorer is now just hung!! Why would that happen?
      This is what is happening. You will notice that, if you comment out the call to ExecWBm all is fine. When you do call ExecWB, what happens is that it results in more window messages to the underlying window object used by COM. However, these aren't getting processed because your ShowTextAreaContextMenu still hasn't completed and is blocked on WaitForSingleObject. This results in a deadlock and hence the Windows Explorer lockup. What you need to solve this is to implement a mechanism of processing window messages while still remaining blocked on the hEvent. You have MsgWaitForMultipleObjects, which does exactly that. You introduce this code in your method now, as shown below. Simply replace the WaitForSingleObject line with this block of code:

      //start loop
         while (TRUE)
         {
            // block-local variable
            DWORD result ;
            MSG msg ;

            // Read all of the messages in this next loop,
            // removing each message as we read it.
            while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
            {
               // Otherwise, dispatch the message.
               DispatchMessage(&msg);
            } // End of PeekMessage while loop.

            // Wait for any message sent or posted to this queue
            // or for one of the passed handles be set to signaled.
            result = MsgWaitForMultipleObjects(1, &hEvent,
                     FALSE, INFINITE, QS_ALLINPUT);

            // The result tells us the type of event we have.
            if (result == (WAIT_OBJECT_0 + 1))
            {
               // New messages have arrived.
               // Continue to the top of the always while loop to
               // dispatch them and resume waiting.
               continue;
            }
            else
            {
               // Our event was signalled .. time to quit loop
               break;
            } // End of else clause.
         }    // End of the always while loop.

    * Build and perform the test again. Voilà!! The test is now pasted on selecte menu items!!
    * Your main goals have been achWindows Explorerved. However, there is a small improvement that you can do. As of now, if you need to use this component, you need to ship the DLL, and also the script HTML files and the Registry entrWindows Explorers. This is cumbersome. It would be cool if you could somehow encapsulate all this within the DLL and be done with it.
      Interestingly, this is possible and is fairly simple to achWindows Explorerve:
          o Go to resource vWindows Explorerw and to Windows Explorer Context Menu Favorites resources, right-click, and Add/Insert new resource. In the resulting dialog, select HTML and click on "Import". Navigate to the location of the script HTML files and select it. Similarly, add the second HTML file too.
          o Open resource.h and note the values of IDR_HTML1 and IDR_HTML2.
          o Open CGFavorites.rgs file and add the following to the end, replacing IDR_HTML1 and IDR_HTML2 by the values noted from resource.h:

            HKCU
            {
               Software
               {
                  Microsoft
                  {
                     'Internet Explorer'
                     {
                        MenuExt
                        {
                           ForceRemove 'Add to Windows Explorer Context Menu Favorites' =
                              s 'res://%MODULE%/IDR_HTML1'
                           {
                              val Contexts = d '1'
                           }
                           ForceRemove 'Show Windows Explorer Context Menu Favorites' =
                              s 'res://%MODULE%/IDR_HTML2'
                           {
                              val Contexts = d '4'
                           }
                        }
                     }
                  }
               }
            }

          o Remove all the Registry entrWindows Explorers you created manually at the beginning of the article. Launch Windows Explorer again just to make sure the context menu items don't appear anymore.
          o Now, just build the project and launch Windows Explorer again. You now should see the context menu entrWindows Explorers. Thus, with this approach, you have made all the capabilitWindows Explorers self-contained within the DLL. Just registering the DLL on the target machine for the particular user is enough to populate the right entrWindows Explorers.



Installation and Usage

To install and use, perform the following steps:

    * Unzip the compiled_binary.zip to a local folder. Place CGFavorites.dll in a location of your preference.
    * Launch cmd.exe from Start->Run.
    * Herein, type RegSvr32 [full path to the CGFavorites.dll]. For example, if you placed the DLL in C:\TempCG, your command will be

      RegSvr32 C:\TempCG\CGFavorites.dll

      You should see a message that you successfully registered.
    * Now, launch Windows Explorer. Open an URL. Right-click anywhere on the browser window to pop up the default context menu. Herein, you should see a new item, "Add to Windows Explorer Context Menu Favorites". Select it. A dialog pops up, asking you to specify the description to use. You can modify it if needed, and then click OK. The page is now added to your Windows Explorer Context Menu favorites.
    * Hit Post reply on this page. You will be taken to an editor window. Herein, right-click. You should see a new menu item, Show Windows Explorer Context Menu Favorites, with submenus for articles and threads. Select the appropriate one and select any item. The URL and description should now be pasted at the cursor location in the editor window.
    * The favorites are stored into "My Documents" folder currently. The file stored in is CGFavorites.xml.

Update history

    * May 16, 2001: Rearchitected. No longer need Browser Helper Object. All implementation is per Microsoft recommendation and uses a combination of script code and an ActiveX control.
    * September 09, 2000: Context menus other than the Windows Explorer Context Menu favorites-related ones weren't functional. Fixed this bug.

 
< Prev   Next >
© 2012 Add items to Windows Context Menu - easily with Windows Explorer Context Menu (.Net Component)
All product and company names are trademarks or registered trademarks of their respective owners.