Synchronize with trunk revision 59636 (just before Alex's CreateProcess revamp).
[reactos.git] / dll / win32 / shell32 / shell32_main.cpp
index 005c8b7..32ab14e 100644 (file)
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
-#include <precomp.h>
+#include "precomp.h"
+#include "shell32_version.h"
+#include <reactos/version.h>
 
 WINE_DEFAULT_DEBUG_CHANNEL(shell);
 
-const char * const SHELL_Authors[] = { "Copyright 1993-2009 WINE team", "Copyright 1998-2009 ReactOS Team", 0 };
+const char * const SHELL_Authors[] = { "Copyright 1993-"COPYRIGHT_YEAR" WINE team", "Copyright 1998-"COPYRIGHT_YEAR" ReactOS Team", 0 };
 
 #define MORE_DEBUG 1
 /*************************************************************************
@@ -36,147 +38,213 @@ const char * const SHELL_Authors[] = { "Copyright 1993-2009 WINE team", "Copyrig
  *   '"a b"'   -> 'a b'
  * - escaped quotes must be converted back to '"'
  *   '\"'      -> '"'
- * - an odd number of '\'s followed by '"' correspond to half that number
- *   of '\' followed by a '"' (extension of the above)
- *   '\\\"'    -> '\"'
- *   '\\\\\"'  -> '\\"'
- * - an even number of '\'s followed by a '"' correspond to half that number
- *   of '\', plus a regular quote serving as an argument delimiter (which
- *   means it does not appear in the result)
- *   'a\\"b c"'   -> 'a\b c'
- *   'a\\\\"b c"' -> 'a\\b c'
- * - '\' that are not followed by a '"' are copied literally
+ * - consecutive backslashes preceding a quote see their number halved with
+ *   the remainder escaping the quote:
+ *   2n   backslashes + quote -> n backslashes + quote as an argument delimiter
+ *   2n+1 backslashes + quote -> n backslashes + literal quote
+ * - backslashes that are not followed by a quote are copied literally:
  *   'a\b'     -> 'a\b'
  *   'a\\b'    -> 'a\\b'
- *
- * Note:
- * '\t' == 0x0009
- * ' '  == 0x0020
- * '"'  == 0x0022
- * '\\' == 0x005c
+ * - in quoted strings, consecutive quotes see their number divided by three
+ *   with the remainder modulo 3 deciding whether to close the string or not.
+ *   Note that the opening quote must be counted in the consecutive quotes,
+ *   that's the (1+) below:
+ *   (1+) 3n   quotes -> n quotes
+ *   (1+) 3n+1 quotes -> n quotes plus closes the quoted string
+ *   (1+) 3n+2 quotes -> n+1 quotes plus closes the quoted string
+ * - in unquoted strings, the first quote opens the quoted string and the
+ *   remaining consecutive quotes follow the above rule.
  */
 LPWSTR* WINAPI CommandLineToArgvW(LPCWSTR lpCmdline, int* numargs)
 {
     DWORD argc;
     LPWSTR  *argv;
-    LPCWSTR cs;
-    LPWSTR arg,s,d;
+    LPCWSTR s;
+    LPWSTR d;
     LPWSTR cmdline;
-    int in_quotes,bcount;
+    int qcount,bcount;
+
+    if(!numargs)
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return NULL;
+    }
 
     if (*lpCmdline==0)
     {
         /* Return the path to the executable */
-        DWORD len, size=16;
+        DWORD len, deslen=MAX_PATH, size;
 
-        argv = (LPWSTR *)LocalAlloc(LMEM_FIXED, size);
+        size = sizeof(LPWSTR) + deslen*sizeof(WCHAR) + sizeof(LPWSTR);
         for (;;)
         {
-            len = GetModuleFileNameW(0, (LPWSTR)(argv+1), (size-sizeof(LPWSTR))/sizeof(WCHAR));
+            if (!(argv = (LPWSTR *)LocalAlloc(LMEM_FIXED, size))) return NULL;
+            len = GetModuleFileNameW(0, (LPWSTR)(argv+1), deslen);
             if (!len)
             {
                 LocalFree(argv);
                 return NULL;
             }
-            if (len < size) break;
-            size*=2;
-            argv = (LPWSTR *)LocalReAlloc(argv, size, 0);
+            if (len < deslen) break;
+            deslen*=2;
+            size = sizeof(LPWSTR) + deslen*sizeof(WCHAR) + sizeof(LPWSTR);
+            LocalFree( argv );
         }
         argv[0]=(LPWSTR)(argv+1);
-        if (numargs)
-            *numargs=1;
+        *numargs=1;
 
         return argv;
     }
 
-    /* to get a writable copy */
-    argc=0;
-    bcount=0;
-    in_quotes=0;
-    cs=lpCmdline;
-    while (1)
+    /* --- First count the arguments */
+    argc=1;
+    s=lpCmdline;
+    /* The first argument, the executable path, follows special rules */
+    if (*s=='"')
     {
-        if (*cs==0 || ((*cs==0x0009 || *cs==0x0020) && !in_quotes))
-        {
-            /* space */
-            argc++;
-            /* skip the remaining spaces */
-            while (*cs==0x0009 || *cs==0x0020)
-            {
-                cs++;
-            }
-            if (*cs==0)
+        /* The executable path ends at the next quote, no matter what */
+        s++;
+        while (*s)
+            if (*s++=='"')
                 break;
+    }
+    else
+    {
+        /* The executable path ends at the next space, no matter what */
+        while (*s && *s!=' ' && *s!='\t')
+            s++;
+    }
+    /* skip to the first argument, if any */
+    while (*s==' ' || *s=='\t')
+        s++;
+    if (*s)
+        argc++;
+
+    /* Analyze the remaining arguments */
+    qcount=bcount=0;
+    while (*s)
+    {
+        if ((*s==' ' || *s=='\t') && qcount==0)
+        {
+            /* skip to the next argument and count it if any */
+            while (*s==' ' || *s=='\t')
+                s++;
+            if (*s)
+                argc++;
             bcount=0;
-            continue;
         }
-        else if (*cs==0x005c)
+        else if (*s=='\\')
         {
             /* '\', count them */
             bcount++;
+            s++;
         }
-        else if ((*cs==0x0022) && ((bcount & 1)==0))
+        else if (*s=='"')
         {
-            /* unescaped '"' */
-            in_quotes=!in_quotes;
+            /* '"' */
+            if ((bcount & 1)==0)
+                qcount++; /* unescaped '"' */
+            s++;
             bcount=0;
+            /* consecutive quotes, see comment in copying code below */
+            while (*s=='"')
+            {
+                qcount++;
+                s++;
+            }
+            qcount=qcount % 3;
+            if (qcount==2)
+                qcount=0;
         }
         else
         {
             /* a regular character */
             bcount=0;
+            s++;
         }
-        cs++;
     }
-    /* Allocate in a single lump, the string array, and the strings that go with it.
-     * This way the caller can make a single GlobalFree call to free both, as per MSDN.
+
+    /* Allocate in a single lump, the string array, and the strings that go
+     * with it. This way the caller can make a single LocalFree() call to free
+     * both, as per MSDN.
      */
-    argv = (LPWSTR *)LocalAlloc(LMEM_FIXED, argc*sizeof(LPWSTR)+(wcslen(lpCmdline)+1)*sizeof(WCHAR));
-    
+    argv=(LPWSTR *)LocalAlloc(LMEM_FIXED, argc*sizeof(LPWSTR)+(strlenW(lpCmdline)+1)*sizeof(WCHAR));
     if (!argv)
         return NULL;
-    
     cmdline=(LPWSTR)(argv+argc);
-    wcscpy(cmdline, lpCmdline);
+    strcpyW(cmdline, lpCmdline);
 
-    argc=0;
-    bcount=0;
-    in_quotes=0;
-    arg=d=s=cmdline;
+    /* --- Then split and copy the arguments */
+    argv[0]=d=cmdline;
+    argc=1;
+    /* The first argument, the executable path, follows special rules */
+    if (*d=='"')
+    {
+        /* The executable path ends at the next quote, no matter what */
+        s=d+1;
+        while (*s)
+        {
+            if (*s=='"')
+            {
+                s++;
+                break;
+            }
+            *d++=*s++;
+        }
+    }
+    else
+    {
+        /* The executable path ends at the next space, no matter what */
+        while (*d && *d!=' ' && *d!='\t')
+            d++;
+        s=d;
+        if (*s)
+            s++;
+    }
+    /* close the executable path */
+    *d++=0;
+    /* skip to the first argument and initialize it if any */
+    while (*s==' ' || *s=='\t')
+        s++;
+    if (!*s)
+    {
+        /* There are no parameters so we are all done */
+        *numargs=argc;
+        return argv;
+    }
+
+    /* Split and copy the remaining arguments */
+    argv[argc++]=d;
+    qcount=bcount=0;
     while (*s)
     {
-        if ((*s==0x0009 || *s==0x0020) && !in_quotes)
+        if ((*s==' ' || *s=='\t') && qcount==0)
         {
-            /* Close the argument and copy it */
-            *d=0;
-            argv[argc++]=arg;
+            /* close the argument */
+            *d++=0;
+            bcount=0;
 
-            /* skip the remaining spaces */
+            /* skip to the next one and initialize it if any */
             do {
                 s++;
-            } while (*s==0x0009 || *s==0x0020);
-
-            /* Start with a new argument */
-            arg=d=s;
-            bcount=0;
+            } while (*s==' ' || *s=='\t');
+            if (*s)
+                argv[argc++]=d;
         }
-        else if (*s==0x005c)
+        else if (*s=='\\')
         {
-            /* '\\' */
             *d++=*s++;
             bcount++;
         }
-        else if (*s==0x0022)
+        else if (*s=='"')
         {
-            /* '"' */
             if ((bcount & 1)==0)
             {
                 /* Preceded by an even number of '\', this is half that
                  * number of '\', plus a quote which we erase.
                  */
                 d-=bcount/2;
-                in_quotes=!in_quotes;
-                s++;
+                qcount++;
             }
             else
             {
@@ -185,9 +253,24 @@ LPWSTR* WINAPI CommandLineToArgvW(LPCWSTR lpCmdline, int* numargs)
                  */
                 d=d-bcount/2-1;
                 *d++='"';
-                s++;
             }
+            s++;
             bcount=0;
+            /* Now count the number of consecutive quotes. Note that qcount
+             * already takes into account the opening quote if any, as well as
+             * the quote that lead us here.
+             */
+            while (*s=='"')
+            {
+                if (++qcount==3)
+                {
+                    *d++='"';
+                    qcount=0;
+                }
+                s++;
+            }
+            if (qcount==2)
+                qcount=0;
         }
         else
         {
@@ -196,13 +279,8 @@ LPWSTR* WINAPI CommandLineToArgvW(LPCWSTR lpCmdline, int* numargs)
             bcount=0;
         }
     }
-    if (*arg)
-    {
-        *d='\0';
-        argv[argc++]=arg;
-    }
-    if (numargs)
-        *numargs=argc;
+    *d='\0';
+    *numargs=argc;
 
     return argv;
 }
