shellord.c 57.6 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1
/*
2 3
 * The parameters of many functions changes between different OS versions
 * (NT uses Unicode strings, 95 uses ASCII strings)
4
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
5
 * Copyright 1997 Marcus Meissner
6
 *           1998 Jürgen Schmied
7 8 9 10 11 12 13 14 15 16 17 18 19
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
20
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Alexandre Julliard's avatar
Alexandre Julliard committed
21
 */
22 23
#include "config.h"

Alexandre Julliard's avatar
Alexandre Julliard committed
24
#include <string.h>
25
#include <stdarg.h>
26
#include <stdio.h>
27 28 29

#define COBJMACROS

Alexandre Julliard's avatar
Alexandre Julliard committed
30
#include "winerror.h"
31 32
#include "windef.h"
#include "winbase.h"
33
#include "winreg.h"
34
#include "wine/debug.h"
35
#include "winnls.h"
36
#include "winternl.h"
37

38
#include "shellapi.h"
39
#include "objbase.h"
40
#include "shlguid.h"
41 42
#include "wingdi.h"
#include "winuser.h"
43
#include "shlobj.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
44
#include "shell32_main.h"
45
#include "undocshell.h"
46
#include "pidl.h"
47
#include "shlwapi.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
48
#include "commdlg.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
49

50 51
WINE_DEFAULT_DEBUG_CHANNEL(shell);
WINE_DECLARE_DEBUG_CHANNEL(pidl);
52

53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
/* FIXME: !!! move CREATEMRULIST and flags to header file !!! */
/*        !!! it is in both here and comctl32undoc.c      !!! */
typedef struct tagCREATEMRULIST
{
    DWORD  cbSize;        /* size of struct */
    DWORD  nMaxItems;     /* max no. of items in list */
    DWORD  dwFlags;       /* see below */
    HKEY   hKey;          /* root reg. key under which list is saved */
    LPCSTR lpszSubKey;    /* reg. subkey */
    PROC   lpfnCompare;   /* item compare proc */
} CREATEMRULISTA, *LPCREATEMRULISTA;

/* dwFlags */
#define MRUF_STRING_LIST  0 /* list will contain strings */
#define MRUF_BINARY_LIST  1 /* list will contain binary data */
#define MRUF_DELAYED_SAVE 2 /* only save list order to reg. is FreeMRUList */

extern HANDLE WINAPI CreateMRUListA(LPCREATEMRULISTA lpcml);
extern DWORD  WINAPI FreeMRUList(HANDLE hMRUList);
extern INT    WINAPI AddMRUData(HANDLE hList, LPCVOID lpData, DWORD cbData);
extern INT    WINAPI FindMRUData(HANDLE hList, LPCVOID lpData, DWORD cbData, LPINT lpRegNum);
extern INT    WINAPI EnumMRUListA(HANDLE hList, INT nItemPos, LPVOID lpBuffer, DWORD nBufferSize);

76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94

/* Get a function pointer from a DLL handle */
#define GET_FUNC(func, module, name, fail) \
  do { \
    if (!func) { \
      if (!SHELL32_h##module && !(SHELL32_h##module = LoadLibraryA(#module ".dll"))) return fail; \
      func = (void*)GetProcAddress(SHELL32_h##module, name); \
      if (!func) return fail; \
    } \
  } while (0)

/* Function pointers for GET_FUNC macro */
static HMODULE SHELL32_hshlwapi=NULL;
static HANDLE (WINAPI *pSHAllocShared)(LPCVOID,DWORD,DWORD);
static LPVOID (WINAPI *pSHLockShared)(HANDLE,DWORD);
static BOOL   (WINAPI *pSHUnlockShared)(LPVOID);
static BOOL   (WINAPI *pSHFreeShared)(HANDLE,DWORD);


Alexandre Julliard's avatar
Alexandre Julliard committed
95
/*************************************************************************
96
 * ParseFieldA					[internal]
Alexandre Julliard's avatar
Alexandre Julliard committed
97
 *
98
 * copies a field from a ',' delimited string
99
 *
100
 * first field is nField = 1
Alexandre Julliard's avatar
Alexandre Julliard committed
101
 */
102 103 104 105
DWORD WINAPI ParseFieldA(
	LPCSTR src,
	DWORD nField,
	LPSTR dst,
106
	DWORD len)
107
{
108
	WARN("(%s,0x%08x,%p,%d) semi-stub.\n",debugstr_a(src),nField,dst,len);
109 110 111 112

	if (!src || !src[0] || !dst || !len)
	  return 0;

113 114 115 116 117
	/* skip n fields delimited by ',' */
	while (nField > 1)
	{
	  if (*src=='\0') return FALSE;
	  if (*(src++)==',') nField--;
118 119
	}

120 121
	/* copy part till the next ',' to dst */
	while ( *src!='\0' && *src!=',' && (len--)>0 ) *(dst++)=*(src++);
122

123
	/* finalize the string */
124
	*dst=0x0;
125

126
	return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
127 128 129
}

/*************************************************************************
130 131
 * ParseFieldW			[internal]
 *
132
 * copies a field from a ',' delimited string
133
 *
134
 * first field is nField = 1
Alexandre Julliard's avatar
Alexandre Julliard committed
135
 */
136
DWORD WINAPI ParseFieldW(LPCWSTR src, DWORD nField, LPWSTR dst, DWORD len)
137
{
138
	WARN("(%s,0x%08x,%p,%d) semi-stub.\n", debugstr_w(src), nField, dst, len);
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156

	if (!src || !src[0] || !dst || !len)
	  return 0;

	/* skip n fields delimited by ',' */
	while (nField > 1)
	{
	  if (*src == 0x0) return FALSE;
	  if (*src++ == ',') nField--;
	}

	/* copy part till the next ',' to dst */
	while ( *src != 0x0 && *src != ',' && (len--)>0 ) *(dst++) = *(src++);

	/* finalize the string */
	*dst = 0x0;

	return TRUE;
157 158 159
}

/*************************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
160
 * ParseField			[SHELL32.58]
161
 */
162
DWORD WINAPI ParseFieldAW(LPCVOID src, DWORD nField, LPVOID dst, DWORD len)
163
{
164
	if (SHELL_OsIsUnicode())
165 166
	  return ParseFieldW(src, nField, dst, len);
	return ParseFieldA(src, nField, dst, len);
Alexandre Julliard's avatar
Alexandre Julliard committed
167 168 169
}

/*************************************************************************
170
 * GetFileNameFromBrowse			[SHELL32.63]
171
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
172
 */
173 174 175 176 177 178 179 180 181
BOOL WINAPI GetFileNameFromBrowse(
	HWND hwndOwner,
	LPSTR lpstrFile,
	DWORD nMaxFile,
	LPCSTR lpstrInitialDir,
	LPCSTR lpstrDefExt,
	LPCSTR lpstrFilter,
	LPCSTR lpstrTitle)
{
Alexandre Julliard's avatar
Alexandre Julliard committed
182 183 184 185 186
    HMODULE hmodule;
    FARPROC pGetOpenFileNameA;
    OPENFILENAMEA ofn;
    BOOL ret;

187
    TRACE("%p, %s, %d, %s, %s, %s, %s)\n",
188 189 190
	  hwndOwner, lpstrFile, nMaxFile, lpstrInitialDir, lpstrDefExt,
	  lpstrFilter, lpstrTitle);

Alexandre Julliard's avatar
Alexandre Julliard committed
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
    hmodule = LoadLibraryA("comdlg32.dll");
    if(!hmodule) return FALSE;
    pGetOpenFileNameA = GetProcAddress(hmodule, "GetOpenFileNameA");
    if(!pGetOpenFileNameA)
    {
	FreeLibrary(hmodule);
	return FALSE;
    }

    memset(&ofn, 0, sizeof(ofn));

    ofn.lStructSize = sizeof(ofn);
    ofn.hwndOwner = hwndOwner;
    ofn.lpstrFilter = lpstrFilter;
    ofn.lpstrFile = lpstrFile;
    ofn.nMaxFile = nMaxFile;
    ofn.lpstrInitialDir = lpstrInitialDir;
    ofn.lpstrTitle = lpstrTitle;
    ofn.lpstrDefExt = lpstrDefExt;
    ofn.Flags = OFN_EXPLORER | OFN_HIDEREADONLY | OFN_FILEMUSTEXIST;
    ret = pGetOpenFileNameA(&ofn);
212

Alexandre Julliard's avatar
Alexandre Julliard committed
213 214
    FreeLibrary(hmodule);
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
215 216 217
}

/*************************************************************************
218 219
 * SHGetSetSettings				[SHELL32.68]
 */
220
VOID WINAPI SHGetSetSettings(LPSHELLSTATE lpss, DWORD dwMask, BOOL bSet)
221
{
222 223
  if(bSet)
  {
224
    FIXME("%p 0x%08x TRUE\n", lpss, dwMask);
225 226 227 228 229
  }
  else
  {
    SHGetSettings((LPSHELLFLAGSTATE)lpss,dwMask);
  }
230 231 232 233
}

/*************************************************************************
 * SHGetSettings				[SHELL32.@]
234
 *
235 236 237
 * NOTES
 *  the registry path are for win98 (tested)
 *  and possibly are the same in nt40
238
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
239
 */
240
VOID WINAPI SHGetSettings(LPSHELLFLAGSTATE lpsfs, DWORD dwMask)
241 242 243 244 245
{
	HKEY	hKey;
	DWORD	dwData;
	DWORD	dwDataSize = sizeof (DWORD);

246
	TRACE("(%p 0x%08x)\n",lpsfs,dwMask);
247

248
	if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced",
249 250
				 0, 0, 0, KEY_ALL_ACCESS, 0, &hKey, 0))
	  return;
251

252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
	if ( (SSF_SHOWEXTENSIONS & dwMask) && !RegQueryValueExA(hKey, "HideFileExt", 0, 0, (LPBYTE)&dwData, &dwDataSize))
	  lpsfs->fShowExtensions  = ((dwData == 0) ?  0 : 1);

	if ( (SSF_SHOWINFOTIP & dwMask) && !RegQueryValueExA(hKey, "ShowInfoTip", 0, 0, (LPBYTE)&dwData, &dwDataSize))
	  lpsfs->fShowInfoTip  = ((dwData == 0) ?  0 : 1);

	if ( (SSF_DONTPRETTYPATH & dwMask) && !RegQueryValueExA(hKey, "DontPrettyPath", 0, 0, (LPBYTE)&dwData, &dwDataSize))
	  lpsfs->fDontPrettyPath  = ((dwData == 0) ?  0 : 1);

	if ( (SSF_HIDEICONS & dwMask) && !RegQueryValueExA(hKey, "HideIcons", 0, 0, (LPBYTE)&dwData, &dwDataSize))
	  lpsfs->fHideIcons  = ((dwData == 0) ?  0 : 1);

	if ( (SSF_MAPNETDRVBUTTON & dwMask) && !RegQueryValueExA(hKey, "MapNetDrvBtn", 0, 0, (LPBYTE)&dwData, &dwDataSize))
	  lpsfs->fMapNetDrvBtn  = ((dwData == 0) ?  0 : 1);

	if ( (SSF_SHOWATTRIBCOL & dwMask) && !RegQueryValueExA(hKey, "ShowAttribCol", 0, 0, (LPBYTE)&dwData, &dwDataSize))
	  lpsfs->fShowAttribCol  = ((dwData == 0) ?  0 : 1);

	if (((SSF_SHOWALLOBJECTS | SSF_SHOWSYSFILES) & dwMask) && !RegQueryValueExA(hKey, "Hidden", 0, 0, (LPBYTE)&dwData, &dwDataSize))
	{ if (dwData == 0)
	  { if (SSF_SHOWALLOBJECTS & dwMask)	lpsfs->fShowAllObjects  = 0;
	    if (SSF_SHOWSYSFILES & dwMask)	lpsfs->fShowSysFiles  = 0;
	  }
	  else if (dwData == 1)
	  { if (SSF_SHOWALLOBJECTS & dwMask)	lpsfs->fShowAllObjects  = 1;
	    if (SSF_SHOWSYSFILES & dwMask)	lpsfs->fShowSysFiles  = 0;
	  }
	  else if (dwData == 2)
	  { if (SSF_SHOWALLOBJECTS & dwMask)	lpsfs->fShowAllObjects  = 0;
	    if (SSF_SHOWSYSFILES & dwMask)	lpsfs->fShowSysFiles  = 1;
	  }
	}
	RegCloseKey (hKey);

286
	TRACE("-- 0x%04x\n", *(WORD*)lpsfs);
Alexandre Julliard's avatar
Alexandre Julliard committed
287 288
}

