shellord.c 58.5 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
/* 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 */
63
    int (CALLBACK *lpfnCompare)(LPCVOID, LPCVOID, DWORD); /* item compare proc */
64 65 66 67 68 69 70 71 72 73 74 75 76
} 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
	if (IS_INTRESOURCE(lpCaption))
436
	  LoadStringW(hInstance, LOWORD(lpCaption), szTitle, ARRAY_SIZE(szTitle));
437
	else
438
	  pszTitle = lpCaption;
439

Kevin Koltzau's avatar
Kevin Koltzau committed
440
	if (IS_INTRESOURCE(lpText))
441
	  LoadStringW(hInstance, LOWORD(lpText), szText, ARRAY_SIZE(szText));
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
WORD WINAPI ArrangeWindows(HWND hwndParent, DWORD dwReserved, const RECT *lpRect,
        WORD cKids, const HWND *lpKids)
Alexandre Julliard's avatar
Alexandre Julliard committed
601
{
602
    FIXME("(%p 0x%08x %p 0x%04x %p):stub.\n",
603
	   hwndParent, dwReserved, lpRect, cKids, lpKids);
Alexandre Julliard's avatar
Alexandre Julliard committed
604 605 606
    return 0;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
607
/*************************************************************************
608
 * SignalFileOpen				[SHELL32.103]
Alexandre Julliard's avatar
Alexandre Julliard committed
609 610 611 612
 *
 * NOTES
 *     exported by ordinal
 */
613 614
BOOL WINAPI
SignalFileOpen (PCIDLIST_ABSOLUTE pidl)
Alexandre Julliard's avatar
Alexandre Julliard committed
615
{
616
    FIXME("(%p):stub.\n", pidl);
Alexandre Julliard's avatar
Alexandre Julliard committed
617

618
    return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
619 620
}

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

639
    /* Get the key for the policies location in the registry
640 641 642 643 644 645 646 647
     */
    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)) {
648 649
	    TRACE("No Explorer Policies location exists. Policy wanted=%s\n",
		  policy);
650 651 652 653 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
	    *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
686
 *   buffer       [IN/OUT] 2048 byte area to construct MRU data
687 688 689 690 691
 *   len          [OUT] ptr to int to receive space used in buffer
 *
 * RETURNS
 *   position within MRU list that data was added.
 */
692
static INT SHADD_create_add_mru_data(HANDLE mruhandle, LPCSTR doc_name, LPCSTR new_lnk_name,
693 694 695 696
                                     LPSTR buffer, INT *len)
{
    LPSTR ptr;
    INT wlen;
697

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

726
    /* Add the new entry into the MRU list
727
     */
728
    return AddMRUData(mruhandle, buffer, *len);
729 730
}

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

769 770
    TRACE("%04x %p\n", uFlags, pv);

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

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

    /* 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.
     */
809 810 811 812
    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");
813
	return;
814
    }
815 816 817 818

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

	/* 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);
863
	return;
864 865 866 867 868
    }

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

    /* Get the pure document name from the input
     */
