xref: /reactos/dll/win32/userenv/desktop.c (revision 40462c92)
1 /*
2  *  ReactOS kernel
3  *  Copyright (C) 2004 ReactOS Team
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License along
16  *  with this program; if not, write to the Free Software Foundation, Inc.,
17  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 /*
20  * COPYRIGHT:       See COPYING in the top level directory
21  * PROJECT:         ReactOS system libraries
22  * FILE:            dll/win32/userenv/desktop.c
23  * PURPOSE:         Desktop and start menu support functions.
24  * PROGRAMMER:      Eric Kohl
25  */
26 
27 #include "precomp.h"
28 
29 #include <shlobj.h>
30 
31 #define NDEBUG
32 #include <debug.h>
33 
34 /* FUNCTIONS ***************************************************************/
35 
36 static
37 BOOL
38 GetDesktopPath(BOOL bCommonPath,
39                LPWSTR lpDesktopPath)
40 {
41     WCHAR szPath[MAX_PATH];
42     DWORD dwLength;
43     DWORD dwType;
44     HKEY hKey;
45     LONG Error;
46 
47     DPRINT("GetDesktopPath() called\n");
48 
49     Error = RegOpenKeyExW(HKEY_CURRENT_USER,
50                           L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders",
51                           0,
52                           KEY_QUERY_VALUE,
53                           &hKey);
54     if (Error != ERROR_SUCCESS)
55     {
56         DPRINT1("RegOpenKeyExW() failed\n");
57         SetLastError((DWORD)Error);
58         return FALSE;
59     }
60 
61     dwLength = MAX_PATH * sizeof(WCHAR);
62     Error = RegQueryValueExW(hKey,
63                              bCommonPath ? L"Common Desktop" : L"Desktop",
64                              0,
65                              &dwType,
66                              (LPBYTE)szPath,
67                              &dwLength);
68     if (Error != ERROR_SUCCESS)
69     {
70         DPRINT1("RegQueryValueExW() failed\n");
71         RegCloseKey(hKey);
72         SetLastError((DWORD)Error);
73         return FALSE;
74     }
75 
76     RegCloseKey(hKey);
77 
78     if (dwType == REG_EXPAND_SZ)
79     {
80         ExpandEnvironmentStringsW(szPath,
81                                   lpDesktopPath,
82                                   MAX_PATH);
83     }
84     else
85     {
86         wcscpy(lpDesktopPath, szPath);
87     }
88 
89     DPRINT("GetDesktopPath() done\n");
90 
91     return TRUE;
92 }
93 
94 
95 static
96 BOOL
97 GetProgramsPath(BOOL bCommonPath,
98                 LPWSTR lpProgramsPath)
99 {
100     WCHAR szPath[MAX_PATH];
101     DWORD dwLength;
102     DWORD dwType;
103     HKEY hKey;
104     LONG Error;
105 
106     DPRINT("GetProgramsPath() called\n");
107 
108     Error = RegOpenKeyExW(HKEY_CURRENT_USER,
109                           L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders",
110                           0,
111                           KEY_QUERY_VALUE,
112                           &hKey);
113     if (Error != ERROR_SUCCESS)
114     {
115         DPRINT1("RegOpenKeyExW() failed\n");
116         SetLastError((DWORD)Error);
117         return FALSE;
118     }
119 
120     dwLength = MAX_PATH * sizeof(WCHAR);
121     Error = RegQueryValueExW(hKey,
122                              bCommonPath ? L"Common Programs" : L"Programs",
123                              0,
124                              &dwType,
125                              (LPBYTE)szPath,
126                              &dwLength);
127     if (Error != ERROR_SUCCESS)
128     {
129         DPRINT1("RegQueryValueExW() failed\n");
130         RegCloseKey(hKey);
131         SetLastError((DWORD)Error);
132         return FALSE;
133     }
134 
135     RegCloseKey(hKey);
136 
137     if (dwType == REG_EXPAND_SZ)
138     {
139         ExpandEnvironmentStringsW(szPath,
140                                   lpProgramsPath,
141                                   MAX_PATH);
142     }
143     else
144     {
145         wcscpy(lpProgramsPath,
146                szPath);
147     }
148 
149     DPRINT("GetProgramsPath() done\n");
150 
151     return TRUE;
152 }
153 
154 
155 BOOL
156 WINAPI
157 AddDesktopItemA(BOOL bCommonItem,
158                 LPCSTR lpItemName,
159                 LPCSTR lpArguments,
160                 LPCSTR lpIconLocation,
161                 INT iIcon,
162                 LPCSTR lpWorkingDirectory, /* Optional */
163                 WORD wHotKey,
164                 INT iShowCmd)
165 {
166     UNICODE_STRING ItemName;
167     UNICODE_STRING Arguments;
168     UNICODE_STRING IconLocation;
169     UNICODE_STRING WorkingDirectory;
170     BOOL bResult;
171 
172     if (!RtlCreateUnicodeStringFromAsciiz(&ItemName,
173                                           (LPSTR)lpItemName))
174     {
175         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
176         return FALSE;
177     }
178 
179     if (!RtlCreateUnicodeStringFromAsciiz(&Arguments,
180                                           (LPSTR)lpArguments))
181     {
182         RtlFreeUnicodeString(&ItemName);
183         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
184         return FALSE;
185     }
186 
187     if (!RtlCreateUnicodeStringFromAsciiz(&IconLocation,
188                                           (LPSTR)lpIconLocation))
189     {
190         RtlFreeUnicodeString(&Arguments);
191         RtlFreeUnicodeString(&ItemName);
192         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
193         return FALSE;
194     }
195 
196     if (lpWorkingDirectory != NULL)
197     {
198         if (!RtlCreateUnicodeStringFromAsciiz(&WorkingDirectory,
199                                               (LPSTR)lpWorkingDirectory))
200         {
201             RtlFreeUnicodeString(&IconLocation);
202             RtlFreeUnicodeString(&Arguments);
203             RtlFreeUnicodeString(&ItemName);
204             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
205             return FALSE;
206         }
207     }
208 
209     bResult = AddDesktopItemW(bCommonItem,
210                               ItemName.Buffer,
211                               Arguments.Buffer,
212                               IconLocation.Buffer,
213                               iIcon,
214                               (lpWorkingDirectory != NULL) ? WorkingDirectory.Buffer : NULL,
215                               wHotKey,
216                               iShowCmd);
217 
218     if (lpWorkingDirectory != NULL)
219     {
220         RtlFreeUnicodeString(&WorkingDirectory);
221     }
222 
223     RtlFreeUnicodeString(&IconLocation);
224     RtlFreeUnicodeString(&Arguments);
225     RtlFreeUnicodeString(&ItemName);
226 
227     return bResult;
228 }
229 
230 
231 BOOL
232 WINAPI
233 AddDesktopItemW(BOOL bCommonDesktop,
234                 LPCWSTR lpItemName,
235                 LPCWSTR lpArguments,
236                 LPCWSTR lpIconLocation,
237                 INT iIcon,
238                 LPCWSTR lpWorkingDirectory,  /* Optional */
239                 WORD wHotKey,
240                 INT iShowCmd)
241 {
242     DYN_FUNCS Ole32;
243     WCHAR szLinkPath[MAX_PATH];
244     WCHAR szArguments[MAX_PATH];
245     WCHAR szCommand[MAX_PATH];
246     WIN32_FIND_DATAW FindData;
247     HANDLE hFind;
248     LPWSTR Ptr;
249     DWORD dwLength;
250     IShellLinkW* psl;
251     IPersistFile* ppf;
252     HRESULT hr;
253     BOOL bResult;
254 
255     DPRINT("AddDesktopItemW() called\n");
256 
257     bResult = FALSE;
258 
259     if (!GetDesktopPath(bCommonDesktop, szLinkPath))
260     {
261         DPRINT1("GetDesktopPath() failed\n");
262         return FALSE;
263     }
264     DPRINT("Desktop path: '%S'\n", szLinkPath);
265 
266     /* Make sure the path exists */
267     hFind = FindFirstFileW(szLinkPath,
268                            &FindData);
269     if (hFind == INVALID_HANDLE_VALUE)
270     {
271         DPRINT("'%S' does not exist\n", szLinkPath);
272 
273         /* Create directory path */
274         if (!CreateDirectoryPath(szLinkPath, NULL))
275             return FALSE;
276     }
277     else
278     {
279         DPRINT("'%S' exists\n", szLinkPath);
280         FindClose(hFind);
281     }
282 
283     /* Append backslash, item name and ".lnk" extension */
284     wcscat(szLinkPath, L"\\");
285     wcscat(szLinkPath, lpItemName);
286     wcscat(szLinkPath, L".lnk");
287     DPRINT("Link path: '%S'\n", szLinkPath);
288 
289     /* Split 'lpArguments' string into command and arguments */
290     Ptr = wcschr(lpArguments, L' ');
291     DPRINT("Ptr %p  lpArguments %p\n", Ptr, lpArguments);
292     if (Ptr != NULL)
293     {
294         dwLength = (DWORD)(Ptr - lpArguments);
295         DPRINT("dwLength %lu\n", dwLength);
296         memcpy(szCommand, lpArguments, dwLength * sizeof(WCHAR));
297         szCommand[dwLength] = 0;
298         Ptr++;
299         wcscpy(szArguments, Ptr);
300     }
301     else
302     {
303         wcscpy(szCommand, lpArguments);
304         szArguments[0] = 0;
305     }
306     DPRINT("szCommand: '%S'\n", szCommand);
307     DPRINT("szArguments: '%S'\n", szArguments);
308 
309     /* Dynamically load ole32.dll */
310     if (!LoadDynamicImports(&DynOle32, &Ole32))
311     {
312         DPRINT1("USERENV: Unable to load OLE32.DLL\n");
313         return FALSE;
314     }
315 
316     Ole32.fn.CoInitialize(NULL);
317 
318     hr = Ole32.fn.CoCreateInstance(&CLSID_ShellLink,
319                                    NULL,
320                                    CLSCTX_INPROC_SERVER,
321                                    &IID_IShellLinkW,
322                                    (LPVOID*)&psl);
323     if (!SUCCEEDED(hr))
324     {
325         Ole32.fn.CoUninitialize();
326         UnloadDynamicImports(&Ole32);
327         return FALSE;
328     }
329 
330     hr = psl->lpVtbl->QueryInterface(psl,
331                                      &IID_IPersistFile,
332                                      (LPVOID*)&ppf);
333     if (SUCCEEDED(hr))
334     {
335         psl->lpVtbl->SetDescription(psl,
336                                     lpItemName);
337 
338         psl->lpVtbl->SetPath(psl,
339                              szCommand);
340 
341         psl->lpVtbl->SetArguments(psl,
342                                   szArguments);
343 
344         psl->lpVtbl->SetIconLocation(psl,
345                                      lpIconLocation,
346                                      iIcon);
347 
348         if (lpWorkingDirectory != NULL)
349         {
350             psl->lpVtbl->SetWorkingDirectory(psl,
351                                              lpWorkingDirectory);
352         }
353         else
354         {
355             psl->lpVtbl->SetWorkingDirectory(psl,
356                                              L"%HOMEDRIVE%%HOMEPATH%");
357         }
358 
359         psl->lpVtbl->SetHotkey(psl,
360                                wHotKey);
361 
362         psl->lpVtbl->SetShowCmd(psl,
363                                 iShowCmd);
364 
365         hr = ppf->lpVtbl->Save(ppf,
366                                szLinkPath,
367                                TRUE);
368         if (SUCCEEDED(hr))
369             bResult = TRUE;
370 
371         ppf->lpVtbl->Release(ppf);
372     }
373 
374     psl->lpVtbl->Release(psl);
375 
376     Ole32.fn.CoUninitialize();
377 
378     UnloadDynamicImports(&Ole32);
379 
380     DPRINT("AddDesktopItemW() done\n");
381 
382     return bResult;
383 }
384 
385 
386 BOOL
387 WINAPI
388 DeleteDesktopItemA(BOOL bCommonItem,
389                    LPCSTR lpItemName)
390 {
391     UNICODE_STRING ItemName;
392     BOOL bResult;
393 
394     if (!RtlCreateUnicodeStringFromAsciiz(&ItemName,
395                                           (LPSTR)lpItemName))
396     {
397         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
398         return FALSE;
399     }
400 
401     bResult = DeleteDesktopItemW(bCommonItem,
402                                  ItemName.Buffer);
403 
404     RtlFreeUnicodeString(&ItemName);
405 
406     return bResult;
407 }
408 
409 
410 BOOL
411 WINAPI
412 DeleteDesktopItemW(BOOL bCommonItem,
413                    LPCWSTR lpItemName)
414 {
415     WCHAR szLinkPath[MAX_PATH];
416 
417     DPRINT("DeleteDesktopItemW() called\n");
418 
419     if (!GetDesktopPath(bCommonItem, szLinkPath))
420     {
421         DPRINT1("GetDesktopPath() failed\n");
422         return FALSE;
423     }
424 
425     wcscat(szLinkPath, L"\\");
426     wcscat(szLinkPath, lpItemName);
427     wcscat(szLinkPath, L".lnk");
428     DPRINT("Link path: '%S'\n", szLinkPath);
429 
430     return DeleteFileW (szLinkPath);
431 }
432 
433 
434 BOOL
435 WINAPI
436 CreateGroupA(LPCSTR lpGroupName,
437              BOOL bCommonGroup)
438 {
439     UNICODE_STRING GroupName;
440     BOOL bResult;
441 
442     if (!RtlCreateUnicodeStringFromAsciiz(&GroupName,
443                                           (LPSTR)lpGroupName))
444     {
445         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
446         return FALSE;
447     }
448 
449     bResult = CreateGroupW(GroupName.Buffer, bCommonGroup);
450 
451     RtlFreeUnicodeString(&GroupName);
452 
453     return bResult;
454 }
455 
456 
457 BOOL
458 WINAPI
459 CreateGroupW(LPCWSTR lpGroupName,
460              BOOL bCommonGroup)
461 {
462     WCHAR szGroupPath[MAX_PATH];
463 
464     DPRINT1("CreateGroupW() called\n");
465 
466     if (lpGroupName == NULL || *lpGroupName == 0)
467         return TRUE;
468 
469     if (!GetProgramsPath(bCommonGroup, szGroupPath))
470     {
471         DPRINT1("GetProgramsPath() failed\n");
472         return FALSE;
473     }
474     DPRINT1("Programs path: '%S'\n", szGroupPath);
475 
476     wcscat(szGroupPath, L"\\");
477     wcscat(szGroupPath, lpGroupName);
478     DPRINT1("Group path: '%S'\n", szGroupPath);
479 
480     /* Create directory path */
481     if (!CreateDirectoryPath (szGroupPath, NULL))
482         return FALSE;
483 
484     /* FIXME: Notify the shell */
485 
486     DPRINT1("CreateGroupW() done\n");
487 
488     return TRUE;
489 }
490 
491 
492 BOOL
493 WINAPI
494 DeleteGroupA(LPCSTR lpGroupName,
495              BOOL bCommonGroup)
496 {
497     UNICODE_STRING GroupName;
498     BOOL bResult;
499 
500     if (!RtlCreateUnicodeStringFromAsciiz(&GroupName,
501                                           (LPSTR)lpGroupName))
502     {
503         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
504         return FALSE;
505     }
506 
507     bResult = DeleteGroupW(GroupName.Buffer, bCommonGroup);
508 
509     RtlFreeUnicodeString(&GroupName);
510 
511     return bResult;
512 }
513 
514 
515 BOOL
516 WINAPI
517 DeleteGroupW(LPCWSTR lpGroupName,
518              BOOL bCommonGroup)
519 {
520     WCHAR szGroupPath[MAX_PATH];
521 
522     DPRINT("DeleteGroupW() called\n");
523 
524     if (lpGroupName == NULL || *lpGroupName == 0)
525         return TRUE;
526 
527     if (!GetProgramsPath(bCommonGroup, szGroupPath))
528     {
529         DPRINT1("GetProgramsPath() failed\n");
530         return FALSE;
531     }
532     DPRINT("Programs path: '%S'\n", szGroupPath);
533 
534     wcscat(szGroupPath, L"\\");
535     wcscat(szGroupPath, lpGroupName);
536     DPRINT("Group path: '%S'\n", szGroupPath);
537 
538     /* Remove directory path */
539     if (!RemoveDirectoryPath (szGroupPath))
540         return FALSE;
541 
542     /* FIXME: Notify the shell */
543 
544     DPRINT("DeleteGroupW() done\n");
545 
546     return TRUE;
547 }
548 
549 
550 BOOL
551 WINAPI
552 AddItemA(LPCSTR lpGroupName,  /* Optional */
553          BOOL bCommonGroup,
554          LPCSTR lpItemName,
555          LPCSTR lpArguments,
556          LPCSTR lpIconLocation,
557          INT iIcon,
558          LPCSTR lpWorkingDirectory,  /* Optional */
559          WORD wHotKey,
560          INT iShowCmd)
561 {
562     UNICODE_STRING GroupName;
563     UNICODE_STRING ItemName;
564     UNICODE_STRING Arguments;
565     UNICODE_STRING IconLocation;
566     UNICODE_STRING WorkingDirectory;
567     BOOL bResult;
568 
569     if (!RtlCreateUnicodeStringFromAsciiz(&ItemName,
570                                           (LPSTR)lpItemName))
571     {
572         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
573         return FALSE;
574     }
575 
576     if (!RtlCreateUnicodeStringFromAsciiz(&Arguments,
577                                           (LPSTR)lpArguments))
578     {
579         RtlFreeUnicodeString(&ItemName);
580         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
581         return FALSE;
582     }
583 
584     if (!RtlCreateUnicodeStringFromAsciiz(&IconLocation,
585                                           (LPSTR)lpIconLocation))
586     {
587         RtlFreeUnicodeString(&Arguments);
588         RtlFreeUnicodeString(&ItemName);
589         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
590         return FALSE;
591     }
592 
593     if (lpGroupName != NULL)
594     {
595         if (!RtlCreateUnicodeStringFromAsciiz(&GroupName,
596                                               (LPSTR)lpGroupName))
597         {
598             RtlFreeUnicodeString(&IconLocation);
599             RtlFreeUnicodeString(&Arguments);
600             RtlFreeUnicodeString(&ItemName);
601             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
602             return FALSE;
603         }
604     }
605 
606     if (lpWorkingDirectory != NULL)
607     {
608         if (!RtlCreateUnicodeStringFromAsciiz(&WorkingDirectory,
609                                               (LPSTR)lpWorkingDirectory))
610         {
611             if (lpGroupName != NULL)
612             {
613                 RtlFreeUnicodeString(&GroupName);
614             }
615             RtlFreeUnicodeString(&IconLocation);
616             RtlFreeUnicodeString(&Arguments);
617             RtlFreeUnicodeString(&ItemName);
618             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
619             return FALSE;
620         }
621     }
622 
623     bResult = AddItemW((lpGroupName != NULL) ? GroupName.Buffer : NULL,
624                        bCommonGroup,
625                        ItemName.Buffer,
626                        Arguments.Buffer,
627                        IconLocation.Buffer,
628                        iIcon,
629                        (lpWorkingDirectory != NULL) ? WorkingDirectory.Buffer : NULL,
630                        wHotKey,
631                        iShowCmd);
632 
633     if (lpGroupName != NULL)
634     {
635         RtlFreeUnicodeString(&GroupName);
636     }
637 
638     if (lpWorkingDirectory != NULL)
639     {
640         RtlFreeUnicodeString(&WorkingDirectory);
641     }
642 
643     RtlFreeUnicodeString(&IconLocation);
644     RtlFreeUnicodeString(&Arguments);
645     RtlFreeUnicodeString(&ItemName);
646 
647     return bResult;
648 }
649 
650 
651 BOOL
652 WINAPI
653 AddItemW(LPCWSTR lpGroupName,  /* Optional */
654          BOOL bCommonGroup,
655          LPCWSTR lpItemName,
656          LPCWSTR lpArguments,
657          LPCWSTR lpIconLocation,
658          INT iIcon,
659          LPCWSTR lpWorkingDirectory,  /* Optional */
660          WORD wHotKey,
661          INT iShowCmd)
662 {
663     DYN_FUNCS Ole32;
664     WCHAR szLinkPath[MAX_PATH];
665     WCHAR szArguments[MAX_PATH];
666     WCHAR szCommand[MAX_PATH];
667     WIN32_FIND_DATAW FindData;
668     HANDLE hFind;
669     LPWSTR Ptr;
670     DWORD dwLength;
671     IShellLinkW* psl;
672     IPersistFile* ppf;
673     HRESULT hr;
674     BOOL bResult;
675 
676     DPRINT("AddItemW() called\n");
677 
678     bResult = FALSE;
679 
680     if (!GetProgramsPath(bCommonGroup, szLinkPath))
681     {
682         DPRINT1("GetProgramsPath() failed\n");
683         return FALSE;
684     }
685 
686     DPRINT("Programs path: '%S'\n", szLinkPath);
687 
688     if (lpGroupName != NULL && *lpGroupName != 0)
689     {
690         wcscat(szLinkPath, L"\\");
691         wcscat(szLinkPath, lpGroupName);
692 
693         /* Make sure the path exists */
694         hFind = FindFirstFileW(szLinkPath,
695                                &FindData);
696         if (hFind == INVALID_HANDLE_VALUE)
697         {
698             DPRINT("'%S' does not exist\n", szLinkPath);
699             if (!CreateGroupW(lpGroupName,
700                               bCommonGroup))
701                 return FALSE;
702         }
703         else
704         {
705             DPRINT("'%S' exists\n", szLinkPath);
706             FindClose(hFind);
707         }
708     }
709 
710     wcscat(szLinkPath, L"\\");
711     wcscat(szLinkPath, lpItemName);
712     wcscat(szLinkPath, L".lnk");
713     DPRINT("Link path: '%S'\n", szLinkPath);
714 
715     /* Split 'lpArguments' string into command and arguments */
716     Ptr = wcschr(lpArguments, L' ');
717     DPRINT("Ptr %p  lpArguments %p\n", Ptr, lpArguments);
718     if (Ptr != NULL)
719     {
720         dwLength = (DWORD)(Ptr - lpArguments);
721         DPRINT("dwLength %lu\n", dwLength);
722         memcpy(szCommand, lpArguments, dwLength * sizeof(WCHAR));
723         szCommand[dwLength] = 0;
724         Ptr++;
725         wcscpy(szArguments, Ptr);
726     }
727     else
728     {
729         wcscpy(szCommand, lpArguments);
730         szArguments[0] = 0;
731     }
732     DPRINT("szCommand: '%S'\n", szCommand);
733     DPRINT("szArguments: '%S'\n", szArguments);
734 
735     /* Dynamically load ole32.dll */
736     if (!LoadDynamicImports(&DynOle32, &Ole32))
737     {
738         DPRINT1("USERENV: Unable to load OLE32.DLL\n");
739         return FALSE;
740     }
741 
742     Ole32.fn.CoInitialize(NULL);
743 
744     hr = Ole32.fn.CoCreateInstance(&CLSID_ShellLink,
745                                    NULL,
746                                    CLSCTX_INPROC_SERVER,
747                                    &IID_IShellLinkW,
748                                    (LPVOID*)&psl);
749     if (!SUCCEEDED(hr))
750     {
751         Ole32.fn.CoUninitialize();
752         UnloadDynamicImports(&Ole32);
753         return FALSE;
754     }
755 
756     hr = psl->lpVtbl->QueryInterface(psl,
757                                      &IID_IPersistFile,
758                                      (LPVOID*)&ppf);
759     if (SUCCEEDED(hr))
760     {
761         psl->lpVtbl->SetDescription(psl,
762                                     lpItemName);
763 
764         psl->lpVtbl->SetPath(psl,
765                              szCommand);
766 
767         psl->lpVtbl->SetArguments(psl,
768                                   szArguments);
769 
770         psl->lpVtbl->SetIconLocation(psl,
771                                      lpIconLocation,
772                                      iIcon);
773 
774         if (lpWorkingDirectory != NULL)
775         {
776             psl->lpVtbl->SetWorkingDirectory(psl,
777                                              lpWorkingDirectory);
778         }
779         else
780         {
781             psl->lpVtbl->SetWorkingDirectory(psl,
782                                              L"%HOMEDRIVE%%HOMEPATH%");
783         }
784 
785         psl->lpVtbl->SetHotkey(psl,
786                                wHotKey);
787 
788         psl->lpVtbl->SetShowCmd(psl,
789                                 iShowCmd);
790 
791         hr = ppf->lpVtbl->Save(ppf,
792                                szLinkPath,
793                                TRUE);
794         if (SUCCEEDED(hr))
795             bResult = TRUE;
796 
797         ppf->lpVtbl->Release(ppf);
798     }
799 
800     psl->lpVtbl->Release(psl);
801 
802     Ole32.fn.CoUninitialize();
803     UnloadDynamicImports(&Ole32);
804 
805     DPRINT("AddItemW() done\n");
806 
807     return bResult;
808 }
809 
810 
811 BOOL
812 WINAPI
813 DeleteItemA(LPCSTR lpGroupName, /* Optional */
814             BOOL bCommonGroup,
815             LPCSTR lpItemName,
816             BOOL bDeleteGroup)
817 {
818     UNICODE_STRING GroupName;
819     UNICODE_STRING ItemName;
820     BOOL bResult;
821 
822     if (lpGroupName != NULL)
823     {
824         if (!RtlCreateUnicodeStringFromAsciiz(&GroupName,
825                                               (LPSTR)lpGroupName))
826         {
827             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
828             return FALSE;
829         }
830     }
831 
832     if (!RtlCreateUnicodeStringFromAsciiz(&ItemName,
833                                           (LPSTR)lpItemName))
834     {
835         if (lpGroupName != NULL)
836         {
837             RtlFreeUnicodeString(&GroupName);
838         }
839 
840         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
841         return FALSE;
842     }
843 
844     bResult = DeleteItemW((lpGroupName != NULL) ? GroupName.Buffer : NULL,
845                           bCommonGroup,
846                           ItemName.Buffer,
847                           bDeleteGroup);
848 
849     RtlFreeUnicodeString(&ItemName);
850     if (lpGroupName != NULL)
851     {
852         RtlFreeUnicodeString(&GroupName);
853     }
854 
855     return bResult;
856 }
857 
858 
859 BOOL
860 WINAPI
861 DeleteItemW(LPCWSTR lpGroupName, /* Optional */
862             BOOL bCommonGroup,
863             LPCWSTR lpItemName,
864             BOOL bDeleteGroup)
865 {
866     WCHAR szItemPath[MAX_PATH];
867     LPWSTR Ptr;
868 
869     DPRINT("DeleteItemW() called\n");
870 
871     if (!GetProgramsPath(bCommonGroup, szItemPath))
872     {
873         DPRINT1("GetProgramsPath() failed\n");
874         return FALSE;
875     }
876     DPRINT("Programs path: '%S'\n", szItemPath);
877 
878     if (lpGroupName != NULL && *lpGroupName != 0)
879     {
880         wcscat(szItemPath, L"\\");
881         wcscat(szItemPath, lpGroupName);
882     }
883 
884     wcscat(szItemPath, L"\\");
885     wcscat(szItemPath, lpItemName);
886     wcscat(szItemPath, L".lnk");
887     DPRINT("Item path: '%S'\n", szItemPath);
888 
889     if (!DeleteFileW(szItemPath))
890         return FALSE;
891 
892     /* FIXME: Notify the shell */
893 
894     if (bDeleteGroup)
895     {
896         Ptr = wcsrchr(szItemPath, L'\\');
897         if (Ptr == NULL)
898             return TRUE;
899 
900         *Ptr = 0;
901         DPRINT("Item path: '%S'\n", szItemPath);
902         if (RemoveDirectoryW(szItemPath))
903         {
904             /* FIXME: Notify the shell */
905         }
906     }
907 
908     DPRINT("DeleteItemW() done\n");
909 
910     return TRUE;
911 }
912 
913 /* EOF */
914