shellord.c 55.4 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
Alexandre Julliard's avatar
Alexandre Julliard committed
6
 *           1998 Jrgen 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

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

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

52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
/* 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);

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

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

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

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

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

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

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

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

	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;
156 157 158
}

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

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

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

Alexandre Julliard's avatar
Alexandre Julliard committed
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
    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);
211

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

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

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

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

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

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
	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);

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

Alexandre Julliard's avatar
Alexandre Julliard committed
288
/*************************************************************************
289
 * SHShellFolderView_Message			[SHELL32.73]
Alexandre Julliard's avatar
Alexandre Julliard committed
290
 *
Jon Griffiths's avatar
Jon Griffiths committed
291 292 293 294 295 296 297 298 299
 * 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
300
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
301 302
 * NOTES
 *  Message SFVM_REARRANGE = 1
Jon Griffiths's avatar
Jon Griffiths committed
303
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
304
 *    This message gets sent when a column gets clicked to instruct the
Jon Griffiths's avatar
Jon Griffiths committed
305
 *    shell view to re-sort the item list. dwParam identifies the column
Alexandre Julliard's avatar
Alexandre Julliard committed
306 307
 *    that was clicked.
 */
308
LRESULT WINAPI SHShellFolderView_Message(
309
	HWND hwndCabinet,
310 311
	UINT uMessage,
	LPARAM lParam)
312
{
313
	FIXME("%p %08x %08lx stub\n",hwndCabinet, uMessage, lParam);
314
	return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
315 316
}

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

337
/*************************************************************************
338
 * ShellMessageBoxW				[SHELL32.182]
339
 *
Jon Griffiths's avatar
Jon Griffiths committed
340
 * See ShellMessageBoxA.
341 342 343 344 345 346
 *
 * 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.
347
 */
