shellord.c 62.3 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"
49
#include "commoncontrols.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
50

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

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

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

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

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

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

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

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

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

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

	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;
158 159 160
}

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

/*************************************************************************
171
 * GetFileNameFromBrowseA			[internal]
Alexandre Julliard's avatar
Alexandre Julliard committed
172
 */
173
static BOOL GetFileNameFromBrowseA(
174 175 176 177 178 179 180 181
	HWND hwndOwner,
	LPSTR lpstrFile,
	DWORD nMaxFile,
	LPCSTR lpstrInitialDir,
	LPCSTR lpstrDefExt,
	LPCSTR lpstrFilter,
	LPCSTR lpstrTitle)
{
Alexandre Julliard's avatar
Alexandre Julliard committed
182
    HMODULE hmodule;
183
    BOOL (WINAPI *pGetOpenFileNameA)(LPOPENFILENAMEA);
Alexandre Julliard's avatar
Alexandre Julliard committed
184 185 186
    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
    hmodule = LoadLibraryA("comdlg32.dll");
    if(!hmodule) return FALSE;
193
    pGetOpenFileNameA = (void *)GetProcAddress(hmodule, "GetOpenFileNameA");
Alexandre Julliard's avatar
Alexandre Julliard committed
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
    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
/*************************************************************************
 * GetFileNameFromBrowseW			[internal]
 */
220
static BOOL GetFileNameFromBrowseW(
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 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
	HWND hwndOwner,
	LPWSTR lpstrFile,
	DWORD nMaxFile,
	LPCWSTR lpstrInitialDir,
	LPCWSTR lpstrDefExt,
	LPCWSTR lpstrFilter,
	LPCWSTR lpstrTitle)
{
    HMODULE hmodule;
    BOOL (WINAPI *pGetOpenFileNameW)(LPOPENFILENAMEW);
    OPENFILENAMEW ofn;
    BOOL ret;

    TRACE("%p, %s, %d, %s, %s, %s, %s)\n",
	  hwndOwner, debugstr_w(lpstrFile), nMaxFile, debugstr_w(lpstrInitialDir), debugstr_w(lpstrDefExt),
	  debugstr_w(lpstrFilter), debugstr_w(lpstrTitle));

    hmodule = LoadLibraryA("comdlg32.dll");
    if(!hmodule) return FALSE;
    pGetOpenFileNameW = (void *)GetProcAddress(hmodule, "GetOpenFileNameW");
    if(!pGetOpenFileNameW)
    {
	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 = pGetOpenFileNameW(&ofn);

    FreeLibrary(hmodule);
    return ret;
}

/*************************************************************************
 * GetFileNameFromBrowse			[SHELL32.63]
 *
 */
BOOL WINAPI GetFileNameFromBrowseAW(
	HWND hwndOwner,
	LPVOID lpstrFile,
	DWORD nMaxFile,
	LPCVOID lpstrInitialDir,
	LPCVOID lpstrDefExt,
	LPCVOID lpstrFilter,
	LPCVOID lpstrTitle)
{
    if (SHELL_OsIsUnicode())
        return GetFileNameFromBrowseW(hwndOwner, lpstrFile, nMaxFile, lpstrInitialDir, lpstrDefExt, lpstrFilter, lpstrTitle);

    return GetFileNameFromBrowseA(hwndOwner, lpstrFile, nMaxFile, lpstrInitialDir, lpstrDefExt, lpstrFilter, lpstrTitle);
}

Alexandre Julliard's avatar
Alexandre Julliard committed
283
/*************************************************************************
284 285
 * SHGetSetSettings				[SHELL32.68]
 */
286
VOID WINAPI SHGetSetSettings(LPSHELLSTATE lpss, DWORD dwMask, BOOL bSet)
287
{
288 289
  if(bSet)
  {
290
    FIXME("%p 0x%08x TRUE\n", lpss, dwMask);
291 292 293 294 295
  }
  else
  {
    SHGetSettings((LPSHELLFLAGSTATE)lpss,dwMask);
  }
296 297 298 299
}

/*************************************************************************
 * SHGetSettings				[SHELL32.@]
300
 *
301 302 303
 * NOTES
 *  the registry path are for win98 (tested)
 *  and possibly are the same in nt40
304
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
305
 */
306
VOID WINAPI SHGetSettings(LPSHELLFLAGSTATE lpsfs, DWORD dwMask)
307 308 309 310 311
{
	HKEY	hKey;
	DWORD	dwData;
	DWORD	dwDataSize = sizeof (DWORD);

312
	TRACE("(%p 0x%08x)\n",lpsfs,dwMask);
313

314
	if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced",
315 316
				 0, 0, 0, KEY_ALL_ACCESS, 0, &hKey, 0))
	  return;
317

318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
	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);

352
	TRACE("-- 0x%04x\n", *(WORD*)lpsfs);
Alexandre Julliard's avatar
Alexandre Julliard committed
353 354
}

Alexandre Julliard's avatar
Alexandre Julliard committed
355
/*************************************************************************
356
 * SHShellFolderView_Message			[SHELL32.73]
Alexandre Julliard's avatar
Alexandre Julliard committed
357
 *
Jon Griffiths's avatar
Jon Griffiths committed
358 359 360 361 362 363 364 365 366
 * 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
367
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
368 369
 * NOTES
 *  Message SFVM_REARRANGE = 1
Jon Griffiths's avatar
Jon Griffiths committed
370
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
371
 *    This message gets sent when a column gets clicked to instruct the
Jon Griffiths's avatar
Jon Griffiths committed
372
 *    shell view to re-sort the item list. dwParam identifies the column
Alexandre Julliard's avatar
Alexandre Julliard committed
373 374
 *    that was clicked.
 */
375
LRESULT WINAPI SHShellFolderView_Message(
376
	HWND hwndCabinet,
377 378
	UINT uMessage,
	LPARAM lParam)
379
{
380
	FIXME("%p %08x %08lx stub\n",hwndCabinet, uMessage, lParam);
381
	return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
382 383
}

Alexandre Julliard's avatar
Alexandre Julliard committed
384
/*************************************************************************
385
 * RegisterShellHook				[SHELL32.181]
Alexandre Julliard's avatar
Alexandre Julliard committed
386
 *
Jon Griffiths's avatar
Jon Griffiths committed
387 388
 * Register a shell hook.
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
389
 * PARAMS
Jon Griffiths's avatar
Jon Griffiths committed
390 391
 *      hwnd   [I]  Window handle
 *      dwType [I]  Type of hook.
392
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
393
 * NOTES
Jon Griffiths's avatar
Jon Griffiths committed
394
 *     Exported by ordinal
Alexandre Julliard's avatar
Alexandre Julliard committed
395
 */
396 397 398 399
BOOL WINAPI RegisterShellHook(
	HWND hWnd,
	DWORD dwType)
{
400
	FIXME("(%p,0x%08x):stub.\n",hWnd, dwType);
401
	return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
402
}
Jon Griffiths's avatar
Jon Griffiths committed
403

