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
24 #include <shlwapi_undoc.h>
26 WINE_DEFAULT_DEBUG_CHANNEL(shelldde
);
28 typedef DWORD(CALLBACK
* pfnCommandHandler
)(PWSTR strCommand
, PWSTR strPath
, LPITEMIDLIST pidl
, INT unkS
);
30 struct DDECommandHandler
33 pfnCommandHandler Handler
;
36 extern DDECommandHandler HandlerList
[];
37 extern const int HandlerListLength
;
40 static DWORD dwDDEInst
;
43 static HSZ hszProgmanTopic
;
44 static HSZ hszProgmanService
;
46 static HSZ hszAppProperties
;
47 static HSZ hszFolders
;
49 static BOOL bInitialized
;
51 static BOOL
Dde_OnConnect(HSZ hszTopic
, HSZ hszService
)
53 WCHAR szTopic
[MAX_PATH
];
54 WCHAR szService
[MAX_PATH
];
56 DdeQueryStringW(dwDDEInst
, hszTopic
, szTopic
, _countof(szTopic
), CP_WINUNICODE
);
57 DdeQueryStringW(dwDDEInst
, hszService
, szService
, _countof(szService
), CP_WINUNICODE
);
59 DbgPrint("Dde_OnConnect: topic=%S, service=%S\n", szTopic
, szService
);
64 static void Dde_OnConnectConfirm(HCONV hconv
, HSZ hszTopic
, HSZ hszService
)
66 WCHAR szTopic
[MAX_PATH
];
67 WCHAR szService
[MAX_PATH
];
69 DdeQueryStringW(dwDDEInst
, hszTopic
, szTopic
, _countof(szTopic
), CP_WINUNICODE
);
70 DdeQueryStringW(dwDDEInst
, hszService
, szService
, _countof(szService
), CP_WINUNICODE
);
72 DbgPrint("Dde_OnConnectConfirm: hconv=%p, topic=%S, service=%S\n", hconv
, szTopic
, szService
);
75 static BOOL
Dde_OnWildConnect(HSZ hszTopic
, HSZ hszService
)
77 WCHAR szTopic
[MAX_PATH
];
78 WCHAR szService
[MAX_PATH
];
80 DdeQueryStringW(dwDDEInst
, hszTopic
, szTopic
, _countof(szTopic
), CP_WINUNICODE
);
81 DdeQueryStringW(dwDDEInst
, hszService
, szService
, _countof(szService
), CP_WINUNICODE
);
83 DbgPrint("Dde_OnWildConnect: topic=%S, service=%S\n", szTopic
, szService
);
88 static HDDEDATA
Dde_OnRequest(UINT uFmt
, HCONV hconv
, HSZ hszTopic
, HSZ hszItem
)
90 WCHAR szTopic
[MAX_PATH
];
91 WCHAR szItem
[MAX_PATH
];
93 DdeQueryStringW(dwDDEInst
, hszTopic
, szTopic
, _countof(szTopic
), CP_WINUNICODE
);
94 DdeQueryStringW(dwDDEInst
, hszItem
, szItem
, _countof(szItem
), CP_WINUNICODE
);
96 DbgPrint("Dde_OnRequest: uFmt=%d, hconv=%p, topic=%S, item=%S\n", hconv
, szTopic
, szItem
);
101 static LPITEMIDLIST
_ILReadFromSharedMemory(PCWSTR strField
)
103 LPITEMIDLIST ret
= NULL
;
105 // Ensure it really is an IDLIST-formatted parameter
106 // Format for IDLIST params: ":pid:shared"
107 if (*strField
!= L
':')
110 HANDLE hData
= (HANDLE
) StrToIntW(strField
+ 1);
111 PWSTR strSecond
= StrChrW(strField
+ 1, L
':');
115 int pid
= StrToIntW(strSecond
+ 1);
116 void* pvShared
= SHLockShared(hData
, pid
);
119 ret
= ILClone((LPCITEMIDLIST
) pvShared
);
120 SHUnlockShared(pvShared
);
121 SHFreeShared(hData
, pid
);
127 static DWORD
Dde_OnExecute(HCONV hconv
, HSZ hszTopic
, HDDEDATA hdata
)
129 WCHAR szTopic
[MAX_PATH
];
130 WCHAR szCommand
[MAX_PATH
];
133 DdeQueryStringW(dwDDEInst
, hszTopic
, szTopic
, _countof(szTopic
), CP_WINUNICODE
);
135 pszCommand
= (WCHAR
*) DdeAccessData(hdata
, NULL
);
137 return DDE_FNOTPROCESSED
;
139 StringCchCopyW(szCommand
, _countof(szCommand
), pszCommand
);
141 DdeUnaccessData(hdata
);
143 DbgPrint("Dde_OnExecute: hconv=%p, topic=%S, command=%S\n", hconv
, szTopic
, pszCommand
);
146 [ViewFolder("%l", %I, %S)] -- Open a folder in standard mode
147 [ExploreFolder("%l", %I, %S)] -- Open a folder in "explore" mode (file tree is shown to the left by default)
148 [FindFolder("%l", %I)] -- Open a folder in "find" mode (search panel is shown to the left by default)
149 [ShellFile("%1","%1",%S)] -- Execute the contents of the specified .SCF file
151 Approximate grammar (Upper names define rules, <lower> names define terminals, single-quotes are literals):
154 Command = ('[' Function ']') | Function
155 Function = <identifier> '(' Parameters ')'
156 Parameters = (<quoted-string> (',' <idlist> (',' <number>)?)?)?
159 <identifier> = [a-zA-Z]+
160 <quoted-string> = \"([^\"]|\\.)\"
161 <idlist> = \:[0-9]+\:[0-9]+
165 WCHAR Command
[MAX_PATH
] = L
"";
166 WCHAR Path
[MAX_PATH
] = L
"";
167 LPITEMIDLIST IdList
= NULL
;
168 INT UnknownParameter
= 0;
170 // Simplified parsing (assumes the command will not be TOO broken):
172 PWSTR cmd
= szCommand
;
173 // 1. if starts with [, skip first char
179 ERR("Empty command. Nothing to run.\n");
180 return DDE_FNOTPROCESSED
;
183 // Read until first (, and take text before ( as command name
185 PWSTR cmdEnd
= StrChrW(cmd
, L
'(');
189 ERR("Could not find '('. Invalid command.\n");
190 return DDE_FNOTPROCESSED
;
195 StringCchCopy(Command
, _countof(Command
), cmd
);
200 // Read first param after (, expecting quoted string
203 // Copy unescaped string
205 BOOL isQuote
= FALSE
;
209 while (*arg
&& (isQuote
|| *arg
!= L
','))
214 if (isQuote
&& arg
!= cmd
) // do not copy the " at the beginning of the string
233 // Read second param, expecting an idlist in shared memory
238 ERR("Expected ':'. Invalid command.\n");
239 return DDE_FNOTPROCESSED
;
242 PWSTR idlistEnd
= StrChrW(cmd
, L
',');
245 idlistEnd
= StrChrW(cmd
, L
')');
249 ERR("Expected ',' or ')'. Invalid command.\n");
250 return DDE_FNOTPROCESSED
;
253 IdList
= _ILReadFromSharedMemory(cmd
);
258 // Read third param, expecting an integer
261 UnknownParameter
= StrToIntW(cmd
);
264 DbgPrint("Parse end: cmd=%S, S=%d, pidl=%p, path=%S\n", Command
, UnknownParameter
, IdList
, Path
);
266 // Find handler in list
267 for (int i
= 0; i
< HandlerListLength
; i
++)
269 DDECommandHandler
& handler
= HandlerList
[i
];
270 if (StrCmpW(handler
.Command
, Command
) == 0)
272 return handler
.Handler(Command
, Path
, IdList
, UnknownParameter
);
277 ERR("Unknown command %S\n", Command
);
278 return DDE_FNOTPROCESSED
;
281 static void Dde_OnDisconnect(HCONV hconv
)
283 DbgPrint("Dde_OnDisconnect: hconv=%p\n", hconv
);
286 static HDDEDATA CALLBACK
DdeCallback(
299 return (HDDEDATA
) (DWORD_PTR
) Dde_OnConnect(hsz1
, hsz2
);
300 case XTYP_CONNECT_CONFIRM
:
301 Dde_OnConnectConfirm(hconv
, hsz1
, hsz2
);
303 case XTYP_WILDCONNECT
:
304 return (HDDEDATA
) (DWORD_PTR
) Dde_OnWildConnect(hsz1
, hsz2
);
306 return Dde_OnRequest(uFmt
, hconv
, hsz1
, hsz2
);
308 return (HDDEDATA
) (DWORD_PTR
) Dde_OnExecute(hconv
, hsz1
, hdata
);
309 case XTYP_DISCONNECT
:
310 Dde_OnDisconnect(hconv
);
315 DbgPrint("DdeCallback: unknown uType=%d\n", uType
);
319 /*************************************************************************
320 * ShellDDEInit (SHELL32.@)
322 * Registers the Shell DDE services with the system so that applications
326 * bInit [I] TRUE to initialize the services, FALSE to uninitialize.
331 EXTERN_C
void WINAPI
ShellDDEInit(BOOL bInit
)
333 DbgPrint("ShellDDEInit bInit = %s\n", bInit
? "TRUE" : "FALSE");
335 if (bInit
&& !bInitialized
)
337 DdeInitializeW(&dwDDEInst
, DdeCallback
, CBF_FAIL_ADVISES
| CBF_FAIL_POKES
, 0);
339 hszProgmanTopic
= DdeCreateStringHandleW(dwDDEInst
, L
"Progman", CP_WINUNICODE
);
340 hszProgmanService
= DdeCreateStringHandleW(dwDDEInst
, L
"Progman", CP_WINUNICODE
);
341 hszShell
= DdeCreateStringHandleW(dwDDEInst
, L
"Shell", CP_WINUNICODE
);
342 hszAppProperties
= DdeCreateStringHandleW(dwDDEInst
, L
"AppProperties", CP_WINUNICODE
);
343 hszFolders
= DdeCreateStringHandleW(dwDDEInst
, L
"Folders", CP_WINUNICODE
);
345 if (hszProgmanTopic
&& hszProgmanService
&&
346 hszShell
&& hszAppProperties
&& hszFolders
&&
347 DdeNameService(dwDDEInst
, hszFolders
, 0, DNS_REGISTER
) &&
348 DdeNameService(dwDDEInst
, hszProgmanService
, 0, DNS_REGISTER
) &&
349 DdeNameService(dwDDEInst
, hszShell
, 0, DNS_REGISTER
))
354 else if (!bInit
&& bInitialized
)
356 /* unregister all services */
357 DdeNameService(dwDDEInst
, 0, 0, DNS_UNREGISTER
);
360 DdeFreeStringHandle(dwDDEInst
, hszFolders
);
361 if (hszAppProperties
)
362 DdeFreeStringHandle(dwDDEInst
, hszAppProperties
);
364 DdeFreeStringHandle(dwDDEInst
, hszShell
);
365 if (hszProgmanService
)
366 DdeFreeStringHandle(dwDDEInst
, hszProgmanService
);
368 DdeFreeStringHandle(dwDDEInst
, hszProgmanTopic
);
370 DdeUninitialize(dwDDEInst
);
372 bInitialized
= FALSE
;
376 static DWORD CALLBACK
DDE_OnViewFolder(PWSTR strCommand
, PWSTR strPath
, LPITEMIDLIST pidl
, INT unkS
)
382 static DWORD CALLBACK
DDW_OnExploreFolder(PWSTR strCommand
, PWSTR strPath
, LPITEMIDLIST pidl
, INT unkS
)
388 static DWORD CALLBACK
DDE_OnFindFolder(PWSTR strCommand
, PWSTR strPath
, LPITEMIDLIST pidl
, INT unkS
)
391 return DDE_FNOTPROCESSED
;
394 static DWORD CALLBACK
DDE_OnShellFile(PWSTR strCommand
, PWSTR strPath
, LPITEMIDLIST pidl
, INT unkS
)
397 return DDE_FNOTPROCESSED
;
400 DDECommandHandler HandlerList
[] = {
402 { L
"ViewFolder", DDE_OnViewFolder
},
403 { L
"ExploreFolder", DDW_OnExploreFolder
},
404 { L
"FindFolder", DDE_OnFindFolder
},
405 { L
"ShellFile", DDE_OnShellFile
}
408 const int HandlerListLength
= _countof(HandlerList
);