348 349 350 351 352 353 354 355
int WINAPIV ShellMessageBoxW(
	HINSTANCE hInstance,
	HWND hWnd,
	LPCWSTR lpText,
	LPCWSTR lpCaption,
	UINT uType,
	...)
{
356
	WCHAR	szText[100],szTitle[100];
357 358
	LPCWSTR pszText = szText, pszTitle = szTitle;
	LPWSTR  pszTemp;
359
	va_list args;
360 361
	int	ret;

362 363 364
	va_start(args, uType);
	/* wvsprintfA(buf,fmt, args); */

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

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

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

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

	va_end(args);

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

Alexandre Julliard's avatar
Alexandre Julliard committed
388
/*************************************************************************
389
 * ShellMessageBoxA				[SHELL32.183]
Jon Griffiths's avatar
Jon Griffiths committed
390 391 392 393 394 395 396 397 398 399 400 401 402 403 404
 *
 * 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
405
 */
406 407 408 409 410 411 412 413
int WINAPIV ShellMessageBoxA(
	HINSTANCE hInstance,
	HWND hWnd,
	LPCSTR lpText,
	LPCSTR lpCaption,
	UINT uType,
	...)
{
414
	char	szText[100],szTitle[100];
415 416
	LPCSTR  pszText = szText, pszTitle = szTitle;
	LPSTR   pszTemp;
417
	va_list args;
418 419
	int	ret;

420 421 422
	va_start(args, uType);
	/* wvsprintfA(buf,fmt, args); */

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

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

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

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

	va_end(args);

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

Alexandre Julliard's avatar
Alexandre Julliard committed
446
/*************************************************************************
447
 * SHRegisterDragDrop				[SHELL32.86]
Alexandre Julliard's avatar
Alexandre Julliard committed
448
 *
449
 * Probably equivalent to RegisterDragDrop but under Windows 95 it could use the
450
 * shell32 built-in "mini-COM" without the need to load ole32.dll - see SHLoadOLE
451 452 453 454
 * 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.
455
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
456
 * NOTES
Alexandre Julliard's avatar
Alexandre Julliard committed
457
 *     exported by ordinal
458 459 460
 *
 * SEE ALSO
 *     RegisterDragDrop, SHLoadOLE
Alexandre Julliard's avatar
Alexandre Julliard committed
461
 */
462 463 464
HRESULT WINAPI SHRegisterDragDrop(
	HWND hWnd,
	LPDROPTARGET pDropTarget)
465
{
466 467 468 469 470 471 472 473 474 475 476 477
        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;
        }
478
	return RegisterDragDrop(hWnd, pDropTarget);
Alexandre Julliard's avatar
Alexandre Julliard committed
479 480 481
}

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

Eric Kohl's avatar
Eric Kohl committed
503 504 505
/*************************************************************************
 * SHDoDragDrop					[SHELL32.88]
 *
506 507 508 509
 * 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
510 511
 * NOTES
 *     exported by ordinal
512 513 514
 *
 * SEE ALSO
 *     DoDragDrop, SHLoadOLE
Eric Kohl's avatar
Eric Kohl committed
515
 */
516 517 518 519 520 521
HRESULT WINAPI SHDoDragDrop(
	HWND hWnd,
	LPDATAOBJECT lpDataObject,
	LPDROPSOURCE lpDropSource,
	DWORD dwOKEffect,
	LPDWORD pdwEffect)
Alexandre Julliard's avatar
Alexandre Julliard committed
522
{
523
    FIXME("(%p %p %p 0x%08x %p):stub.\n",
524
    hWnd, lpDataObject, lpDropSource, dwOKEffect, pdwEffect);
525
	return DoDragDrop(lpDataObject, lpDropSource, dwOKEffect, pdwEffect);
Alexandre Julliard's avatar
Alexandre Julliard committed
526 527 528
}

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

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

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

558 559 560 561 562 563 564 565 566 567 568 569 570
/*************************************************************************
 * 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
 */
571
static INT SHADD_get_policy(LPCSTR policy, LPDWORD type, LPVOID buffer, LPDWORD len)
572 573 574 575
{
    HKEY Policy_basekey;
    INT ret;

576
    /* Get the key for the policies location in the registry
577 578 579 580 581 582 583 584
     */
    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)) {
585 586
	    TRACE("No Explorer Policies location exists. Policy wanted=%s\n",
		  policy);
587 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
	    *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
623
 *   buffer       [IN/OUT] 2048 byte area to construct MRU data
624 625 626 627 628
 *   len          [OUT] ptr to int to receive space used in buffer
 *
 * RETURNS
 *   position within MRU list that data was added.
 */
629
static INT SHADD_create_add_mru_data(HANDLE mruhandle, LPCSTR doc_name, LPCSTR new_lnk_name,
630 631 632 633
                                     LPSTR buffer, INT *len)
{
    LPSTR ptr;
    INT wlen;
634

635 636 637 638
    /*FIXME: Document:
     *  RecentDocs MRU data structure seems to be:
     *    +0h   document file name w/ terminating 0h
     *    +nh   short int w/ size of remaining
639
     *    +n+2h 02h 30h, or 01h 30h, or 00h 30h  -  unknown
640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662
     *    +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;

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

Alexandre Julliard's avatar
Alexandre Julliard committed
668
/*************************************************************************
669
 * SHAddToRecentDocs				[SHELL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
670
 *
671 672
 * Modify (add/clear) Shell's list of recently used documents.
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
673
 * PARAMETERS
674
 *   uFlags  [IN] SHARD_PATHA, SHARD_PATHW or SHARD_PIDL
Alexandre Julliard's avatar
Alexandre Julliard committed
675 676
 *   pv      [IN] string or pidl, NULL clears the list
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
677 678
 * NOTES
 *     exported by name
679
 *
680 681
 * FIXME
 *  convert to unicode
Alexandre Julliard's avatar
Alexandre Julliard committed
682
 */
683
void WINAPI SHAddToRecentDocs (UINT uFlags,LPCVOID pv)
684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705
{
/* 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;

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

708 709 710 711
    /*FIXME: Document:
     *  RecentDocs MRU data structure seems to be:
     *    +0h   document file name w/ terminating 0h
     *    +nh   short int w/ size of remaining
712
     *    +n+2h 02h 30h, or 01h 30h, or 00h 30h  -  unknown
713 714 715 716 717 718 719 720 721 722 723
     *    +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;
    ret=SHADD_get_policy( "NoRecentDocsHistory", &type, &data, &datalen);
    if ((ret > 0) && (ret != ERROR_FILE_NOT_FOUND)) {
	ERR("Error %d getting policy \"NoRecentDocsHistory\"\n", ret);
724
	return;
725 726
    }
    if (ret == ERROR_SUCCESS) {
727
	if (!( (type == REG_DWORD) ||
728
	       ((type == REG_BINARY) && (datalen == 4)) )) {
729
	    ERR("Error policy data for \"NoRecentDocsHistory\" not formatted correctly, type=%d, len=%d\n",
730
		type, datalen);
731
	    return;
Alexandre Julliard's avatar
Alexandre Julliard committed
732
	}
733

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

    /* 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.
     */
746 747 748 749
    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");
750
	return;
751
    }
752 753 754 755

    /* Get path to user's "Recent" directory
     */
    if(SUCCEEDED(SHGetMalloc(&ppM))) {
756
	if (SUCCEEDED(SHGetSpecialFolderLocation(hwnd, CSIDL_RECENT,
757 758 759 760
						 &pidl))) {
	    SHGetPathFromIDListA(pidl, link_dir);
	    IMalloc_Free(ppM, pidl);
	}
761 762 763 764 765
	else {
	    /* serious issues */
	    link_dir[0] = 0;
	    ERR("serious issues 1\n");
	}
766 767 768 769 770
	IMalloc_Release(ppM);
    }
    else {
	/* serious issues */
	link_dir[0] = 0;
771
	ERR("serious issues 2\n");
772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787
    }
    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);
	 * }
	 */