404
/*************************************************************************
405
 * ShellMessageBoxW				[SHELL32.182]
406
 *
Jon Griffiths's avatar
Jon Griffiths committed
407
 * See ShellMessageBoxA.
408 409 410 411 412 413
 *
 * 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.
414
 */
415 416 417 418 419 420 421 422
int WINAPIV ShellMessageBoxW(
	HINSTANCE hInstance,
	HWND hWnd,
	LPCWSTR lpText,
	LPCWSTR lpCaption,
	UINT uType,
	...)
{
423
	WCHAR	szText[100],szTitle[100];
424 425
	LPCWSTR pszText = szText, pszTitle = szTitle;
	LPWSTR  pszTemp;
426
	__ms_va_list args;
427 428
	int	ret;

429
	__ms_va_start(args, uType);
430 431
	/* wvsprintfA(buf,fmt, args); */

Kevin Koltzau's avatar
Kevin Koltzau committed
432 433
	TRACE("(%p,%p,%p,%p,%08x)\n",
	    hInstance,hWnd,lpText,lpCaption,uType);
434

Kevin Koltzau's avatar
Kevin Koltzau committed
435 436
	if (IS_INTRESOURCE(lpCaption))
	  LoadStringW(hInstance, LOWORD(lpCaption), szTitle, sizeof(szTitle)/sizeof(szTitle[0]));
437
	else
438
	  pszTitle = lpCaption;
439

Kevin Koltzau's avatar
Kevin Koltzau committed
440 441
	if (IS_INTRESOURCE(lpText))
	  LoadStringW(hInstance, LOWORD(lpText), szText, sizeof(szText)/sizeof(szText[0]));
442
	else
443
	  pszText = lpText;
444

445
	FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
446
		       pszText, 0, 0, (LPWSTR)&pszTemp, 0, &args);
Patrik Stridvall's avatar
Patrik Stridvall committed
447

448
	__ms_va_end(args);
Patrik Stridvall's avatar
Patrik Stridvall committed
449

450
	ret = MessageBoxW(hWnd,pszTemp,pszTitle,uType);
451
        LocalFree(pszTemp);
452
	return ret;
453
}
Alexandre Julliard's avatar
Alexandre Julliard committed
454

Alexandre Julliard's avatar
Alexandre Julliard committed
455
/*************************************************************************
456
 * ShellMessageBoxA				[SHELL32.183]
Jon Griffiths's avatar
Jon Griffiths committed
457 458 459 460 461 462 463 464 465 466 467 468 469 470 471
 *
 * 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
472
 */
473 474 475 476 477 478 479 480
int WINAPIV ShellMessageBoxA(
	HINSTANCE hInstance,
	HWND hWnd,
	LPCSTR lpText,
	LPCSTR lpCaption,
	UINT uType,
	...)
{
481
	char	szText[100],szTitle[100];
482 483
	LPCSTR  pszText = szText, pszTitle = szTitle;
	LPSTR   pszTemp;
484
	__ms_va_list args;
485 486
	int	ret;

487
	__ms_va_start(args, uType);
488 489
	/* wvsprintfA(buf,fmt, args); */

Kevin Koltzau's avatar
Kevin Koltzau committed
490 491
	TRACE("(%p,%p,%p,%p,%08x)\n",
	    hInstance,hWnd,lpText,lpCaption,uType);
492

Kevin Koltzau's avatar
Kevin Koltzau committed
493 494
	if (IS_INTRESOURCE(lpCaption))
	  LoadStringA(hInstance, LOWORD(lpCaption), szTitle, sizeof(szTitle));
495
	else
496
	  pszTitle = lpCaption;
497

Kevin Koltzau's avatar
Kevin Koltzau committed
498 499
	if (IS_INTRESOURCE(lpText))
	  LoadStringA(hInstance, LOWORD(lpText), szText, sizeof(szText));
500
	else
501
	  pszText = lpText;
502

503
	FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
504
		       pszText, 0, 0, (LPSTR)&pszTemp, 0, &args);
Patrik Stridvall's avatar
Patrik Stridvall committed
505

506
	__ms_va_end(args);
Patrik Stridvall's avatar
Patrik Stridvall committed
507

508
	ret = MessageBoxA(hWnd,pszTemp,pszTitle,uType);
509
        LocalFree(pszTemp);
510
	return ret;
511 512
}

Alexandre Julliard's avatar
Alexandre Julliard committed
513
/*************************************************************************
514
 * SHRegisterDragDrop				[SHELL32.86]
Alexandre Julliard's avatar
Alexandre Julliard committed
515
 *
516
 * Probably equivalent to RegisterDragDrop but under Windows 95 it could use the
517
 * shell32 built-in "mini-COM" without the need to load ole32.dll - see SHLoadOLE
518 519 520 521
 * 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.
522
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
523
 * NOTES
Alexandre Julliard's avatar
Alexandre Julliard committed
524
 *     exported by ordinal
525 526 527
 *
 * SEE ALSO
 *     RegisterDragDrop, SHLoadOLE
Alexandre Julliard's avatar
Alexandre Julliard committed
528
 */
529 530 531
HRESULT WINAPI SHRegisterDragDrop(
	HWND hWnd,
	LPDROPTARGET pDropTarget)
532
{
533 534 535 536 537 538 539 540 541 542 543 544
        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;
        }
545
	return RegisterDragDrop(hWnd, pDropTarget);
Alexandre Julliard's avatar
Alexandre Julliard committed
546 547 548
}

/*************************************************************************
549
 * SHRevokeDragDrop				[SHELL32.87]
Alexandre Julliard's avatar
Alexandre Julliard committed
550
 *
551
 * Probably equivalent to RevokeDragDrop but under Windows 95 it could use the
552
 * shell32 built-in "mini-COM" without the need to load ole32.dll - see SHLoadOLE
553 554 555 556
 * for details. Function removed from Windows Vista.
 *
 * We call ole32 RevokeDragDrop which seems to work even if OleInitialize was
 * not called.
557
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
558
 * NOTES
Alexandre Julliard's avatar
Alexandre Julliard committed
559
 *     exported by ordinal
560 561 562
 *
 * SEE ALSO
 *     RevokeDragDrop, SHLoadOLE
Alexandre Julliard's avatar
Alexandre Julliard committed
563
 */