@@ -241,17 +319,17 @@ static DWORD shgfi_get_exe_type(LPCWSTR szFullPath)
 
     SetFilePointer( hfile, mz_header.e_lfanew, NULL, SEEK_SET );
     ReadFile( hfile, magic, sizeof(magic), &len, NULL );
-    
+
     if ( *(DWORD*)magic == IMAGE_NT_SIGNATURE )
     {
         SetFilePointer( hfile, mz_header.e_lfanew, NULL, SEEK_SET );
         ReadFile( hfile, &nt, sizeof(nt), &len, NULL );
         CloseHandle( hfile );
-        
+
         /* DLL files are not executable and should return 0 */
         if (nt.FileHeader.Characteristics & IMAGE_FILE_DLL)
             return 0;
-        
+
         if (nt.OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI)
         {
              return IMAGE_NT_SIGNATURE |
@@ -266,7 +344,7 @@ static DWORD shgfi_get_exe_type(LPCWSTR szFullPath)
         SetFilePointer( hfile, mz_header.e_lfanew, NULL, SEEK_SET );
         ReadFile( hfile, &ne, sizeof(ne), &len, NULL );
         CloseHandle( hfile );
-        
+
         if (ne.ne_exetyp == 2)
             return IMAGE_OS2_SIGNATURE | (ne.ne_expver << 16);
         return 0;
@@ -586,7 +664,7 @@ DWORD_PTR WINAPI SHGetFileInfoW(LPCWSTR path,DWORD dwFileAttributes,
                                 GetSystemMetrics( SM_CXICON),
                                 GetSystemMetrics( SM_CYICON),
                                 &psfi->hIcon, 0, 1, 0);
-                        
+
                         if (ret != 0 && ret != 0xFFFFFFFF)
                         {
                             IconNotYetLoaded=FALSE;
@@ -973,7 +1051,7 @@ INT_PTR CALLBACK AboutAuthorsDlgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM
             const char* const *pstr = SHELL_Authors;
 
             // Add the authors to the list
-            SendDlgItemMessageW( hWnd, IDC_SHELL_ABOUT_AUTHORS_LISTBOX, WM_SETREDRAW, FALSE, 0 );
+            SendDlgItemMessageW( hWnd, IDC_ABOUT_AUTHORS_LISTBOX, WM_SETREDRAW, FALSE, 0 );
 
             while (*pstr)
             {
@@ -981,11 +1059,11 @@ INT_PTR CALLBACK AboutAuthorsDlgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM
 
                 /* authors list is in utf-8 format */
                 MultiByteToWideChar( CP_UTF8, 0, *pstr, -1, name, sizeof(name)/sizeof(WCHAR) );
-                SendDlgItemMessageW( hWnd, IDC_SHELL_ABOUT_AUTHORS_LISTBOX, LB_ADDSTRING, (WPARAM)-1, (LPARAM)name );
+                SendDlgItemMessageW( hWnd, IDC_ABOUT_AUTHORS_LISTBOX, LB_ADDSTRING, (WPARAM)-1, (LPARAM)name );
                 pstr++;
             }
 
-            SendDlgItemMessageW( hWnd, IDC_SHELL_ABOUT_AUTHORS_LISTBOX, WM_SETREDRAW, TRUE, 0 );
+            SendDlgItemMessageW( hWnd, IDC_ABOUT_AUTHORS_LISTBOX, WM_SETREDRAW, TRUE, 0 );
 
             return TRUE;
         }
@@ -1032,20 +1110,20 @@ INT_PTR CALLBACK AboutDlgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam
                 }
 
                 // Set App-specific stuff (icon, app name, szOtherStuff string)
-                SendDlgItemMessageW(hWnd, IDC_SHELL_ABOUT_ICON, STM_SETICON, (WPARAM)info->hIcon, 0);
+                SendDlgItemMessageW(hWnd, IDC_ABOUT_ICON, STM_SETICON, (WPARAM)info->hIcon, 0);
 
                 GetWindowTextW( hWnd, szAppTitleTemplate, sizeof(szAppTitleTemplate) / sizeof(WCHAR) );
                 swprintf( szAppTitle, szAppTitleTemplate, info->szApp );
                 SetWindowTextW( hWnd, szAppTitle );
 
-                SetDlgItemTextW( hWnd, IDC_SHELL_ABOUT_APPNAME, info->szApp );
-                SetDlgItemTextW( hWnd, IDC_SHELL_ABOUT_OTHERSTUFF, info->szOtherStuff );
+                SetDlgItemTextW( hWnd, IDC_ABOUT_APPNAME, info->szApp );
+                SetDlgItemTextW( hWnd, IDC_ABOUT_OTHERSTUFF, info->szOtherStuff );
 
                 // Set the registered user and organization name
                 if(RegOpenKeyExW( HKEY_LOCAL_MACHINE, szRegKey, 0, KEY_QUERY_VALUE, &hRegKey ) == ERROR_SUCCESS)
                 {
-                    SetRegTextData( hWnd, hRegKey, L"RegisteredOwner", IDC_SHELL_ABOUT_REG_USERNAME );
-                    SetRegTextData( hWnd, hRegKey, L"RegisteredOrganization", IDC_SHELL_ABOUT_REG_ORGNAME );
+                    SetRegTextData( hWnd, hRegKey, L"RegisteredOwner", IDC_ABOUT_REG_USERNAME );
+                    SetRegTextData( hWnd, hRegKey, L"RegisteredOrganization", IDC_ABOUT_REG_ORGNAME );
 
                     RegCloseKey( hRegKey );
                 }
@@ -1111,13 +1189,13 @@ INT_PTR CALLBACK AboutDlgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam
                         swprintf( szBuf, L"%u MB", (UINT)MemStat.ullTotalPhys / 1024 / 1024 );
                     }
 