788
	FIXME("should delete all files in %s\\\n", link_dir);
789 790 791 792 793 794 795 796 797 798 799

	/* 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);
800
	return;
801 802 803 804 805
    }

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

    /* Get the pure document name from the input
     */
813 814 815
    switch (uFlags)
    {
    case SHARD_PIDL:
816
	SHGetPathFromIDListA((LPCITEMIDLIST) pv, doc_name);
817 818 819 820 821 822 823 824 825 826 827 828 829
        break;

    case SHARD_PATHA:
        lstrcpynA(doc_name, (LPCSTR)pv, MAX_PATH);
        break;

    case SHARD_PATHW:
        WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)pv, -1, doc_name, MAX_PATH, NULL, NULL);
        break;

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

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


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

839 840
    {  /* on input needs:
	*      doc_name    -  pure file-spec, no path
841 842 843 844 845
	*      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
846
	*                  -  path and file name of new .lnk file
847
	*/
848
	CREATEMRULISTA mymru;
849 850 851 852 853 854 855 856 857
	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;

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

874 875
	/* Now get the MRU entry that will be replaced
	 * and delete the .lnk file for it
876
	 */
877 878
	if ((bufused = EnumMRUListA(mruhandle, (pos == -1) ? 14 : pos,
                                    buffer, 2048)) != -1) {
879 880 881 882 883 884 885 886 887 888 889 890 891
	    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)) {
892
			if ((attr = GetFileAttributesA(old_lnk_name)) == INVALID_FILE_ATTRIBUTES) {
893
			    if ((err = GetLastError()) != ERROR_FILE_NOT_FOUND) {
894
				ERR("Delete for %s failed, err=%d, attr=%08x\n",
895 896 897 898 899 900 901 902
				    old_lnk_name, err, attr);
			    }
			    else {
				TRACE("old .lnk file %s did not exist\n",
				      old_lnk_name);
			    }
			}
			else {
903
			    ERR("Delete for %s failed, attr=%08x\n",
904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920
				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);
921
	while (GetFileAttributesA(new_lnk_filepath) != INVALID_FILE_ATTRIBUTES) {
922 923 924 925
	    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
926
	}
927 928 929 930 931 932 933
	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);
934
	FreeMRUList(mruhandle);
935 936 937 938 939
	TRACE("Updated MRU list, new doc is position %d\n", pos);
    }

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