876 877 878
    switch (uFlags)
    {
    case SHARD_PIDL:
879 880 881 882 883
        if (!SHGetPathFromIDListA(pv, doc_name))
        {
            WARN("can't get path from PIDL\n");
            return;
        }
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 = 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
	    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 */
954
                if (ptr[0] && (lstrlenA(ptr) <= len-1)) {
955 956 957 958
		    /* 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
 *  SHWinHelp					[SHELL32.127]
Alexandre Julliard's avatar
Alexandre Julliard committed
1090 1091 1092
 *
 */
HRESULT WINAPI SHWinHelp (DWORD v, DWORD w, DWORD x, DWORD z)
1093
{	FIXME("0x%08x 0x%08x 0x%08x 0x%08x stub\n",v,w,x,z);
Alexandre Julliard's avatar
Alexandre Julliard committed
1094 1095 1096
	return 0;
}
/*************************************************************************
Eric Kohl's avatar
Eric Kohl committed
1097
 *  SHRunControlPanel [SHELL32.161]
Alexandre Julliard's avatar
Alexandre Julliard committed
1098 1099
 *
 */
1100 1101 1102 1103
BOOL WINAPI SHRunControlPanel (LPCWSTR commandLine, HWND parent)
{
	FIXME("(%s, %p): stub\n", debugstr_w(commandLine), parent);
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1104
}
1105

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

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

1205
/*************************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
1206
 * ReadCabinetState				[SHELL32.651] NT 4.0
1207 1208
 *
 */
1209 1210 1211 1212 1213
BOOL WINAPI ReadCabinetState(CABINETSTATE *cs, int length)
{
	HKEY hkey = 0;
	DWORD type, r;

1214
	TRACE("%p %d\n", cs, length);
1215

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

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

1279
/*************************************************************************
1280
 * FileIconInit 				[SHELL32.660]
1281 1282
 *
 */
1283
BOOL WINAPI FileIconInit(BOOL bFullInit)
1284
{	FIXME("(%s)\n", bFullInit ? "true" : "false");
1285
	return FALSE;
1286
}
1287

1288
/*************************************************************************
1289 1290 1291 1292 1293 1294
 * IsUserAnAdmin    [SHELL32.680] NT 4.0
 *
 * Checks whether the current user is a member of the Administrators group.
 *
 * PARAMS
 *     None
1295
 *
1296 1297 1298
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
1299
 */
1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324
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;
        }
    }

1325
    lpGroups = heap_alloc(dwSize);
1326 1327 1328 1329 1330 1331 1332 1333
    if (lpGroups == NULL)
    {
        CloseHandle(hToken);
        return FALSE;
    }

    if (!GetTokenInformation(hToken, TokenGroups, lpGroups, dwSize, &dwSize))
    {
1334
        heap_free(lpGroups);
1335 1336 1337 1338 1339 1340 1341 1342 1343
        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))
    {
1344
        heap_free(lpGroups);
1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357
        return FALSE;
    }

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

    FreeSid(lpSid);
1358
    heap_free(lpGroups);
1359
    return bResult;
Alexandre Julliard's avatar
Alexandre Julliard committed
1360
}
1361

1362
/*************************************************************************
1363
 * SHAllocShared				[SHELL32.520]
1364
 *
1365
 * See shlwapi.SHAllocShared
1366
 */
1367 1368 1369 1370
HANDLE WINAPI SHAllocShared(LPVOID lpvData, DWORD dwSize, DWORD dwProcId)
{
    GET_FUNC(pSHAllocShared, shlwapi, (char*)7, NULL);
    return pSHAllocShared(lpvData, dwSize, dwProcId);
1371
}
1372

1373
/*************************************************************************
1374
 * SHLockShared					[SHELL32.521]
1375
 *
1376
 * See shlwapi.SHLockShared
1377
 */
1378 1379 1380 1381
LPVOID WINAPI SHLockShared(HANDLE hShared, DWORD dwProcId)
{
    GET_FUNC(pSHLockShared, shlwapi, (char*)8, NULL);
    return pSHLockShared(hShared, dwProcId);
1382
}
1383

1384
/*************************************************************************
1385
 * SHUnlockShared				[SHELL32.522]
1386
 *
1387
 * See shlwapi.SHUnlockShared
1388
 */
1389
BOOL WINAPI SHUnlockShared(LPVOID lpView)
1390
{
1391 1392
    GET_FUNC(pSHUnlockShared, shlwapi, (char*)9, FALSE);
    return pSHUnlockShared(lpView);
1393
}
1394

1395
/*************************************************************************
1396
 * SHFreeShared					[SHELL32.523]
1397
 *
1398
 * See shlwapi.SHFreeShared
1399
 */
1400
BOOL WINAPI SHFreeShared(HANDLE hShared, DWORD dwProcId)
1401
{
1402 1403
    GET_FUNC(pSHFreeShared, shlwapi, (char*)10, FALSE);
    return pSHFreeShared(hShared, dwProcId);
1404 1405 1406
}

