shell32_main.c 31 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1 2 3
/*
 * 				Shell basics
 *
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
 * Copyright 1998 Marcus Meissner
 * Copyright 1998 Juergen Schmied (jsch)  *  <juergen.schmied@metronet.de>
 *
 * 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
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
Alexandre Julliard's avatar
Alexandre Julliard committed
20
 */
21 22 23

#include "config.h"

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

28 29 30
#include "windef.h"
#include "winerror.h"
#include "winreg.h"
31 32 33 34 35
#include "dlgs.h"
#include "shellapi.h"
#include "shlobj.h"
#include "shlguid.h"
#include "shlwapi.h"
36

37
#include "undocshell.h"
38 39 40
#include "wine/winuser16.h"
#include "authors.h"
#include "heap.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
41
#include "pidl.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
42
#include "shell32_main.h"
43

44
#include "wine/debug.h"
45

46
WINE_DEFAULT_DEBUG_CHANNEL(shell);
47

48
#define MORE_DEBUG 1
Alexandre Julliard's avatar
Alexandre Julliard committed
49
/*************************************************************************
50
 * CommandLineToArgvW			[SHELL32.@]
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
 *
 * We must interpret the quotes in the command line to rebuild the argv 
 * array correctly:
 * - arguments are separated by spaces or tabs
 * - quotes serve as optional argument delimiters
 *   '"a b"'   -> 'a b'
 * - escaped quotes must be converted back to '"'
 *   '\"'      -> '"'
 * - an odd number of '\'s followed by '"' correspond to half that number 
 *   of '\' followed by a '"' (extension of the above)
 *   '\\\"'    -> '\"'
 *   '\\\\\"'  -> '\\"'
 * - an even number of '\'s followed by a '"' correspond to half that number
 *   of '\', plus a regular quote serving as an argument delimiter (which 
 *   means it does not appear in the result)
 *   'a\\"b c"'   -> 'a\b c'
 *   'a\\\\"b c"' -> 'a\\b c'
 * - '\' that are not followed by a '"' are copied literally
 *   'a\b'     -> 'a\b'
 *   'a\\b'    -> 'a\\b'
 *
 * Note:
 * '\t' == 0x0009
 * ' '  == 0x0020
 * '"'  == 0x0022
 * '\\' == 0x005c
Alexandre Julliard's avatar
Alexandre Julliard committed
77
 */
78
LPWSTR* WINAPI CommandLineToArgvW(LPCWSTR lpCmdline, int* numargs)
79 80
{
    DWORD argc;
81
    HGLOBAL hargv;
82
    LPWSTR  *argv;
83
    LPCWSTR cs;
84 85 86 87 88 89 90 91
    LPWSTR arg,s,d;
    LPWSTR cmdline;
    int in_quotes,bcount;

    if (*lpCmdline==0) {
        /* Return the path to the executable */
        DWORD size;

92
        hargv=0;
93 94 95
        size=16;
        do {
            size*=2;
96 97 98 99
            hargv=GlobalReAlloc(hargv, size, 0);
            argv=GlobalLock(hargv);
        } while (GetModuleFileNameW((HMODULE)0, (LPWSTR)(argv+1), size-sizeof(LPWSTR)) == 0);
        argv[0]=(LPWSTR)(argv+1);
100 101 102 103 104 105 106 107 108 109
        if (numargs)
            *numargs=2;

        return argv;
    }

    /* to get a writeable copy */
    argc=0;
    bcount=0;
    in_quotes=0;
110
    cs=lpCmdline;
111
    while (1) {
112
        if (*cs==0 || ((*cs==0x0009 || *cs==0x0020) && !in_quotes)) {
113 114 115
            /* space */
            argc++;
            /* skip the remaining spaces */
116 117
            while (*cs==0x0009 || *cs==0x0020) {
                cs++;
118
            }
119
            if (*cs==0)
120 121 122
                break;
            bcount=0;
            continue;
123
        } else if (*cs==0x005c) {
124 125
            /* '\', count them */
            bcount++;
126
        } else if ((*cs==0x0022) && ((bcount & 1)==0)) {
127 128 129 130 131 132 133
            /* unescaped '"' */
            in_quotes=!in_quotes;
            bcount=0;
        } else {
            /* a regular character */
            bcount=0;
        }
134
        cs++;
135
    }
136 137 138 139 140 141 142 143 144
    /* Allocate in a single lump, the string array, and the strings that go with it.
     * This way the caller can make a single GlobalFree call to free both, as per MSDN.
     */
    hargv=GlobalAlloc(0, argc*sizeof(LPWSTR)+(strlenW(lpCmdline)+1)*sizeof(WCHAR));
    argv=GlobalLock(hargv);
    if (!argv)
        return NULL;
    cmdline=(LPWSTR)(argv+argc);
    strcpyW(cmdline, lpCmdline);
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193

    argc=0;
    bcount=0;
    in_quotes=0;
    arg=d=s=cmdline;
    while (*s) {
        if ((*s==0x0009 || *s==0x0020) && !in_quotes) {
            /* Close the argument and copy it */
            *d=0;
            argv[argc++]=arg;

            /* skip the remaining spaces */
            do {
                s++;
            } while (*s==0x0009 || *s==0x0020);

            /* Start with a new argument */
            arg=d=s;
            bcount=0;
        } else if (*s==0x005c) {
            /* '\\' */
            *d++=*s++;
            bcount++;
        } else if (*s==0x0022) {
            /* '"' */
            if ((bcount & 1)==0) {
                /* Preceeded by an even number of '\', this is half that 
                 * number of '\', plus a quote which we erase.
                 */
                d-=bcount/2;
                in_quotes=!in_quotes;
                s++;
            } else {
                /* Preceeded by an odd number of '\', this is half that 
                 * number of '\' followed by a '"'
                 */
                d=d-bcount/2-1;
                *d++='"';
                s++;
            }
            bcount=0;
        } else {
            /* a regular character */
            *d++=*s++;
            bcount=0;
        }
    }
    if (*arg) {
        *d='\0';
194
        argv[argc]=arg;
195 196 197 198 199
    }
    if (numargs)
        *numargs=argc;

    return argv;
Alexandre Julliard's avatar
Alexandre Julliard committed
200 201 202
}