940
    {  /* on input needs:
941 942
	*      doc_name    -  pure file-spec, no path
	*      new_lnk_filepath
943
	*                  -  path and file name of new .lnk file
944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961
 	*      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)) {

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

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

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

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

 fail:
    CoUninitialize();

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

Alexandre Julliard's avatar
Alexandre Julliard committed
1021
/*************************************************************************
1022
 * SHCreateShellFolderViewEx			[SHELL32.174]
Alexandre Julliard's avatar
Alexandre Julliard committed
1023
 *
1024 1025 1026 1027 1028 1029
 * 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
1030 1031
 * NOTES
 *  see IShellFolder::CreateViewObject
Alexandre Julliard's avatar
Alexandre Julliard committed
1032
 */
1033
HRESULT WINAPI SHCreateShellFolderViewEx(
1034 1035
	LPCSFV psvcbi,    /* [in] shelltemplate struct */
	IShellView **ppv) /* [out] IShellView pointer */
1036 1037 1038
{
	IShellView * psf;
	HRESULT hRes;
1039

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

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

1046 1047 1048 1049 1050 1051 1052 1053
	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
1054
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1055
/*************************************************************************
1056
 *  SHWinHelp					[SHELL32.127]
Alexandre Julliard's avatar
Alexandre Julliard committed
1057 1058 1059
 *
 */
HRESULT WINAPI SHWinHelp (DWORD v, DWORD w, DWORD x, DWORD z)
1060
{	FIXME("0x%08x 0x%08x 0x%08x 0x%08x stub\n",v,w,x,z);
Alexandre Julliard's avatar
Alexandre Julliard committed
1061 1062 1063
	return 0;
}
/*************************************************************************
Eric Kohl's avatar
Eric Kohl committed
1064
 *  SHRunControlPanel [SHELL32.161]
Alexandre Julliard's avatar
Alexandre Julliard committed
1065 1066
 *
 */
Eric Kohl's avatar
Eric Kohl committed
1067
HRESULT WINAPI SHRunControlPanel (DWORD x, DWORD z)
1068
{	FIXME("0x%08x 0x%08x stub\n",x,z);
Alexandre Julliard's avatar
Alexandre Julliard committed
1069 1070
	return 0;
}
1071

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

	*lpUnknown = SHELL32_IExplorerInterface;

	if (!SHELL32_IExplorerInterface)
	  return E_FAIL;

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

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 };

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

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

1210
	if( (cs == NULL) || (length < (int)sizeof(*cs))  )
1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223
		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 */
1224
	if ( (r != ERROR_SUCCESS) || (cs->cLength < sizeof(*cs)) ||
1225 1226 1227
		(cs->cLength != length) )
	{
		ERR("Initializing shell cabinet settings\n");
1228 1229
		memset(cs, 0, sizeof(*cs));
		cs->cLength          = sizeof(*cs);
1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243
		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;
1244
}
1245

1246
/*************************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
1247
 * WriteCabinetState				[SHELL32.652] NT 4.0
1248 1249
 *
 */
1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270
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);
1271
}
1272

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

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

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

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

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

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

1342
/*************************************************************************
1343
 * SHLoadOLE					[SHELL32.151]
1344
 *
1345
 * To reduce the memory usage of Windows 95, its shell32 contained an
1346 1347 1348 1349 1350 1351
 * 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
1352
 * information from the shell32 "mini-COM" to ole32.dll.
1353 1354 1355 1356 1357 1358 1359
 *
 * 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)
1360
 */
1361
HRESULT WINAPI SHLoadOLE(LPARAM lParam)
1362
{	FIXME("0x%08lx stub\n",lParam);
1363 1364 1365
	return S_OK;
}
/*************************************************************************
1366
 * DriveType					[SHELL32.64]
1367 1368
 *
 */
1369
HRESULT WINAPI DriveType(DWORD u)
1370
{	FIXME("0x%04x stub\n",u);
1371 1372
	return 0;
}
1373 1374 1375 1376 1377 1378 1379 1380
/*************************************************************************
 * InvalidateDriveType			[SHELL32.65]
 *
 */
int WINAPI InvalidateDriveType(int u)
{	FIXME("0x%08x stub\n",u);
	return 0;
}
1381
/*************************************************************************
1382
 * SHAbortInvokeCommand				[SHELL32.198]
1383 1384
 *
 */
1385
HRESULT WINAPI SHAbortInvokeCommand(void)
1386
{	FIXME("stub\n");
1387 1388 1389
	return 1;
}
/*************************************************************************
1390
 * SHOutOfMemoryMessageBox			[SHELL32.126]
1391 1392
 *
 */
1393 1394 1395 1396 1397
int WINAPI SHOutOfMemoryMessageBox(
	HWND hwndOwner,
	LPCSTR lpCaption,
	UINT uType)
{
1398
	FIXME("%p %s 0x%08x stub\n",hwndOwner, lpCaption, uType);
Eric Kohl's avatar
Eric Kohl committed
1399 1400
	return 0;
}
1401
/*************************************************************************
1402
 * SHFlushClipboard				[SHELL32.121]
1403 1404
 *
 */
1405
HRESULT WINAPI SHFlushClipboard(void)
1406
{	FIXME("stub\n");
1407 1408
	return 1;
}
1409

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

1423
/************************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
1424
 *	@				[SHELL32.654]
1425
 *
1426 1427 1428 1429 1430
 * 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 ;-)
1431
 */