564 565
HRESULT WINAPI SHRevokeDragDrop(HWND hWnd)
{
566
    TRACE("(%p)\n", hWnd);
567
    return RevokeDragDrop(hWnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
568 569
}

Eric Kohl's avatar
Eric Kohl committed
570 571 572
/*************************************************************************
 * SHDoDragDrop					[SHELL32.88]
 *
573 574 575 576
 * 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
577 578
 * NOTES
 *     exported by ordinal
579 580 581
 *
 * SEE ALSO
 *     DoDragDrop, SHLoadOLE
Eric Kohl's avatar
Eric Kohl committed
582
 */
583 584 585 586 587 588
HRESULT WINAPI SHDoDragDrop(
	HWND hWnd,
	LPDATAOBJECT lpDataObject,
	LPDROPSOURCE lpDropSource,
	DWORD dwOKEffect,
	LPDWORD pdwEffect)
Alexandre Julliard's avatar
Alexandre Julliard committed
589
{
590
    FIXME("(%p %p %p 0x%08x %p):stub.\n",
591
    hWnd, lpDataObject, lpDropSource, dwOKEffect, pdwEffect);
592
	return DoDragDrop(lpDataObject, lpDropSource, dwOKEffect, pdwEffect);
Alexandre Julliard's avatar
Alexandre Julliard committed
593 594 595
}

/*************************************************************************
596
 * ArrangeWindows				[SHELL32.184]
597
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
598
 */
599 600 601 602 603 604
WORD WINAPI ArrangeWindows(
	HWND hwndParent,
	DWORD dwReserved,
	LPCRECT lpRect,
	WORD cKids,
	CONST HWND * lpKids)
Alexandre Julliard's avatar
Alexandre Julliard committed
605
{
606
    FIXME("(%p 0x%08x %p 0x%04x %p):stub.\n",
607
	   hwndParent, dwReserved, lpRect, cKids, lpKids);
Alexandre Julliard's avatar
Alexandre Julliard committed
608 609 610
    return 0;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
611
/*************************************************************************
612
 * SignalFileOpen				[SHELL32.103]
Alexandre Julliard's avatar
Alexandre Julliard committed
613 614 615 616 617 618 619
 *
 * NOTES
 *     exported by ordinal
 */
DWORD WINAPI
SignalFileOpen (DWORD dwParam1)
{
620
    FIXME("(0x%08x):stub.\n", dwParam1);
Alexandre Julliard's avatar
Alexandre Julliard committed
621

Alexandre Julliard's avatar
Alexandre Julliard committed
622 623 624
    return 0;
}

625 626 627 628 629 630 631 632 633 634 635 636 637
/*************************************************************************
 * 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
 */
638
static INT SHADD_get_policy(LPCSTR policy, LPDWORD type, LPVOID buffer, LPDWORD len)
639 640 641 642
{
    HKEY Policy_basekey;
    INT ret;

643
    /* Get the key for the policies location in the registry
644 645 646 647 648 649 650 651
     */
    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)) {
652 653
	    TRACE("No Explorer Policies location exists. Policy wanted=%s\n",
		  policy);
654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689
	    *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
690
 *   buffer       [IN/OUT] 2048 byte area to construct MRU data
691 692 693 694 695
 *   len          [OUT] ptr to int to receive space used in buffer
 *
 * RETURNS
 *   position within MRU list that data was added.
 */
696
static INT SHADD_create_add_mru_data(HANDLE mruhandle, LPCSTR doc_name, LPCSTR new_lnk_name,
697 698 699 700
                                     LPSTR buffer, INT *len)
{
    LPSTR ptr;
    INT wlen;
701

702 703 704 705
    /*FIXME: Document:
     *  RecentDocs MRU data structure seems to be:
     *    +0h   document file name w/ terminating 0h
     *    +nh   short int w/ size of remaining
706
     *    +n+2h 02h 30h, or 01h 30h, or 00h 30h  -  unknown
707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729
     *    +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;

730
    /* Add the new entry into the MRU list
731
     */
732
    return AddMRUData(mruhandle, buffer, *len);
733 734
}

Alexandre Julliard's avatar
Alexandre Julliard committed
735
/*************************************************************************
736
 * SHAddToRecentDocs				[SHELL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
737
 *
738 739
 * Modify (add/clear) Shell's list of recently used documents.
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
740
 * PARAMETERS
741
 *   uFlags  [IN] SHARD_PATHA, SHARD_PATHW or SHARD_PIDL
Alexandre Julliard's avatar
Alexandre Julliard committed
742 743
 *   pv      [IN] string or pidl, NULL clears the list
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
744 745
 * NOTES
 *     exported by name
746
 *
747 748
 * FIXME
 *  convert to unicode
Alexandre Julliard's avatar
Alexandre Julliard committed
749
 */
750
void WINAPI SHAddToRecentDocs (UINT uFlags,LPCVOID pv)
751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772
{
/* 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;

773 774
    TRACE("%04x %p\n", uFlags, pv);

775 776 777 778
    /*FIXME: Document:
     *  RecentDocs MRU data structure seems to be:
     *    +0h   document file name w/ terminating 0h
     *    +nh   short int w/ size of remaining
779
     *    +n+2h 02h 30h, or 01h 30h, or 00h 30h  -  unknown
780 781 782 783 784 785 786 787
     *    +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;
788
    ret=SHADD_get_policy( "NoRecentDocsHistory", &type, data, &datalen);
789 790
    if ((ret > 0) && (ret != ERROR_FILE_NOT_FOUND)) {
	ERR("Error %d getting policy \"NoRecentDocsHistory\"\n", ret);
791
	return;
792 793
    }
    if (ret == ERROR_SUCCESS) {
794
	if (!( (type == REG_DWORD) ||
795
	       ((type == REG_BINARY) && (datalen == 4)) )) {
796
	    ERR("Error policy data for \"NoRecentDocsHistory\" not formatted correctly, type=%d, len=%d\n",
797
		type, datalen);
798
	    return;
Alexandre Julliard's avatar
Alexandre Julliard committed
799
	}
800

801
	TRACE("policy value for NoRecentDocsHistory = %08x\n", data[0]);
802 803
	/* now test the actual policy value */
	if ( data[0] != 0)
804
	    return;
805 806 807 808 809 810 811 812
    }

    /* 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.
     */
813 814 815 816
    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");
817
	return;
818
    }
819 820 821 822

    /* Get path to user's "Recent" directory
     */
    if(SUCCEEDED(SHGetMalloc(&ppM))) {
823
	if (SUCCEEDED(SHGetSpecialFolderLocation(hwnd, CSIDL_RECENT,
824 825 826 827
						 &pidl))) {
	    SHGetPathFromIDListA(pidl, link_dir);
	    IMalloc_Free(ppM, pidl);
	}
828 829 830 831 832
	else {
	    /* serious issues */
	    link_dir[0] = 0;
	    ERR("serious issues 1\n");
	}
833 834 835 836 837
	IMalloc_Release(ppM);
    }
    else {
	/* serious issues */
	link_dir[0] = 0;
838
	ERR("serious issues 2\n");
839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854
    }
    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);
	 * }
	 */
855
	FIXME("should delete all files in %s\\\n", link_dir);
856 857 858 859 860 861 862 863 864 865 866

	/* 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);
867
	return;
868 869 870 871 872
    }

    /* Have data to add, the jobs to be done:
     *   1. Add document to MRU list in registry "HKCU\Software\
     *      Microsoft\Windows\CurrentVersion\Explorer\RecentDocs".
873
     *   2. Add shortcut to document in the user's Recent directory
874 875 876 877 878 879
     *      (CSIDL_RECENT).
     *   3. Add shortcut to Start menu's Documents submenu.
     */

    /* Get the pure document name from the input
     */