/*************************************************************************
1407
 * SetAppStartingCursor				[SHELL32.99]
Eric Kohl's avatar
Eric Kohl committed
1408
 */
1409
HRESULT WINAPI SetAppStartingCursor(HWND u, DWORD v)
1410
{	FIXME("hwnd=%p 0x%04x stub\n",u,v );
1411 1412
	return 0;
}
1413

1414
/*************************************************************************
1415
 * SHLoadOLE					[SHELL32.151]
1416
 *
1417
 * To reduce the memory usage of Windows 95, its shell32 contained an
1418 1419 1420 1421 1422 1423
 * 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
1424
 * information from the shell32 "mini-COM" to ole32.dll.
1425 1426 1427 1428 1429 1430 1431
 *
 * 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)
1432
 */
1433
HRESULT WINAPI SHLoadOLE(LPARAM lParam)
1434
{	FIXME("0x%08lx stub\n",lParam);
1435 1436 1437
	return S_OK;
}
/*************************************************************************
1438
 * DriveType					[SHELL32.64]
1439 1440
 *
 */
1441
int WINAPI DriveType(int u)
1442
{	FIXME("0x%04x stub\n",u);
1443 1444
	return 0;
}
1445 1446 1447 1448 1449 1450 1451 1452
/*************************************************************************
 * InvalidateDriveType			[SHELL32.65]
 *
 */
int WINAPI InvalidateDriveType(int u)
{	FIXME("0x%08x stub\n",u);
	return 0;
}
1453
/*************************************************************************
1454
 * SHAbortInvokeCommand				[SHELL32.198]
1455 1456
 *
 */
1457
HRESULT WINAPI SHAbortInvokeCommand(void)
1458
{	FIXME("stub\n");
1459 1460 1461
	return 1;
}
/*************************************************************************
1462
 * SHOutOfMemoryMessageBox			[SHELL32.126]
1463 1464
 *
 */
1465 1466 1467 1468 1469
int WINAPI SHOutOfMemoryMessageBox(
	HWND hwndOwner,
	LPCSTR lpCaption,
	UINT uType)
{
1470
	FIXME("%p %s 0x%08x stub\n",hwndOwner, lpCaption, uType);
Eric Kohl's avatar
Eric Kohl committed
1471 1472
	return 0;
}
1473
/*************************************************************************
1474
 * SHFlushClipboard				[SHELL32.121]
1475 1476
 *
 */
1477
HRESULT WINAPI SHFlushClipboard(void)
1478
{	FIXME("stub\n");
1479 1480
	return 1;
}
1481

1482
/*************************************************************************
1483
 * SHWaitForFileToOpen				[SHELL32.97]
1484 1485
 *
 */
1486
BOOL WINAPI SHWaitForFileToOpen(
1487
	LPCITEMIDLIST pidl,
1488 1489 1490
	DWORD dwFlags,
	DWORD dwTimeout)
{
1491
	FIXME("%p 0x%08x 0x%08x stub\n", pidl, dwFlags, dwTimeout);
1492
	return FALSE;
1493
}
Juergen Schmied's avatar
Juergen Schmied committed
1494

1495 1496 1497 1498 1499 1500
/************************************************************************
 *	RLBuildListOfPaths			[SHELL32.146]
 *
 * NOTES
 *   builds a DPA
 */
1501
DWORD WINAPI RLBuildListOfPaths (void)
1502
{	FIXME("stub\n");
1503 1504
	return 0;
}
1505 1506 1507 1508
/************************************************************************
 *	SHValidateUNC				[SHELL32.173]
 *
 */
1509
BOOL WINAPI SHValidateUNC (HWND hwndOwner, PWSTR pszFile, UINT fConnect)
1510
{
1511 1512
	FIXME("(%p, %s, 0x%08x): stub\n", hwndOwner, debugstr_w(pszFile), fConnect);
	return FALSE;
1513 1514 1515
}

/************************************************************************
1516
 * DoEnvironmentSubstA [SHELL32.@]
1517
 *
1518
 * See DoEnvironmentSubstW.
1519
 */