/*************************************************************************
Juergen Schmied's avatar
Juergen Schmied committed
203
 * SHGetFileInfoA			[SHELL32.@]
204
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
205 206
 */

207 208 209
DWORD WINAPI SHGetFileInfoA(LPCSTR path,DWORD dwFileAttributes,
                              SHFILEINFOA *psfi, UINT sizeofpsfi,
                              UINT flags )
210 211 212 213 214
{
	char szLoaction[MAX_PATH];
	int iIndex;
	DWORD ret = TRUE, dwAttributes = 0;
	IShellFolder * psfParent = NULL;
215
	IExtractIconA * pei = NULL;
Juergen Schmied's avatar
Juergen Schmied committed
216
	LPITEMIDLIST	pidlLast = NULL, pidl = NULL;
217
	HRESULT hr = S_OK;
218
    BOOL IconNotYetLoaded=TRUE;
219

Juergen Schmied's avatar
Juergen Schmied committed
220 221
	TRACE("(%s fattr=0x%lx sfi=%p(attr=0x%08lx) size=0x%x flags=0x%x)\n", 
	  (flags & SHGFI_PIDL)? "pidl" : path, dwFileAttributes, psfi, psfi->dwAttributes, sizeofpsfi, flags);
222 223 224 225

	if ((flags & SHGFI_USEFILEATTRIBUTES) && (flags & (SHGFI_ATTRIBUTES|SHGFI_EXETYPE|SHGFI_PIDL)))
	  return FALSE;
	
226 227 228 229
	/* windows initializes this values regardless of the flags */
	psfi->szDisplayName[0] = '\0';
	psfi->szTypeName[0] = '\0';
	psfi->iIcon = 0;
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247

	if (flags & SHGFI_EXETYPE) {
	  BOOL status = FALSE;
	  HANDLE hfile;
	  DWORD BinaryType;
	  IMAGE_DOS_HEADER mz_header;
	  IMAGE_NT_HEADERS nt;
	  DWORD len;
	  char magic[4];

	  if (flags != SHGFI_EXETYPE) return 0;

	  status = GetBinaryTypeA (path, &BinaryType);
	  if (!status) return 0;
	  if ((BinaryType == SCS_DOS_BINARY)
		|| (BinaryType == SCS_PIF_BINARY)) return 0x4d5a;

	  hfile = CreateFileA( path, GENERIC_READ, FILE_SHARE_READ,
248
		NULL, OPEN_EXISTING, 0, 0 );
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 283 284 285 286 287 288
	  if ( hfile == INVALID_HANDLE_VALUE ) return 0;

	/* The next section is adapted from MODULE_GetBinaryType, as we need
	 * to examine the image header to get OS and version information. We
	 * know from calling GetBinaryTypeA that the image is valid and either
	 * an NE or PE, so much error handling can be omitted.
	 * Seek to the start of the file and read the header information.
	 */

	  SetFilePointer( hfile, 0, NULL, SEEK_SET );  
	  ReadFile( hfile, &mz_header, sizeof(mz_header), &len, NULL );

         SetFilePointer( hfile, mz_header.e_lfanew, NULL, SEEK_SET );
         ReadFile( hfile, magic, sizeof(magic), &len, NULL );
         if ( *(DWORD*)magic      == IMAGE_NT_SIGNATURE )
         {
             SetFilePointer( hfile, mz_header.e_lfanew, NULL, SEEK_SET ); 
             ReadFile( hfile, &nt, sizeof(nt), &len, NULL );
	      CloseHandle( hfile );
	      if (nt.OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI) {
                 return IMAGE_NT_SIGNATURE
			| (nt.OptionalHeader.MajorSubsystemVersion << 24)
			| (nt.OptionalHeader.MinorSubsystemVersion << 16);
	      }
	      return IMAGE_NT_SIGNATURE;
	  }
         else if ( *(WORD*)magic == IMAGE_OS2_SIGNATURE )
         {
             IMAGE_OS2_HEADER ne;
             SetFilePointer( hfile, mz_header.e_lfanew, NULL, SEEK_SET ); 
             ReadFile( hfile, &ne, sizeof(ne), &len, NULL );
	      CloseHandle( hfile );
             if (ne.ne_exetyp == 2) return IMAGE_OS2_SIGNATURE
			| (ne.ne_expver << 16);
	      return 0;
	  }
	  CloseHandle( hfile );
	  return 0;
      }

289
	
290 291
	/* translate the path into a pidl only when SHGFI_USEFILEATTRIBUTES in not specified 
	   the pidl functions fail on not existing file names */
Alexandre Julliard's avatar
Alexandre Julliard committed
292
	if (flags & SHGFI_PIDL)
293 294
	{
	  pidl = (LPCITEMIDLIST) path;
295 296
	  if (!pidl )
	  {
297
	    ERR("pidl is null!\n");
298 299
	    return FALSE;
	  }
Alexandre Julliard's avatar
Alexandre Julliard committed
300
	}
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320
	else if (!(flags & SHGFI_USEFILEATTRIBUTES))
	{
	  hr = SHILCreateFromPathA ( path, &pidl, &dwAttributes);
	  /* note: the attributes in ISF::ParseDisplayName are not implemented */
	}
	
	/* get the parent shellfolder */
	if (pidl)
	{
	  hr = SHBindToParent( pidl, &IID_IShellFolder, (LPVOID*)&psfParent, &pidlLast);
	}
	
	/* get the attributes of the child */
	if (SUCCEEDED(hr) && (flags & SHGFI_ATTRIBUTES))
	{
	  if (!(flags & SHGFI_ATTR_SPECIFIED))
	  {
	    psfi->dwAttributes = 0xffffffff;
	  }
	  IShellFolder_GetAttributesOf(psfParent, 1 , &pidlLast, &(psfi->dwAttributes));
Alexandre Julliard's avatar
Alexandre Julliard committed
321
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
322

323 324 325 326
	/* get the displayname */
	if (SUCCEEDED(hr) && (flags & SHGFI_DISPLAYNAME))
	{ 
	  if (flags & SHGFI_USEFILEATTRIBUTES)
327
	  {
Juergen Schmied's avatar
Juergen Schmied committed
328
	    strcpy (psfi->szDisplayName, PathFindFileNameA(path));
Alexandre Julliard's avatar
Alexandre Julliard committed
329 330
	  }
	  else
331 332 333 334
	  {
	    STRRET str;
	    hr = IShellFolder_GetDisplayNameOf(psfParent, pidlLast, SHGDN_INFOLDER, &str);
	    StrRetToStrNA (psfi->szDisplayName, MAX_PATH, &str, pidlLast);
Alexandre Julliard's avatar
Alexandre Julliard committed
335 336
	  }
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
337

338 339
	/* get the type name */
	if (SUCCEEDED(hr) && (flags & SHGFI_TYPENAME))
340
        {
341 342 343 344 345 346 347 348 349 350 351 352 353
            if (!(flags & SHGFI_USEFILEATTRIBUTES))
                _ILGetFileType(pidlLast, psfi->szTypeName, 80);
            else
            {
                char sTemp[64];
                strcpy(sTemp,PathFindExtensionA(path));
                if (!( HCR_MapTypeToValue(sTemp, sTemp, 64, TRUE)
                       && HCR_MapTypeToValue(sTemp, psfi->szTypeName, 80, FALSE )))
                {
                    lstrcpynA (psfi->szTypeName, sTemp, 80 - 6);
                    strcat (psfi->szTypeName, "-file");
                }
            }
354
        }
355

356
	/* ### icons ###*/
357
	if (flags & SHGFI_LINKOVERLAY)
358
	  FIXME("set icon to link, stub\n");
359 360

	if (flags & SHGFI_SELECTED)
361
	  FIXME("set icon to selected, stub\n");
362 363

	if (flags & SHGFI_SHELLICONSIZE)
364
	  FIXME("set icon to shell size, stub\n");
365

366 367 368 369 370
	/* get the iconlocation */
	if (SUCCEEDED(hr) && (flags & SHGFI_ICONLOCATION ))
	{
	  UINT uDummy,uFlags;
	  hr = IShellFolder_GetUIObjectOf(psfParent, 0, 1, &pidlLast, &IID_IExtractIconA, &uDummy, (LPVOID*)&pei);
371

372 373
	  if (SUCCEEDED(hr))
	  {
374
	    hr = IExtractIconA_GetIconLocation(pei, (flags & SHGFI_OPENICON)? GIL_OPENICON : 0,szLoaction, MAX_PATH, &iIndex, &uFlags);
375
	    /* FIXME what to do with the index? */
376 377 378 379 380 381 382

	    if(uFlags != GIL_NOTFILENAME)
	      strcpy (psfi->szDisplayName, szLoaction);
	    else
	      ret = FALSE;
	      
	    IExtractIconA_Release(pei);
383 384
	  }
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
385

386 387 388
	/* get icon index (or load icon)*/
	if (SUCCEEDED(hr) && (flags & (SHGFI_ICON | SHGFI_SYSICONINDEX)))
	{
389

390 391 392 393 394 395 396 397 398 399 400 401 402 403 404
	  if (flags & SHGFI_USEFILEATTRIBUTES)
	  {
	    char sTemp [MAX_PATH];
	    char * szExt;
	    DWORD dwNr=0;

	    lstrcpynA(sTemp, path, MAX_PATH);
	    szExt = (LPSTR) PathFindExtensionA(sTemp);
	    if( szExt && HCR_MapTypeToValue(szExt, sTemp, MAX_PATH, TRUE)
              && HCR_GetDefaultIcon(sTemp, sTemp, MAX_PATH, &dwNr))
            {
              if (!strcmp("%1",sTemp))            /* icon is in the file */
              {
                strcpy(sTemp, path);
              }
405 406 407 408 409 410 411 412 413 414
              IconNotYetLoaded=FALSE;
              psfi->iIcon = 0;
              if (SHGFI_LARGEICON)
                PrivateExtractIconsA(sTemp,dwNr,GetSystemMetrics(SM_CXICON),
                                     GetSystemMetrics(SM_CYICON),
                                     &psfi->hIcon,0,1,0);
              else
                PrivateExtractIconsA(sTemp,dwNr,GetSystemMetrics(SM_CXSMICON),
                                     GetSystemMetrics(SM_CYSMICON),
                                     &psfi->hIcon,0,1,0);
415 416 417 418 419
            }
            else                                  /* default icon */
            {
              psfi->iIcon = 0;
            }          
420
	  }
421 422
	  else
	  {
423 424
	    if (!(PidlToSicIndex(psfParent, pidlLast, (flags & SHGFI_LARGEICON), 
	      (flags & SHGFI_OPENICON)? GIL_OPENICON : 0, &(psfi->iIcon))))
425 426 427
	    {
	      ret = FALSE;
	    }
428
	  }
429 430
	  if (ret) 
	  {
431
	    ret = (DWORD) ((flags & SHGFI_LARGEICON) ? ShellBigIconList : ShellSmallIconList);
432 433 434
	  }
	}

435
	/* icon handle */
436
	if (SUCCEEDED(hr) && (flags & SHGFI_ICON) && IconNotYetLoaded)
437
	  psfi->hIcon = ImageList_GetIcon((flags & SHGFI_LARGEICON) ? ShellBigIconList:ShellSmallIconList, psfi->iIcon, ILD_NORMAL);
438 439

	if (flags & (SHGFI_UNKNOWN1 | SHGFI_UNKNOWN2 | SHGFI_UNKNOWN3))
440
	  FIXME("unknown attribute!\n");
441 442 443 444 445 446 447

	if (psfParent)
	  IShellFolder_Release(psfParent);

	if (hr != S_OK)
	  ret = FALSE;

Juergen Schmied's avatar
Juergen Schmied committed
448
	if(pidlLast) SHFree(pidlLast);
449
#ifdef MORE_DEBUG
450 451
	TRACE ("icon=0x%08x index=0x%08x attr=0x%08lx name=%s type=%s ret=0x%08lx\n", 
		psfi->hIcon, psfi->iIcon, psfi->dwAttributes, psfi->szDisplayName, psfi->szTypeName, ret);
452
#endif
453
	return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
454 455
}

456
/*************************************************************************
Juergen Schmied's avatar
Juergen Schmied committed
457
 * SHGetFileInfoW			[SHELL32.@]
458 459
 */

460 461 462
DWORD WINAPI SHGetFileInfoW(LPCWSTR path,DWORD dwFileAttributes,
                              SHFILEINFOW *psfi, UINT sizeofpsfi,
                              UINT flags )
463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482
{
	INT len;
	LPSTR temppath;
	DWORD ret;
	SHFILEINFOA temppsfi;

	len = WideCharToMultiByte(CP_ACP, 0, path, -1, NULL, 0, NULL, NULL);
	temppath = HeapAlloc(GetProcessHeap(), 0, len);
	WideCharToMultiByte(CP_ACP, 0, path, -1, temppath, len, NULL, NULL);

        WideCharToMultiByte(CP_ACP, 0, psfi->szDisplayName, -1, temppsfi.szDisplayName,
                            sizeof(temppsfi.szDisplayName), NULL, NULL);
        WideCharToMultiByte(CP_ACP, 0, psfi->szTypeName, -1, temppsfi.szTypeName,
                            sizeof(temppsfi.szTypeName), NULL, NULL);

	ret = SHGetFileInfoA(temppath, dwFileAttributes, &temppsfi, sizeof(temppsfi), flags);

	HeapFree(GetProcessHeap(), 0, temppath);
	
	return ret;
483 484
}

Juergen Schmied's avatar
Juergen Schmied committed
485
/*************************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
486
 * SHGetFileInfo			[SHELL32.@]
Juergen Schmied's avatar
Juergen Schmied committed
487 488 489 490 491 492 493 494
 */
DWORD WINAPI SHGetFileInfoAW(
	LPCVOID path,
	DWORD dwFileAttributes,
	LPVOID psfi,
	UINT sizeofpsfi,
	UINT flags)
{
495
	if(SHELL_OsIsUnicode())
Juergen Schmied's avatar
Juergen Schmied committed
496 497 498 499
	  return SHGetFileInfoW(path, dwFileAttributes, psfi, sizeofpsfi, flags );
	return SHGetFileInfoA(path, dwFileAttributes, psfi, sizeofpsfi, flags );
}

500
/*************************************************************************
501
 * DuplicateIcon			[SHELL32.@]
502 503 504 505
 */
HICON WINAPI DuplicateIcon( HINSTANCE hInstance, HICON hIcon)
{
    ICONINFO IconInfo;
506
    HICON hDupIcon = 0;
507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522

    TRACE("(%04x, %04x)\n", hInstance, hIcon);

    if(GetIconInfo(hIcon, &IconInfo))
    {
        hDupIcon = CreateIconIndirect(&IconInfo);

        /* clean up hbmMask and hbmColor */
        DeleteObject(IconInfo.hbmMask);        
        DeleteObject(IconInfo.hbmColor);        
    }
 
    return hDupIcon;
}
    

Alexandre Julliard's avatar
Alexandre Julliard committed
523
/*************************************************************************
524
 * ExtractIconA				[SHELL32.@]
525
 *
Andreas Mohr's avatar
Andreas Mohr committed
526 527
 * FIXME
 *  if the filename is not a file return 1
Alexandre Julliard's avatar
Alexandre Julliard committed
528
 */
529 530 531
HICON WINAPI ExtractIconA( HINSTANCE hInstance, LPCSTR lpszExeFileName,
	UINT nIconIndex )
{   HGLOBAL16 handle = InternalExtractIcon16(hInstance,lpszExeFileName,nIconIndex, 1);
532
    TRACE("\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
533 534 535 536 537 538 539 540 541 542 543 544
    if( handle )
    {
	HICON16* ptr = (HICON16*)GlobalLock16(handle);
	HICON16  hIcon = *ptr;

	GlobalFree16(handle);
	return hIcon;
    }
    return 0;
}

/*************************************************************************
545
 * ExtractIconW				[SHELL32.@]
546
 *
547
 * FIXME: if the filename is not a file return 1
Alexandre Julliard's avatar
Alexandre Julliard committed
548
 */
549 550
HICON WINAPI ExtractIconW( HINSTANCE hInstance, LPCWSTR lpszExeFileName,
	UINT nIconIndex )
Alexandre Julliard's avatar
Alexandre Julliard committed
551
{ LPSTR  exefn;
552
  HICON  ret;
553
  TRACE("\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
554 555

  exefn = HEAP_strdupWtoA(GetProcessHeap(),0,lpszExeFileName);
556
  ret = ExtractIconA(hInstance,exefn,nIconIndex);
Alexandre Julliard's avatar
Alexandre Julliard committed
557 558 559 560 561 562 563 564

	HeapFree(GetProcessHeap(),0,exefn);
	return ret;
}

typedef struct
{ LPCSTR  szApp;
    LPCSTR  szOtherStuff;
565
    HICON hIcon;
Alexandre Julliard's avatar
Alexandre Julliard committed
566 567 568 569 570 571 572 573 574
} ABOUT_INFO;

#define		IDC_STATIC_TEXT		100
#define		IDC_LISTBOX		99
#define		IDC_WINE_TEXT		98

#define		DROP_FIELD_TOP		(-15)
#define		DROP_FIELD_HEIGHT	15

575
static HICON hIconTitleFont;
Alexandre Julliard's avatar
Alexandre Julliard committed
576

577 578
static BOOL __get_dropline( HWND hWnd, LPRECT lprect )
{ HWND hWndCtl = GetDlgItem(hWnd, IDC_WINE_TEXT);
Alexandre Julliard's avatar
Alexandre Julliard committed
579
    if( hWndCtl )
580 581
  { GetWindowRect( hWndCtl, lprect );
	MapWindowPoints( 0, hWnd, (LPPOINT)lprect, 2 );
Alexandre Julliard's avatar
Alexandre Julliard committed
582 583 584 585 586 587 588
	lprect->bottom = (lprect->top += DROP_FIELD_TOP);
	return TRUE;
    }
    return FALSE;
}

/*************************************************************************
589
 * SHAppBarMessage			[SHELL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
590
 */
591
UINT WINAPI SHAppBarMessage(DWORD msg, PAPPBARDATA data)
592
{
593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616
        int width=data->rc.right - data->rc.left;
        int height=data->rc.bottom - data->rc.top;
        RECT rec=data->rc;
        switch (msg)
        { case ABM_GETSTATE:
               return ABS_ALWAYSONTOP | ABS_AUTOHIDE;
          case ABM_GETTASKBARPOS:
               GetWindowRect(data->hWnd, &rec);
               data->rc=rec;
               return TRUE;
          case ABM_ACTIVATE:
               SetActiveWindow(data->hWnd);
               return TRUE;
          case ABM_GETAUTOHIDEBAR:
               data->hWnd=GetActiveWindow();
               return TRUE;
          case ABM_NEW:
               SetWindowPos(data->hWnd,HWND_TOP,rec.left,rec.top,
                                        width,height,SWP_SHOWWINDOW);
               return TRUE;
          case ABM_QUERYPOS:
               GetWindowRect(data->hWnd, &(data->rc));
               return TRUE;
          case ABM_REMOVE:
617 618 619
               FIXME("ABM_REMOVE broken\n");
               /* FIXME: this is wrong; should it be DestroyWindow instead? */
               /*CloseHandle(data->hWnd);*/
620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635
               return TRUE;
          case ABM_SETAUTOHIDEBAR:
               SetWindowPos(data->hWnd,HWND_TOP,rec.left+1000,rec.top,
                                       width,height,SWP_SHOWWINDOW);          
               return TRUE;
          case ABM_SETPOS:
               data->uEdge=(ABE_RIGHT | ABE_LEFT);
               SetWindowPos(data->hWnd,HWND_TOP,data->rc.left,data->rc.top,
                                  width,height,SWP_SHOWWINDOW);
               return TRUE;
          case ABM_WINDOWPOSCHANGED:
               SetWindowPos(data->hWnd,HWND_TOP,rec.left,rec.top,
                                        width,height,SWP_SHOWWINDOW);
               return TRUE;
          }
      return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
636 637 638
}

/*************************************************************************
639
 * SHHelpShortcuts_RunDLL		[SHELL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
640 641 642
 *
 */
DWORD WINAPI SHHelpShortcuts_RunDLL (DWORD dwArg1, DWORD dwArg2, DWORD dwArg3, DWORD dwArg4)
643
{ FIXME("(%lx, %lx, %lx, %lx) empty stub!\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
644 645 646 647 648 649
	dwArg1, dwArg2, dwArg3, dwArg4);

  return 0;
}

/*************************************************************************
650
 * SHLoadInProc				[SHELL32.@]
651 652
 * Create an instance of specified object class from within 
 * the shell process and release it immediately
Alexandre Julliard's avatar
Alexandre Julliard committed
653 654
 */

655 656 657 658 659 660 661 662 663 664 665 666
DWORD WINAPI SHLoadInProc (REFCLSID rclsid)
{
	IUnknown * pUnk = NULL;
	TRACE("%s\n", debugstr_guid(rclsid));

	CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown,(LPVOID*)pUnk);
	if(pUnk)
	{
	  IUnknown_Release(pUnk);
          return NOERROR;
	}
	return DISP_E_MEMBERNOTFOUND;
Alexandre Julliard's avatar
Alexandre Julliard committed
667 668 669
}

/*************************************************************************
670
 * AboutDlgProc			(internal)
Alexandre Julliard's avatar
Alexandre Julliard committed
671
 */
672
BOOL WINAPI AboutDlgProc( HWND hWnd, UINT msg, WPARAM wParam,
673
                              LPARAM lParam )
674
{   HWND hWndCtl;
Alexandre Julliard's avatar
Alexandre Julliard committed
675 676
    char Template[512], AppTitle[512];

677
    TRACE("\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
678 679 680 681 682 683

    switch(msg)
    { case WM_INITDIALOG:
      { ABOUT_INFO *info = (ABOUT_INFO *)lParam;
            if (info)
        { const char* const *pstr = SHELL_People;
684 685
                SendDlgItemMessageA(hWnd, stc1, STM_SETICON,info->hIcon, 0);
                GetWindowTextA( hWnd, Template, sizeof(Template) );
Alexandre Julliard's avatar
Alexandre Julliard committed
686
                sprintf( AppTitle, Template, info->szApp );
687 688
                SetWindowTextA( hWnd, AppTitle );
                SetWindowTextA( GetDlgItem(hWnd, IDC_STATIC_TEXT),
Alexandre Julliard's avatar
Alexandre Julliard committed
689
                                  info->szOtherStuff );
690 691
                hWndCtl = GetDlgItem(hWnd, IDC_LISTBOX);
                SendMessageA( hWndCtl, WM_SETREDRAW, 0, 0 );
692 693 694 695 696 697
                if (!hIconTitleFont)
                {
                    LOGFONTA logFont;
                    SystemParametersInfoA( SPI_GETICONTITLELOGFONT, 0, &logFont, 0 );
                    hIconTitleFont = CreateFontIndirectA( &logFont );
                }
698
                SendMessageA( hWndCtl, WM_SETFONT, hIconTitleFont, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
699
                while (*pstr)
700
          { SendMessageA( hWndCtl, LB_ADDSTRING, (WPARAM)-1, (LPARAM)*pstr );
Alexandre Julliard's avatar
Alexandre Julliard committed
701 702
                    pstr++;
                }
703
                SendMessageA( hWndCtl, WM_SETREDRAW, 1, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
704 705 706 707 708
            }
        }
        return 1;

    case WM_PAINT:
709 710 711
      { RECT rect;
	    PAINTSTRUCT ps;
	    HDC hDC = BeginPaint( hWnd, &ps );
Alexandre Julliard's avatar
Alexandre Julliard committed
712

713
	    if( __get_dropline( hWnd, &rect ) ) {
714 715 716
	        SelectObject( hDC, GetStockObject( BLACK_PEN ) );
	        MoveToEx( hDC, rect.left, rect.top, NULL );
		LineTo( hDC, rect.right, rect.bottom );
717
	    }
718
	    EndPaint( hWnd, &ps );
Alexandre Julliard's avatar
Alexandre Julliard committed
719 720 721
	}
	break;

722
#if 0  /* FIXME: should use DoDragDrop */
Alexandre Julliard's avatar
Alexandre Julliard committed
723
    case WM_LBTRACKPOINT:
724
	hWndCtl = GetDlgItem(hWnd, IDC_LISTBOX);
725
	if( (INT16)GetKeyState( VK_CONTROL ) < 0 )
726 727
      { if( DragDetect( hWndCtl, *((LPPOINT)&lParam) ) )
        { INT idx = SendMessageA( hWndCtl, LB_GETCURSEL, 0, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
728
		if( idx != -1 )
729
          { INT length = SendMessageA( hWndCtl, LB_GETTEXTLEN, (WPARAM)idx, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
730 731 732 733
		    HGLOBAL16 hMemObj = GlobalAlloc16( GMEM_MOVEABLE, length + 1 );
		    char* pstr = (char*)GlobalLock16( hMemObj );

		    if( pstr )
734
            { HCURSOR hCursor = LoadCursorA( 0, MAKEINTRESOURCEA(OCR_DRAGOBJECT) );
735 736 737
			SendMessageA( hWndCtl, LB_GETTEXT, (WPARAM)idx, (LPARAM)pstr );
			SendMessageA( hWndCtl, LB_DELETESTRING, (WPARAM)idx, 0 );
			UpdateWindow( hWndCtl );
Alexandre Julliard's avatar
Alexandre Julliard committed
738
			if( !DragObject16((HWND16)hWnd, (HWND16)hWnd, DRAGOBJ_DATA, 0, (WORD)hMemObj, hCursor) )
739
			    SendMessageA( hWndCtl, LB_ADDSTRING, (WPARAM)-1, (LPARAM)pstr );
Alexandre Julliard's avatar
Alexandre Julliard committed
740 741 742 743 744 745 746
		    }
            if( hMemObj )
              GlobalFree16( hMemObj );
		}
	    }
	}
	break;
747
#endif
Alexandre Julliard's avatar
Alexandre Julliard committed
748 749 750

    case WM_QUERYDROPOBJECT:
	if( wParam == 0 )
751
      { LPDRAGINFO16 lpDragInfo = MapSL((SEGPTR)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
752
	    if( lpDragInfo && lpDragInfo->wFlags == DRAGOBJ_DATA )
753
        { RECT rect;
Alexandre Julliard's avatar
Alexandre Julliard committed
754
		if( __get_dropline( hWnd, &rect ) )
755
          { POINT pt;
756 757
	    pt.x=lpDragInfo->pt.x;
	    pt.x=lpDragInfo->pt.y;
Alexandre Julliard's avatar
Alexandre Julliard committed
758
		    rect.bottom += DROP_FIELD_HEIGHT;
759 760
		    if( PtInRect( &rect, pt ) )
            { SetWindowLongA( hWnd, DWL_MSGRESULT, 1 );
Alexandre Julliard's avatar
Alexandre Julliard committed
761 762 763 764 765 766 767 768 769
			return TRUE;
		    }
		}
	    }
	}
	break;

    case WM_DROPOBJECT:
	if( wParam == hWnd )
770
      { LPDRAGINFO16 lpDragInfo = MapSL((SEGPTR)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
771 772 773 774 775
	    if( lpDragInfo && lpDragInfo->wFlags == DRAGOBJ_DATA && lpDragInfo->hList )
        { char* pstr = (char*)GlobalLock16( (HGLOBAL16)(lpDragInfo->hList) );
		if( pstr )
          { static char __appendix_str[] = " with";

776 777
		    hWndCtl = GetDlgItem( hWnd, IDC_WINE_TEXT );
		    SendMessageA( hWndCtl, WM_GETTEXT, 512, (LPARAM)Template );
778
		    if( !strncmp( Template, "WINE", 4 ) )
779
			SetWindowTextA( GetDlgItem(hWnd, IDC_STATIC_TEXT), Template );
Alexandre Julliard's avatar
Alexandre Julliard committed
780 781 782
		    else
          { char* pch = Template + strlen(Template) - strlen(__appendix_str);
			*pch = '\0';
783 784
			SendMessageA( GetDlgItem(hWnd, IDC_LISTBOX), LB_ADDSTRING, 
					(WPARAM)-1, (LPARAM)Template );
Alexandre Julliard's avatar
Alexandre Julliard committed
785 786
		    }

787 788
		    strcpy( Template, pstr );
		    strcat( Template, __appendix_str );
789 790
		    SetWindowTextA( hWndCtl, Template );
		    SetWindowLongA( hWnd, DWL_MSGRESULT, 1 );
Alexandre Julliard's avatar
Alexandre Julliard committed
791 792 793 794 795 796 797 798
		    return TRUE;
		}
	    }
	}
	break;

    case WM_COMMAND:
        if (wParam == IDOK)
799
    {  EndDialog(hWnd, TRUE);
Alexandre Julliard's avatar
Alexandre Julliard committed
800 801 802
            return TRUE;
        }
        break;
803 804 805
    case WM_CLOSE:
      EndDialog(hWnd, TRUE);
      break;
Alexandre Julliard's avatar
Alexandre Julliard committed
806
    }
807

Alexandre Julliard's avatar
Alexandre Julliard committed
808 809 810 811 812
    return 0;
}


/*************************************************************************
813
 * ShellAboutA				[SHELL32.288]
Alexandre Julliard's avatar
Alexandre Julliard committed
814
 */
815 816
BOOL WINAPI ShellAboutA( HWND hWnd, LPCSTR szApp, LPCSTR szOtherStuff,
                             HICON hIcon )
Alexandre Julliard's avatar
Alexandre Julliard committed
817
{   ABOUT_INFO info;
818 819
    HRSRC hRes;
    LPVOID template;
820
    TRACE("\n");
821 822 823 824 825 826

    if(!(hRes = FindResourceA(shell32_hInstance, "SHELL_ABOUT_MSGBOX", RT_DIALOGA)))
        return FALSE;
    if(!(template = (LPVOID)LoadResource(shell32_hInstance, hRes)))
        return FALSE;

Alexandre Julliard's avatar
Alexandre Julliard committed
827 828 829
    info.szApp        = szApp;
    info.szOtherStuff = szOtherStuff;
    info.hIcon        = hIcon;
830
    if (!hIcon) info.hIcon = LoadIconA( 0, IDI_WINLOGOA );
831
    return DialogBoxIndirectParamA( GetWindowLongA( hWnd, GWL_HINSTANCE ),
832
                                      template, hWnd, AboutDlgProc, (LPARAM)&info );
Alexandre Julliard's avatar
Alexandre Julliard committed
833 834 835 836
}


/*************************************************************************
837
 * ShellAboutW				[SHELL32.289]
Alexandre Julliard's avatar
Alexandre Julliard committed
838
 */
839 840 841
BOOL WINAPI ShellAboutW( HWND hWnd, LPCWSTR szApp, LPCWSTR szOtherStuff,
                             HICON hIcon )
{   BOOL ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
842
    ABOUT_INFO info;
843 844
    HRSRC hRes;
    LPVOID template;
Alexandre Julliard's avatar
Alexandre Julliard committed
845

846
    TRACE("\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
847
    
848 849 850 851 852
    if(!(hRes = FindResourceA(shell32_hInstance, "SHELL_ABOUT_MSGBOX", RT_DIALOGA)))
        return FALSE;
    if(!(template = (LPVOID)LoadResource(shell32_hInstance, hRes)))
        return FALSE;

Alexandre Julliard's avatar
Alexandre Julliard committed
853 854 855
    info.szApp        = HEAP_strdupWtoA( GetProcessHeap(), 0, szApp );
    info.szOtherStuff = HEAP_strdupWtoA( GetProcessHeap(), 0, szOtherStuff );
    info.hIcon        = hIcon;
856
    if (!hIcon) info.hIcon = LoadIconA( 0, IDI_WINLOGOA );
857
    ret = DialogBoxIndirectParamA( GetWindowLongA( hWnd, GWL_HINSTANCE ),
858
                                   template, hWnd, AboutDlgProc, (LPARAM)&info );
Alexandre Julliard's avatar
Alexandre Julliard committed
859 860 861 862 863 864
    HeapFree( GetProcessHeap(), 0, (LPSTR)info.szApp );
    HeapFree( GetProcessHeap(), 0, (LPSTR)info.szOtherStuff );
    return ret;
}

/*************************************************************************
865
 * FreeIconList (SHELL32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
866 867
 */
void WINAPI FreeIconList( DWORD dw )
868
{ FIXME("(%lx): stub\n",dw);
Alexandre Julliard's avatar
Alexandre Julliard committed
869 870
}

871
/***********************************************************************
872
 * DllGetVersion [SHELL32.@]
873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888
 *
 * Retrieves version information of the 'SHELL32.DLL'
 *
 * PARAMS
 *     pdvi [O] pointer to version information structure.
 *
 * RETURNS
 *     Success: S_OK
 *     Failure: E_INVALIDARG
 *
 * NOTES
 *     Returns version of a shell32.dll from IE4.01 SP1.
 */

HRESULT WINAPI SHELL32_DllGetVersion (DLLVERSIONINFO *pdvi)
{
889
	if (pdvi->cbSize != sizeof(DLLVERSIONINFO))
890
	{
891
	  WARN("wrong DLLVERSIONINFO size from app\n");
892 893 894 895 896 897 898 899
	  return E_INVALIDARG;
	}

	pdvi->dwMajorVersion = 4;
	pdvi->dwMinorVersion = 72;
	pdvi->dwBuildNumber = 3110;
	pdvi->dwPlatformID = 1;

900
	TRACE("%lu.%lu.%lu.%lu\n",
901 902 903 904 905
	   pdvi->dwMajorVersion, pdvi->dwMinorVersion,
	   pdvi->dwBuildNumber, pdvi->dwPlatformID);

	return S_OK;
}
906 907
/*************************************************************************
 * global variables of the shell32.dll
908
 * all are once per process
909 910
 *
 */
911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927
void	(WINAPI *pDLLInitComctl)(LPVOID);

LPVOID	(WINAPI *pCOMCTL32_Alloc) (INT);  
BOOL	(WINAPI *pCOMCTL32_Free) (LPVOID);  

HDPA	(WINAPI *pDPA_Create) (INT);  
INT	(WINAPI *pDPA_InsertPtr) (const HDPA, INT, LPVOID); 
BOOL	(WINAPI *pDPA_Sort) (const HDPA, PFNDPACOMPARE, LPARAM); 
LPVOID	(WINAPI *pDPA_GetPtr) (const HDPA, INT);   
BOOL	(WINAPI *pDPA_Destroy) (const HDPA); 
INT	(WINAPI *pDPA_Search) (const HDPA, LPVOID, INT, PFNDPACOMPARE, LPARAM, UINT);
LPVOID	(WINAPI *pDPA_DeletePtr) (const HDPA hdpa, INT i);
HANDLE  (WINAPI *pCreateMRUListA) (LPVOID lpcml);
DWORD   (WINAPI *pFreeMRUListA) (HANDLE hMRUList);
INT     (WINAPI *pAddMRUData) (HANDLE hList, LPCVOID lpData, DWORD cbData);
INT     (WINAPI *pFindMRUData) (HANDLE hList, LPCVOID lpData, DWORD cbData, LPINT lpRegNum);
INT     (WINAPI *pEnumMRUListA) (HANDLE hList, INT nItemPos, LPVOID lpBuffer, DWORD nBufferSize);
928

929
static HINSTANCE	hComctl32;
930

Juergen Schmied's avatar
Juergen Schmied committed
931
LONG		shell32_ObjCount = 0;
932
HINSTANCE	shell32_hInstance = 0; 
933 934 935
HIMAGELIST	ShellSmallIconList = 0;
HIMAGELIST	ShellBigIconList = 0;

Alexandre Julliard's avatar
Alexandre Julliard committed
936

937 938 939 940 941 942 943 944 945
/*************************************************************************
 * SHELL32 LibMain
 *
 * NOTES
 *  calling oleinitialize here breaks sone apps.
 */

BOOL WINAPI Shell32LibMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
{
946
	TRACE("0x%x 0x%lx %p\n", hinstDLL, fdwReason, fImpLoad);
Alexandre Julliard's avatar
Alexandre Julliard committed
947

948
	switch (fdwReason)
949 950
	{
	  case DLL_PROCESS_ATTACH:
951
	    shell32_hInstance = hinstDLL;
Juergen Schmied's avatar
Juergen Schmied committed
952 953
	    hComctl32 = GetModuleHandleA("COMCTL32.DLL");	
	    DisableThreadLibraryCalls(shell32_hInstance);
954

955
	    if (!hComctl32)
956
	    {
957
	      ERR("P A N I C SHELL32 loading failed\n");
958
	      return FALSE;
959
	    }
960 961 962 963 964 965 966 967 968 969 970 971

	    /* comctl32 */
	    pDLLInitComctl=(void*)GetProcAddress(hComctl32,"InitCommonControlsEx");
	    pCOMCTL32_Alloc=(void*)GetProcAddress(hComctl32, (LPCSTR)71L);
	    pCOMCTL32_Free=(void*)GetProcAddress(hComctl32, (LPCSTR)73L);
	    pDPA_Create=(void*)GetProcAddress(hComctl32, (LPCSTR)328L);
	    pDPA_Destroy=(void*)GetProcAddress(hComctl32, (LPCSTR)329L);
	    pDPA_GetPtr=(void*)GetProcAddress(hComctl32, (LPCSTR)332L);
	    pDPA_InsertPtr=(void*)GetProcAddress(hComctl32, (LPCSTR)334L);
	    pDPA_DeletePtr=(void*)GetProcAddress(hComctl32, (LPCSTR)336L);
	    pDPA_Sort=(void*)GetProcAddress(hComctl32, (LPCSTR)338L);
	    pDPA_Search=(void*)GetProcAddress(hComctl32, (LPCSTR)339L);
972 973 974 975 976
	    pCreateMRUListA=(void*)GetProcAddress(hComctl32, (LPCSTR)151L /*"CreateMRUListA"*/);
	    pFreeMRUListA=(void*)GetProcAddress(hComctl32, (LPCSTR)152L /*"FreeMRUList"*/);
	    pAddMRUData=(void*)GetProcAddress(hComctl32, (LPCSTR)167L /*"AddMRUData"*/);
	    pFindMRUData=(void*)GetProcAddress(hComctl32, (LPCSTR)169L /*"FindMRUData"*/);
	    pEnumMRUListA=(void*)GetProcAddress(hComctl32, (LPCSTR)154L /*"EnumMRUListA"*/);
977 978 979 980 981 982 983 984

	    /* initialize the common controls */
	    if (pDLLInitComctl)
	    {
	      pDLLInitComctl(NULL);
	    }

	    SIC_Initialize();
Juergen Schmied's avatar
Juergen Schmied committed
985
	    SYSTRAY_Init();
986 987
	    InitChangeNotifications();
	    SHInitRestricted(NULL, NULL);
988 989 990 991 992 993 994 995 996
	    break;

	  case DLL_THREAD_ATTACH:
	    break;

	  case DLL_THREAD_DETACH:
	    break;

	  case DLL_PROCESS_DETACH:
997
	      shell32_hInstance = 0;
998 999

	      if (pdesktopfolder) 
1000 1001
	      {
	        IShellFolder_Release(pdesktopfolder);
1002
	        pdesktopfolder = NULL;
1003 1004
	      }

1005
	      SIC_Destroy();
1006 1007
	      FreeChangeNotifications();
	      
1008
	      /* this one is here to check if AddRef/Release is balanced */
1009
	      if (shell32_ObjCount)
1010
	      {
Juergen Schmied's avatar
Juergen Schmied committed
1011
	        WARN("leaving with %lu objects left (memory leak)\n", shell32_ObjCount);
1012
	      }
1013
              break;
1014 1015
	}
	return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1016
}
1017 1018

/*************************************************************************
1019
 * DllInstall         [SHELL32.@]
1020 1021 1022 1023 1024 1025 1026
 *
 * PARAMETERS
 *   
 *    BOOL bInstall - TRUE for install, FALSE for uninstall
 *    LPCWSTR pszCmdLine - command line (unused by shell32?)
 */

1027
HRESULT WINAPI SHELL32_DllInstall(BOOL bInstall, LPCWSTR cmdline)
1028
{
1029
   FIXME("(%s, %s): stub!\n", bInstall ? "TRUE":"FALSE", debugstr_w(cmdline));
1030 1031 1032

   return S_OK;		/* indicate success */
}
Andreas Mohr's avatar
Andreas Mohr committed
1033 1034 1035 1036 1037 1038 1039 1040 1041 1042

/***********************************************************************
 *              DllCanUnloadNow (SHELL32.@)
 */
HRESULT WINAPI SHELL32_DllCanUnloadNow(void)
{
    FIXME("(void): stub\n");

    return S_FALSE;
}