880 881 882
    switch (uFlags)
    {
    case SHARD_PIDL:
883
        SHGetPathFromIDListA(pv, doc_name);
884 885 886
        break;

    case SHARD_PATHA:
887
        lstrcpynA(doc_name, pv, MAX_PATH);
888 889 890
        break;

    case SHARD_PATHW:
891
        WideCharToMultiByte(CP_ACP, 0, pv, -1, doc_name, MAX_PATH, NULL, NULL);
892 893 894 895 896
        break;

    default:
        FIXME("Unsupported flags: %u\n", uFlags);
        return;
897
    }
898 899

    TRACE("full document name %s\n", debugstr_a(doc_name));
900
    PathStripPathA(doc_name);
901
    TRACE("stripped document name %s\n", debugstr_a(doc_name));
902 903 904 905


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

906 907
    {  /* on input needs:
	*      doc_name    -  pure file-spec, no path
908 909 910 911 912
	*      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
913
	*                  -  path and file name of new .lnk file
914
	*/
915
	CREATEMRULISTA mymru;
916 917 918 919 920 921 922 923 924
	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;

925
	mymru.cbSize = sizeof(CREATEMRULISTA);
926 927 928 929
	mymru.nMaxItems = 15;
	mymru.dwFlags = MRUF_BINARY_LIST | MRUF_DELAYED_SAVE;
	mymru.hKey = HCUbasekey;
	mymru.lpszSubKey = "RecentDocs";
930
	mymru.lpfnCompare = (PROC)SHADD_compare_mru;
931
	mruhandle = CreateMRUListA(&mymru);
932 933 934 935
	if (!mruhandle) {
	    /* MRU failed */
	    ERR("MRU processing failed, handle zero\n");
	    RegCloseKey(HCUbasekey);
936
	    return;
937 938
	}
	len = lstrlenA(doc_name);
939
	pos = FindMRUData(mruhandle, doc_name, len, 0);
940

941 942
	/* Now get the MRU entry that will be replaced
	 * and delete the .lnk file for it
943
	 */
944 945
	if ((bufused = EnumMRUListA(mruhandle, (pos == -1) ? 14 : pos,
                                    buffer, 2048)) != -1) {
946 947 948 949 950 951 952 953 954 955 956 957 958
	    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)) {
959
			if ((attr = GetFileAttributesA(old_lnk_name)) == INVALID_FILE_ATTRIBUTES) {
960
			    if ((err = GetLastError()) != ERROR_FILE_NOT_FOUND) {
961
				ERR("Delete for %s failed, err=%d, attr=%08x\n",
962 963 964 965 966 967 968 969
				    old_lnk_name, err, attr);
			    }
			    else {
				TRACE("old .lnk file %s did not exist\n",
				      old_lnk_name);
			    }
			}
			else {
970
			    ERR("Delete for %s failed, attr=%08x\n",
971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987
				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);
988
	while (GetFileAttributesA(new_lnk_filepath) != INVALID_FILE_ATTRIBUTES) {
989 990 991 992
	    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
993
	}
994 995 996 997 998 999 1000
	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);
1001
	FreeMRUList(mruhandle);
1002 1003 1004 1005 1006
	TRACE("Updated MRU list, new doc is position %d\n", pos);
    }

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

1007
    {  /* on input needs:
1008 1009
	*      doc_name    -  pure file-spec, no path
	*      new_lnk_filepath
1010
	*                  -  path and file name of new .lnk file
1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028
 	*      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)) {

1029
	    hres = IShellLinkA_QueryInterface(psl, &IID_IPersistFile,
1030 1031 1032
					     (LPVOID *)&pPf);
	    if(FAILED(hres)) {
		/* bombed */
1033
		ERR("failed QueryInterface for IPersistFile %08x\n", hres);
1034 1035 1036 1037
		goto fail;
	    }

	    /* Set the document path or pidl */
1038
	    if (uFlags == SHARD_PIDL) {
1039
                hres = IShellLinkA_SetIDList(psl, pv);
1040
	    } else {
1041
                hres = IShellLinkA_SetPath(psl, pv);
1042 1043 1044
	    }
	    if(FAILED(hres)) {
		/* bombed */
1045
		ERR("failed Set{IDList|Path} %08x\n", hres);
1046 1047 1048 1049 1050 1051 1052 1053
		goto fail;
	    }

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

1058
	    MultiByteToWideChar(CP_ACP, 0, new_lnk_filepath, -1,
1059 1060 1061 1062 1063
				widelink, MAX_PATH);
	    /* create the short cut */
	    hres = IPersistFile_Save(pPf, widelink, TRUE);
	    if(FAILED(hres)) {
		/* bombed */
1064
		ERR("failed IPersistFile::Save %08x\n", hres);
1065 1066 1067 1068 1069 1070 1071
		IPersistFile_Release(pPf);
		IShellLinkA_Release(psl);
		goto fail;
	    }
	    hres = IPersistFile_SaveCompleted(pPf, widelink);
	    IPersistFile_Release(pPf);
	    IShellLinkA_Release(psl);
1072
	    TRACE("shortcut %s has been created, result=%08x\n",
1073 1074 1075
		  new_lnk_filepath, hres);
	}
	else {
1076
	    ERR("CoCreateInstance failed, hres=%08x\n", hres);
1077 1078 1079 1080 1081 1082 1083 1084
	}
    }

 fail:
    CoUninitialize();

    /* all done */
    RegCloseKey(HCUbasekey);
1085
    return;
Alexandre Julliard's avatar
Alexandre Julliard committed
1086
}
1087

Alexandre Julliard's avatar
Alexandre Julliard committed
1088
/*************************************************************************
1089
 * SHCreateShellFolderViewEx			[SHELL32.174]
Alexandre Julliard's avatar
Alexandre Julliard committed
1090
 *
1091 1092 1093 1094 1095 1096
 * 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
1097 1098
 * NOTES
 *  see IShellFolder::CreateViewObject
Alexandre Julliard's avatar
Alexandre Julliard committed
1099
 */
1100
HRESULT WINAPI SHCreateShellFolderViewEx(
1101 1102
	LPCSFV psvcbi,    /* [in] shelltemplate struct */
	IShellView **ppv) /* [out] IShellView pointer */