1432 1433 1434 1435
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
1436
}
1437 1438 1439 1440 1441 1442 1443

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

/************************************************************************
1459
 *	DoEnvironmentSubstA			[SHELL32.@]
1460
 *
1461 1462 1463 1464
 * 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.
 *
1465 1466
 * PARAMS
 *  pszString  [I] '\0' terminated string with %keyword%.
1467
 *             [O] '\0' terminated string with %keyword% substituted.
1468
 *  cchString  [I] size of str.
1469
 *
1470
 * RETURNS
1471 1472
 *     cchString length in the HIWORD;
 *     TRUE in LOWORD if subst was successful and FALSE in other case
1473
 */
1474
DWORD WINAPI DoEnvironmentSubstA(LPSTR pszString, UINT cchString)
1475
{
1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491
    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? */
1492
}
1493

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

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

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

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

1530
/*************************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
1531
 *      @	[SHELL32.714]
1532 1533 1534 1535 1536 1537
 */
DWORD WINAPI SHELL32_714(LPVOID x)
{
 	FIXME("(%s)stub\n", debugstr_w(x));
	return 0;
}
1538

1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572
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;
}

1573
/*************************************************************************
1574
 *      SHAddFromPropSheetExtArray	[SHELL32.167]
1575
 */
1576
UINT WINAPI SHAddFromPropSheetExtArray(HPSXA hpsxa, LPFNADDPROPSHEETPAGE lpfnAddPage, LPARAM lParam)
1577
{
1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600
    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;
1601 1602 1603
}

/*************************************************************************
1604
 *      SHCreatePropSheetExtArray	[SHELL32.168]
1605
 */
1606
HPSXA WINAPI SHCreatePropSheetExtArray(HKEY hKey, LPCWSTR pszSubKey, UINT max_iface)
1607 1608 1609 1610 1611 1612 1613
{
    return SHCreatePropSheetExtArrayEx(hKey, pszSubKey, max_iface, NULL);
}

/*************************************************************************
 *      SHCreatePropSheetExtArrayEx	[SHELL32.194]
 */
1614
HPSXA WINAPI SHCreatePropSheetExtArrayEx(HKEY hKey, LPCWSTR pszSubKey, UINT max_iface, LPDATAOBJECT pDataObj)
1615
{
1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 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 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679
    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 */
        psxa = (PPSXA)LocalAlloc(LMEM_FIXED, FIELD_OFFSET(PSXA, pspsx[max_iface]));
        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)))
                            {
1680
                                if (SUCCEEDED(psxi->lpVtbl->Initialize(psxi, NULL, pDataObj, hKey)))
1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711
                                {
                                    /* 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;
1712 1713 1714
}

/*************************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
1715
 *      SHReplaceFromPropSheetExtArray	[SHELL32.170]
1716
 */
1717
UINT WINAPI SHReplaceFromPropSheetExtArray(HPSXA hpsxa, UINT uPageID, LPFNADDPROPSHEETPAGE lpfnReplaceWith, LPARAM lParam)
1718
{
1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742
    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;
1743 1744 1745
}

/*************************************************************************
1746
 *      SHDestroyPropSheetExtArray	[SHELL32.169]
1747
 */
1748
void WINAPI SHDestroyPropSheetExtArray(HPSXA hpsxa)
1749
{
1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763
    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]);
        }

        LocalFree((HLOCAL)psxa);
    }
1764
}
1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776

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

1780
    TRACE("(%p, %d, %p, %p)\n", pidlFolder, cpidlFiles, lppidlFiles, ppdataObject);
1781 1782
    if (TRACE_ON(pidl))
    {
1783
	pdump (pidlFolder);
1784
	for (i=0; i<cpidlFiles; i++) pdump (lppidlFiles[i]);
1785 1786 1787 1788 1789 1790
    }
    *ppdataObject = IDataObject_Constructor( hwnd, pidlFolder,
					     lppidlFiles, cpidlFiles);
    if (*ppdataObject) return S_OK;
    return E_OUTOFMEMORY;
}
1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804

/*************************************************************************
 * SHCreateStdEnumFmtEtc			[SHELL32.74]
 *
 * NOTES
 *
 */
HRESULT WINAPI SHCreateStdEnumFmtEtc(
	DWORD cFormats,
	const FORMATETC *lpFormats,
	LPENUMFORMATETC *ppenumFormatetc)
{
	IEnumFORMATETC *pef;
	HRESULT hRes;
1805
	TRACE("cf=%d fe=%p pef=%p\n", cFormats, lpFormats, ppenumFormatetc);
1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816

	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;
}
1817 1818 1819