-                    SetDlgItemTextW( hWnd, IDC_SHELL_ABOUT_PHYSMEM, szBuf);
+                    SetDlgItemTextW( hWnd, IDC_ABOUT_PHYSMEM, szBuf);
                 }
 
                 // Add the Authors dialog
-                hWndAuthors = CreateDialogW( shell32_hInstance, MAKEINTRESOURCEW(IDD_SHELL_ABOUT_AUTHORS), hWnd, AboutAuthorsDlgProc );
+                hWndAuthors = CreateDialogW( shell32_hInstance, MAKEINTRESOURCEW(IDD_ABOUT_AUTHORS), hWnd, AboutAuthorsDlgProc );
                 LoadStringW( shell32_hInstance, IDS_SHELL_ABOUT_AUTHORS, szAuthorsText, sizeof(szAuthorsText) / sizeof(WCHAR) );
-                SetDlgItemTextW( hWnd, IDC_SHELL_ABOUT_AUTHORS, szAuthorsText );
+                SetDlgItemTextW( hWnd, IDC_ABOUT_AUTHORS, szAuthorsText );
             }
 
             return TRUE;
@@ -1130,7 +1208,7 @@ INT_PTR CALLBACK AboutDlgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam
                 PAINTSTRUCT ps;
                 HDC hdc;
                 HDC hdcMem;