1103 1104 1105
{
	IShellView * psf;
	HRESULT hRes;
1106

1107
	TRACE("sf=%p pidl=%p cb=%p mode=0x%08x parm=%p\n",
1108
	  psvcbi->pshf, psvcbi->pidl, psvcbi->pfnCallback,
1109
	  psvcbi->fvm, psvcbi->psvOuter);
1110

1111
	psf = IShellView_Constructor(psvcbi->pshf);
1112

1113 1114 1115 1116 1117 1118 1119 1120
	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
1121
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1122
/*************************************************************************
1123
 *  SHWinHelp					[SHELL32.127]
Alexandre Julliard's avatar
Alexandre Julliard committed
1124 1125 1126
 *
 */
HRESULT WINAPI SHWinHelp (DWORD v, DWORD w, DWORD x, DWORD z)
1127
{	FIXME("0x%08x 0x%08x 0x%08x 0x%08x stub\n",v,w,x,z);
Alexandre Julliard's avatar
Alexandre Julliard committed
1128 1129 1130
	return 0;
}
/*************************************************************************
Eric Kohl's avatar
Eric Kohl committed
1131
 *  SHRunControlPanel [SHELL32.161]
Alexandre Julliard's avatar
Alexandre Julliard committed
1132 1133
 *
 */
Eric Kohl's avatar
Eric Kohl committed
1134
HRESULT WINAPI SHRunControlPanel (DWORD x, DWORD z)
1135
{	FIXME("0x%08x 0x%08x stub\n",x,z);
Alexandre Julliard's avatar
Alexandre Julliard committed
1136 1137
	return 0;
}
1138

1139
static LPUNKNOWN SHELL32_IExplorerInterface=0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1140
/*************************************************************************
1141
 * SHSetInstanceExplorer			[SHELL32.176]
Alexandre Julliard's avatar
Alexandre Julliard committed
1142
 *
1143 1144
 * NOTES
 *  Sets the interface
Alexandre Julliard's avatar
Alexandre Julliard committed
1145
 */
Kevin Koltzau's avatar
Kevin Koltzau committed
1146
VOID WINAPI SHSetInstanceExplorer (LPUNKNOWN lpUnknown)
1147
{	TRACE("%p\n", lpUnknown);
1148
	SHELL32_IExplorerInterface = lpUnknown;
Alexandre Julliard's avatar
Alexandre Julliard committed
1149 1150
}
/*************************************************************************
1151
 * SHGetInstanceExplorer			[SHELL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
1152 1153
 *
 * NOTES
1154
 *  gets the interface pointer of the explorer and a reference
Alexandre Julliard's avatar
Alexandre Julliard committed
1155
 */
1156
HRESULT WINAPI SHGetInstanceExplorer (IUnknown **lpUnknown)
1157
{	TRACE("%p\n", lpUnknown);
1158 1159 1160 1161 1162 1163

	*lpUnknown = SHELL32_IExplorerInterface;

	if (!SHELL32_IExplorerInterface)
	  return E_FAIL;

1164
	IUnknown_AddRef(SHELL32_IExplorerInterface);
1165
	return NOERROR;
Alexandre Julliard's avatar
Alexandre Julliard committed
1166 1167
}
/*************************************************************************
1168
 * SHFreeUnusedLibraries			[SHELL32.123]
Alexandre Julliard's avatar
Alexandre Julliard committed
1169
 *
1170 1171 1172 1173
 * 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
1174
 * NOTES
1175 1176 1177 1178
 *     exported by ordinal
 *
 * SEE ALSO
 *     CoFreeUnusedLibraries, SHLoadOLE
Alexandre Julliard's avatar
Alexandre Julliard committed
1179
 */
1180 1181 1182
void WINAPI SHFreeUnusedLibraries (void)
{
	FIXME("stub\n");
1183
	CoFreeUnusedLibraries();
Alexandre Julliard's avatar
Alexandre Julliard committed
1184
}
1185 1186 1187 1188
/*************************************************************************
 * DAD_AutoScroll				[SHELL32.129]
 *
 */
1189
BOOL WINAPI DAD_AutoScroll(HWND hwnd, AUTO_SCROLL_DATA *samples, LPPOINT pt)
1190
{
1191
    FIXME("hwnd = %p %p %p\n",hwnd,samples,pt);
1192 1193 1194 1195 1196 1197 1198 1199
    return 0;
}
/*************************************************************************
 * DAD_DragEnter				[SHELL32.130]
 *
 */
BOOL WINAPI DAD_DragEnter(HWND hwnd)
{
1200
    FIXME("hwnd = %p\n",hwnd);
1201 1202 1203 1204 1205 1206 1207 1208
    return FALSE;
}
/*************************************************************************
 * DAD_DragEnterEx				[SHELL32.131]
 *
 */
BOOL WINAPI DAD_DragEnterEx(HWND hwnd, POINT p)
{
1209
    FIXME("hwnd = %p (%d,%d)\n",hwnd,p.x,p.y);
1210 1211 1212 1213 1214 1215 1216 1217
    return FALSE;
}
/*************************************************************************
 * DAD_DragMove				[SHELL32.134]
 *
 */
BOOL WINAPI DAD_DragMove(POINT p)
{
1218
    FIXME("(%d,%d)\n",p.x,p.y);
1219 1220 1221
    return FALSE;
}
/*************************************************************************
1222
 * DAD_DragLeave				[SHELL32.132]
1223 1224 1225 1226 1227 1228 1229
 *
 */
BOOL WINAPI DAD_DragLeave(VOID)
{
    FIXME("\n");
    return FALSE;
}
1230 1231 1232 1233 1234 1235
/*************************************************************************
 * DAD_SetDragImage				[SHELL32.136]
 *
 * NOTES
 *  exported by name
 */
1236 1237 1238 1239 1240
BOOL WINAPI DAD_SetDragImage(
	HIMAGELIST himlTrack,
	LPPOINT lppt)
{
	FIXME("%p %p stub\n",himlTrack, lppt);
1241 1242
  return 0;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1243
/*************************************************************************
1244
 * DAD_ShowDragImage				[SHELL32.137]
Alexandre Julliard's avatar
Alexandre Julliard committed
1245 1246 1247 1248
 *
 * NOTES
 *  exported by name
 */
1249 1250 1251 1252
BOOL WINAPI DAD_ShowDragImage(BOOL bShow)
{
	FIXME("0x%08x stub\n",bShow);
	return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1253
}
1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265

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

1266
/*************************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
1267
 * ReadCabinetState				[SHELL32.651] NT 4.0
1268 1269
 *
 */
1270 1271 1272 1273 1274
BOOL WINAPI ReadCabinetState(CABINETSTATE *cs, int length)
{
	HKEY hkey = 0;
	DWORD type, r;

1275
	TRACE("%p %d\n", cs, length);
1276

1277
	if( (cs == NULL) || (length < (int)sizeof(*cs))  )
1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290
		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 */
1291
	if ( (r != ERROR_SUCCESS) || (cs->cLength < sizeof(*cs)) ||
1292 1293 1294
		(cs->cLength != length) )
	{
		ERR("Initializing shell cabinet settings\n");
1295 1296
		memset(cs, 0, sizeof(*cs));
		cs->cLength          = sizeof(*cs);
1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310
		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;
1311
}
1312

1313
/*************************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
1314
 * WriteCabinetState				[SHELL32.652] NT 4.0
1315 1316
 *
 */
1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337
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);
1338
}
1339

1340
/*************************************************************************
1341
 * FileIconInit 				[SHELL32.660]
1342 1343
 *
 */
1344
BOOL WINAPI FileIconInit(BOOL bFullInit)
1345
{	FIXME("(%s)\n", bFullInit ? "true" : "false");
1346 1347
	return 0;
}
1348

1349
/*************************************************************************
1350 1351 1352 1353 1354 1355
 * IsUserAnAdmin    [SHELL32.680] NT 4.0
 *
 * Checks whether the current user is a member of the Administrators group.
 *
 * PARAMS
 *     None
1356
 *
1357 1358 1359
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
1360
 */
1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420
BOOL WINAPI IsUserAnAdmin(VOID)
{
    SID_IDENTIFIER_AUTHORITY Authority = {SECURITY_NT_AUTHORITY};
    HANDLE hToken;
    DWORD dwSize;
    PTOKEN_GROUPS lpGroups;
    PSID lpSid;
    DWORD i;
    BOOL bResult = FALSE;

    TRACE("\n");
    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
    {
        return FALSE;
    }

    if (!GetTokenInformation(hToken, TokenGroups, NULL, 0, &dwSize))
    {
        if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
        {
            CloseHandle(hToken);
            return FALSE;
        }
    }

    lpGroups = HeapAlloc(GetProcessHeap(), 0, dwSize);
    if (lpGroups == NULL)
    {
        CloseHandle(hToken);
        return FALSE;
    }

    if (!GetTokenInformation(hToken, TokenGroups, lpGroups, dwSize, &dwSize))
    {
        HeapFree(GetProcessHeap(), 0, lpGroups);
        CloseHandle(hToken);
        return FALSE;
    }

    CloseHandle(hToken);
    if (!AllocateAndInitializeSid(&Authority, 2, SECURITY_BUILTIN_DOMAIN_RID,
                                  DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0,
                                  &lpSid))
    {
        HeapFree(GetProcessHeap(), 0, lpGroups);
        return FALSE;
    }

    for (i = 0; i < lpGroups->GroupCount; i++)
    {
        if (EqualSid(lpSid, lpGroups->Groups[i].Sid))
        {
            bResult = TRUE;
            break;
        }
    }

    FreeSid(lpSid);
    HeapFree(GetProcessHeap(), 0, lpGroups);
    return bResult;
Alexandre Julliard's avatar
Alexandre Julliard committed
1421
}
1422

1423
/*************************************************************************
1424
 * SHAllocShared				[SHELL32.520]
1425
 *
1426
 * See shlwapi.SHAllocShared
1427
 */
1428 1429 1430 1431
HANDLE WINAPI SHAllocShared(LPVOID lpvData, DWORD dwSize, DWORD dwProcId)
{
    GET_FUNC(pSHAllocShared, shlwapi, (char*)7, NULL);
    return pSHAllocShared(lpvData, dwSize, dwProcId);
1432
}
1433

1434
/*************************************************************************
1435
 * SHLockShared					[SHELL32.521]
1436
 *
1437
 * See shlwapi.SHLockShared
1438
 */
1439 1440 1441 1442
LPVOID WINAPI SHLockShared(HANDLE hShared, DWORD dwProcId)
{
    GET_FUNC(pSHLockShared, shlwapi, (char*)8, NULL);
    return pSHLockShared(hShared, dwProcId);
1443
}
1444

1445
/*************************************************************************
1446
 * SHUnlockShared				[SHELL32.522]
1447
 *
1448
 * See shlwapi.SHUnlockShared
1449
 */
1450
BOOL WINAPI SHUnlockShared(LPVOID lpView)
1451
{
1452 1453
    GET_FUNC(pSHUnlockShared, shlwapi, (char*)9, FALSE);
    return pSHUnlockShared(lpView);
1454
}
1455

1456
/*************************************************************************
1457
 * SHFreeShared					[SHELL32.523]
1458
 *
1459
 * See shlwapi.SHFreeShared
1460
 */
1461
BOOL WINAPI SHFreeShared(HANDLE hShared, DWORD dwProcId)
1462
{
1463 1464
    GET_FUNC(pSHFreeShared, shlwapi, (char*)10, FALSE);
    return pSHFreeShared(hShared, dwProcId);
1465 1466 1467
}

/*************************************************************************
1468
 * SetAppStartingCursor				[SHELL32.99]
Eric Kohl's avatar
Eric Kohl committed
1469
 */
1470
HRESULT WINAPI SetAppStartingCursor(HWND u, DWORD v)
1471
{	FIXME("hwnd=%p 0x%04x stub\n",u,v );
1472 1473
	return 0;
}
1474

1475
/*************************************************************************
1476
 * SHLoadOLE					[SHELL32.151]
1477
 *
1478
 * To reduce the memory usage of Windows 95, its shell32 contained an
1479 1480 1481 1482 1483 1484
 * 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
1485
 * information from the shell32 "mini-COM" to ole32.dll.
1486 1487 1488 1489 1490 1491 1492
 *
 * 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)
1493
 */
1494
HRESULT WINAPI SHLoadOLE(LPARAM lParam)
1495
{	FIXME("0x%08lx stub\n",lParam);
1496 1497 1498
	return S_OK;
}
/*************************************************************************
1499
 * DriveType					[SHELL32.64]
1500 1501
 *
 */
1502
HRESULT WINAPI DriveType(DWORD u)
1503
{	FIXME("0x%04x stub\n",u);
1504 1505
	return 0;
}
1506 1507 1508 1509 1510 1511 1512 1513
/*************************************************************************
 * InvalidateDriveType			[SHELL32.65]
 *
 */
int WINAPI InvalidateDriveType(int u)
{	FIXME("0x%08x stub\n",u);
	return 0;
}
1514
/*************************************************************************
1515
 * SHAbortInvokeCommand				[SHELL32.198]
1516 1517
 *
 */
1518
HRESULT WINAPI SHAbortInvokeCommand(void)
1519
{	FIXME("stub\n");
1520 1521 1522
	return 1;
}
/*************************************************************************
1523
 * SHOutOfMemoryMessageBox			[SHELL32.126]
1524 1525
 *
 */
1526 1527 1528 1529 1530
int WINAPI SHOutOfMemoryMessageBox(
	HWND hwndOwner,
	LPCSTR lpCaption,
	UINT uType)
{
1531
	FIXME("%p %s 0x%08x stub\n",hwndOwner, lpCaption, uType);
Eric Kohl's avatar
Eric Kohl committed
1532 1533
	return 0;
}
1534
/*************************************************************************
1535
 * SHFlushClipboard				[SHELL32.121]
1536 1537
 *
 */
1538
HRESULT WINAPI SHFlushClipboard(void)
1539
{	FIXME("stub\n");
1540 1541
	return 1;
}
1542

1543
/*************************************************************************
1544
 * SHWaitForFileToOpen				[SHELL32.97]
1545 1546
 *
 */
1547
BOOL WINAPI SHWaitForFileToOpen(
1548
	LPCITEMIDLIST pidl,
1549 1550 1551
	DWORD dwFlags,
	DWORD dwTimeout)
{
1552
	FIXME("%p 0x%08x 0x%08x stub\n", pidl, dwFlags, dwTimeout);
1553 1554
	return 0;
}
Juergen Schmied's avatar
Juergen Schmied committed
1555

1556
/************************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
1557
 *	@				[SHELL32.654]
1558
 *
1559 1560 1561 1562 1563
 * 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 ;-)
1564
 */
1565 1566 1567 1568
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
1569
}
1570 1571 1572 1573 1574 1575 1576