Alexandre Julliard's avatar
Alexandre Julliard committed
289
/*************************************************************************
290
 * SHShellFolderView_Message			[SHELL32.73]
Alexandre Julliard's avatar
Alexandre Julliard committed
291
 *
Jon Griffiths's avatar
Jon Griffiths committed
292 293 294 295 296 297 298 299 300
 * Send a message to an explorer cabinet window.
 *
 * PARAMS
 *  hwndCabinet [I] The window containing the shellview to communicate with
 *  dwMessage   [I] The SFVM message to send
 *  dwParam     [I] Message parameter
 *
 * RETURNS
 *  fixme.
Alexandre Julliard's avatar
Alexandre Julliard committed
301
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
302 303
 * NOTES
 *  Message SFVM_REARRANGE = 1
Jon Griffiths's avatar
Jon Griffiths committed
304
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
305
 *    This message gets sent when a column gets clicked to instruct the
Jon Griffiths's avatar
Jon Griffiths committed
306
 *    shell view to re-sort the item list. dwParam identifies the column
Alexandre Julliard's avatar
Alexandre Julliard committed
307 308
 *    that was clicked.
 */
309
LRESULT WINAPI SHShellFolderView_Message(
310
	HWND hwndCabinet,
311 312
	UINT uMessage,
	LPARAM lParam)
313
{
314
	FIXME("%p %08x %08lx stub\n",hwndCabinet, uMessage, lParam);
315
	return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
316 317
}

Alexandre Julliard's avatar
Alexandre Julliard committed
318
/*************************************************************************
319
 * RegisterShellHook				[SHELL32.181]
Alexandre Julliard's avatar
Alexandre Julliard committed
320
 *
Jon Griffiths's avatar
Jon Griffiths committed
321 322
 * Register a shell hook.
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
323
 * PARAMS
Jon Griffiths's avatar
Jon Griffiths committed
324 325
 *      hwnd   [I]  Window handle
 *      dwType [I]  Type of hook.
326
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
327
 * NOTES
Jon Griffiths's avatar
Jon Griffiths committed
328
 *     Exported by ordinal
Alexandre Julliard's avatar
Alexandre Julliard committed
329
 */
330 331 332 333
BOOL WINAPI RegisterShellHook(
	HWND hWnd,
	DWORD dwType)
{
334
	FIXME("(%p,0x%08x):stub.\n",hWnd, dwType);
335
	return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
336
}
Jon Griffiths's avatar
Jon Griffiths committed
337

338
/*************************************************************************
339
 * ShellMessageBoxW				[SHELL32.182]
340
 *
Jon Griffiths's avatar
Jon Griffiths committed
341
 * See ShellMessageBoxA.
342 343 344 345 346 347
 *
 * NOTE:
 * shlwapi.ShellMessageBoxWrapW is a duplicate of shell32.ShellMessageBoxW
 * because we can't forward to it in the .spec file since it's exported by
 * ordinal. If you change the implementation here please update the code in
 * shlwapi as well.
348
 */
349 350 351 352 353 354 355 356
int WINAPIV ShellMessageBoxW(
	HINSTANCE hInstance,
	HWND hWnd,
	LPCWSTR lpText,
	LPCWSTR lpCaption,
	UINT uType,
	...)
{
357
	WCHAR	szText[100],szTitle[100];
358 359
	LPCWSTR pszText = szText, pszTitle = szTitle;
	LPWSTR  pszTemp;
360
	__ms_va_list args;
361 362
	int	ret;

363
	__ms_va_start(args, uType);
364 365
	/* wvsprintfA(buf,fmt, args); */

Kevin Koltzau's avatar
Kevin Koltzau committed
366 367
	TRACE("(%p,%p,%p,%p,%08x)\n",
	    hInstance,hWnd,lpText,lpCaption,uType);
368

Kevin Koltzau's avatar
Kevin Koltzau committed
369 370
	if (IS_INTRESOURCE(lpCaption))
	  LoadStringW(hInstance, LOWORD(lpCaption), szTitle, sizeof(szTitle)/sizeof(szTitle[0]));
371
	else
372
	  pszTitle = lpCaption;
373

Kevin Koltzau's avatar
Kevin Koltzau committed
374 375
	if (IS_INTRESOURCE(lpText))
	  LoadStringW(hInstance, LOWORD(lpText), szText, sizeof(szText)/sizeof(szText[0]));
376
	else
377
	  pszText = lpText;
378

379
	FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
380
		       pszText, 0, 0, (LPWSTR)&pszTemp, 0, &args);
Patrik Stridvall's avatar
Patrik Stridvall committed
381

382
	__ms_va_end(args);
Patrik Stridvall's avatar
Patrik Stridvall committed
383

384
	ret = MessageBoxW(hWnd,pszTemp,pszTitle,uType);
385
        LocalFree(pszTemp);
386
	return ret;
387
}
Alexandre Julliard's avatar
Alexandre Julliard committed
388

Alexandre Julliard's avatar
Alexandre Julliard committed
389
/*************************************************************************
390
 * ShellMessageBoxA				[SHELL32.183]
Jon Griffiths's avatar
Jon Griffiths committed
391 392 393 394 395 396 397 398 399 400 401 402 403 404 405
 *
 * Format and output an error message.
 *
 * PARAMS
 *  hInstance [I] Instance handle of message creator
 *  hWnd      [I] Window handle of message creator
 *  lpText    [I] Resource Id of title or LPSTR
 *  lpCaption [I] Resource Id of title or LPSTR
 *  uType     [I] Type of error message
 *
 * RETURNS
 *  A return value from MessageBoxA().
 *
 * NOTES
 *     Exported by ordinal
Alexandre Julliard's avatar
Alexandre Julliard committed
406
 */
407 408 409 410 411 412 413 414
int WINAPIV ShellMessageBoxA(
	HINSTANCE hInstance,
	HWND hWnd,
	LPCSTR lpText,
	LPCSTR lpCaption,
	UINT uType,
	...)
{
415
	char	szText[100],szTitle[100];
416 417
	LPCSTR  pszText = szText, pszTitle = szTitle;
	LPSTR   pszTemp;
418
	__ms_va_list args;
419 420
	int	ret;

421
	__ms_va_start(args, uType);
422 423
	/* wvsprintfA(buf,fmt, args); */

Kevin Koltzau's avatar
Kevin Koltzau committed
424 425
	TRACE("(%p,%p,%p,%p,%08x)\n",
	    hInstance,hWnd,lpText,lpCaption,uType);
426

Kevin Koltzau's avatar
Kevin Koltzau committed
427 428
	if (IS_INTRESOURCE(lpCaption))
	  LoadStringA(hInstance, LOWORD(lpCaption), szTitle, sizeof(szTitle));
429
	else
430
	  pszTitle = lpCaption;
431

Kevin Koltzau's avatar
Kevin Koltzau committed
432 433
	if (IS_INTRESOURCE(lpText))
	  LoadStringA(hInstance, LOWORD(lpText), szText, sizeof(szText));
434
	else
435
	  pszText = lpText;
436

437
	FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
438
		       pszText, 0, 0, (LPSTR)&pszTemp, 0, &args);
Patrik Stridvall's avatar
Patrik Stridvall committed
439

440
	__ms_va_end(args);
Patrik Stridvall's avatar
Patrik Stridvall committed
441

442
	ret = MessageBoxA(hWnd,pszTemp,pszTitle,uType);
443
        LocalFree(pszTemp);
444
	return ret;
445 446
}

Alexandre Julliard's avatar
Alexandre Julliard committed
447
/*************************************************************************
448
 * SHRegisterDragDrop				[SHELL32.86]
Alexandre Julliard's avatar
Alexandre Julliard committed
449
 *
450
 * Probably equivalent to RegisterDragDrop but under Windows 95 it could use the
451
 * shell32 built-in "mini-COM" without the need to load ole32.dll - see SHLoadOLE
452 453 454 455
 * for details. Under Windows 98 this function initializes the true OLE when called
 * the first time, on XP always returns E_OUTOFMEMORY and it got removed from Vista.
 *
 * We follow Windows 98 behaviour.
456
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
457
 * NOTES
Alexandre Julliard's avatar
Alexandre Julliard committed
458
 *     exported by ordinal
459 460 461
 *
 * SEE ALSO
 *     RegisterDragDrop, SHLoadOLE
Alexandre Julliard's avatar
Alexandre Julliard committed
462
 */
463 464 465
HRESULT WINAPI SHRegisterDragDrop(
	HWND hWnd,
	LPDROPTARGET pDropTarget)
466
{
467 468 469 470 471 472 473 474 475 476 477 478
        static BOOL ole_initialized = FALSE;
        HRESULT hr;

        TRACE("(%p,%p)\n", hWnd, pDropTarget);

        if (!ole_initialized)
        {
            hr = OleInitialize(NULL);
            if (FAILED(hr))
                return hr;
            ole_initialized = TRUE;
        }
479
	return RegisterDragDrop(hWnd, pDropTarget);
Alexandre Julliard's avatar
Alexandre Julliard committed
480 481 482
}