1520
DWORD WINAPI DoEnvironmentSubstA(LPSTR pszString, UINT cchString)
1521
{
1522 1523
    LPSTR dst;
    BOOL res = FALSE;
1524 1525 1526 1527
    DWORD len = cchString;

    TRACE("(%s, %d)\n", debugstr_a(pszString), cchString);

1528
    if ((dst = heap_alloc(cchString * sizeof(CHAR))))
1529
    {
1530 1531 1532
        len = ExpandEnvironmentStringsA(pszString, dst, cchString);
        /* len includes the terminating 0 */
        if (len && len < cchString)
1533 1534
        {
            res = TRUE;
1535
            memcpy(pszString, dst, len);
1536
        }
1537 1538 1539
        else
            len = cchString;

1540
        heap_free(dst);
1541
    }
1542
    return MAKELONG(len, res);
1543
}
1544

1545
/************************************************************************
1546
 * DoEnvironmentSubstW [SHELL32.@]
1547
 *
1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562
 * Replace all %KEYWORD% in the string with the value of the named
 * environment variable. If the buffer is too small, the string is not modified.
 *
 * PARAMS
 *  pszString  [I] '\0' terminated string with %keyword%.
 *             [O] '\0' terminated string with %keyword% substituted.
 *  cchString  [I] size of str.
 *
 * RETURNS
 *  Success:  The string in the buffer is updated
 *            HIWORD: TRUE
 *            LOWORD: characters used in the buffer, including space for the terminating 0
 *  Failure:  buffer too small. The string is not modified.
 *            HIWORD: FALSE
 *            LOWORD: provided size of the buffer in characters
1563
 */
1564
DWORD WINAPI DoEnvironmentSubstW(LPWSTR pszString, UINT cchString)
1565
{
1566 1567 1568 1569 1570 1571
    LPWSTR dst;
    BOOL res = FALSE;
    DWORD len = cchString;

    TRACE("(%s, %d)\n", debugstr_w(pszString), cchString);

1572
    if ((cchString < MAXLONG) && (dst = heap_alloc(cchString * sizeof(WCHAR))))
1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583
    {
        len = ExpandEnvironmentStringsW(pszString, dst, cchString);
        /* len includes the terminating 0 */
        if (len && len <= cchString)
        {
            res = TRUE;
            memcpy(pszString, dst, len * sizeof(WCHAR));
        }
        else
            len = cchString;

1584
        heap_free(dst);
1585 1586
    }
    return MAKELONG(len, res);
1587 1588
}

1589 1590 1591
/************************************************************************
 *	DoEnvironmentSubst			[SHELL32.53]
 *
1592
 * See DoEnvironmentSubstA.  
1593
 */
1594
DWORD WINAPI DoEnvironmentSubstAW(LPVOID x, UINT y)
1595
{
1596 1597 1598
    if (SHELL_OsIsUnicode())
        return DoEnvironmentSubstW(x, y);
    return DoEnvironmentSubstA(x, y);
1599
}
1600

1601
/*************************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
1602
 *      @                             [SHELL32.243]
1603
 *
1604 1605 1606 1607 1608
 * Win98+ by-ordinal routine.  In Win98 this routine returns zero and
 * does nothing else.  Possibly this does something in NT or SHELL32 5.0?
 *
 */

1609 1610 1611
BOOL WINAPI shell32_243(DWORD a, DWORD b)
{
  return FALSE;
1612
}
1613

1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624
/*************************************************************************
 *      GUIDFromStringW   [SHELL32.704]
 */
BOOL WINAPI GUIDFromStringW(LPCWSTR str, LPGUID guid)
{
    UNICODE_STRING guid_str;

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

1625
/*************************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
1626
 *      @	[SHELL32.714]
1627 1628 1629 1630 1631 1632
 */
DWORD WINAPI SHELL32_714(LPVOID x)
{
 	FIXME("(%s)stub\n", debugstr_w(x));
	return 0;
}
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
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;
}

1668
/*************************************************************************
1669
 *      SHAddFromPropSheetExtArray	[SHELL32.167]
1670
 */