/************************************************************************
 *	RLBuildListOfPaths			[SHELL32.146]
 *
 * NOTES
 *   builds a DPA
 */
1577
DWORD WINAPI RLBuildListOfPaths (void)
1578
{	FIXME("stub\n");
1579 1580
	return 0;
}
1581 1582 1583 1584
/************************************************************************
 *	SHValidateUNC				[SHELL32.173]
 *
 */
1585
HRESULT WINAPI SHValidateUNC (DWORD x, DWORD y, DWORD z)
1586
{
1587
	FIXME("0x%08x 0x%08x 0x%08x stub\n",x,y,z);
1588 1589 1590 1591
	return 0;
}

/************************************************************************
1592
 *	DoEnvironmentSubstA			[SHELL32.@]
1593
 *
1594 1595 1596 1597
 * 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.
 *
1598 1599
 * PARAMS
 *  pszString  [I] '\0' terminated string with %keyword%.
1600
 *             [O] '\0' terminated string with %keyword% substituted.
1601
 *  cchString  [I] size of str.
1602
 *
1603
 * RETURNS
1604 1605
 *     cchString length in the HIWORD;
 *     TRUE in LOWORD if subst was successful and FALSE in other case
1606
 */
1607
DWORD WINAPI DoEnvironmentSubstA(LPSTR pszString, UINT cchString)
1608
{
1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624
    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? */
1625
}
1626

