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
25 WINE_DEFAULT_DEBUG_CHANNEL(shelldde
);
27 typedef DWORD(CALLBACK
* pfnCommandHandler
)(PWSTR strCommand
, PWSTR strPath
, LPITEMIDLIST pidl
, INT unkS
);
29 struct DDECommandHandler
32 pfnCommandHandler Handler
;
35 extern DDECommandHandler HandlerList
[];
36 extern const int HandlerListLength
;
39 static DWORD dwDDEInst
;
42 static HSZ hszProgmanTopic
;
43 static HSZ hszProgmanService
;
45 static HSZ hszAppProperties
;
46 static HSZ hszFolders
;
48 static BOOL bInitialized
;
50 static BOOL
Dde_OnConnect(HSZ hszTopic
, HSZ hszService
)
52 WCHAR szTopic
[MAX_PATH
];
53 WCHAR szService
[MAX_PATH
];
55 DdeQueryStringW(dwDDEInst
, hszTopic
, szTopic
, _countof(szTopic
), CP_WINUNICODE
);
56 DdeQueryStringW(dwDDEInst
, hszService
, szService
, _countof(szService
), CP_WINUNICODE
);
58 TRACE("Dde_OnConnect: topic=%S, service=%S\n", szTopic
, szService
);
63 static void Dde_OnConnectConfirm(HCONV hconv
, HSZ hszTopic
, HSZ hszService
)
65 WCHAR szTopic
[MAX_PATH
];
66 WCHAR szService
[MAX_PATH
];
68 DdeQueryStringW(dwDDEInst
, hszTopic
, szTopic
, _countof(szTopic
), CP_WINUNICODE
);
69 DdeQueryStringW(dwDDEInst
, hszService
, szService
, _countof(szService
), CP_WINUNICODE
);
71 TRACE("Dde_OnConnectConfirm: hconv=%p, topic=%S, service=%S\n", hconv
, szTopic
, szService
);
74 static BOOL
Dde_OnWildConnect(HSZ hszTopic
, HSZ hszService
)
76 WCHAR szTopic
[MAX_PATH
];
77 WCHAR szService
[MAX_PATH
];
79 DdeQueryStringW(dwDDEInst
, hszTopic
, szTopic
, _countof(szTopic
), CP_WINUNICODE
);
80 DdeQueryStringW(dwDDEInst
, hszService
, szService
, _countof(szService
), CP_WINUNICODE
);
82 TRACE("Dde_OnWildConnect: topic=%S, service=%S\n", szTopic
, szService
);
87 static HDDEDATA
Dde_OnRequest(UINT uFmt
, HCONV hconv
, HSZ hszTopic
, HSZ hszItem
)
89 WCHAR szTopic
[MAX_PATH
];
90 WCHAR szItem
[MAX_PATH
];
92 DdeQueryStringW(dwDDEInst
, hszTopic
, szTopic
, _countof(szTopic
), CP_WINUNICODE
);
93 DdeQueryStringW(dwDDEInst
, hszItem
, szItem
, _countof(szItem
), CP_WINUNICODE
);
95 TRACE("Dde_OnRequest: uFmt=%d, hconv=%p, topic=%S, item=%S\n", hconv
, szTopic
, szItem
);
100 static LPITEMIDLIST
_ILReadFromSharedMemory(PCWSTR strField
)
102 LPITEMIDLIST ret
= NULL
;
104 // Ensure it really is an IDLIST-formatted parameter
105 // Format for IDLIST params: ":pid:shared"
106 if (*strField
!= L
':')
109 HANDLE hData
= (HANDLE
) StrToIntW(strField
+ 1);
110 PWSTR strSecond
= StrChrW(strField
+ 1, L
':');
114 int pid
= StrToIntW(strSecond
+ 1);
115 void* pvShared
= SHLockShared(hData
, pid
);
118 ret
= ILClone((LPCITEMIDLIST
) pvShared
);
119 SHUnlockShared(pvShared
);
120 SHFreeShared(hData
, pid
);
126 static DWORD
Dde_OnExecute(HCONV hconv
, HSZ hszTopic
, HDDEDATA hdata
)
128 WCHAR szTopic
[MAX_PATH
];
129 WCHAR szCommand
[MAX_PATH
];
132 DdeQueryStringW(dwDDEInst
, hszTopic
, szTopic
, _countof(szTopic
), CP_WINUNICODE
);
134 pszCommand
= (WCHAR
*) DdeAccessData(hdata
, NULL
);
136 return DDE_FNOTPROCESSED
;
138 StringCchCopyW(szCommand
, _countof(szCommand
), pszCommand
);
140 DdeUnaccessData(hdata
);
142 TRACE("Dde_OnExecute: hconv=%p, topic=%S, command=%S\n", hconv
, szTopic
, pszCommand
);
145 [ViewFolder("%l", %I, %S)] -- Open a folder in standard mode
146 [ExploreFolder("%l", %I, %S)] -- Open a folder in "explore" mode (file tree is shown to the left by default)
147 [FindFolder("%l", %I)] -- Open a folder in "find" mode (search panel is shown to the left by default)
148 [ShellFile("%1","%1",%S)] -- Execute the contents of the specified .SCF file
150 Approximate grammar (Upper names define rules, <lower> names define terminals, single-quotes are literals):
153 Command = ('[' Function ']') | Function
154 Function = <identifier> '(' Parameters ')'
155 Parameters = (<quoted-string> (',' <idlist> (',' <number>)?)?)?
158 <identifier> = [a-zA-Z]+
159 <quoted-string> = \"([^\"]|\\.)\"
160 <idlist> = \:[0-9]+\:[0-9]+
164 WCHAR Command
[MAX_PATH
] = L
"";
165 WCHAR Path
[MAX_PATH
] = L
"";
166 LPITEMIDLIST IdList
= NULL
;
167 INT UnknownParameter
= 0;
169 // Simplified parsing (assumes the command will not be TOO broken):
171 PWSTR cmd
= szCommand
;
172 // 1. if starts with [, skip first char
178 ERR("Empty command. Nothing to run.\n");
179 return DDE_FNOTPROCESSED
;
182 // Read until first (, and take text before ( as command name
184 PWSTR cmdEnd
= StrChrW(cmd
, L
'(');
188 ERR("Could not find '('. Invalid command.\n");
189 return DDE_FNOTPROCESSED
;
194 StringCchCopy(Command
, _countof(Command
), cmd
);
199 // Read first param after (, expecting quoted string
202 // Copy unescaped string
204 BOOL isQuote
= FALSE
;
208 while (*arg
&& (isQuote
|| *arg
!= L
','))
213 if (isQuote
&& arg
!= cmd
) // do not copy the " at the beginning of the string
232 // Read second param, expecting an idlist in shared memory
237 ERR("Expected ':'. Invalid command.\n");
238 return DDE_FNOTPROCESSED
;
241 PWSTR idlistEnd
= StrChrW(cmd
, L
',');
244 idlistEnd
= StrChrW(cmd
, L
')');
248 ERR("Expected ',' or ')'. Invalid command.\n");
249 return DDE_FNOTPROCESSED
;
252 IdList
= _ILReadFromSharedMemory(cmd
);
257 // Read third param, expecting an integer
260 UnknownParameter
= StrToIntW(cmd
);
263 TRACE("Parse end: cmd=%S, S=%d, pidl=%p, path=%S\n", Command
, UnknownParameter
, IdList
, Path
);
265 // Find handler in list
266 for (int i
= 0; i
< HandlerListLength
; i
++)
268 DDECommandHandler
& handler
= HandlerList
[i
];
269 if (StrCmpW(handler
.Command
, Command
) == 0)
271 return handler
.Handler(Command
, Path
, IdList
, UnknownParameter
);
276 ERR("Unknown command %S\n", Command
);
277 return DDE_FNOTPROCESSED
;
280 static void Dde_OnDisconnect(HCONV hconv
)
282 TRACE("Dde_OnDisconnect: hconv=%p\n", hconv
);
285 static HDDEDATA CALLBACK
DdeCallback(
298 return (HDDEDATA
) (DWORD_PTR
) Dde_OnConnect(hsz1
, hsz2
);
299 case XTYP_CONNECT_CONFIRM
:
300 Dde_OnConnectConfirm(hconv
, hsz1
, hsz2
);
302 case XTYP_WILDCONNECT
:
303 return (HDDEDATA
) (DWORD_PTR
) Dde_OnWildConnect(hsz1
, hsz2
);
305 return Dde_OnRequest(uFmt
, hconv
, hsz1
, hsz2
);
307 return (HDDEDATA
) (DWORD_PTR
) Dde_OnExecute(hconv
, hsz1
, hdata
);
308 case XTYP_DISCONNECT
:
309 Dde_OnDisconnect(hconv
);
314 WARN("DdeCallback: unknown uType=%d\n", uType
);
318 /*************************************************************************
319 * ShellDDEInit (SHELL32.@)
321 * Registers the Shell DDE services with the system so that applications
325 * bInit [I] TRUE to initialize the services, FALSE to uninitialize.
330 EXTERN_C
void WINAPI
ShellDDEInit(BOOL bInit
)
332 TRACE("ShellDDEInit bInit = %s\n", bInit
? "TRUE" : "FALSE");
334 if (bInit
&& !bInitialized
)
336 DdeInitializeW(&dwDDEInst
, DdeCallback
, CBF_FAIL_ADVISES
| CBF_FAIL_POKES
, 0);
338 hszProgmanTopic
= DdeCreateStringHandleW(dwDDEInst
, L
"Progman", CP_WINUNICODE
);
339 hszProgmanService
= DdeCreateStringHandleW(dwDDEInst
, L
"Progman", CP_WINUNICODE
);
340 hszShell
= DdeCreateStringHandleW(dwDDEInst
, L
"Shell", CP_WINUNICODE
);
341 hszAppProperties
= DdeCreateStringHandleW(dwDDEInst
, L
"AppProperties", CP_WINUNICODE
);
342 hszFolders
= DdeCreateStringHandleW(dwDDEInst
, L
"Folders", CP_WINUNICODE
);
344 if (hszProgmanTopic
&& hszProgmanService
&&
345 hszShell
&& hszAppProperties
&& hszFolders
&&
346 DdeNameService(dwDDEInst
, hszFolders
, 0, DNS_REGISTER
) &&
347 DdeNameService(dwDDEInst
, hszProgmanService
, 0, DNS_REGISTER
) &&
348 DdeNameService(dwDDEInst
, hszShell
, 0, DNS_REGISTER
))
353 else if (!bInit
&& bInitialized
)
355 /* unregister all services */
356 DdeNameService(dwDDEInst
, 0, 0, DNS_UNREGISTER
);
359 DdeFreeStringHandle(dwDDEInst
, hszFolders
);
360 if (hszAppProperties
)
361 DdeFreeStringHandle(dwDDEInst
, hszAppProperties
);
363 DdeFreeStringHandle(dwDDEInst
, hszShell
);
364 if (hszProgmanService
)
365 DdeFreeStringHandle(dwDDEInst
, hszProgmanService
);
367 DdeFreeStringHandle(dwDDEInst
, hszProgmanTopic
);
369 DdeUninitialize(dwDDEInst
);
371 bInitialized
= FALSE
;
375 static DWORD CALLBACK
DDE_OnViewFolder(PWSTR strCommand
, PWSTR strPath
, LPITEMIDLIST pidl
, INT unkS
)
378 pidl
= ILCreateFromPathW(strPath
);
381 return DDE_FNOTPROCESSED
;
383 if (FAILED(SHOpenNewFrame(pidl
, NULL
, 0, 0)))
384 return DDE_FNOTPROCESSED
;
389 static DWORD CALLBACK
DDW_OnExploreFolder(PWSTR strCommand
, PWSTR strPath
, LPITEMIDLIST pidl
, INT unkS
)
392 pidl
= ILCreateFromPathW(strPath
);
395 return DDE_FNOTPROCESSED
;
397 if (FAILED(SHOpenNewFrame(pidl
, NULL
, 0, SH_EXPLORER_CMDLINE_FLAG_E
)))
398 return DDE_FNOTPROCESSED
;
403 static DWORD CALLBACK
DDE_OnFindFolder(PWSTR strCommand
, PWSTR strPath
, LPITEMIDLIST pidl
, INT unkS
)
406 return DDE_FNOTPROCESSED
;
409 static DWORD CALLBACK
DDE_OnShellFile(PWSTR strCommand
, PWSTR strPath
, LPITEMIDLIST pidl
, INT unkS
)
412 return DDE_FNOTPROCESSED
;
415 DDECommandHandler HandlerList
[] = {
417 { L
"ViewFolder", DDE_OnViewFolder
},
418 { L
"ExploreFolder", DDW_OnExploreFolder
},
419 { L
"FindFolder", DDE_OnFindFolder
},
420 { L
"ShellFile", DDE_OnShellFile
}
423 const int HandlerListLength
= _countof(HandlerList
);