1671
UINT WINAPI SHAddFromPropSheetExtArray(HPSXA hpsxa, LPFNADDPROPSHEETPAGE lpfnAddPage, LPARAM lParam)
1672
{
1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695
    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;
1696 1697 1698
}

/*************************************************************************
1699
 *      SHCreatePropSheetExtArray	[SHELL32.168]
1700
 */
1701
HPSXA WINAPI SHCreatePropSheetExtArray(HKEY hKey, LPCWSTR pszSubKey, UINT max_iface)
1702 1703 1704 1705 1706 1707 1708
{
    return SHCreatePropSheetExtArrayEx(hKey, pszSubKey, max_iface, NULL);
}

/*************************************************************************
 *      SHCreatePropSheetExtArrayEx	[SHELL32.194]
 */
1709
HPSXA WINAPI SHCreatePropSheetExtArrayEx(HKEY hKey, LPCWSTR pszSubKey, UINT max_iface, LPDATAOBJECT pDataObj)
1710
{
1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738
    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 */
1739
        psxa = LocalAlloc(LMEM_FIXED, FIELD_OFFSET(PSXA, pspsx[max_iface]));
1740 1741 1742 1743 1744 1745 1746 1747 1748
        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
            {
1749
                dwHandlerLen = ARRAY_SIZE(szHandler);
1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760
                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;
                }

1761
                /* The CLSID is stored either in the key itself or in its default value. */
1762
                if (FAILED(lRet = SHCLSIDFromStringW(szHandler, &clsid)))
1763
                {
1764 1765
                    dwClsidSize = sizeof(szClsidHandler);
                    if (SHGetValueW(hkPropSheetHandlers, szHandler, NULL, NULL, szClsidHandler, &dwClsidSize) == ERROR_SUCCESS)
1766
                    {
1767
                        /* Force a NULL-termination and convert the string */
1768
                        szClsidHandler[ARRAY_SIZE(szClsidHandler) - 1] = 0;
1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780
                        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)))
1781
                        {
1782
                            if (SUCCEEDED(psxi->lpVtbl->Initialize(psxi, NULL, pDataObj, hKey)))
1783
                            {
1784 1785
                                /* Add the IShellPropSheetExt instance to the array */
                                psxa->pspsx[psxa->uiCount++] = pspsx;
1786 1787
                            }
                            else
1788 1789
                            {
                                psxi->lpVtbl->Release(psxi);
1790
                                pspsx->lpVtbl->Release(pspsx);
1791
                            }
1792
                        }
1793 1794
                        else
                            pspsx->lpVtbl->Release(pspsx);
1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812
                    }
                }

            } 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;
1813 1814 1815
}

/*************************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
1816
 *      SHReplaceFromPropSheetExtArray	[SHELL32.170]
1817
 */
1818
UINT WINAPI SHReplaceFromPropSheetExtArray(HPSXA hpsxa, UINT uPageID, LPFNADDPROPSHEETPAGE lpfnReplaceWith, LPARAM lParam)
1819
{
1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843
    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;
1844 1845 1846
}

/*************************************************************************
1847
 *      SHDestroyPropSheetExtArray	[SHELL32.169]
1848
 */
1849
void WINAPI SHDestroyPropSheetExtArray(HPSXA hpsxa)
1850
{
1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862
    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]);
        }

1863
        LocalFree(psxa);
1864
    }
1865
}
1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877

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

1881
    TRACE("(%p, %d, %p, %p)\n", pidlFolder, cpidlFiles, lppidlFiles, ppdataObject);
1882 1883
    if (TRACE_ON(pidl))
    {
1884
	pdump (pidlFolder);
1885
	for (i=0; i<cpidlFiles; i++) pdump (lppidlFiles[i]);
1886 1887 1888 1889 1890 1891
    }
    *ppdataObject = IDataObject_Constructor( hwnd, pidlFolder,
					     lppidlFiles, cpidlFiles);
    if (*ppdataObject) return S_OK;
    return E_OUTOFMEMORY;
}
1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905