1627
/************************************************************************
1628
 *	DoEnvironmentSubstW			[SHELL32.@]
1629
 *
1630
 * See DoEnvironmentSubstA.  
1631
 */
1632
DWORD WINAPI DoEnvironmentSubstW(LPWSTR pszString, UINT cchString)
1633
{
1634 1635
	FIXME("(%s, %d): stub\n", debugstr_w(pszString), cchString);
	return MAKELONG(FALSE,cchString);
1636 1637
}

1638 1639 1640
/************************************************************************
 *	DoEnvironmentSubst			[SHELL32.53]
 *
1641
 * See DoEnvironmentSubstA.  
1642
 */
1643
DWORD WINAPI DoEnvironmentSubstAW(LPVOID x, UINT y)
1644
{
1645 1646 1647
    if (SHELL_OsIsUnicode())
        return DoEnvironmentSubstW(x, y);
    return DoEnvironmentSubstA(x, y);
1648
}
1649

1650
/*************************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
1651
 *      @                             [SHELL32.243]
1652
 *
1653 1654 1655 1656 1657
 * Win98+ by-ordinal routine.  In Win98 this routine returns zero and
 * does nothing else.  Possibly this does something in NT or SHELL32 5.0?
 *
 */

1658 1659 1660
BOOL WINAPI shell32_243(DWORD a, DWORD b)
{
  return FALSE;
1661
}
1662

1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673
/*************************************************************************
 *      GUIDFromStringW   [SHELL32.704]
 */
BOOL WINAPI GUIDFromStringW(LPCWSTR str, LPGUID guid)
{
    UNICODE_STRING guid_str;

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

1674
/*************************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
1675
 *      @	[SHELL32.714]
1676 1677 1678 1679 1680 1681
 */
DWORD WINAPI SHELL32_714(LPVOID x)
{
 	FIXME("(%s)stub\n", debugstr_w(x));
	return 0;
}
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 1712 1713 1714 1715 1716
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;
}

1717
/*************************************************************************
1718
 *      SHAddFromPropSheetExtArray	[SHELL32.167]
1719
 */
1720
UINT WINAPI SHAddFromPropSheetExtArray(HPSXA hpsxa, LPFNADDPROPSHEETPAGE lpfnAddPage, LPARAM lParam)
1721
{
1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744
    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;
1745 1746 1747
}

/*************************************************************************
1748
 *      SHCreatePropSheetExtArray	[SHELL32.168]
1749
 */
1750
HPSXA WINAPI SHCreatePropSheetExtArray(HKEY hKey, LPCWSTR pszSubKey, UINT max_iface)
1751 1752 1753 1754 1755 1756 1757
{
    return SHCreatePropSheetExtArrayEx(hKey, pszSubKey, max_iface, NULL);
}

/*************************************************************************
 *      SHCreatePropSheetExtArrayEx	[SHELL32.194]
 */
1758
HPSXA WINAPI SHCreatePropSheetExtArrayEx(HKEY hKey, LPCWSTR pszSubKey, UINT max_iface, LPDATAOBJECT pDataObj)
1759
{
1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787
    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 */
1788
        psxa = LocalAlloc(LMEM_FIXED, FIELD_OFFSET(PSXA, pspsx[max_iface]));
1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809
        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;
                }

1810
                /* The CLSID is stored either in the key itself or in its default value. */
1811
                if (FAILED(lRet = SHCLSIDFromStringW(szHandler, &clsid)))
1812
                {
1813 1814
                    dwClsidSize = sizeof(szClsidHandler);
                    if (SHGetValueW(hkPropSheetHandlers, szHandler, NULL, NULL, szClsidHandler, &dwClsidSize) == ERROR_SUCCESS)
1815
                    {
1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829
                        /* Force a NULL-termination and convert the string */
                        szClsidHandler[(sizeof(szClsidHandler) / sizeof(szClsidHandler[0])) - 1] = 0;
                        lRet = SHCLSIDFromStringW(szClsidHandler, &clsid);
                    }
                }

                if (SUCCEEDED(lRet))
                {
                    /* 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)))
1830
                        {
1831
                            if (SUCCEEDED(psxi->lpVtbl->Initialize(psxi, NULL, pDataObj, hKey)))
1832
                            {
1833 1834
                                /* Add the IShellPropSheetExt instance to the array */
                                psxa->pspsx[psxa->uiCount++] = pspsx;
1835 1836
                            }
                            else
1837 1838
                            {
                                psxi->lpVtbl->Release(psxi);
1839
                                pspsx->lpVtbl->Release(pspsx);
1840
                            }
1841
                        }
1842 1843
                        else
                            pspsx->lpVtbl->Release(pspsx);
1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861
                    }
                }

            } 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;
1862 1863 1864
}

/*************************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
1865
 *      SHReplaceFromPropSheetExtArray	[SHELL32.170]
1866
 */
1867
UINT WINAPI SHReplaceFromPropSheetExtArray(HPSXA hpsxa, UINT uPageID, LPFNADDPROPSHEETPAGE lpfnReplaceWith, LPARAM lParam)
1868
{
1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892
    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;
1893 1894 1895
}

/*************************************************************************
1896
 *      SHDestroyPropSheetExtArray	[SHELL32.169]
1897
 */
1898
void WINAPI SHDestroyPropSheetExtArray(HPSXA hpsxa)
1899
{
1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911
    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]);
        }

1912
        LocalFree(psxa);
1913
    }
1914
}
1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926

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

1930
    TRACE("(%p, %d, %p, %p)\n", pidlFolder, cpidlFiles, lppidlFiles, ppdataObject);