/*************************************************************************
483
 * SHRevokeDragDrop				[SHELL32.87]
Alexandre Julliard's avatar
Alexandre Julliard committed
484
 *
485
 * Probably equivalent to RevokeDragDrop but under Windows 95 it could use the
486
 * shell32 built-in "mini-COM" without the need to load ole32.dll - see SHLoadOLE
487 488 489 490
 * for details. Function removed from Windows Vista.
 *
 * We call ole32 RevokeDragDrop which seems to work even if OleInitialize was
 * not called.
491
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
492
 * NOTES
Alexandre Julliard's avatar
Alexandre Julliard committed
493
 *     exported by ordinal
494 495 496
 *
 * SEE ALSO
 *     RevokeDragDrop, SHLoadOLE
Alexandre Julliard's avatar
Alexandre Julliard committed
497
 */
498 499
HRESULT WINAPI SHRevokeDragDrop(HWND hWnd)
{
500
    TRACE("(%p)\n", hWnd);
501
    return RevokeDragDrop(hWnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
502 503
}

Eric Kohl's avatar
Eric Kohl committed
504 505 506
/*************************************************************************
 * SHDoDragDrop					[SHELL32.88]
 *
507 508 509 510
 * Probably equivalent to DoDragDrop but under Windows 9x it could use the
 * shell32 built-in "mini-COM" without the need to load ole32.dll - see SHLoadOLE
 * for details
 *
Eric Kohl's avatar
Eric Kohl committed
511 512
 * NOTES
 *     exported by ordinal
513 514 515
 *
 * SEE ALSO
 *     DoDragDrop, SHLoadOLE
Eric Kohl's avatar
Eric Kohl committed
516
 */
517 518 519 520 521 522
HRESULT WINAPI SHDoDragDrop(
	HWND hWnd,
	LPDATAOBJECT lpDataObject,
	LPDROPSOURCE lpDropSource,
	DWORD dwOKEffect,
	LPDWORD pdwEffect)
Alexandre Julliard's avatar
Alexandre Julliard committed
523
{
524
    FIXME("(%p %p %p 0x%08x %p):stub.\n",
525
    hWnd, lpDataObject, lpDropSource, dwOKEffect, pdwEffect);
526
	return DoDragDrop(lpDataObject, lpDropSource, dwOKEffect, pdwEffect);
Alexandre Julliard's avatar
Alexandre Julliard committed
527 528 529
}

/*************************************************************************
530
 * ArrangeWindows				[SHELL32.184]
531
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
532
 */
533 534 535 536 537 538
WORD WINAPI ArrangeWindows(
	HWND hwndParent,
	DWORD dwReserved,
	LPCRECT lpRect,
	WORD cKids,
	CONST HWND * lpKids)
Alexandre Julliard's avatar
Alexandre Julliard committed
539
{
540
    FIXME("(%p 0x%08x %p 0x%04x %p):stub.\n",
541
	   hwndParent, dwReserved, lpRect, cKids, lpKids);
Alexandre Julliard's avatar
Alexandre Julliard committed
542 543 544
    return 0;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
545
/*************************************************************************
546
 * SignalFileOpen				[SHELL32.103]
Alexandre Julliard's avatar
Alexandre Julliard committed
547 548 549 550 551 552 553
 *
 * NOTES
 *     exported by ordinal
 */
DWORD WINAPI
SignalFileOpen (DWORD dwParam1)
{
554
    FIXME("(0x%08x):stub.\n", dwParam1);
Alexandre Julliard's avatar
Alexandre Julliard committed
555

Alexandre Julliard's avatar
Alexandre Julliard committed
556 557 558
    return 0;
}

559 560 561 562 563 564 565 566 567 568 569 570 571
/*************************************************************************
 * SHADD_get_policy - helper function for SHAddToRecentDocs
 *
 * PARAMETERS
 *   policy    [IN]  policy name (null termed string) to find
 *   type      [OUT] ptr to DWORD to receive type
 *   buffer    [OUT] ptr to area to hold data retrieved
 *   len       [IN/OUT] ptr to DWORD holding size of buffer and getting
 *                      length filled
 *
 * RETURNS
 *   result of the SHQueryValueEx call
 */
572
static INT SHADD_get_policy(LPCSTR policy, LPDWORD type, LPVOID buffer, LPDWORD len)
573 574 575 576
{
    HKEY Policy_basekey;
    INT ret;

577
    /* Get the key for the policies location in the registry
578 579 580 581 582 583 584 585
     */
    if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,
		      "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer",
		      0, KEY_READ, &Policy_basekey)) {

	if (RegOpenKeyExA(HKEY_CURRENT_USER,
			  "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer",
			  0, KEY_READ, &Policy_basekey)) {
586 587
	    TRACE("No Explorer Policies location exists. Policy wanted=%s\n",
		  policy);
588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623
	    *len = 0;
	    return ERROR_FILE_NOT_FOUND;
	}
    }

    /* Retrieve the data if it exists
     */
    ret = SHQueryValueExA(Policy_basekey, policy, 0, type, buffer, len);
    RegCloseKey(Policy_basekey);
    return ret;
}


/*************************************************************************
 * SHADD_compare_mru - helper function for SHAddToRecentDocs
 *
 * PARAMETERS
 *   data1     [IN] data being looked for
 *   data2     [IN] data in MRU
 *   cbdata    [IN] length from FindMRUData call (not used)
 *
 * RETURNS
 *   position within MRU list that data was added.
 */
static INT CALLBACK SHADD_compare_mru(LPCVOID data1, LPCVOID data2, DWORD cbData)
{
    return lstrcmpiA(data1, data2);
}

/*************************************************************************
 * SHADD_create_add_mru_data - helper function for SHAddToRecentDocs
 *
 * PARAMETERS
 *   mruhandle    [IN] handle for created MRU list
 *   doc_name     [IN] null termed pure doc name
 *   new_lnk_name [IN] null termed path and file name for .lnk file
624
 *   buffer       [IN/OUT] 2048 byte area to construct MRU data
625 626 627 628 629
 *   len          [OUT] ptr to int to receive space used in buffer
 *
 * RETURNS
 *   position within MRU list that data was added.
 */
630
static INT SHADD_create_add_mru_data(HANDLE mruhandle, LPCSTR doc_name, LPCSTR new_lnk_name,
631 632 633 634
                                     LPSTR buffer, INT *len)
{
    LPSTR ptr;
    INT wlen;
635

636 637 638 639
    /*FIXME: Document:
     *  RecentDocs MRU data structure seems to be:
     *    +0h   document file name w/ terminating 0h
     *    +nh   short int w/ size of remaining
640
     *    +n+2h 02h 30h, or 01h 30h, or 00h 30h  -  unknown
641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663
     *    +n+4h 10 bytes zeros  -   unknown
     *    +n+eh shortcut file name w/ terminating 0h
     *    +n+e+nh 3 zero bytes  -  unknown
     */

    /* Create the MRU data structure for "RecentDocs"
	 */
    ptr = buffer;
    lstrcpyA(ptr, doc_name);
    ptr += (lstrlenA(buffer) + 1);
    wlen= lstrlenA(new_lnk_name) + 1 + 12;
    *((short int*)ptr) = wlen;
    ptr += 2;   /* step past the length */
    *(ptr++) = 0x30;  /* unknown reason */
    *(ptr++) = 0;     /* unknown, but can be 0x00, 0x01, 0x02 */
    memset(ptr, 0, 10);
    ptr += 10;
    lstrcpyA(ptr, new_lnk_name);
    ptr += (lstrlenA(new_lnk_name) + 1);
    memset(ptr, 0, 3);
    ptr += 3;
    *len = ptr - buffer;

664
    /* Add the new entry into the MRU list
665
     */
666
    return AddMRUData(mruhandle, buffer, *len);
667 668
}

Alexandre Julliard's avatar
Alexandre Julliard committed
669
/*************************************************************************
670
 * SHAddToRecentDocs				[SHELL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
671
 *
672 673
 * Modify (add/clear) Shell's list of recently used documents.
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
674
 * PARAMETERS
675
 *   uFlags  [IN] SHARD_PATHA, SHARD_PATHW or SHARD_PIDL
Alexandre Julliard's avatar
Alexandre Julliard committed
676 677
 *   pv      [IN] string or pidl, NULL clears the list
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
678 679
 * NOTES
 *     exported by name
680
 *
681 682
 * FIXME
 *  convert to unicode
Alexandre Julliard's avatar
Alexandre Julliard committed
683
 */