/*************************************************************************
 * SHCreateStdEnumFmtEtc			[SHELL32.74]
 *
 * NOTES
 *
 */
HRESULT WINAPI SHCreateStdEnumFmtEtc(
	DWORD cFormats,
	const FORMATETC *lpFormats,
	LPENUMFORMATETC *ppenumFormatetc)
{
	IEnumFORMATETC *pef;
	HRESULT hRes;
1906
	TRACE("cf=%d fe=%p pef=%p\n", cFormats, lpFormats, ppenumFormatetc);
1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917

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

1919 1920 1921
/*************************************************************************
 *		SHFindFiles (SHELL32.90)
 */
1922 1923 1924 1925 1926
BOOL WINAPI SHFindFiles( LPCITEMIDLIST pidlFolder, LPCITEMIDLIST pidlSaveFile )
{
    FIXME("%p %p\n", pidlFolder, pidlSaveFile );
    return FALSE;
}
1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938

/*************************************************************************
 *		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.
 *
1939 1940 1941
 * RETURNS
 *  Nothing
 *
1942 1943 1944 1945 1946 1947 1948
 * 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)
{
1949 1950 1951
    FIXME("%s, %d, 0x%x, %d - stub\n", debugstr_w(pszHashItem), iIndex, uFlags, iImageIndex);
}

1952 1953 1954 1955 1956
/*************************************************************************
 *		SHUpdateImageA (SHELL32.191)
 *
 * See SHUpdateImageW.
 */
1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970
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)
{
1971
    FIXME("%p, 0x%08x, %s, %s - stub\n", hwnd, dwType, debugstr_w(szObject), debugstr_w(szPage));
1972 1973 1974 1975 1976 1977 1978

    return TRUE;
}

BOOL WINAPI SHGetNewLinkInfoA(LPCSTR pszLinkTo, LPCSTR pszDir, LPSTR pszName, BOOL *pfMustCopy,
                              UINT uFlags)
{
1979 1980 1981 1982
    WCHAR wszLinkTo[MAX_PATH];
    WCHAR wszDir[MAX_PATH];
    WCHAR wszName[MAX_PATH];
    BOOL res;
1983

1984 1985 1986 1987 1988 1989 1990 1991 1992
    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;
1993 1994 1995 1996 1997
}

BOOL WINAPI SHGetNewLinkInfoW(LPCWSTR pszLinkTo, LPCWSTR pszDir, LPWSTR pszName, BOOL *pfMustCopy,
                              UINT uFlags)
{
1998 1999 2000 2001 2002 2003 2004
    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),
2005 2006
          pszName, pfMustCopy, uFlags);

2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042
    *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;
2043 2044 2045 2046
}

HRESULT WINAPI SHStartNetConnectionDialog(HWND hwnd, LPCSTR pszRemoteName, DWORD dwType)
{
2047
    FIXME("%p, %s, 0x%08x - stub\n", hwnd, debugstr_a(pszRemoteName), dwType);
2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058

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

2059 2060 2061 2062 2063 2064 2065 2066 2067
/*************************************************************************
 *              SHRemoveLocalizedName (SHELL32.@)
 */
HRESULT WINAPI SHRemoveLocalizedName(const WCHAR *path)
{
    FIXME("%s stub\n", debugstr_w(path));
    return S_OK;
}

2068 2069 2070 2071 2072 2073 2074 2075 2076
/*************************************************************************
 *              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;
}
2077 2078 2079 2080 2081 2082 2083 2084 2085

/*************************************************************************
 *              LinkWindow_RegisterClass (SHELL32.258)
 */
BOOL WINAPI LinkWindow_RegisterClass(void)
{
    FIXME("()\n");
    return TRUE;
}
2086 2087 2088 2089 2090 2091 2092 2093 2094

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

/*************************************************************************
2097
 *              SHFlushSFCache (SHELL32.526)
2098 2099 2100 2101 2102 2103
 *
 * 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.
2104
 */
2105
void WINAPI SHFlushSFCache(void)
2106 2107
{
}