1931 1932
    if (TRACE_ON(pidl))
    {
1933
	pdump (pidlFolder);
1934
	for (i=0; i<cpidlFiles; i++) pdump (lppidlFiles[i]);
1935 1936 1937 1938 1939 1940
    }
    *ppdataObject = IDataObject_Constructor( hwnd, pidlFolder,
					     lppidlFiles, cpidlFiles);
    if (*ppdataObject) return S_OK;
    return E_OUTOFMEMORY;
}
1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954

/*************************************************************************
 * SHCreateStdEnumFmtEtc			[SHELL32.74]
 *
 * NOTES
 *
 */
HRESULT WINAPI SHCreateStdEnumFmtEtc(
	DWORD cFormats,
	const FORMATETC *lpFormats,
	LPENUMFORMATETC *ppenumFormatetc)
{
	IEnumFORMATETC *pef;
	HRESULT hRes;
1955
	TRACE("cf=%d fe=%p pef=%p\n", cFormats, lpFormats, ppenumFormatetc);
1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966

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

1968 1969 1970
/*************************************************************************
 *		SHFindFiles (SHELL32.90)
 */
1971 1972 1973 1974 1975
BOOL WINAPI SHFindFiles( LPCITEMIDLIST pidlFolder, LPCITEMIDLIST pidlSaveFile )
{
    FIXME("%p %p\n", pidlFolder, pidlSaveFile );
    return FALSE;
}
1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987

/*************************************************************************
 *		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.
 *
1988 1989 1990
 * RETURNS
 *  Nothing
 *
1991 1992 1993 1994 1995 1996 1997
 * 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)
{
1998 1999 2000
    FIXME("%s, %d, 0x%x, %d - stub\n", debugstr_w(pszHashItem), iIndex, uFlags, iImageIndex);
}

2001 2002 2003 2004 2005
/*************************************************************************
 *		SHUpdateImageA (SHELL32.191)
 *
 * See SHUpdateImageW.
 */
2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019
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)
{
2020
    FIXME("%p, 0x%08x, %s, %s - stub\n", hwnd, dwType, debugstr_w(szObject), debugstr_w(szPage));
2021 2022 2023 2024 2025 2026 2027

    return TRUE;
}

BOOL WINAPI SHGetNewLinkInfoA(LPCSTR pszLinkTo, LPCSTR pszDir, LPSTR pszName, BOOL *pfMustCopy,
                              UINT uFlags)
{
2028 2029 2030 2031
    WCHAR wszLinkTo[MAX_PATH];
    WCHAR wszDir[MAX_PATH];
    WCHAR wszName[MAX_PATH];
    BOOL res;
2032

2033 2034 2035 2036 2037 2038 2039 2040 2041
    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;
2042 2043 2044 2045 2046
}

BOOL WINAPI SHGetNewLinkInfoW(LPCWSTR pszLinkTo, LPCWSTR pszDir, LPWSTR pszName, BOOL *pfMustCopy,
                              UINT uFlags)
{
2047 2048 2049 2050 2051 2052 2053
    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),
2054 2055
          pszName, pfMustCopy, uFlags);

2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091
    *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;
2092 2093 2094 2095
}

HRESULT WINAPI SHStartNetConnectionDialog(HWND hwnd, LPCSTR pszRemoteName, DWORD dwType)
{
2096
    FIXME("%p, %s, 0x%08x - stub\n", hwnd, debugstr_a(pszRemoteName), dwType);
2097 2098 2099 2100 2101 2102

    return S_OK;
}

HRESULT WINAPI SHEmptyRecycleBinA(HWND hwnd, LPCSTR pszRootPath, DWORD dwFlags)
{
2103
    FIXME("%p, %s, 0x%08x - stub\n", hwnd, debugstr_a(pszRootPath), dwFlags);
2104 2105 2106 2107 2108 2109

    return S_OK;
}

HRESULT WINAPI SHEmptyRecycleBinW(HWND hwnd, LPCWSTR pszRootPath, DWORD dwFlags)
{
2110
    FIXME("%p, %s, 0x%08x - stub\n", hwnd, debugstr_w(pszRootPath), dwFlags);
2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139

    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;
2140
}
2141 2142 2143 2144 2145 2146 2147 2148 2149 2150

/*************************************************************************
 *              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;
}
2151 2152 2153 2154 2155 2156 2157 2158 2159

/*************************************************************************
 *              LinkWindow_RegisterClass (SHELL32.258)
 */
BOOL WINAPI LinkWindow_RegisterClass(void)
{
    FIXME("()\n");
    return TRUE;
}
2160 2161 2162 2163 2164 2165 2166 2167 2168

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

/*************************************************************************
2171
 *              SHFlushSFCache (SHELL32.526)
2172 2173 2174 2175 2176 2177
 *
 * 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.
2178
 */
2179
void WINAPI SHFlushSFCache(void)
2180 2181
{
}
2182

2183 2184 2185 2186 2187 2188 2189
/*************************************************************************
 *              SHGetImageList (SHELL32.727)
 *
 * Returns a copy of a shell image list.
 *
 * NOTES
 *   Windows XP features 4 sizes of image list, and Vista 5. Wine currently
2190 2191
 *   only supports the traditional small and large image lists, so requests
 *   for the others will currently fail.
2192
 */
2193 2194
HRESULT WINAPI SHGetImageList(int iImageList, REFIID riid, void **ppv)
{
2195 2196 2197 2198 2199
    HIMAGELIST hLarge, hSmall;
    HIMAGELIST hNew;
    HRESULT ret = E_FAIL;

    /* Wine currently only maintains large and small image lists */
2200
    if ((iImageList != SHIL_LARGE) && (iImageList != SHIL_SMALL) && (iImageList != SHIL_SYSSMALL))
2201 2202 2203 2204 2205
    {
        FIXME("Unsupported image list %i requested\n", iImageList);
        return E_FAIL;
    }

2206
    Shell_GetImageLists(&hLarge, &hSmall);
2207 2208 2209 2210 2211 2212
    hNew = ImageList_Duplicate(iImageList == SHIL_LARGE ? hLarge : hSmall);

    /* Get the interface for the new image list */
    if (hNew)
    {
        ret = HIMAGELIST_QueryInterface(hNew, riid, ppv);
2213
        ImageList_Destroy(hNew);
2214 2215 2216
    }

    return ret;
2217
}
2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250

/*************************************************************************
 * SHCreateShellFolderView			[SHELL32.256]
 *
 * Create a new instance of the default Shell folder view object.
 *
 * RETURNS
 *  Success: S_OK
 *  Failure: error value
 *
 * NOTES
 *  see IShellFolder::CreateViewObject
 */
HRESULT WINAPI SHCreateShellFolderView(const SFV_CREATE *pcsfv,
                        IShellView **ppsv)
{
	IShellView * psf;
	HRESULT hRes;

	TRACE("sf=%p outer=%p callback=%p\n",
	  pcsfv->pshf, pcsfv->psvOuter, pcsfv->psfvcb);

	psf = IShellView_Constructor(pcsfv->pshf);

	if (!psf)
	  return E_OUTOFMEMORY;

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

	return hRes;
}