4 * Copyright 2004 Robert Shearman
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
32 #include "shell32_main.h"
34 #include "wine/debug.h"
35 #include "wine/unicode.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(shell
);
40 static HSZ hszProgmanTopic
;
41 static HSZ hszProgmanService
;
42 static HSZ hszAsterisk
;
44 static HSZ hszAppProperties
;
45 static HSZ hszFolders
;
48 static DWORD dwDDEInst
;
50 static const char *debugstr_hsz( HSZ hsz
)
53 if (!DdeQueryStringW( dwDDEInst
, hsz
, buffer
, ARRAY_SIZE(buffer
), CP_WINUNICODE
))
55 return debugstr_w( buffer
);
58 static inline BOOL
Dde_OnConnect(HSZ hszTopic
, HSZ hszService
)
60 if ((hszTopic
== hszProgmanTopic
) && (hszService
== hszProgmanService
))
62 if ((hszTopic
== hszProgmanTopic
) && (hszService
== hszAppProperties
))
64 if ((hszTopic
== hszShell
) && (hszService
== hszFolders
))
66 if ((hszTopic
== hszShell
) && (hszService
== hszAppProperties
))
71 static inline void Dde_OnConnectConfirm(HCONV hconv
, HSZ hszTopic
, HSZ hszService
)
73 TRACE( "%p %s %s\n", hconv
, debugstr_hsz(hszTopic
), debugstr_hsz(hszService
) );
76 static inline BOOL
Dde_OnWildConnect(HSZ hszTopic
, HSZ hszService
)
82 /* Returned string must be freed by caller */
83 static WCHAR
*get_programs_path(const WCHAR
*name
)
85 static const WCHAR slashW
[] = {'/',0};
86 WCHAR
*programs
, *path
;
89 SHGetKnownFolderPath(&FOLDERID_Programs
, 0, NULL
, &programs
);
91 len
= lstrlenW(programs
) + 1 + lstrlenW(name
);
92 path
= heap_alloc((len
+ 1) * sizeof(*path
));
93 lstrcpyW(path
, programs
);
94 lstrcatW(path
, slashW
);
97 CoTaskMemFree(programs
);
102 static inline HDDEDATA
Dde_OnRequest(UINT uFmt
, HCONV hconv
, HSZ hszTopic
,
105 if (hszTopic
== hszProgmanTopic
&& hszItem
== hszGroups
&& uFmt
== CF_TEXT
)
107 static const WCHAR asteriskW
[] = {'*',0};
108 static const WCHAR newlineW
[] = {'\r','\n',0};
109 static const WCHAR dotW
[] = {'.',0};
110 static const WCHAR dotdotW
[] = {'.','.',0};
112 WIN32_FIND_DATAW finddata
;
115 WCHAR
*groups_data
= heap_alloc(sizeof(WCHAR
));
120 programs
= get_programs_path(asteriskW
);
121 hfind
= FindFirstFileW(programs
, &finddata
);
126 if ((finddata
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) &&
127 lstrcmpW(finddata
.cFileName
, dotW
) && lstrcmpW(finddata
.cFileName
, dotdotW
))
129 len
+= lstrlenW(finddata
.cFileName
) + 2;
130 groups_data
= heap_realloc(groups_data
, len
* sizeof(WCHAR
));
131 lstrcatW(groups_data
, finddata
.cFileName
);
132 lstrcatW(groups_data
, newlineW
);
134 } while (FindNextFileW(hfind
, &finddata
));
138 len
= WideCharToMultiByte(CP_ACP
, 0, groups_data
, -1, NULL
, 0, NULL
, NULL
);
139 groups_dataA
= heap_alloc(len
* sizeof(WCHAR
));
140 WideCharToMultiByte(CP_ACP
, 0, groups_data
, -1, groups_dataA
, len
, NULL
, NULL
);
141 ret
= DdeCreateDataHandle(dwDDEInst
, (BYTE
*)groups_dataA
, len
, 0, hszGroups
, uFmt
, 0);
143 heap_free(groups_dataA
);
144 heap_free(groups_data
);
148 else if (hszTopic
== hszProgmanTopic
&& hszItem
== hszProgmanService
&& uFmt
== CF_TEXT
)
150 static BYTE groups_data
[] = "\r\n";
151 FIXME( "returning empty groups list\n" );
152 /* This is a workaround for an application which expects some data
153 * and cannot handle NULL. */
154 return DdeCreateDataHandle( dwDDEInst
, groups_data
, sizeof(groups_data
), 0, hszProgmanService
, uFmt
, 0 );
156 FIXME( "%u %p %s %s: stub\n", uFmt
, hconv
, debugstr_hsz(hszTopic
), debugstr_hsz(hszItem
) );
160 static DWORD
PROGMAN_OnExecute(WCHAR
*command
, int argc
, WCHAR
**argv
)
162 static const WCHAR create_groupW
[] = {'C','r','e','a','t','e','G','r','o','u','p',0};
163 static const WCHAR delete_groupW
[] = {'D','e','l','e','t','e','G','r','o','u','p',0};
164 static const WCHAR show_groupW
[] = {'S','h','o','w','G','r','o','u','p',0};
165 static const WCHAR add_itemW
[] = {'A','d','d','I','t','e','m',0};
166 static const WCHAR delete_itemW
[] = {'D','e','l','e','t','e','I','t','e','m',0};
167 static const WCHAR replace_itemW
[] = {'R','e','p','l','a','c','e','I','t','e','m',0};
168 static const WCHAR exit_progmanW
[] = {'E','x','i','t','P','r','o','g','m','a','n',0};
170 static const WCHAR dotexeW
[] = {'.','e','x','e',0};
171 static const WCHAR dotlnkW
[] = {'.','l','n','k',0};
172 static const WCHAR slashW
[] = {'/',0};
174 static WCHAR
*last_group
;
176 if (!strcmpiW(command
, create_groupW
))
180 if (argc
< 1) return DDE_FNOTPROCESSED
;
182 path
= get_programs_path(argv
[0]);
184 CreateDirectoryW(path
, NULL
);
185 ShellExecuteW(NULL
, NULL
, path
, NULL
, NULL
, SW_SHOWNORMAL
);
187 heap_free(last_group
);
190 else if (!strcmpiW(command
, delete_groupW
))
193 SHFILEOPSTRUCTW shfos
= {0};
196 if (argc
< 1) return DDE_FNOTPROCESSED
;
198 path
= get_programs_path(argv
[0]);
200 path2
= heap_alloc((strlenW(path
) + 2) * sizeof(*path
));
201 strcpyW(path2
, path
);
202 path2
[strlenW(path
) + 1] = 0;
204 shfos
.wFunc
= FO_DELETE
;
206 shfos
.fFlags
= FOF_NOCONFIRMATION
;
208 ret
= SHFileOperationW(&shfos
);
213 if (ret
|| shfos
.fAnyOperationsAborted
) return DDE_FNOTPROCESSED
;
215 else if (!strcmpiW(command
, show_groupW
))
219 /* Win32 requires the second parameter to be present but seems to
220 * ignore its actual value. */
221 if (argc
< 2) return DDE_FNOTPROCESSED
;
223 path
= get_programs_path(argv
[0]);
225 ShellExecuteW(NULL
, NULL
, path
, NULL
, NULL
, SW_SHOWNORMAL
);
227 heap_free(last_group
);
230 else if (!strcmpiW(command
, add_itemW
))
238 if (argc
< 1) return DDE_FNOTPROCESSED
;
240 hres
= CoCreateInstance(&CLSID_ShellLink
, NULL
, CLSCTX_INPROC_SERVER
,
241 &IID_IShellLinkW
, (void **)&link
);
242 if (FAILED(hres
)) return DDE_FNOTPROCESSED
;
244 len
= SearchPathW(NULL
, argv
[0], dotexeW
, 0, NULL
, NULL
);
247 IShellLinkW_Release(link
);
248 return DDE_FNOTPROCESSED
;
250 path
= heap_alloc(len
* sizeof(WCHAR
));
251 SearchPathW(NULL
, argv
[0], dotexeW
, len
, path
, NULL
);
252 IShellLinkW_SetPath(link
, path
);
255 if (argc
>= 2) IShellLinkW_SetDescription(link
, argv
[1]);
256 if (argc
>= 4) IShellLinkW_SetIconLocation(link
, argv
[2], atoiW(argv
[3]));
257 if (argc
>= 7) IShellLinkW_SetWorkingDirectory(link
, argv
[6]);
258 if (argc
>= 8) IShellLinkW_SetHotkey(link
, atoiW(argv
[7]));
261 if (atoiW(argv
[8]) == 0) IShellLinkW_SetShowCmd(link
, SW_SHOWMINNOACTIVE
);
262 else if (atoiW(argv
[8]) == 1) IShellLinkW_SetShowCmd(link
, SW_SHOWNORMAL
);
265 hres
= IShellLinkW_QueryInterface(link
, &IID_IPersistFile
, (void **)&file
);
268 IShellLinkW_Release(link
);
269 return DDE_FNOTPROCESSED
;
273 name
= heap_alloc((strlenW(last_group
) + 1 + strlenW(argv
[1]) + 5) * sizeof(*name
));
274 lstrcpyW(name
, last_group
);
275 lstrcatW(name
, slashW
);
276 lstrcatW(name
, argv
[1]);
277 lstrcatW(name
, dotlnkW
);
281 const WCHAR
*filename
= PathFindFileNameW(argv
[0]);
282 int len
= PathFindExtensionW(filename
) - filename
;
283 name
= heap_alloc((strlenW(last_group
) + 1 + len
+ 5) * sizeof(*name
));
284 lstrcpyW(name
, last_group
);
285 lstrcatW(name
, slashW
);
286 lstrcpynW(name
+strlenW(name
), filename
, len
+ 1);
287 lstrcatW(name
, dotlnkW
);
289 hres
= IPersistFile_Save(file
, name
, TRUE
);
292 IPersistFile_Release(file
);
293 IShellLinkW_Release(link
);
295 if (FAILED(hres
)) return DDE_FNOTPROCESSED
;
297 else if (!strcmpiW(command
, delete_itemW
) || !strcmpiW(command
, replace_itemW
))
302 if (argc
< 1) return DDE_FNOTPROCESSED
;
304 name
= heap_alloc((strlenW(last_group
) + 1 + strlenW(argv
[0]) + 5) * sizeof(*name
));
305 lstrcpyW(name
, last_group
);
306 lstrcatW(name
, slashW
);
307 lstrcatW(name
, argv
[0]);
308 lstrcatW(name
, dotlnkW
);
310 ret
= DeleteFileW(name
);
314 if (!ret
) return DDE_FNOTPROCESSED
;
316 else if (!strcmpiW(command
, exit_progmanW
))
322 FIXME("unhandled command %s\n", debugstr_w(command
));
323 return DDE_FNOTPROCESSED
;
328 static DWORD
parse_dde_command(HSZ hszTopic
, WCHAR
*command
)
330 static const WCHAR opcode_end
[] = {' ',',','(',')','[',']','"',0};
331 static const WCHAR param_end
[] = {',','(',')','[',']',0};
333 WCHAR
*original
= command
;
334 WCHAR
*opcode
= NULL
, **argv
= NULL
, *p
;
336 DWORD ret
= DDE_FACK
;
338 while (*command
== ' ') command
++;
340 if (*command
!= '[') goto error
;
341 while (*command
== '[')
344 argv
= heap_alloc(sizeof(*argv
));
347 while (*command
== ' ') command
++;
348 if (!(p
= strpbrkW(command
, opcode_end
))) goto error
;
350 opcode
= strndupW(command
, p
- command
);
353 while (*command
== ' ') command
++;
358 while (*command
!= ')')
360 while (*command
== ' ') command
++;
364 if (!(p
= strchrW(command
, '"'))) goto error
;
368 if (!(p
= strpbrkW(command
, param_end
))) goto error
;
369 while (p
[-1] == ' ') p
--;
373 argv
= heap_realloc(argv
, argc
* sizeof(*argv
));
374 argv
[argc
-1] = strndupW(command
, p
- command
);
377 if (*command
== '"') command
++;
378 while (*command
== ' ') command
++;
379 if (*command
== ',') command
++;
380 else if (*command
!= ')') goto error
;
384 while (*command
== ' ') command
++;
387 if (*command
!= ']') goto error
;
389 while (*command
== ' ') command
++;
391 if (hszTopic
== hszProgmanTopic
)
392 ret
= PROGMAN_OnExecute(opcode
, argc
, argv
);
395 FIXME("unhandled topic %s, command %s\n", debugstr_hsz(hszTopic
), debugstr_w(opcode
));
396 ret
= DDE_FNOTPROCESSED
;
400 for (i
= 0; i
< argc
; i
++) heap_free(argv
[i
]);
403 if (ret
== DDE_FNOTPROCESSED
) break;
409 ERR("failed to parse command %s\n", debugstr_w(original
));
411 for (i
= 0; i
< argc
; i
++) heap_free(argv
[i
]);
413 return DDE_FNOTPROCESSED
;
416 static DWORD
Dde_OnExecute(HCONV hconv
, HSZ hszTopic
, HDDEDATA hdata
)
422 len
= DdeGetData(hdata
, NULL
, 0, 0);
423 if (!len
) return DDE_FNOTPROCESSED
;
424 command
= heap_alloc(len
);
425 DdeGetData(hdata
, (BYTE
*)command
, len
, 0);
427 TRACE("conv=%p topic=%s data=%s\n", hconv
, debugstr_hsz(hszTopic
), debugstr_w(command
));
429 ret
= parse_dde_command(hszTopic
, command
);
435 static inline void Dde_OnDisconnect(HCONV hconv
)
437 TRACE( "%p\n", hconv
);
440 static HDDEDATA CALLBACK
DdeCallback(
453 return (HDDEDATA
)(DWORD_PTR
)Dde_OnConnect(hsz1
, hsz2
);
454 case XTYP_CONNECT_CONFIRM
:
455 Dde_OnConnectConfirm(hconv
, hsz1
, hsz2
);
457 case XTYP_WILDCONNECT
:
458 return (HDDEDATA
)(DWORD_PTR
)Dde_OnWildConnect(hsz1
, hsz2
);
460 return Dde_OnRequest(uFmt
, hconv
, hsz1
, hsz2
);
462 return (HDDEDATA
)(DWORD_PTR
)Dde_OnExecute(hconv
, hsz1
, hdata
);
463 case XTYP_DISCONNECT
:
464 Dde_OnDisconnect(hconv
);
471 /*************************************************************************
472 * ShellDDEInit (SHELL32.@)
474 * Registers the Shell DDE services with the system so that applications
478 * bInit [I] TRUE to initialize the services, FALSE to uninitialize.
483 void WINAPI
ShellDDEInit(BOOL bInit
)
485 TRACE("bInit = %s\n", bInit
? "TRUE" : "FALSE");
489 static const WCHAR wszProgman
[] = {'P','r','o','g','m','a','n',0};
490 static const WCHAR wszAsterisk
[] = {'*',0};
491 static const WCHAR wszShell
[] = {'S','h','e','l','l',0};
492 static const WCHAR wszAppProperties
[] =
493 {'A','p','p','P','r','o','p','e','r','t','i','e','s',0};
494 static const WCHAR wszFolders
[] = {'F','o','l','d','e','r','s',0};
495 static const WCHAR wszGroups
[] = {'G','r','o','u','p','s',0};
497 DdeInitializeW(&dwDDEInst
, DdeCallback
, CBF_FAIL_ADVISES
| CBF_FAIL_POKES
, 0);
499 hszProgmanTopic
= DdeCreateStringHandleW(dwDDEInst
, wszProgman
, CP_WINUNICODE
);
500 hszProgmanService
= DdeCreateStringHandleW(dwDDEInst
, wszProgman
, CP_WINUNICODE
);
501 hszAsterisk
= DdeCreateStringHandleW(dwDDEInst
, wszAsterisk
, CP_WINUNICODE
);
502 hszShell
= DdeCreateStringHandleW(dwDDEInst
, wszShell
, CP_WINUNICODE
);
503 hszAppProperties
= DdeCreateStringHandleW(dwDDEInst
, wszAppProperties
, CP_WINUNICODE
);
504 hszFolders
= DdeCreateStringHandleW(dwDDEInst
, wszFolders
, CP_WINUNICODE
);
505 hszGroups
= DdeCreateStringHandleW(dwDDEInst
, wszGroups
, CP_WINUNICODE
);
507 DdeNameService(dwDDEInst
, hszFolders
, 0, DNS_REGISTER
);
508 DdeNameService(dwDDEInst
, hszProgmanService
, 0, DNS_REGISTER
);
509 DdeNameService(dwDDEInst
, hszShell
, 0, DNS_REGISTER
);
513 /* unregister all services */
514 DdeNameService(dwDDEInst
, 0, 0, DNS_UNREGISTER
);
516 DdeFreeStringHandle(dwDDEInst
, hszFolders
);
517 DdeFreeStringHandle(dwDDEInst
, hszAppProperties
);
518 DdeFreeStringHandle(dwDDEInst
, hszShell
);
519 DdeFreeStringHandle(dwDDEInst
, hszAsterisk
);
520 DdeFreeStringHandle(dwDDEInst
, hszProgmanService
);
521 DdeFreeStringHandle(dwDDEInst
, hszProgmanTopic
);
523 DdeUninitialize(dwDDEInst
);