684
void WINAPI SHAddToRecentDocs (UINT uFlags,LPCVOID pv)
685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706
{
/* If list is a string list lpfnCompare has the following prototype
 * int CALLBACK MRUCompareString(LPCSTR s1, LPCSTR s2)
 * for binary lists the prototype is
 * int CALLBACK MRUCompareBinary(LPCVOID data1, LPCVOID data2, DWORD cbData)
 * where cbData is the no. of bytes to compare.
 * Need to check what return value means identical - 0?
 */


    UINT olderrormode;
    HKEY HCUbasekey;
    CHAR doc_name[MAX_PATH];
    CHAR link_dir[MAX_PATH];
    CHAR new_lnk_filepath[MAX_PATH];
    CHAR new_lnk_name[MAX_PATH];
    IMalloc *ppM;
    LPITEMIDLIST pidl;
    HWND hwnd = 0;       /* FIXME:  get real window handle */
    INT ret;
    DWORD data[64], datalen, type;

707 708
    TRACE("%04x %p\n", uFlags, pv);

709 710 711 712
    /*FIXME: Document:
     *  RecentDocs MRU data structure seems to be:
     *    +0h   document file name w/ terminating 0h
     *    +nh   short int w/ size of remaining
713
     *    +n+2h 02h 30h, or 01h 30h, or 00h 30h  -  unknown
714 715 716 717 718 719 720 721
     *    +n+4h 10 bytes zeros  -   unknown
     *    +n+eh shortcut file name w/ terminating 0h
     *    +n+e+nh 3 zero bytes  -  unknown
     */

    /* See if we need to do anything.
     */
    datalen = 64;
722
    ret=SHADD_get_policy( "NoRecentDocsHistory", &type, data, &datalen);
723 724
    if ((ret > 0) && (ret != ERROR_FILE_NOT_FOUND)) {
	ERR("Error %d getting policy \"NoRecentDocsHistory\"\n", ret);
725
	return;
726 727
    }
    if (ret == ERROR_SUCCESS) {
728
	if (!( (type == REG_DWORD) ||
729
	       ((type == REG_BINARY) && (datalen == 4)) )) {
730
	    ERR("Error policy data for \"NoRecentDocsHistory\" not formatted correctly, type=%d, len=%d\n",
731
		type, datalen);
732
	    return;
Alexandre Julliard's avatar
Alexandre Julliard committed
733
	}
734

735
	TRACE("policy value for NoRecentDocsHistory = %08x\n", data[0]);
736 737
	/* now test the actual policy value */
	if ( data[0] != 0)
738
	    return;
739 740 741 742 743 744 745 746
    }

    /* Open key to where the necessary info is
     */
    /* FIXME: This should be done during DLL PROCESS_ATTACH (or THREAD_ATTACH)
     *        and the close should be done during the _DETACH. The resulting
     *        key is stored in the DLL global data.
     */
747 748 749 750
    if (RegCreateKeyExA(HKEY_CURRENT_USER,
			"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer",
			0, 0, 0, KEY_READ, 0, &HCUbasekey, 0)) {
	ERR("Failed to create 'Software\\Microsoft\\Windows\\CurrentVersion\\Explorer'\n");
751
	return;
752
    }
753 754 755 756

    /* Get path to user's "Recent" directory
     */
    if(SUCCEEDED(SHGetMalloc(&ppM))) {
757
	if (SUCCEEDED(SHGetSpecialFolderLocation(hwnd, CSIDL_RECENT,
758 759 760 761
						 &pidl))) {
	    SHGetPathFromIDListA(pidl, link_dir);
	    IMalloc_Free(ppM, pidl);
	}
762 763 764 765 766
	else {
	    /* serious issues */
	    link_dir[0] = 0;
	    ERR("serious issues 1\n");
	}
767 768 769 770 771
	IMalloc_Release(ppM);
    }
    else {
	/* serious issues */
	link_dir[0] = 0;
772
	ERR("serious issues 2\n");
773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788
    }
    TRACE("Users Recent dir %s\n", link_dir);

    /* If no input, then go clear the lists */
    if (!pv) {
	/* clear user's Recent dir
	 */

	/* FIXME: delete all files in "link_dir"
	 *
	 * while( more files ) {
	 *    lstrcpyA(old_lnk_name, link_dir);
	 *    PathAppendA(old_lnk_name, filenam);
	 *    DeleteFileA(old_lnk_name);
	 * }
	 */
789
	FIXME("should delete all files in %s\\\n", link_dir);
790 791 792 793 794 795 796 797 798 799 800

	/* clear MRU list
	 */
	/* MS Bug ?? v4.72.3612.1700 of shell32 does the delete against
	 *  HKEY_LOCAL_MACHINE version of ...CurrentVersion\Explorer
	 *  and naturally it fails w/ rc=2. It should do it against
	 *  HKEY_CURRENT_USER which is where it is stored, and where
	 *  the MRU routines expect it!!!!
	 */
	RegDeleteKeyA(HCUbasekey, "RecentDocs");
	RegCloseKey(HCUbasekey);
801
	return;
802 803 804 805 806
    }

    /* Have data to add, the jobs to be done:
     *   1. Add document to MRU list in registry "HKCU\Software\
     *      Microsoft\Windows\CurrentVersion\Explorer\RecentDocs".
807
     *   2. Add shortcut to document in the user's Recent directory
808 809 810 811 812 813
     *      (CSIDL_RECENT).
     *   3. Add shortcut to Start menu's Documents submenu.
     */

    /* Get the pure document name from the input
     */
814 815 816
    switch (uFlags)
    {
    case SHARD_PIDL:
817
        SHGetPathFromIDListA(pv, doc_name);
818 819 820
        break;

    case SHARD_PATHA:
821
        lstrcpynA(doc_name, pv, MAX_PATH);
822 823 824
        break;

    case SHARD_PATHW:
825
        WideCharToMultiByte(CP_ACP, 0, pv, -1, doc_name, MAX_PATH, NULL, NULL);
826 827 828 829 830
        break;

    default:
        FIXME("Unsupported flags: %u\n", uFlags);
        return;
831
    }
832 833

    TRACE("full document name %s\n", debugstr_a(doc_name));
834
    PathStripPathA(doc_name);
835
    TRACE("stripped document name %s\n", debugstr_a(doc_name));
836 837 838 839


    /* ***  JOB 1: Update registry for ...\Explorer\RecentDocs list  *** */

840 841
    {  /* on input needs:
	*      doc_name    -  pure file-spec, no path
842 843 844 845 846
	*      link_dir    -  path to the user's Recent directory
	*      HCUbasekey  -  key of ...Windows\CurrentVersion\Explorer" node
	* creates:
	*      new_lnk_name-  pure file-spec, no path for new .lnk file
	*      new_lnk_filepath
847
	*                  -  path and file name of new .lnk file
848
	*/
849
	CREATEMRULISTA mymru;
850 851 852 853 854 855 856 857 858
	HANDLE mruhandle;
	INT len, pos, bufused, err;
	INT i;
	DWORD attr;
	CHAR buffer[2048];
	CHAR *ptr;
	CHAR old_lnk_name[MAX_PATH];
	short int slen;

859
	mymru.cbSize = sizeof(CREATEMRULISTA);
860 861 862 863
	mymru.nMaxItems = 15;
	mymru.dwFlags = MRUF_BINARY_LIST | MRUF_DELAYED_SAVE;
	mymru.hKey = HCUbasekey;
	mymru.lpszSubKey = "RecentDocs";
864
	mymru.lpfnCompare = (PROC)SHADD_compare_mru;
865
	mruhandle = CreateMRUListA(&mymru);
866 867 868 869
	if (!mruhandle) {
	    /* MRU failed */
	    ERR("MRU processing failed, handle zero\n");
	    RegCloseKey(HCUbasekey);
870
	    return;
871 872
	}
	len = lstrlenA(doc_name);
873
	pos = FindMRUData(mruhandle, doc_name, len, 0);
874

875 876
	/* Now get the MRU entry that will be replaced
	 * and delete the .lnk file for it
877
	 */
878 879
	if ((bufused = EnumMRUListA(mruhandle, (pos == -1) ? 14 : pos,
                                    buffer, 2048)) != -1) {
880 881 882 883 884 885 886 887 888 889 890 891 892
	    ptr = buffer;
	    ptr += (lstrlenA(buffer) + 1);
	    slen = *((short int*)ptr);
	    ptr += 2;  /* skip the length area */
	    if (bufused >= slen + (ptr-buffer)) {
		/* buffer size looks good */
		ptr += 12; /* get to string */
		len = bufused - (ptr-buffer);  /* get length of buf remaining */
		if ((lstrlenA(ptr) > 0) && (lstrlenA(ptr) <= len-1)) {
		    /* appears to be good string */
		    lstrcpyA(old_lnk_name, link_dir);
		    PathAppendA(old_lnk_name, ptr);
		    if (!DeleteFileA(old_lnk_name)) {
893
			if ((attr = GetFileAttributesA(old_lnk_name)) == INVALID_FILE_ATTRIBUTES) {
894
			    if ((err = GetLastError()) != ERROR_FILE_NOT_FOUND) {
895
				ERR("Delete for %s failed, err=%d, attr=%08x\n",
896 897 898 899 900 901 902 903
				    old_lnk_name, err, attr);
			    }
			    else {
				TRACE("old .lnk file %s did not exist\n",
				      old_lnk_name);
			    }
			}
			else {
904
			    ERR("Delete for %s failed, attr=%08x\n",
905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921
				old_lnk_name, attr);
			}
		    }
		    else {
			TRACE("deleted old .lnk file %s\n", old_lnk_name);
		    }
		}
	    }
	}

	/* Create usable .lnk file name for the "Recent" directory
	 */
	wsprintfA(new_lnk_name, "%s.lnk", doc_name);
	lstrcpyA(new_lnk_filepath, link_dir);
	PathAppendA(new_lnk_filepath, new_lnk_name);
	i = 1;
	olderrormode = SetErrorMode(SEM_FAILCRITICALERRORS);
922
	while (GetFileAttributesA(new_lnk_filepath) != INVALID_FILE_ATTRIBUTES) {
923 924 925 926
	    i++;
	    wsprintfA(new_lnk_name, "%s (%u).lnk", doc_name, i);
	    lstrcpyA(new_lnk_filepath, link_dir);
	    PathAppendA(new_lnk_filepath, new_lnk_name);
Alexandre Julliard's avatar
Alexandre Julliard committed
927
	}
928 929 930 931 932 933 934
	SetErrorMode(olderrormode);
	TRACE("new shortcut will be %s\n", new_lnk_filepath);

	/* Now add the new MRU entry and data
	 */
	pos = SHADD_create_add_mru_data(mruhandle, doc_name, new_lnk_name,
					buffer, &len);
935
	FreeMRUList(mruhandle);
936 937 938 939 940
	TRACE("Updated MRU list, new doc is position %d\n", pos);
    }

    /* ***  JOB 2: Create shortcut in user's "Recent" directory  *** */

941
    {  /* on input needs:
942 943
	*      doc_name    -  pure file-spec, no path
	*      new_lnk_filepath
944
	*                  -  path and file name of new .lnk file
945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962
 	*      uFlags[in]  -  flags on call to SHAddToRecentDocs
	*      pv[in]      -  document path/pidl on call to SHAddToRecentDocs
	*/
	IShellLinkA *psl = NULL;
	IPersistFile *pPf = NULL;
	HRESULT hres;
	CHAR desc[MAX_PATH];
	WCHAR widelink[MAX_PATH];

	CoInitialize(0);

	hres = CoCreateInstance( &CLSID_ShellLink,
				 NULL,
				 CLSCTX_INPROC_SERVER,
				 &IID_IShellLinkA,
				 (LPVOID )&psl);
	if(SUCCEEDED(hres)) {

963
	    hres = IShellLinkA_QueryInterface(psl, &IID_IPersistFile,
964 965 966
					     (LPVOID *)&pPf);
	    if(FAILED(hres)) {
		/* bombed */
967
		ERR("failed QueryInterface for IPersistFile %08x\n", hres);
968 969 970 971
		goto fail;
	    }

	    /* Set the document path or pidl */
972
	    if (uFlags == SHARD_PIDL) {
973
                hres = IShellLinkA_SetIDList(psl, pv);
974
	    } else {
975
                hres = IShellLinkA_SetPath(psl, pv);
976 977 978
	    }
	    if(FAILED(hres)) {
		/* bombed */
979
		ERR("failed Set{IDList|Path} %08x\n", hres);
980 981 982 983 984 985 986 987
		goto fail;
	    }

	    lstrcpyA(desc, "Shortcut to ");
	    lstrcatA(desc, doc_name);
	    hres = IShellLinkA_SetDescription(psl, desc);
	    if(FAILED(hres)) {
		/* bombed */
988
		ERR("failed SetDescription %08x\n", hres);
989 990 991
		goto fail;
	    }

992
	    MultiByteToWideChar(CP_ACP, 0, new_lnk_filepath, -1,
993 994 995 996 997
				widelink, MAX_PATH);
	    /* create the short cut */
	    hres = IPersistFile_Save(pPf, widelink, TRUE);
	    if(FAILED(hres)) {
		/* bombed */
998
		ERR("failed IPersistFile::Save %08x\n", hres);
999 1000 1001 1002 1003 1004 1005
		IPersistFile_Release(pPf);
		IShellLinkA_Release(psl);
		goto fail;
	    }
	    hres = IPersistFile_SaveCompleted(pPf, widelink);
	    IPersistFile_Release(pPf);
	    IShellLinkA_Release(psl);
1006
	    TRACE("shortcut %s has been created, result=%08x\n",
1007 1008 1009
		  new_lnk_filepath, hres);
	}
	else {
1010
	    ERR("CoCreateInstance failed, hres=%08x\n", hres);
1011 1012 1013 1014 1015 1016 1017 1018
	}
    }

 fail:
    CoUninitialize();

    /* all done */
    RegCloseKey(HCUbasekey);
1019
    return;
Alexandre Julliard's avatar
Alexandre Julliard committed
1020
}
1021