-                
+
                 hdc = BeginPaint(hWnd, &ps);
                 hdcMem = CreateCompatibleDC(hdc);
 
@@ -1155,7 +1233,7 @@ INT_PTR CALLBACK AboutDlgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam
                     EndDialog(hWnd, TRUE);
                     return TRUE;
 
-                case IDC_SHELL_ABOUT_AUTHORS:
+                case IDC_ABOUT_AUTHORS:
                 {
                     static BOOL bShowingAuthors = FALSE;
                     WCHAR szAuthorsText[20];
@@ -1171,7 +1249,7 @@ INT_PTR CALLBACK AboutDlgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam
                         ShowWindow( hWndAuthors, SW_SHOW );
                     }
 
-                    SetDlgItemTextW( hWnd, IDC_SHELL_ABOUT_AUTHORS, szAuthorsText );
+                    SetDlgItemTextW( hWnd, IDC_ABOUT_AUTHORS, szAuthorsText );
                     bShowingAuthors = !bShowingAuthors;
                     return TRUE;
                 }
@@ -1231,9 +1309,12 @@ BOOL WINAPI ShellAboutW( HWND hWnd, LPCWSTR szApp, LPCWSTR szOtherStuff,
     TRACE("\n");
 
     // DialogBoxIndirectParamW will be called with the hInstance of the calling application, so we have to preload the dialog template
-    if(!(hRes = FindResourceW(shell32_hInstance, MAKEINTRESOURCEW(IDD_SHELL_ABOUT), (LPWSTR)RT_DIALOG)))
+    hRes = FindResourceW(shell32_hInstance, MAKEINTRESOURCEW(IDD_ABOUT), (LPWSTR)RT_DIALOG);
+    if(!hRes)
         return FALSE;
-    if(!(DlgTemplate = (DLGTEMPLATE *)LoadResource(shell32_hInstance, hRes)))
+
+    DlgTemplate = (DLGTEMPLATE *)LoadResource(shell32_hInstance, hRes);
+    if(!DlgTemplate)
         return FALSE;
 
     info.szApp        = szApp;
@@ -1256,7 +1337,7 @@ EXTERN_C void WINAPI FreeIconList( DWORD dw )
 /*************************************************************************
  * SHLoadNonloadedIconOverlayIdentifiers (SHELL32.@)
  */
-EXTERN_C HRESULT WINAPI SHLoadNonloadedIconOverlayIdentifiers( VOID )
+EXTERN_C HRESULT WINAPI SHLoadNonloadedIconOverlayIdentifiers(VOID)
 {
     FIXME("stub\n");
     return S_OK;
@@ -1269,55 +1350,30 @@ public:
 
 
 BEGIN_OBJECT_MAP(ObjectMap)
-OBJECT_ENTRY(CLSID_ShellFSFolder, CFSFolder)
-OBJECT_ENTRY(CLSID_MyComputer, CDrivesFolder)
-OBJECT_ENTRY(CLSID_ShellDesktop, CDesktopFolder)
-OBJECT_ENTRY(CLSID_ShellItem, ShellItem)
-OBJECT_ENTRY(CLSID_ShellLink, ShellLink)
-OBJECT_ENTRY(CLSID_DragDropHelper, IDropTargetHelperImpl)
-OBJECT_ENTRY(CLSID_ControlPanel, CControlPanelFolder)
-OBJECT_ENTRY(CLSID_AutoComplete, CAutoComplete)
-OBJECT_ENTRY(CLSID_MyDocuments, CMyDocsFolder)
-OBJECT_ENTRY(CLSID_NetworkPlaces, CNetFolder)
-OBJECT_ENTRY(CLSID_FontsFolderShortcut, CFontsFolder)
-OBJECT_ENTRY(CLSID_Printers, CPrinterFolder)
-OBJECT_ENTRY(CLSID_AdminFolderShortcut, CAdminToolsFolder)
-OBJECT_ENTRY(CLSID_RecycleBin, CBitBucket)
-OBJECT_ENTRY(CLSID_OpenWithMenu, COpenWithMenu)
-OBJECT_ENTRY(CLSID_NewMenu, CNewMenu)
-OBJECT_ENTRY(CLSID_StartMenu, CStartMenuCallback)
-OBJECT_ENTRY(CLSID_MenuBandSite, CMenuBandSite)
+    OBJECT_ENTRY(CLSID_ShellFSFolder, CFSFolder)
+    OBJECT_ENTRY(CLSID_MyComputer, CDrivesFolder)
+    OBJECT_ENTRY(CLSID_ShellDesktop, CDesktopFolder)
+    OBJECT_ENTRY(CLSID_ShellItem, CShellItem)
+    OBJECT_ENTRY(CLSID_ShellLink, CShellLink)
+    OBJECT_ENTRY(CLSID_DragDropHelper, CDropTargetHelper)
+    OBJECT_ENTRY(CLSID_ControlPanel, CControlPanelFolder)
+    OBJECT_ENTRY(CLSID_AutoComplete, CAutoComplete)
+    OBJECT_ENTRY(CLSID_MyDocuments, CMyDocsFolder)
+    OBJECT_ENTRY(CLSID_NetworkPlaces, CNetFolder)
+    OBJECT_ENTRY(CLSID_FontsFolderShortcut, CFontsFolder)
+    OBJECT_ENTRY(CLSID_Printers, CPrinterFolder)
+    OBJECT_ENTRY(CLSID_AdminFolderShortcut, CAdminToolsFolder)
+    OBJECT_ENTRY(CLSID_RecycleBin, CRecycleBin)
+    OBJECT_ENTRY(CLSID_OpenWithMenu, COpenWithMenu)
+    OBJECT_ENTRY(CLSID_NewMenu, CNewMenu)
+    OBJECT_ENTRY(CLSID_StartMenu, CStartMenu)
+    OBJECT_ENTRY(CLSID_MenuBandSite, CMenuBandSite)
+    OBJECT_ENTRY(CLSID_MenuBand, CMenuBand)
 END_OBJECT_MAP()
 
 CShell32Module                                gModule;
 
 
-/*
-static const struct {
-    REFIID            riid;
-    LPFNCREATEINSTANCE    lpfnCI;
-} InterfaceTable[] = {
-    {CLSID_ShellFSFolder,    &IFSFolder_Constructor},
-    {CLSID_MyComputer,    &ISF_MyComputer_Constructor},
-    {CLSID_ShellDesktop,    &ISF_Desktop_Constructor},
-    {CLSID_ShellItem,    &IShellItem_Constructor},
-    {CLSID_ShellLink,    &IShellLink_Constructor},
-    {CLSID_DragDropHelper, &IDropTargetHelper_Constructor},
-    {CLSID_ControlPanel,    &IControlPanel_Constructor},
-    {CLSID_AutoComplete,   &IAutoComplete_Constructor},
-    {CLSID_MyDocuments,    &ISF_MyDocuments_Constructor},
-    {CLSID_NetworkPlaces,  &ISF_NetworkPlaces_Constructor},
-    {CLSID_FontsFolderShortcut, &ISF_Fonts_Constructor},
-    {CLSID_Printers,       &ISF_Printers_Constructor},
-    {CLSID_AdminFolderShortcut, &ISF_AdminTools_Constructor},
-    {CLSID_RecycleBin,     &RecycleBin_Constructor},
-    {CLSID_OpenWithMenu,   &SHEOW_Constructor},
-    {CLSID_NewMenu,        &INewItem_Constructor},
-    {CLSID_StartMenu,      &StartMenu_Constructor},
-    {CLSID_MenuBandSite,   &MenuBandSite_Constructor},
-};
-*/
-
 /***********************************************************************
  * DllGetVersion [SHELL32.@]
  *
@@ -1446,19 +1502,43 @@ STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
 }
 
 /***********************************************************************
- *              DllRegisterServer (BROWSEUI.@)
+ *              DllRegisterServer (SHELL32.@)
  */
 STDAPI DllRegisterServer()
 {
-    return gModule.DllRegisterServer(FALSE);
+    HRESULT hr;
+
+    hr = gModule.DllRegisterServer(FALSE);
+    if (FAILED(hr))
+        return hr;
+
+    hr = gModule.UpdateRegistryFromResource(IDR_FOLDEROPTIONS, TRUE, NULL);
+    if (FAILED(hr))
+        return hr;
+
+    hr = SHELL_RegisterShellFolders();
+    if (FAILED(hr))
+        return hr;
+
+    return S_OK;
 }
 
 /***********************************************************************
- *              DllUnregisterServer (BROWSEUI.@)
+ *              DllUnregisterServer (SHELL32.@)
  */
 STDAPI DllUnregisterServer()
 {
-    return gModule.DllUnregisterServer(FALSE);
+    HRESULT hr;
+
+    hr = gModule.DllUnregisterServer(FALSE);
+    if (FAILED(hr))
+        return hr;
+
+    hr = gModule.UpdateRegistryFromResource(IDR_FOLDEROPTIONS, FALSE, NULL);
+    if (FAILED(hr))
+        return hr;
+
+    return S_OK;
 }
 
 /*************************************************************************