/*************************************************************************
1820
 *		SHELL32_256 (SHELL32.256)
1821 1822 1823 1824 1825
 */
HRESULT WINAPI SHELL32_256(LPDWORD lpdw0, LPDWORD lpdw1)
{
    HRESULT ret = S_OK;

1826
    FIXME("stub %p 0x%08x %p\n", lpdw0, lpdw0 ? *lpdw0 : 0, lpdw1);
1827 1828 1829 1830 1831

    if (!lpdw0 || *lpdw0 != 0x10)
        ret = E_INVALIDARG;
    else
    {
1832
        LPVOID lpdata = 0;/*LocalAlloc(LMEM_ZEROINIT, 0x4E4);*/
1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843

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

    return ret;
}
1844

1845 1846 1847
/*************************************************************************
 *		SHFindFiles (SHELL32.90)
 */
1848 1849 1850 1851 1852
BOOL WINAPI SHFindFiles( LPCITEMIDLIST pidlFolder, LPCITEMIDLIST pidlSaveFile )
{
    FIXME("%p %p\n", pidlFolder, pidlSaveFile );
    return FALSE;
}
1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864

/*************************************************************************
 *		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.
 *
1865 1866 1867
 * RETURNS
 *  Nothing
 *
1868 1869 1870 1871 1872 1873 1874
 * 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)
{
1875 1876 1877
    FIXME("%s, %d, 0x%x, %d - stub\n", debugstr_w(pszHashItem), iIndex, uFlags, iImageIndex);
}

1878 1879 1880 1881 1882
/*************************************************************************
 *		SHUpdateImageA (SHELL32.191)
 *
 * See SHUpdateImageW.
 */
1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896
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)
{
1897
    FIXME("%p, 0x%08x, %s, %s - stub\n", hwnd, dwType, debugstr_w(szObject), debugstr_w(szPage));
1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921

    return TRUE;
}

BOOL WINAPI SHGetNewLinkInfoA(LPCSTR pszLinkTo, LPCSTR pszDir, LPSTR pszName, BOOL *pfMustCopy,
                              UINT uFlags)
{
    FIXME("%s, %s, %p, %p, 0x%08x - stub\n", debugstr_a(pszLinkTo), debugstr_a(pszDir),
          pszName, pfMustCopy, uFlags);

    return FALSE;
}

BOOL WINAPI SHGetNewLinkInfoW(LPCWSTR pszLinkTo, LPCWSTR pszDir, LPWSTR pszName, BOOL *pfMustCopy,
                              UINT uFlags)
{
    FIXME("%s, %s, %p, %p, 0x%08x - stub\n", debugstr_w(pszLinkTo), debugstr_w(pszDir),
          pszName, pfMustCopy, uFlags);

    return FALSE;
}

HRESULT WINAPI SHStartNetConnectionDialog(HWND hwnd, LPCSTR pszRemoteName, DWORD dwType)
{
1922
    FIXME("%p, %s, 0x%08x - stub\n", hwnd, debugstr_a(pszRemoteName), dwType);
1923 1924 1925 1926 1927 1928

    return S_OK;
}

HRESULT WINAPI SHEmptyRecycleBinA(HWND hwnd, LPCSTR pszRootPath, DWORD dwFlags)
{
1929
    FIXME("%p, %s, 0x%08x - stub\n", hwnd, debugstr_a(pszRootPath), dwFlags);
1930 1931 1932 1933 1934 1935

    return S_OK;
}

HRESULT WINAPI SHEmptyRecycleBinW(HWND hwnd, LPCWSTR pszRootPath, DWORD dwFlags)
{
1936
    FIXME("%p, %s, 0x%08x - stub\n", hwnd, debugstr_w(pszRootPath), dwFlags);
1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965

    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;
1966
}
1967 1968 1969 1970 1971 1972 1973 1974 1975 1976

/*************************************************************************
 *              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;
}
1977 1978 1979 1980 1981 1982 1983 1984 1985

/*************************************************************************
 *              LinkWindow_RegisterClass (SHELL32.258)
 */
BOOL WINAPI LinkWindow_RegisterClass(void)
{
    FIXME("()\n");
    return TRUE;
}
1986 1987 1988 1989 1990 1991 1992 1993 1994

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