Alexandre Julliard's avatar
Alexandre Julliard committed
1022
/*************************************************************************
1023
 * SHCreateShellFolderViewEx			[SHELL32.174]
Alexandre Julliard's avatar
Alexandre Julliard committed
1024
 *
1025 1026 1027 1028 1029 1030
 * Create a new instance of the default Shell folder view object.
 *
 * RETURNS
 *  Success: S_OK
 *  Failure: error value
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
1031 1032
 * NOTES
 *  see IShellFolder::CreateViewObject
Alexandre Julliard's avatar
Alexandre Julliard committed
1033
 */
1034
HRESULT WINAPI SHCreateShellFolderViewEx(
1035 1036
	LPCSFV psvcbi,    /* [in] shelltemplate struct */
	IShellView **ppv) /* [out] IShellView pointer */
1037 1038 1039
{
	IShellView * psf;
	HRESULT hRes;
1040

1041
	TRACE("sf=%p pidl=%p cb=%p mode=0x%08x parm=%p\n",
1042
	  psvcbi->pshf, psvcbi->pidl, psvcbi->pfnCallback,
1043
	  psvcbi->fvm, psvcbi->psvOuter);
1044

1045
	psf = IShellView_Constructor(psvcbi->pshf);
1046

1047 1048 1049 1050 1051 1052 1053 1054
	if (!psf)
	  return E_OUTOFMEMORY;

	IShellView_AddRef(psf);
	hRes = IShellView_QueryInterface(psf, &IID_IShellView, (LPVOID *)ppv);
	IShellView_Release(psf);

	return hRes;
Alexandre Julliard's avatar
Alexandre Julliard committed
1055
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1056
/*************************************************************************
1057
 *  SHWinHelp					[SHELL32.127]
Alexandre Julliard's avatar
Alexandre Julliard committed
1058 1059 1060
 *
 */
HRESULT WINAPI SHWinHelp (DWORD v, DWORD w, DWORD x, DWORD z)
1061
{	FIXME("0x%08x 0x%08x 0x%08x 0x%08x stub\n",v,w,x,z);
Alexandre Julliard's avatar
Alexandre Julliard committed
1062 1063 1064
	return 0;
}
/*************************************************************************
Eric Kohl's avatar
Eric Kohl committed
1065
 *  SHRunControlPanel [SHELL32.161]
Alexandre Julliard's avatar
Alexandre Julliard committed
1066 1067
 *
 */
Eric Kohl's avatar
Eric Kohl committed
1068
HRESULT WINAPI SHRunControlPanel (DWORD x, DWORD z)
1069
{	FIXME("0x%08x 0x%08x stub\n",x,z);
Alexandre Julliard's avatar
Alexandre Julliard committed
1070 1071
	return 0;
}
1072

1073
static LPUNKNOWN SHELL32_IExplorerInterface=0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1074
/*************************************************************************
1075
 * SHSetInstanceExplorer			[SHELL32.176]
Alexandre Julliard's avatar
Alexandre Julliard committed
1076
 *
1077 1078
 * NOTES
 *  Sets the interface
Alexandre Julliard's avatar
Alexandre Julliard committed
1079
 */
Kevin Koltzau's avatar
Kevin Koltzau committed
1080
VOID WINAPI SHSetInstanceExplorer (LPUNKNOWN lpUnknown)
1081
{	TRACE("%p\n", lpUnknown);
1082
	SHELL32_IExplorerInterface = lpUnknown;
Alexandre Julliard's avatar
Alexandre Julliard committed
1083 1084
}
/*************************************************************************
1085
 * SHGetInstanceExplorer			[SHELL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
1086 1087
 *
 * NOTES
1088
 *  gets the interface pointer of the explorer and a reference
Alexandre Julliard's avatar
Alexandre Julliard committed
1089
 */
1090
HRESULT WINAPI SHGetInstanceExplorer (IUnknown **lpUnknown)
1091
{	TRACE("%p\n", lpUnknown);
1092 1093 1094 1095 1096 1097

	*lpUnknown = SHELL32_IExplorerInterface;

	if (!SHELL32_IExplorerInterface)
	  return E_FAIL;

1098
	IUnknown_AddRef(SHELL32_IExplorerInterface);
1099
	return NOERROR;
Alexandre Julliard's avatar
Alexandre Julliard committed
1100 1101
}
/*************************************************************************
1102
 * SHFreeUnusedLibraries			[SHELL32.123]
Alexandre Julliard's avatar
Alexandre Julliard committed
1103
 *
1104 1105 1106 1107
 * Probably equivalent to CoFreeUnusedLibraries but under Windows 9x it could use
 * the shell32 built-in "mini-COM" without the need to load ole32.dll - see SHLoadOLE
 * for details
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
1108
 * NOTES
1109 1110 1111 1112
 *     exported by ordinal
 *
 * SEE ALSO
 *     CoFreeUnusedLibraries, SHLoadOLE
Alexandre Julliard's avatar
Alexandre Julliard committed
1113
 */
1114 1115 1116
void WINAPI SHFreeUnusedLibraries (void)
{
	FIXME("stub\n");
1117
	CoFreeUnusedLibraries();
Alexandre Julliard's avatar
Alexandre Julliard committed
1118
}
1119 1120 1121 1122
/*************************************************************************
 * DAD_AutoScroll				[SHELL32.129]
 *
 */
1123
BOOL WINAPI DAD_AutoScroll(HWND hwnd, AUTO_SCROLL_DATA *samples, LPPOINT pt)
1124
{
1125
    FIXME("hwnd = %p %p %p\n",hwnd,samples,pt);
1126 1127 1128 1129 1130 1131 1132 1133
    return 0;
}
/*************************************************************************
 * DAD_DragEnter				[SHELL32.130]
 *
 */
BOOL WINAPI DAD_DragEnter(HWND hwnd)
{
1134
    FIXME("hwnd = %p\n",hwnd);
1135 1136 1137 1138 1139 1140 1141 1142
    return FALSE;
}
/*************************************************************************
 * DAD_DragEnterEx				[SHELL32.131]
 *
 */
BOOL WINAPI DAD_DragEnterEx(HWND hwnd, POINT p)
{
1143
    FIXME("hwnd = %p (%d,%d)\n",hwnd,p.x,p.y);
1144 1145 1146 1147 1148 1149 1150 1151
    return FALSE;
}
/*************************************************************************
 * DAD_DragMove				[SHELL32.134]
 *
 */
BOOL WINAPI DAD_DragMove(POINT p)
{
1152
    FIXME("(%d,%d)\n",p.x,p.y);
1153 1154 1155
    return FALSE;
}
/*************************************************************************
1156
 * DAD_DragLeave				[SHELL32.132]
1157 1158 1159 1160 1161 1162 1163
 *
 */
BOOL WINAPI DAD_DragLeave(VOID)
{
    FIXME("\n");
    return FALSE;
}
1164 1165 1166 1167 1168 1169
/*************************************************************************
 * DAD_SetDragImage				[SHELL32.136]
 *
 * NOTES
 *  exported by name
 */
1170 1171 1172 1173 1174
BOOL WINAPI DAD_SetDragImage(
	HIMAGELIST himlTrack,
	LPPOINT lppt)
{
	FIXME("%p %p stub\n",himlTrack, lppt);
1175 1176
  return 0;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1177
/*************************************************************************
1178
 * DAD_ShowDragImage				[SHELL32.137]
Alexandre Julliard's avatar
Alexandre Julliard committed
1179 1180 1181 1182
 *
 * NOTES
 *  exported by name
 */
1183 1184 1185 1186
BOOL WINAPI DAD_ShowDragImage(BOOL bShow)
{
	FIXME("0x%08x stub\n",bShow);
	return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1187
}
1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199

static const WCHAR szwCabLocation[] = {
  'S','o','f','t','w','a','r','e','\\',
  'M','i','c','r','o','s','o','f','t','\\',
  'W','i','n','d','o','w','s','\\',
  'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
  'E','x','p','l','o','r','e','r','\\',
  'C','a','b','i','n','e','t','S','t','a','t','e',0
};

static const WCHAR szwSettings[] = { 'S','e','t','t','i','n','g','s',0 };

1200
/*************************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
1201
 * ReadCabinetState				[SHELL32.651] NT 4.0
1202 1203
 *
 */
1204 1205 1206 1207 1208
BOOL WINAPI ReadCabinetState(CABINETSTATE *cs, int length)
{
	HKEY hkey = 0;
	DWORD type, r;

1209
	TRACE("%p %d\n", cs, length);
1210

1211
	if( (cs == NULL) || (length < (int)sizeof(*cs))  )
1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224
		return FALSE;

	r = RegOpenKeyW( HKEY_CURRENT_USER, szwCabLocation, &hkey );
	if( r == ERROR_SUCCESS )
	{
		type = REG_BINARY;
		r = RegQueryValueExW( hkey, szwSettings, 
			NULL, &type, (LPBYTE)cs, (LPDWORD)&length );
		RegCloseKey( hkey );
			
	}

	/* if we can't read from the registry, create default values */
1225
	if ( (r != ERROR_SUCCESS) || (cs->cLength < sizeof(*cs)) ||
1226 1227 1228
		(cs->cLength != length) )
	{
		ERR("Initializing shell cabinet settings\n");
1229 1230
		memset(cs, 0, sizeof(*cs));
		cs->cLength          = sizeof(*cs);
1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244
		cs->nVersion         = 2;
		cs->fFullPathTitle   = FALSE;
		cs->fSaveLocalView   = TRUE;
		cs->fNotShell        = FALSE;
		cs->fSimpleDefault   = TRUE;
		cs->fDontShowDescBar = FALSE;
		cs->fNewWindowMode   = FALSE;
		cs->fShowCompColor   = FALSE;
		cs->fDontPrettyNames = FALSE;
		cs->fAdminsCreateCommonGroups = TRUE;
		cs->fMenuEnumFilter  = 96;
	}
	
	return TRUE;
1245
}
1246

1247
/*************************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
1248
 * WriteCabinetState				[SHELL32.652] NT 4.0
1249 1250
 *
 */
1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271
BOOL WINAPI WriteCabinetState(CABINETSTATE *cs)
{
	DWORD r;
	HKEY hkey = 0;

	TRACE("%p\n",cs);

	if( cs == NULL )
		return FALSE;

	r = RegCreateKeyExW( HKEY_CURRENT_USER, szwCabLocation, 0,
		 NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
	if( r == ERROR_SUCCESS )
	{
		r = RegSetValueExW( hkey, szwSettings, 0, 
			REG_BINARY, (LPBYTE) cs, cs->cLength);

		RegCloseKey( hkey );
	}

	return (r==ERROR_SUCCESS);
1272
}
1273

1274
/*************************************************************************
1275
 * FileIconInit 				[SHELL32.660]
1276 1277
 *
 */
1278
BOOL WINAPI FileIconInit(BOOL bFullInit)
1279
{	FIXME("(%s)\n", bFullInit ? "true" : "false");
1280 1281
	return 0;
}
1282
/*************************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
1283
 * IsUserAdmin					[SHELL32.680] NT 4.0
1284 1285
 *
 */
1286
HRESULT WINAPI IsUserAdmin(void)
1287
{	FIXME("stub\n");
1288
	return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1289
}
1290

1291
/*************************************************************************
1292
 * SHAllocShared				[SHELL32.520]
1293
 *
1294
 * See shlwapi.SHAllocShared
1295
 */
1296 1297 1298 1299
HANDLE WINAPI SHAllocShared(LPVOID lpvData, DWORD dwSize, DWORD dwProcId)
{
    GET_FUNC(pSHAllocShared, shlwapi, (char*)7, NULL);
    return pSHAllocShared(lpvData, dwSize, dwProcId);
1300
}
1301

1302
/*************************************************************************
1303
 * SHLockShared					[SHELL32.521]
1304
 *
1305
 * See shlwapi.SHLockShared
1306
 */
1307 1308 1309 1310
LPVOID WINAPI SHLockShared(HANDLE hShared, DWORD dwProcId)
{
    GET_FUNC(pSHLockShared, shlwapi, (char*)8, NULL);
    return pSHLockShared(hShared, dwProcId);
1311
}
1312

1313
/*************************************************************************
1314
 * SHUnlockShared				[SHELL32.522]
1315
 *
1316
 * See shlwapi.SHUnlockShared
1317
 */
1318
BOOL WINAPI SHUnlockShared(LPVOID lpView)
1319
{
1320 1321
    GET_FUNC(pSHUnlockShared, shlwapi, (char*)9, FALSE);
    return pSHUnlockShared(lpView);
1322
}
1323

1324
/*************************************************************************
1325
 * SHFreeShared					[SHELL32.523]
1326
 *
1327
 * See shlwapi.SHFreeShared
1328
 */
1329
BOOL WINAPI SHFreeShared(HANDLE hShared, DWORD dwProcId)
1330
{
1331 1332
    GET_FUNC(pSHFreeShared, shlwapi, (char*)10, FALSE);
    return pSHFreeShared(hShared, dwProcId);
1333 1334 1335
}

/*************************************************************************
1336
 * SetAppStartingCursor				[SHELL32.99]
Eric Kohl's avatar
Eric Kohl committed
1337
 */
1338
HRESULT WINAPI SetAppStartingCursor(HWND u, DWORD v)
1339
{	FIXME("hwnd=%p 0x%04x stub\n",u,v );
1340 1341
	return 0;
}
1342

1343
/*************************************************************************
1344
 * SHLoadOLE					[SHELL32.151]
1345
 *
1346
 * To reduce the memory usage of Windows 95, its shell32 contained an
1347 1348 1349 1350 1351 1352
 * internal implementation of a part of COM (see e.g. SHGetMalloc, SHCoCreateInstance,
 * SHRegisterDragDrop etc.) that allowed to use in-process STA objects without
 * the need to load OLE32.DLL. If OLE32.DLL was already loaded, the SH* function
 * would just call the Co* functions.
 *
 * The SHLoadOLE was called when OLE32.DLL was being loaded to transfer all the
1353
 * information from the shell32 "mini-COM" to ole32.dll.
1354 1355 1356 1357 1358 1359 1360
 *
 * See http://blogs.msdn.com/oldnewthing/archive/2004/07/05/173226.aspx for a
 * detailed description.
 *
 * Under wine ole32.dll is always loaded as it is imported by shlwapi.dll which is
 * imported by shell32 and no "mini-COM" is used (except for the "LoadWithoutCOM"
 * hack in SHCoCreateInstance)
1361
 */
1362
HRESULT WINAPI SHLoadOLE(LPARAM lParam)
1363
{	FIXME("0x%08lx stub\n",lParam);
1364 1365 1366
	return S_OK;
}
/*************************************************************************
1367
 * DriveType					[SHELL32.64]
1368 1369
 *
 */
1370
HRESULT WINAPI DriveType(DWORD u)
1371
{	FIXME("0x%04x stub\n",u);
1372 1373
	return 0;
}
1374 1375 1376 1377 1378 1379 1380 1381
/*************************************************************************
 * InvalidateDriveType			[SHELL32.65]
 *
 */
int WINAPI InvalidateDriveType(int u)
{	FIXME("0x%08x stub\n",u);
	return 0;
}
1382
/*************************************************************************
1383
 * SHAbortInvokeCommand				[SHELL32.198]
1384 1385
 *
 */
1386
HRESULT WINAPI SHAbortInvokeCommand(void)
1387
{	FIXME("stub\n");
1388 1389 1390
	return 1;
}
/*************************************************************************
1391
 * SHOutOfMemoryMessageBox			[SHELL32.126]
1392 1393
 *
 */
1394 1395 1396 1397 1398
int WINAPI SHOutOfMemoryMessageBox(
	HWND hwndOwner,
	LPCSTR lpCaption,
	UINT uType)
{
1399
	FIXME("%p %s 0x%08x stub\n",hwndOwner, lpCaption, uType);
Eric Kohl's avatar
Eric Kohl committed
1400 1401
	return 0;
}
1402
/*************************************************************************
1403
 * SHFlushClipboard				[SHELL32.121]
1404 1405
 *
 */
1406
HRESULT WINAPI SHFlushClipboard(void)
1407
{	FIXME("stub\n");
1408 1409
	return 1;
}
1410

1411
/*************************************************************************
1412
 * SHWaitForFileToOpen				[SHELL32.97]
1413 1414
 *
 */
1415
BOOL WINAPI SHWaitForFileToOpen(
1416
	LPCITEMIDLIST pidl,
1417 1418 1419
	DWORD dwFlags,
	DWORD dwTimeout)
{
1420
	FIXME("%p 0x%08x 0x%08x stub\n", pidl, dwFlags, dwTimeout);
1421 1422
	return 0;
}
Juergen Schmied's avatar
Juergen Schmied committed
1423

1424
/************************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
1425
 *	@				[SHELL32.654]
1426
 *
1427 1428 1429 1430 1431
 * NOTES
 *  first parameter seems to be a pointer (same as passed to WriteCabinetState)
 *  second one could be a size (0x0c). The size is the same as the structure saved to
 *  HCU\Software\Microsoft\Windows\CurrentVersion\Explorer\CabinetState
 *  I'm (js) guessing: this one is just ReadCabinetState ;-)
1432
 */
1433 1434 1435 1436
HRESULT WINAPI shell32_654 (CABINETSTATE *cs, int length)
{
	TRACE("%p %d\n",cs,length);
	return ReadCabinetState(cs,length);
Juergen Schmied's avatar
Juergen Schmied committed
1437
}
1438 1439 1440 1441 1442 1443 1444

/************************************************************************
 *	RLBuildListOfPaths			[SHELL32.146]
 *
 * NOTES
 *   builds a DPA
 */
1445
DWORD WINAPI RLBuildListOfPaths (void)
1446
{	FIXME("stub\n");
1447 1448
	return 0;
}
1449 1450 1451 1452
/************************************************************************
 *	SHValidateUNC				[SHELL32.173]
 *
 */
1453
HRESULT WINAPI SHValidateUNC (DWORD x, DWORD y, DWORD z)
1454
{
1455
	FIXME("0x%08x 0x%08x 0x%08x stub\n",x,y,z);
1456 1457 1458 1459
	return 0;
}

/************************************************************************
1460
 *	DoEnvironmentSubstA			[SHELL32.@]
1461
 *
1462 1463 1464 1465
 * Replace %KEYWORD% in the str with the value of variable KEYWORD
 * from environment. If it is not found the %KEYWORD% is left
 * intact. If the buffer is too small, str is not modified.
 *
1466 1467
 * PARAMS
 *  pszString  [I] '\0' terminated string with %keyword%.
1468
 *             [O] '\0' terminated string with %keyword% substituted.
1469
 *  cchString  [I] size of str.
1470
 *
1471
 * RETURNS
1472 1473
 *     cchString length in the HIWORD;
 *     TRUE in LOWORD if subst was successful and FALSE in other case
1474
 */
1475
DWORD WINAPI DoEnvironmentSubstA(LPSTR pszString, UINT cchString)
1476
{
1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492
    LPSTR dst;
    BOOL res = FALSE;
    FIXME("(%s, %d) stub\n", debugstr_a(pszString), cchString);
    if (pszString == NULL) /* Really return 0? */
        return 0;
    if ((dst = HeapAlloc(GetProcessHeap(), 0, cchString * sizeof(CHAR))))
    {
        DWORD num = ExpandEnvironmentStringsA(pszString, dst, cchString);
        if (num && num < cchString) /* dest buffer is too small */
        {
            res = TRUE;
            memcpy(pszString, dst, num);
        }
        HeapFree(GetProcessHeap(), 0, dst);
    }
    return MAKELONG(res,cchString); /* Always cchString? */
1493
}
1494

1495
/************************************************************************
1496
 *	DoEnvironmentSubstW			[SHELL32.@]
1497
 *
1498
 * See DoEnvironmentSubstA.  
1499
 */
1500
DWORD WINAPI DoEnvironmentSubstW(LPWSTR pszString, UINT cchString)
1501
{
1502 1503
	FIXME("(%s, %d): stub\n", debugstr_w(pszString), cchString);
	return MAKELONG(FALSE,cchString);
1504 1505
}

1506 1507 1508
/************************************************************************
 *	DoEnvironmentSubst			[SHELL32.53]
 *
1509
 * See DoEnvironmentSubstA.  
1510
 */
1511
DWORD WINAPI DoEnvironmentSubstAW(LPVOID x, UINT y)
1512
{
1513 1514 1515
    if (SHELL_OsIsUnicode())
        return DoEnvironmentSubstW(x, y);
    return DoEnvironmentSubstA(x, y);
1516
}
1517

1518
/*************************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
1519
 *      @                             [SHELL32.243]
1520
 *
1521 1522 1523 1524 1525
 * Win98+ by-ordinal routine.  In Win98 this routine returns zero and
 * does nothing else.  Possibly this does something in NT or SHELL32 5.0?
 *
 */

1526 1527 1528
BOOL WINAPI shell32_243(DWORD a, DWORD b)
{
  return FALSE;
1529
}
1530

1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541
/*************************************************************************
 *      GUIDFromStringW   [SHELL32.704]
 */
BOOL WINAPI GUIDFromStringW(LPCWSTR str, LPGUID guid)
{
    UNICODE_STRING guid_str;

    RtlInitUnicodeString(&guid_str, str);
    return !RtlGUIDFromString(&guid_str, guid);
}

1542
/*************************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
1543
 *      @	[SHELL32.714]
1544 1545 1546 1547 1548 1549
 */
DWORD WINAPI SHELL32_714(LPVOID x)
{
 	FIXME("(%s)stub\n", debugstr_w(x));
	return 0;
}
1550

1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584
typedef struct _PSXA
{
    UINT uiCount;
    UINT uiAllocated;
    IShellPropSheetExt *pspsx[1];
} PSXA, *PPSXA;

typedef struct _PSXA_CALL
{
    LPFNADDPROPSHEETPAGE lpfnAddReplaceWith;
    LPARAM lParam;
    BOOL bCalled;
    BOOL bMultiple;
    UINT uiCount;
} PSXA_CALL, *PPSXA_CALL;

static BOOL CALLBACK PsxaCall(HPROPSHEETPAGE hpage, LPARAM lParam)
{
    PPSXA_CALL Call = (PPSXA_CALL)lParam;

    if (Call != NULL)
    {
        if ((Call->bMultiple || !Call->bCalled) &&
            Call->lpfnAddReplaceWith(hpage, Call->lParam))
        {
            Call->bCalled = TRUE;
            Call->uiCount++;
            return TRUE;
        }
    }

    return FALSE;
}

1585
/*************************************************************************
1586
 *      SHAddFromPropSheetExtArray	[SHELL32.167]
1587
 */
1588
UINT WINAPI SHAddFromPropSheetExtArray(HPSXA hpsxa, LPFNADDPROPSHEETPAGE lpfnAddPage, LPARAM lParam)
1589
{
1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612
    PSXA_CALL Call;
    UINT i;
    PPSXA psxa = (PPSXA)hpsxa;

    TRACE("(%p,%p,%08lx)\n", hpsxa, lpfnAddPage, lParam);

    if (psxa)
    {
        ZeroMemory(&Call, sizeof(Call));
        Call.lpfnAddReplaceWith = lpfnAddPage;
        Call.lParam = lParam;
        Call.bMultiple = TRUE;

        /* Call the AddPage method of all registered IShellPropSheetExt interfaces */
        for (i = 0; i != psxa->uiCount; i++)
        {
            psxa->pspsx[i]->lpVtbl->AddPages(psxa->pspsx[i], PsxaCall, (LPARAM)&Call);
        }

        return Call.uiCount;
    }

    return 0;
1613 1614 1615
}

/*************************************************************************
1616
 *      SHCreatePropSheetExtArray	[SHELL32.168]
1617
 */
1618
HPSXA WINAPI SHCreatePropSheetExtArray(HKEY hKey, LPCWSTR pszSubKey, UINT max_iface)
1619 1620 1621 1622 1623 1624 1625
{
    return SHCreatePropSheetExtArrayEx(hKey, pszSubKey, max_iface, NULL);
}

/*************************************************************************
 *      SHCreatePropSheetExtArrayEx	[SHELL32.194]
 */
1626
HPSXA WINAPI SHCreatePropSheetExtArrayEx(HKEY hKey, LPCWSTR pszSubKey, UINT max_iface, LPDATAOBJECT pDataObj)
1627
{
1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655
    static const WCHAR szPropSheetSubKey[] = {'s','h','e','l','l','e','x','\\','P','r','o','p','e','r','t','y','S','h','e','e','t','H','a','n','d','l','e','r','s',0};
    WCHAR szHandler[64];
    DWORD dwHandlerLen;
    WCHAR szClsidHandler[39];
    DWORD dwClsidSize;
    CLSID clsid;
    LONG lRet;
    DWORD dwIndex;
    IShellExtInit *psxi;
    IShellPropSheetExt *pspsx;
    HKEY hkBase, hkPropSheetHandlers;
    PPSXA psxa = NULL;

    TRACE("(%p,%s,%u)\n", hKey, debugstr_w(pszSubKey), max_iface);

    if (max_iface == 0)
        return NULL;

    /* Open the registry key */
    lRet = RegOpenKeyW(hKey, pszSubKey, &hkBase);
    if (lRet != ERROR_SUCCESS)
        return NULL;

    lRet = RegOpenKeyExW(hkBase, szPropSheetSubKey, 0, KEY_ENUMERATE_SUB_KEYS, &hkPropSheetHandlers);
    RegCloseKey(hkBase);
    if (lRet == ERROR_SUCCESS)
    {
        /* Create and initialize the Property Sheet Extensions Array */
1656
        psxa = LocalAlloc(LMEM_FIXED, FIELD_OFFSET(PSXA, pspsx[max_iface]));
1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691
        if (psxa)
        {
            ZeroMemory(psxa, FIELD_OFFSET(PSXA, pspsx[max_iface]));
            psxa->uiAllocated = max_iface;

            /* Enumerate all subkeys and attempt to load the shell extensions */
            dwIndex = 0;
            do
            {
                dwHandlerLen = sizeof(szHandler) / sizeof(szHandler[0]);
                lRet = RegEnumKeyExW(hkPropSheetHandlers, dwIndex++, szHandler, &dwHandlerLen, NULL, NULL, NULL, NULL);
                if (lRet != ERROR_SUCCESS)
                {
                    if (lRet == ERROR_MORE_DATA)
                        continue;

                    if (lRet == ERROR_NO_MORE_ITEMS)
                        lRet = ERROR_SUCCESS;
                    break;
                }

                dwClsidSize = sizeof(szClsidHandler);
                if (SHGetValueW(hkPropSheetHandlers, szHandler, NULL, NULL, szClsidHandler, &dwClsidSize) == ERROR_SUCCESS)
                {
                    /* Force a NULL-termination and convert the string */
                    szClsidHandler[(sizeof(szClsidHandler) / sizeof(szClsidHandler[0])) - 1] = 0;
                    if (SUCCEEDED(SHCLSIDFromStringW(szClsidHandler, &clsid)))
                    {
                        /* Attempt to get an IShellPropSheetExt and an IShellExtInit instance.
                           Only if both interfaces are supported it's a real shell extension.
                           Then call IShellExtInit's Initialize method. */
                        if (SUCCEEDED(CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER/* | CLSCTX_NO_CODE_DOWNLOAD */, &IID_IShellPropSheetExt, (LPVOID *)&pspsx)))
                        {
                            if (SUCCEEDED(pspsx->lpVtbl->QueryInterface(pspsx, &IID_IShellExtInit, (PVOID *)&psxi)))
                            {
1692
                                if (SUCCEEDED(psxi->lpVtbl->Initialize(psxi, NULL, pDataObj, hKey)))
1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723
                                {
                                    /* Add the IShellPropSheetExt instance to the array */
                                    psxa->pspsx[psxa->uiCount++] = pspsx;
                                }
                                else
                                {
                                    psxi->lpVtbl->Release(psxi);
                                    pspsx->lpVtbl->Release(pspsx);
                                }
                            }
                            else
                                pspsx->lpVtbl->Release(pspsx);
                        }
                    }
                }

            } while (psxa->uiCount != psxa->uiAllocated);
        }
        else
            lRet = ERROR_NOT_ENOUGH_MEMORY;

        RegCloseKey(hkPropSheetHandlers);
    }

    if (lRet != ERROR_SUCCESS && psxa)
    {
        SHDestroyPropSheetExtArray((HPSXA)psxa);
        psxa = NULL;
    }

    return (HPSXA)psxa;
1724 1725 1726
}

/*************************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
1727
 *      SHReplaceFromPropSheetExtArray	[SHELL32.170]
1728
 */
1729
UINT WINAPI SHReplaceFromPropSheetExtArray(HPSXA hpsxa, UINT uPageID, LPFNADDPROPSHEETPAGE lpfnReplaceWith, LPARAM lParam)
1730
{
1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754
    PSXA_CALL Call;
    UINT i;
    PPSXA psxa = (PPSXA)hpsxa;

    TRACE("(%p,%u,%p,%08lx)\n", hpsxa, uPageID, lpfnReplaceWith, lParam);

    if (psxa)
    {
        ZeroMemory(&Call, sizeof(Call));
        Call.lpfnAddReplaceWith = lpfnReplaceWith;
        Call.lParam = lParam;

        /* Call the ReplacePage method of all registered IShellPropSheetExt interfaces.
           Each shell extension is only allowed to call the callback once during the callback. */
        for (i = 0; i != psxa->uiCount; i++)
        {
            Call.bCalled = FALSE;
            psxa->pspsx[i]->lpVtbl->ReplacePage(psxa->pspsx[i], uPageID, PsxaCall, (LPARAM)&Call);
        }

        return Call.uiCount;
    }

    return 0;
1755 1756 1757
}

/*************************************************************************
1758
 *      SHDestroyPropSheetExtArray	[SHELL32.169]
1759
 */
1760
void WINAPI SHDestroyPropSheetExtArray(HPSXA hpsxa)
1761
{
1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773
    UINT i;
    PPSXA psxa = (PPSXA)hpsxa;

    TRACE("(%p)\n", hpsxa);

    if (psxa)
    {
        for (i = 0; i != psxa->uiCount; i++)
        {
            psxa->pspsx[i]->lpVtbl->Release(psxa->pspsx[i]);
        }

1774
        LocalFree(psxa);
1775
    }
1776
}
1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788

/*************************************************************************
 *      CIDLData_CreateFromIDArray	[SHELL32.83]
 *
 *  Create IDataObject from PIDLs??
 */
HRESULT WINAPI CIDLData_CreateFromIDArray(
	LPCITEMIDLIST pidlFolder,
	DWORD cpidlFiles,
	LPCITEMIDLIST *lppidlFiles,
	LPDATAOBJECT *ppdataObject)
{
1789
    UINT i;
1790
    HWND hwnd = 0;   /*FIXME: who should be hwnd of owner? set to desktop */
1791

1792
    TRACE("(%p, %d, %p, %p)\n", pidlFolder, cpidlFiles, lppidlFiles, ppdataObject);
1793 1794
    if (TRACE_ON(pidl))
    {
1795
	pdump (pidlFolder);
1796
	for (i=0; i<cpidlFiles; i++) pdump (lppidlFiles[i]);
1797 1798 1799 1800 1801 1802
    }
    *ppdataObject = IDataObject_Constructor( hwnd, pidlFolder,
					     lppidlFiles, cpidlFiles);
    if (*ppdataObject) return S_OK;
    return E_OUTOFMEMORY;
}
1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816

/*************************************************************************
 * SHCreateStdEnumFmtEtc			[SHELL32.74]
 *
 * NOTES
 *
 */
HRESULT WINAPI SHCreateStdEnumFmtEtc(
	DWORD cFormats,
	const FORMATETC *lpFormats,
	LPENUMFORMATETC *ppenumFormatetc)
{
	IEnumFORMATETC *pef;
	HRESULT hRes;
1817
	TRACE("cf=%d fe=%p pef=%p\n", cFormats, lpFormats, ppenumFormatetc);
1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828

	pef = IEnumFORMATETC_Constructor(cFormats, lpFormats);
	if (!pef)
	  return E_OUTOFMEMORY;

	IEnumFORMATETC_AddRef(pef);
	hRes = IEnumFORMATETC_QueryInterface(pef, &IID_IEnumFORMATETC, (LPVOID*)ppenumFormatetc);
	IEnumFORMATETC_Release(pef);

	return hRes;
}
1829 1830 1831


/*************************************************************************
1832
 *		SHELL32_256 (SHELL32.256)
1833 1834 1835 1836 1837
 */
HRESULT WINAPI SHELL32_256(LPDWORD lpdw0, LPDWORD lpdw1)
{
    HRESULT ret = S_OK;

1838
    FIXME("stub %p 0x%08x %p\n", lpdw0, lpdw0 ? *lpdw0 : 0, lpdw1);
1839 1840 1841 1842 1843

    if (!lpdw0 || *lpdw0 != 0x10)
        ret = E_INVALIDARG;
    else
    {
1844
        LPVOID lpdata = 0;/*LocalAlloc(LMEM_ZEROINIT, 0x4E4);*/
1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855

	if (!lpdata)
            ret = E_OUTOFMEMORY;
	else
	{
            /* Initialize and return unknown lpdata structure */
	}
    }

    return ret;
}
1856

1857 1858 1859
/*************************************************************************
 *		SHFindFiles (SHELL32.90)
 */
1860 1861 1862 1863 1864
BOOL WINAPI SHFindFiles( LPCITEMIDLIST pidlFolder, LPCITEMIDLIST pidlSaveFile )
{
    FIXME("%p %p\n", pidlFolder, pidlSaveFile );
    return FALSE;
}
1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876

/*************************************************************************
 *		SHUpdateImageW (SHELL32.192)
 *
 * Notifies the shell that an icon in the system image list has been changed.
 *
 * PARAMS
 *  pszHashItem [I] Path to file that contains the icon.
 *  iIndex      [I] Zero-based index of the icon in the file.
 *  uFlags      [I] Flags determining the icon attributes. See notes.
 *  iImageIndex [I] Index of the icon in the system image list.
 *
1877 1878 1879
 * RETURNS
 *  Nothing
 *
1880 1881 1882 1883 1884 1885 1886
 * NOTES
 *  uFlags can be one or more of the following flags:
 *  GIL_NOTFILENAME - pszHashItem is not a file name.
 *  GIL_SIMULATEDOC - Create a document icon using the specified icon.
 */
void WINAPI SHUpdateImageW(LPCWSTR pszHashItem, int iIndex, UINT uFlags, int iImageIndex)
{
1887 1888 1889
    FIXME("%s, %d, 0x%x, %d - stub\n", debugstr_w(pszHashItem), iIndex, uFlags, iImageIndex);
}

1890 1891 1892 1893 1894
/*************************************************************************
 *		SHUpdateImageA (SHELL32.191)
 *
 * See SHUpdateImageW.
 */
1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908
VOID WINAPI SHUpdateImageA(LPCSTR pszHashItem, INT iIndex, UINT uFlags, INT iImageIndex)
{
    FIXME("%s, %d, 0x%x, %d - stub\n", debugstr_a(pszHashItem), iIndex, uFlags, iImageIndex);
}

INT WINAPI SHHandleUpdateImage(LPCITEMIDLIST pidlExtra)
{
    FIXME("%p - stub\n", pidlExtra);

    return -1;
}

BOOL WINAPI SHObjectProperties(HWND hwnd, DWORD dwType, LPCWSTR szObject, LPCWSTR szPage)
{
1909
    FIXME("%p, 0x%08x, %s, %s - stub\n", hwnd, dwType, debugstr_w(szObject), debugstr_w(szPage));
1910 1911 1912 1913 1914 1915 1916

    return TRUE;
}

BOOL WINAPI SHGetNewLinkInfoA(LPCSTR pszLinkTo, LPCSTR pszDir, LPSTR pszName, BOOL *pfMustCopy,
                              UINT uFlags)
{
1917 1918 1919 1920
    WCHAR wszLinkTo[MAX_PATH];
    WCHAR wszDir[MAX_PATH];
    WCHAR wszName[MAX_PATH];
    BOOL res;
1921

1922 1923 1924 1925 1926 1927 1928 1929 1930
    MultiByteToWideChar(CP_ACP, 0, pszLinkTo, -1, wszLinkTo, MAX_PATH);
    MultiByteToWideChar(CP_ACP, 0, pszDir, -1, wszDir, MAX_PATH);

    res = SHGetNewLinkInfoW(wszLinkTo, wszDir, wszName, pfMustCopy, uFlags);

    if (res)
        WideCharToMultiByte(CP_ACP, 0, wszName, -1, pszName, MAX_PATH, NULL, NULL);

    return res;
1931 1932 1933 1934 1935
}

BOOL WINAPI SHGetNewLinkInfoW(LPCWSTR pszLinkTo, LPCWSTR pszDir, LPWSTR pszName, BOOL *pfMustCopy,
                              UINT uFlags)
{
1936 1937 1938 1939 1940 1941 1942
    const WCHAR *basename;
    WCHAR *dst_basename;
    int i=2;
    static const WCHAR lnkformat[] = {'%','s','.','l','n','k',0};
    static const WCHAR lnkformatnum[] = {'%','s',' ','(','%','d',')','.','l','n','k',0};

    TRACE("(%s, %s, %p, %p, 0x%08x)\n", debugstr_w(pszLinkTo), debugstr_w(pszDir),
1943 1944
          pszName, pfMustCopy, uFlags);

1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980
    *pfMustCopy = FALSE;

    if (uFlags & SHGNLI_PIDL)
    {
        FIXME("SHGNLI_PIDL flag unsupported\n");
        return FALSE;
    }

    if (uFlags)
        FIXME("ignoring flags: 0x%08x\n", uFlags);

    /* FIXME: should test if the file is a shortcut or DOS program */
    if (GetFileAttributesW(pszLinkTo) == INVALID_FILE_ATTRIBUTES)
        return FALSE;

    basename = strrchrW(pszLinkTo, '\\');
    if (basename)
        basename = basename+1;
    else
        basename = pszLinkTo;

    lstrcpynW(pszName, pszDir, MAX_PATH);
    if (!PathAddBackslashW(pszName))
        return FALSE;

    dst_basename = pszName + strlenW(pszName);

    snprintfW(dst_basename, pszName + MAX_PATH - dst_basename, lnkformat, basename);

    while (GetFileAttributesW(pszName) != INVALID_FILE_ATTRIBUTES)
    {
        snprintfW(dst_basename, pszName + MAX_PATH - dst_basename, lnkformatnum, basename, i);
        i++;
    }

    return TRUE;
1981 1982 1983 1984
}

HRESULT WINAPI SHStartNetConnectionDialog(HWND hwnd, LPCSTR pszRemoteName, DWORD dwType)
{
1985
    FIXME("%p, %s, 0x%08x - stub\n", hwnd, debugstr_a(pszRemoteName), dwType);
1986 1987 1988 1989 1990 1991

    return S_OK;
}

HRESULT WINAPI SHEmptyRecycleBinA(HWND hwnd, LPCSTR pszRootPath, DWORD dwFlags)
{
1992
    FIXME("%p, %s, 0x%08x - stub\n", hwnd, debugstr_a(pszRootPath), dwFlags);
1993 1994 1995 1996 1997 1998

    return S_OK;
}

HRESULT WINAPI SHEmptyRecycleBinW(HWND hwnd, LPCWSTR pszRootPath, DWORD dwFlags)
{
1999
    FIXME("%p, %s, 0x%08x - stub\n", hwnd, debugstr_w(pszRootPath), dwFlags);
2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028

    return S_OK;
}

DWORD WINAPI SHFormatDrive(HWND hwnd, UINT drive, UINT fmtID, UINT options)
{
    FIXME("%p, 0x%08x, 0x%08x, 0x%08x - stub\n", hwnd, drive, fmtID, options);

    return SHFMT_NOFORMAT;
}

HRESULT WINAPI SHQueryRecycleBinA(LPCSTR pszRootPath, LPSHQUERYRBINFO pSHQueryRBInfo)
{
    FIXME("%s, %p - stub\n", debugstr_a(pszRootPath), pSHQueryRBInfo);

    pSHQueryRBInfo->i64Size = 0;
    pSHQueryRBInfo->i64NumItems = 0;

    return S_OK;
}

HRESULT WINAPI SHQueryRecycleBinW(LPCWSTR pszRootPath, LPSHQUERYRBINFO pSHQueryRBInfo)
{
    FIXME("%s, %p - stub\n", debugstr_w(pszRootPath), pSHQueryRBInfo);

    pSHQueryRBInfo->i64Size = 0;
    pSHQueryRBInfo->i64NumItems = 0;

    return S_OK;
2029
}
2030 2031 2032 2033 2034 2035 2036 2037 2038 2039

/*************************************************************************
 *              SHSetLocalizedName (SHELL32.@)
 */
HRESULT WINAPI SHSetLocalizedName(LPWSTR pszPath, LPCWSTR pszResModule, int idsRes)
{
    FIXME("%p, %s, %d - stub\n", pszPath, debugstr_w(pszResModule), idsRes);

    return S_OK;
}
2040 2041 2042 2043 2044 2045 2046 2047 2048

/*************************************************************************
 *              LinkWindow_RegisterClass (SHELL32.258)
 */
BOOL WINAPI LinkWindow_RegisterClass(void)
{
    FIXME("()\n");
    return TRUE;
}
2049 2050 2051 2052 2053 2054 2055 2056 2057

/*************************************************************************
 *              LinkWindow_UnregisterClass (SHELL32.259)
 */
BOOL WINAPI LinkWindow_UnregisterClass(void)
{
    FIXME("()\n");
    return TRUE;
}
2058 2059

/*************************************************************************
2060
 *              SHFlushSFCache (SHELL32.526)
2061 2062 2063 2064 2065 2066
 *
 * Notifies the shell that a user-specified special folder location has changed.
 *
 * NOTES
 *   In Wine, the shell folder registry values are not cached, so this function
 *   has no effect.
2067
 */
2068
void WINAPI SHFlushSFCache(void)
2069 2070
{
}
2071 2072 2073 2074 2075 2076

HRESULT WINAPI SHGetImageList(int iImageList, REFIID riid, void **ppv)
{
    FIXME("STUB: %i %s\n",iImageList,debugstr_guid(riid));
    return E_NOINTERFACE;
}