Sync with trunk head (r48786)
authorTimo Kreuzer <timo.kreuzer@reactos.org>
Fri, 17 Sep 2010 16:17:17 +0000 (16:17 +0000)
committerTimo Kreuzer <timo.kreuzer@reactos.org>
Fri, 17 Sep 2010 16:17:17 +0000 (16:17 +0000)
svn path=/branches/reactos-yarotows/; revision=48787

172 files changed:
1  2 
ReactOS-arm.rbuild
base/setup/usetup/bootsup.c
base/setup/usetup/bootsup.h
base/setup/usetup/interface/usetup.c
base/setup/usetup/lang/bg-BG.h
base/setup/usetup/lang/cs-CZ.h
base/setup/usetup/lang/de-DE.h
base/setup/usetup/lang/el-GR.h
base/setup/usetup/lang/en-US.h
base/setup/usetup/lang/es-ES.h
base/setup/usetup/lang/et-EE.h
base/setup/usetup/lang/fr-FR.h
base/setup/usetup/lang/it-IT.h
base/setup/usetup/lang/ja-JP.h
base/setup/usetup/lang/lt-LT.h
base/setup/usetup/lang/nl-NL.h
base/setup/usetup/lang/pl-PL.h
base/setup/usetup/lang/ru-RU.h
base/setup/usetup/lang/sk-SK.h
base/setup/usetup/lang/sv-SE.h
base/setup/usetup/lang/uk-UA.h
base/setup/usetup/partlist.c
base/setup/usetup/usetup.h
base/system/services/services.c
base/system/winlogon/winlogon.c
boot/freeldr/freeldr/arch/amd64/fathelp.S
boot/freeldr/freeldr/disk/scsiport.c
boot/freeldr/freeldr/freeldr.rbuild
boot/freeldr/freeldr/freeldr_base.rbuild
boot/freeldr/freeldr/setupldr.rbuild
boot/freeldr/freeldr/windows/headless.c
boot/freeldr/freeldr/windows/winldr.c
dll/cpl/desk/effappdlg.c
dll/cpl/desk/preview.c
dll/cpl/desk/theme.c
dll/win32/batt/batt.c
dll/win32/batt/batt.spec
dll/win32/gdi32/objects/palette.c
dll/win32/kernel32/file/bintype.c
dll/win32/kernel32/file/copy.c
dll/win32/kernel32/file/create.c
dll/win32/kernel32/file/curdir.c
dll/win32/lsasrv/lsasrv.c
dll/win32/shell32/shelllink.c
drivers/base/nmidebug/nmidebug.c
drivers/bus/pcix/debug.c
drivers/bus/pcix/device.c
drivers/bus/pcix/enum.c
drivers/bus/pcix/fdo.c
drivers/bus/pcix/intrface/cardbus.c
drivers/bus/pcix/pci.h
drivers/bus/pcix/pci/ppbridge.c
drivers/bus/pcix/pdo.c
drivers/bus/pcix/utils.c
drivers/network/ndis/ndis/time.c
drivers/storage/scsiport/scsiport.c
drivers/storage/scsiport/scsiport_int.h
drivers/usb/usbehci/common.c
drivers/usb/usbehci/fdo.c
drivers/usb/usbehci/irp.c
drivers/usb/usbehci/misc.c
drivers/usb/usbehci/pdo.c
drivers/usb/usbehci/urbreq.c
drivers/usb/usbehci/usbehci.c
drivers/usb/usbehci/usbehci.h
drivers/usb/usbehci/usbiffn.c
drivers/usb/usbhub/fdo.c
drivers/usb/usbhub/misc.c
drivers/usb/usbhub/pdo.c
drivers/usb/usbhub/usbhub.c
drivers/usb/usbhub/usbhub.h
drivers/usb/usbhub/usbhub.rbuild
drivers/video/videoprt/int10.c
hal/halx86/generic/halinit.c
hal/halx86/generic/i386/systimer.S
hal/halx86/generic/legacy/bussupp.c
hal/halx86/generic/legacy/halpcat.c
hal/halx86/generic/misc.c
hal/halx86/generic/timer.c
hal/halx86/hal_mini.rbuild
hal/halx86/include/halp.h
include/crt/_mingw.h
include/ddk/usbdlib.h
include/ndk/i386/asm.h
include/ndk/ketypes.h
include/psdk/d3d9types.h
include/psdk/d3dtypes.h
include/psdk/winuser.h
include/psdk/ws2tcpip.h
include/reactos/drivers/serial/ns16550.h
include/reactos/libs/cportlib/cportlib.h
lib/3rdparty/freetype/freetype.def
lib/cportlib/cport.c
lib/cportlib/cportlib.rbuild
lib/drivers/ip/network/ip.c
lib/drivers/ip/transport/tcp/if.c
lib/drivers/oskittcp/oskittcp/interface.c
lib/lib.rbuild
media/inf/fdc.inf
media/inf/hdc.inf
ntoskrnl/cc/view.c
ntoskrnl/config/cmparse.c
ntoskrnl/config/cmsysini.c
ntoskrnl/config/cmvalche.c
ntoskrnl/config/i386/cmhardwr.c
ntoskrnl/ex/hdlsterm.c
ntoskrnl/ex/sysinfo.c
ntoskrnl/ex/xipdisp.c
ntoskrnl/inbv/inbv.c
ntoskrnl/inbv/inbvport.c
ntoskrnl/include/internal/hdl.h
ntoskrnl/include/internal/i386/ke.h
ntoskrnl/include/internal/inbv.h
ntoskrnl/include/internal/io.h
ntoskrnl/include/internal/ntoskrnl.h
ntoskrnl/io/iomgr/driver.c
ntoskrnl/io/iomgr/iomgr.c
ntoskrnl/io/iomgr/rawfs.c
ntoskrnl/io/pnpmgr/pnpmgr.c
ntoskrnl/io/pnpmgr/pnproot.c
ntoskrnl/kdbg/i386/i386-dis.c
ntoskrnl/kdbg/kdb_cli.c
ntoskrnl/ke/bug.c
ntoskrnl/ke/eventobj.c
ntoskrnl/ke/i386/irqobj.c
ntoskrnl/ke/i386/traphdlr.c
ntoskrnl/ke/i386/v86vdm.c
ntoskrnl/mm/ARM3/i386/init.c
ntoskrnl/mm/ARM3/mdlsup.c
ntoskrnl/mm/ARM3/pagfault.c
ntoskrnl/mm/ARM3/pool.c
ntoskrnl/mm/ARM3/procsup.c
ntoskrnl/mm/ARM3/sysldr.c
ntoskrnl/mm/ARM3/virtual.c
ntoskrnl/mm/freelist.c
ntoskrnl/mm/i386/page.c
ntoskrnl/mm/ppool.c
ntoskrnl/mm/procsup.c
ntoskrnl/mm/section.c
ntoskrnl/ntoskrnl-generic.rbuild
ntoskrnl/ob/obhandle.c
ntoskrnl/ob/oblife.c
ntoskrnl/po/power.c
ntoskrnl/ps/kill.c
ntoskrnl/ps/psmgr.c
ntoskrnl/ps/thread.c
ntoskrnl/se/token.c
subsystems/win32/win32k/dib/dib1bpp.c
subsystems/win32/win32k/dib/dib8bpp.c
subsystems/win32/win32k/eng/bitblt.c
subsystems/win32/win32k/eng/paint.c
subsystems/win32/win32k/ntuser/class.c
subsystems/win32/win32k/ntuser/clipboard.c
subsystems/win32/win32k/ntuser/cursoricon.c
subsystems/win32/win32k/ntuser/event.c
subsystems/win32/win32k/ntuser/input.c
subsystems/win32/win32k/ntuser/keyboard.c
subsystems/win32/win32k/ntuser/menu.c
subsystems/win32/win32k/ntuser/message.c
subsystems/win32/win32k/ntuser/ntuser.c
subsystems/win32/win32k/ntuser/painting.c
subsystems/win32/win32k/ntuser/prop.c
subsystems/win32/win32k/ntuser/scrollbar.c
subsystems/win32/win32k/ntuser/simplecall.c
subsystems/win32/win32k/ntuser/window.c
subsystems/win32/win32k/ntuser/winsta.c
subsystems/win32/win32k/objects/dcattr.c
subsystems/win32/win32k/objects/freetype.c
subsystems/win32/win32k/objects/gdibatch.c
subsystems/win32/win32k/objects/palette.c
subsystems/win32/win32k/objects/path.c
subsystems/win32/win32k/objects/region.c

Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index ae159cd,0000000..53441ba
mode 100644,000000..100644
--- /dev/null
@@@ -1,2936 -1,0 +1,2985 @@@
-       {
 +/*
 + *
 + *      Copyright 1997  Marcus Meissner
 + *      Copyright 1998  Juergen Schmied
 + *      Copyright 2005  Mike McCormack
 + *
 + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 + *
 + * NOTES
 + *   Nearly complete information about the binary formats
 + *   of .lnk files available at http://www.wotsit.org
 + *
 + *  You can use winedump to examine the contents of a link file:
 + *   winedump lnk sc.lnk
 + *
 + *  MSI advertised shortcuts are totally undocumented.  They provide an
 + *   icon for a program that is not yet installed, and invoke MSI to
 + *   install the program when the shortcut is clicked on.  They are
 + *   created by passing a special string to SetPath, and the information
 + *   in that string is parsed an stored.
 + */
 +
 +#include <precomp.h>
 +
 +WINE_DEFAULT_DEBUG_CHANNEL(shell);
 +
 +/* link file formats */
 +
 +#include "pshpack1.h"
 +
 +typedef struct _LINK_HEADER
 +{
 +      DWORD    dwSize;        /* 0x00 size of the header - 0x4c */
 +      GUID     MagicGuid;     /* 0x04 is CLSID_ShellLink */
 +      DWORD    dwFlags;       /* 0x14 describes elements following */
 +      DWORD    dwFileAttr;    /* 0x18 attributes of the target file */
 +      FILETIME Time1;         /* 0x1c */
 +      FILETIME Time2;         /* 0x24 */
 +      FILETIME Time3;         /* 0x2c */
 +      DWORD    dwFileLength;  /* 0x34 File length */
 +      DWORD    nIcon;         /* 0x38 icon number */
 +      DWORD   fStartup;       /* 0x3c startup type */
 +      DWORD   wHotKey;        /* 0x40 hotkey */
 +      DWORD   Unknown5;       /* 0x44 */
 +      DWORD   Unknown6;       /* 0x48 */
 +} LINK_HEADER, * PLINK_HEADER;
 +
 +#define SHLINK_LOCAL  0
 +#define SHLINK_REMOTE 1
 +#define MAX_PROPERTY_SHEET_PAGE 32
 +
 +typedef struct _LOCATION_INFO
 +{
 +    DWORD  dwTotalSize;
 +    DWORD  dwHeaderSize;
 +    DWORD  dwFlags;
 +    DWORD  dwVolTableOfs;
 +    DWORD  dwLocalPathOfs;
 +    DWORD  dwNetworkVolTableOfs;
 +    DWORD  dwFinalPathOfs;
 +} LOCATION_INFO;
 +
 +typedef struct _LOCAL_VOLUME_INFO
 +{
 +    DWORD dwSize;
 +    DWORD dwType;
 +    DWORD dwVolSerial;
 +    DWORD dwVolLabelOfs;
 +} LOCAL_VOLUME_INFO;
 +
 +typedef struct volume_info_t
 +{
 +    DWORD type;
 +    DWORD serial;
 +    WCHAR label[12];  /* assume 8.3 */
 +} volume_info;
 +
 +#include "poppack.h"
 +
 +static const IShellLinkAVtbl slvt;
 +static const IShellLinkWVtbl slvtw;
 +static const IPersistFileVtbl pfvt;
 +static const IPersistStreamVtbl psvt;
 +static const IShellLinkDataListVtbl dlvt;
 +static const IShellExtInitVtbl eivt;
 +static const IContextMenuVtbl cmvt;
 +static const IObjectWithSiteVtbl owsvt;
 +static const IShellPropSheetExtVtbl pse;
 +
 +/* IShellLink Implementation */
 +
 +typedef struct
 +{
 +      const IShellLinkAVtbl *lpVtbl;
 +      const IShellLinkWVtbl *lpvtblw;
 +      const IPersistFileVtbl *lpvtblPersistFile;
 +      const IPersistStreamVtbl *lpvtblPersistStream;
 +      const IShellLinkDataListVtbl *lpvtblShellLinkDataList;
 +      const IShellExtInitVtbl *lpvtblShellExtInit;
 +      const IContextMenuVtbl *lpvtblContextMenu;
 +      const IObjectWithSiteVtbl *lpvtblObjectWithSite;
 +      const IShellPropSheetExtVtbl * lpvtblPropSheetExt;
 +
 +      LONG            ref;
 +
 +      /* data structures according to the information in the link */
 +      LPITEMIDLIST    pPidl;
 +      WORD            wHotKey;
 +      SYSTEMTIME      time1;
 +      SYSTEMTIME      time2;
 +      SYSTEMTIME      time3;
 +
 +      DWORD         iShowCmd;
 +      LPWSTR        sIcoPath;
 +      INT           iIcoNdx;
 +      LPWSTR        sPath;
 +      LPWSTR        sArgs;
 +      LPWSTR        sWorkDir;
 +      LPWSTR        sDescription;
 +      LPWSTR        sPathRel;
 +      LPWSTR        sProduct;
 +      LPWSTR        sComponent;
 +      volume_info   volume;
 +    LPWSTR        sLinkPath;
++    LPWSTR        sCurFile;
 +    BOOL          bRunAs;
 +      BOOL          bDirty;
 +        INT           iIdOpen;  /* id of the "Open" entry in the context menu */
 +      IUnknown      *site;
 +} IShellLinkImpl, *LPIShellLinkImpl;
 +
 +static LPIShellLinkImpl __inline impl_from_IShellLinkW( IShellLinkW *iface )
 +{
 +    return (IShellLinkImpl *)((char*)iface - FIELD_OFFSET(IShellLinkImpl, lpvtblw));
 +}
 +
 +static LPIShellLinkImpl __inline impl_from_IPersistFile( IPersistFile *iface )
 +{
 +    return (IShellLinkImpl *)((char*)iface - FIELD_OFFSET(IShellLinkImpl, lpvtblPersistFile));
 +}
 +
 +static LPIShellLinkImpl __inline impl_from_IPersistStream( IPersistStream *iface )
 +{
 +    return (IShellLinkImpl *)((char*)iface - FIELD_OFFSET(IShellLinkImpl, lpvtblPersistStream));
 +}
 +
 +static LPIShellLinkImpl __inline impl_from_IShellLinkDataList( IShellLinkDataList *iface )
 +{
 +    return (IShellLinkImpl *)((char*)iface - FIELD_OFFSET(IShellLinkImpl, lpvtblShellLinkDataList));
 +}
 +
 +static LPIShellLinkImpl __inline impl_from_IShellExtInit( IShellExtInit *iface )
 +{
 +    return (IShellLinkImpl *)((char*)iface - FIELD_OFFSET(IShellLinkImpl, lpvtblShellExtInit));
 +}
 +
 +static LPIShellLinkImpl __inline impl_from_IContextMenu( IContextMenu *iface )
 +{
 +    return (IShellLinkImpl *)((char*)iface - FIELD_OFFSET(IShellLinkImpl, lpvtblContextMenu));
 +}
 +
 +static LPIShellLinkImpl __inline impl_from_IObjectWithSite( IObjectWithSite *iface )
 +{
 +    return (IShellLinkImpl *)((char*)iface - FIELD_OFFSET(IShellLinkImpl, lpvtblObjectWithSite));
 +}
 +
 +static LPIShellLinkImpl __inline impl_from_IShellPropSheetExt( IShellPropSheetExt *iface )
 +{
 +    return (IShellLinkImpl *)((char*)iface - FIELD_OFFSET(IShellLinkImpl, lpvtblPropSheetExt));
 +}
 +
 +
 +static HRESULT ShellLink_UpdatePath(LPCWSTR sPathRel, LPCWSTR path, LPCWSTR sWorkDir, LPWSTR* psPath);
 +
 +/* strdup on the process heap */
 +static LPWSTR __inline HEAP_strdupAtoW( HANDLE heap, DWORD flags, LPCSTR str)
 +{
++    assert(str);
 +    INT len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
 +    LPWSTR p = HeapAlloc( heap, flags, len*sizeof (WCHAR) );
 +    if( !p )
 +        return p;
 +    MultiByteToWideChar( CP_ACP, 0, str, -1, p, len );
 +    return p;
 +}
 +
 +static LPWSTR __inline strdupW( LPCWSTR src )
 +{
 +    LPWSTR dest;
 +    if (!src) return NULL;
 +    dest = HeapAlloc( GetProcessHeap(), 0, (wcslen(src)+1)*sizeof(WCHAR) );
 +    if (dest)
 +        wcscpy(dest, src);
 +    return dest;
 +}
 +
 +/**************************************************************************
 + *  ShellLink::QueryInterface implementation
 + */
 +static HRESULT ShellLink_QueryInterface( IShellLinkImpl *This, REFIID riid,  LPVOID *ppvObj)
 +{
 +    TRACE("(%p)->(\n\tIID:\t%s)\n",This,debugstr_guid(riid));
 +
 +    *ppvObj = NULL;
 +
 +    if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IShellLinkA))
 +    {
 +        *ppvObj = This;
 +    }
 +    else if(IsEqualIID(riid, &IID_IShellLinkW))
 +    {
 +        *ppvObj = &(This->lpvtblw);
 +    }
 +    else if(IsEqualIID(riid, &IID_IPersistFile))
 +    {
 +        *ppvObj = &(This->lpvtblPersistFile);
 +    }
 +    else if(IsEqualIID(riid, &IID_IPersistStream))
 +    {
 +        *ppvObj = &(This->lpvtblPersistStream);
 +    }
 +    else if(IsEqualIID(riid, &IID_IShellLinkDataList))
 +    {
 +        *ppvObj = &(This->lpvtblShellLinkDataList);
 +    }
 +    else if(IsEqualIID(riid, &IID_IShellExtInit))
 +    {
 +        *ppvObj = &(This->lpvtblShellExtInit);
 +    }
 +    else if(IsEqualIID(riid, &IID_IContextMenu))
 +    {
 +        *ppvObj = &(This->lpvtblContextMenu);
 +    }
 +    else if(IsEqualIID(riid, &IID_IObjectWithSite))
 +    {
 +        *ppvObj = &(This->lpvtblObjectWithSite);
 +    }
 +    else if(IsEqualIID(riid, &IID_IShellPropSheetExt))
 +    {
 +        *ppvObj = &(This->lpvtblPropSheetExt);
 +    }
 +
 +    if(*ppvObj)
 +    {
 +        IUnknown_AddRef((IUnknown*)(*ppvObj));
 +        TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
 +        return S_OK;
 +    }
 +    ERR("-- Interface: E_NOINTERFACE\n");
 +    return E_NOINTERFACE;
 +}
 +
 +/**************************************************************************
 + *  ShellLink::AddRef implementation
 + */
 +static ULONG ShellLink_AddRef( IShellLinkImpl *This )
 +{
 +    ULONG refCount = InterlockedIncrement(&This->ref);
 +
 +    TRACE("(%p)->(count=%u)\n", This, refCount - 1);
 +
 +    return refCount;
 +}
 +
 +/**************************************************************************
 + *  ShellLink::Release implementation
 + */
 +static ULONG ShellLink_Release( IShellLinkImpl *This )
 +{
 +    ULONG refCount = InterlockedDecrement(&This->ref);
 +
 +    TRACE("(%p)->(count=%u)\n", This, refCount + 1);
 +
 +    if (refCount)
 +        return refCount;
 +
 +    TRACE("-- destroying IShellLink(%p)\n",This);
 +
 +    HeapFree(GetProcessHeap(), 0, This->sIcoPath);
 +    HeapFree(GetProcessHeap(), 0, This->sArgs);
 +    HeapFree(GetProcessHeap(), 0, This->sWorkDir);
 +    HeapFree(GetProcessHeap(), 0, This->sDescription);
 +    HeapFree(GetProcessHeap(),0,This->sPath);
 +    HeapFree(GetProcessHeap(),0,This->sLinkPath);
 +
 +    if (This->site)
 +        IUnknown_Release( This->site );
 +
 +    if (This->pPidl)
 +        ILFree(This->pPidl);
 +
 +    LocalFree(This);
 +
 +    return 0;
 +}
 +
 +static HRESULT ShellLink_GetClassID( IShellLinkImpl *This, CLSID *pclsid )
 +{
 +    TRACE("%p %p\n", This, pclsid);
 +
 +    *pclsid = CLSID_ShellLink;
 +    return S_OK;
 +}
 +
 +/**************************************************************************
 + *  IPersistFile_QueryInterface
 + */
 +static HRESULT WINAPI IPersistFile_fnQueryInterface(
 +      IPersistFile* iface,
 +      REFIID riid,
 +      LPVOID *ppvObj)
 +{
 +    IShellLinkImpl *This = impl_from_IPersistFile(iface);
 +    return ShellLink_QueryInterface( This, riid, ppvObj );
 +}
 +
 +/******************************************************************************
 + * IPersistFile_AddRef
 + */
 +static ULONG WINAPI IPersistFile_fnAddRef(IPersistFile* iface)
 +{
 +    IShellLinkImpl *This = impl_from_IPersistFile(iface);
 +    return ShellLink_AddRef( This );
 +}
 +
 +/******************************************************************************
 + * IPersistFile_Release
 + */
 +static ULONG WINAPI IPersistFile_fnRelease(IPersistFile* iface)
 +{
 +    IShellLinkImpl *This = impl_from_IPersistFile(iface);
 +    return IShellLinkA_Release((IShellLinkA*)This);
 +}
 +
 +static HRESULT WINAPI IPersistFile_fnGetClassID(IPersistFile* iface, CLSID *pClassID)
 +{
 +    IShellLinkImpl *This = impl_from_IPersistFile(iface);
 +    return ShellLink_GetClassID( This, pClassID );
 +}
 +
 +static HRESULT WINAPI IPersistFile_fnIsDirty(IPersistFile* iface)
 +{
 +      IShellLinkImpl *This = impl_from_IPersistFile(iface);
 +
 +      TRACE("(%p)\n",This);
 +
 +      if (This->bDirty)
 +          return S_OK;
 +
 +      return S_FALSE;
 +}
 +
 +static HRESULT WINAPI IPersistFile_fnLoad(IPersistFile* iface, LPCOLESTR pszFileName, DWORD dwMode)
 +{
 +      IShellLinkImpl *This = impl_from_IPersistFile(iface);
 +      IPersistStream *StreamThis = (IPersistStream *)&This->lpvtblPersistStream;
 +        HRESULT r;
 +        IStream *stm;
 +
 +        TRACE("(%p, %s, %x)\n",This, debugstr_w(pszFileName), dwMode);
 +
 +        if( dwMode == 0 )
 +              dwMode = STGM_READ | STGM_SHARE_DENY_WRITE;
 +        r = SHCreateStreamOnFileW(pszFileName, dwMode, &stm);
 +        if( SUCCEEDED( r ) )
 +        {
 +            HeapFree(GetProcessHeap(), 0, This->sLinkPath);
 +            This->sLinkPath = strdupW(pszFileName);
 +            r = IPersistStream_Load(StreamThis, stm);
 +            ShellLink_UpdatePath(This->sPathRel, pszFileName, This->sWorkDir, &This->sPath);
 +            IStream_Release( stm );
 +            This->bDirty = FALSE;
 +        }
 +        TRACE("-- returning hr %08x\n", r);
 +        return r;
 +}
 +
 +static BOOL StartLinkProcessor( LPCOLESTR szLink )
 +{
 +    static const WCHAR szFormat[] = {
 +        'w','i','n','e','m','e','n','u','b','u','i','l','d','e','r','.','e','x','e',
 +        ' ','-','w',' ','"','%','s','"',0 };
 +    LONG len;
 +    LPWSTR buffer;
 +    STARTUPINFOW si;
 +    PROCESS_INFORMATION pi;
 +    BOOL ret;
 +
 +    len = sizeof(szFormat) + wcslen( szLink ) * sizeof(WCHAR);
 +    buffer = HeapAlloc( GetProcessHeap(), 0, len );
 +    if( !buffer )
 +        return FALSE;
 +
 +    swprintf( buffer, szFormat, szLink );
 +
 +    TRACE("starting %s\n",debugstr_w(buffer));
 +
 +    memset(&si, 0, sizeof(si));
 +    si.cb = sizeof(si);
 +
 +    ret = CreateProcessW( NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi );
 +
 +    HeapFree( GetProcessHeap(), 0, buffer );
 +
 +    if (ret)
 +    {
 +        CloseHandle( pi.hProcess );
 +        CloseHandle( pi.hThread );
 +    }
 +
 +    return ret;
 +}
 +
 +static HRESULT WINAPI IPersistFile_fnSave(IPersistFile* iface, LPCOLESTR pszFileName, BOOL fRemember)
 +{
 +    IShellLinkImpl *This = impl_from_IPersistFile(iface);
 +    IPersistStream *StreamThis = (IPersistStream *)&This->lpvtblPersistStream;
 +    HRESULT r;
 +    IStream *stm;
 +
 +    TRACE("(%p)->(%s)\n",This,debugstr_w(pszFileName));
 +
 +    if (!pszFileName)
 +        return E_FAIL;
 +
 +    r = SHCreateStreamOnFileW( pszFileName, STGM_READWRITE | STGM_CREATE | STGM_SHARE_EXCLUSIVE, &stm );
 +    if( SUCCEEDED( r ) )
 +    {
 +        r = IPersistStream_Save(StreamThis, stm, FALSE);
 +        IStream_Release( stm );
 +
 +        if( SUCCEEDED( r ) )
-       else
++        {
++            if ( This->sCurFile )
++            {
++                HeapFree(GetProcessHeap(), 0, This->sCurFile);
++            }
++            This->sCurFile = HeapAlloc(GetProcessHeap(), 0, (wcslen(pszFileName)+1) * sizeof(WCHAR));
++            if ( This->sCurFile )
++            {
++                wcscpy(This->sCurFile, pszFileName);
++            }
++
 +            StartLinkProcessor( pszFileName );
 +
 +            This->bDirty = FALSE;
 +        }
-       IShellLinkImpl *This = impl_from_IPersistFile(iface);
-       FIXME("(%p)\n",This);
-       return NOERROR;
++        else
 +        {
 +            DeleteFileW( pszFileName );
 +            WARN("Failed to create shortcut %s\n", debugstr_w(pszFileName) );
 +        }
 +    }
 +
 +    return r;
 +}
 +
 +static HRESULT WINAPI IPersistFile_fnSaveCompleted(IPersistFile* iface, LPCOLESTR pszFileName)
 +{
 +      IShellLinkImpl *This = impl_from_IPersistFile(iface);
 +      FIXME("(%p)->(%s)\n",This,debugstr_w(pszFileName));
 +      return NOERROR;
 +}
 +
 +static HRESULT WINAPI IPersistFile_fnGetCurFile(IPersistFile* iface, LPOLESTR *ppszFileName)
 +{
-     if (This->sComponent || This->sProduct)
-         return S_FALSE;
++    IShellLinkImpl *This = impl_from_IPersistFile(iface);
++
++    *ppszFileName = NULL;
++
++    if ( !This->sCurFile)
++    {
++        /* IPersistFile::GetCurFile called before IPersistFile::Save */
++        return S_FALSE;
++    }
++
++    *ppszFileName = CoTaskMemAlloc((wcslen(This->sCurFile)+1) * sizeof(WCHAR));
++    if (!*ppszFileName)
++    {
++        /* out of memory */
++        return E_OUTOFMEMORY;
++    }
++
++    /* copy last saved filename */
++    wcscpy(*ppszFileName, This->sCurFile);
++
++    return NOERROR;
 +}
 +
 +static const IPersistFileVtbl pfvt =
 +{
 +      IPersistFile_fnQueryInterface,
 +      IPersistFile_fnAddRef,
 +      IPersistFile_fnRelease,
 +      IPersistFile_fnGetClassID,
 +      IPersistFile_fnIsDirty,
 +      IPersistFile_fnLoad,
 +      IPersistFile_fnSave,
 +      IPersistFile_fnSaveCompleted,
 +      IPersistFile_fnGetCurFile
 +};
 +
 +/************************************************************************
 + * IPersistStream_QueryInterface
 + */
 +static HRESULT WINAPI IPersistStream_fnQueryInterface(
 +      IPersistStream* iface,
 +      REFIID     riid,
 +      VOID**     ppvObj)
 +{
 +    IShellLinkImpl *This = impl_from_IPersistStream(iface);
 +    return ShellLink_QueryInterface( This, riid, ppvObj );
 +}
 +
 +/************************************************************************
 + * IPersistStream_Release
 + */
 +static ULONG WINAPI IPersistStream_fnRelease(
 +      IPersistStream* iface)
 +{
 +    IShellLinkImpl *This = impl_from_IPersistStream(iface);
 +    return IShellLinkA_Release((IShellLinkA*)This);
 +}
 +
 +/************************************************************************
 + * IPersistStream_AddRef
 + */
 +static ULONG WINAPI IPersistStream_fnAddRef(
 +      IPersistStream* iface)
 +{
 +    IShellLinkImpl *This = impl_from_IPersistStream(iface);
 +    return ShellLink_AddRef( This );
 +}
 +
 +/************************************************************************
 + * IPersistStream_GetClassID
 + *
 + */
 +static HRESULT WINAPI IPersistStream_fnGetClassID(
 +      IPersistStream* iface,
 +      CLSID* pClassID)
 +{
 +    IShellLinkImpl *This = impl_from_IPersistStream(iface);
 +    return ShellLink_GetClassID( This, pClassID );
 +}
 +
 +/************************************************************************
 + * IPersistStream_IsDirty (IPersistStream)
 + */
 +static HRESULT WINAPI IPersistStream_fnIsDirty(
 +      IPersistStream*  iface)
 +{
 +      IShellLinkImpl *This = impl_from_IPersistStream(iface);
 +
 +      TRACE("(%p)\n", This);
 +
 +      return S_OK;
 +}
 +
 +
 +static HRESULT Stream_LoadString( IStream* stm, BOOL unicode, LPWSTR *pstr )
 +{
 +    DWORD count;
 +    USHORT len;
 +    LPVOID temp;
 +    LPWSTR str;
 +    HRESULT r;
 +
 +    TRACE("%p\n", stm);
 +
 +    count = 0;
 +    r = IStream_Read(stm, &len, sizeof(len), &count);
 +    if ( FAILED (r) || ( count != sizeof(len) ) )
 +        return E_FAIL;
 +
 +    if( unicode )
 +        len *= sizeof (WCHAR);
 +
 +    TRACE("reading %d\n", len);
 +    temp = HeapAlloc(GetProcessHeap(), 0, len+sizeof(WCHAR));
 +    if( !temp )
 +        return E_OUTOFMEMORY;
 +    count = 0;
 +    r = IStream_Read(stm, temp, len, &count);
 +    if( FAILED (r) || ( count != len ) )
 +    {
 +        HeapFree( GetProcessHeap(), 0, temp );
 +        return E_FAIL;
 +    }
 +
 +    TRACE("read %s\n", debugstr_an(temp,len));
 +
 +    /* convert to unicode if necessary */
 +    if( !unicode )
 +    {
 +        count = MultiByteToWideChar( CP_ACP, 0, temp, len, NULL, 0 );
 +        str = HeapAlloc( GetProcessHeap(), 0, (count+1)*sizeof (WCHAR) );
 +        if( !str )
 +        {
 +            HeapFree( GetProcessHeap(), 0, temp );
 +            return E_OUTOFMEMORY;
 +        }
 +        MultiByteToWideChar( CP_ACP, 0, temp, len, str, count );
 +        HeapFree( GetProcessHeap(), 0, temp );
 +    }
 +    else
 +    {
 +        count /= 2;
 +        str = temp;
 +    }
 +    str[count] = 0;
 +
 +    *pstr = str;
 +
 +    return S_OK;
 +}
 +
 +static HRESULT Stream_ReadChunk( IStream* stm, LPVOID *data )
 +{
 +    DWORD size;
 +    ULONG count;
 +    HRESULT r;
 +    struct sized_chunk {
 +        DWORD size;
 +        unsigned char data[1];
 +    } *chunk;
 +
 +    TRACE("%p\n",stm);
 +
 +    r = IStream_Read( stm, &size, sizeof(size), &count );
 +    if( FAILED( r )  || count != sizeof(size) )
 +        return E_FAIL;
 +
 +    chunk = HeapAlloc( GetProcessHeap(), 0, size );
 +    if( !chunk )
 +        return E_OUTOFMEMORY;
 +
 +    chunk->size = size;
 +    r = IStream_Read( stm, chunk->data, size - sizeof(size), &count );
 +    if( FAILED( r ) || count != (size - sizeof(size)) )
 +    {
 +        HeapFree( GetProcessHeap(), 0, chunk );
 +        return E_FAIL;
 +    }
 +
 +    TRACE("Read %d bytes\n",chunk->size);
 +
 +    *data = chunk;
 +
 +    return S_OK;
 +}
 +
 +static BOOL Stream_LoadVolume( LOCAL_VOLUME_INFO *vol, volume_info *volume )
 +{
 +    const int label_sz = sizeof volume->label/sizeof volume->label[0];
 +    LPSTR label;
 +    int len;
 +
 +    volume->serial = vol->dwVolSerial;
 +    volume->type = vol->dwType;
 +
 +    if( !vol->dwVolLabelOfs )
 +        return FALSE;
 +    if( vol->dwSize <= vol->dwVolLabelOfs )
 +        return FALSE;
 +    len = vol->dwSize - vol->dwVolLabelOfs;
 +
 +    label = (LPSTR) vol;
 +    label += vol->dwVolLabelOfs;
 +    MultiByteToWideChar( CP_ACP, 0, label, len, volume->label, label_sz-1);
 +
 +    return TRUE;
 +}
 +
 +static LPWSTR Stream_LoadPath( LPCSTR p, DWORD maxlen )
 +{
 +    int len = 0, wlen;
 +    LPWSTR path;
 +
 +    while( p[len] && (len < maxlen) )
 +        len++;
 +
 +    wlen = MultiByteToWideChar(CP_ACP, 0, p, len, NULL, 0);
 +    path = HeapAlloc(GetProcessHeap(), 0, (wlen+1)*sizeof(WCHAR));
 +    MultiByteToWideChar(CP_ACP, 0, p, len, path, wlen);
 +    path[wlen] = 0;
 +
 +    return path;
 +}
 +
 +static HRESULT Stream_LoadLocation( IStream *stm,
 +                volume_info *volume, LPWSTR *path )
 +{
 +    char *p = NULL;
 +    LOCATION_INFO *loc;
 +    HRESULT r;
 +    DWORD n;
 +
 +    r = Stream_ReadChunk( stm, (LPVOID*) &p );
 +    if( FAILED(r) )
 +        return r;
 +
 +    loc = (LOCATION_INFO*) p;
 +    if (loc->dwTotalSize < sizeof(LOCATION_INFO))
 +    {
 +        HeapFree( GetProcessHeap(), 0, p );
 +        return E_FAIL;
 +    }
 +
 +    /* if there's valid local volume information, load it */
 +    if( loc->dwVolTableOfs &&
 +       ((loc->dwVolTableOfs + sizeof(LOCAL_VOLUME_INFO)) <= loc->dwTotalSize) )
 +    {
 +        LOCAL_VOLUME_INFO *volume_info;
 +
 +        volume_info = (LOCAL_VOLUME_INFO*) &p[loc->dwVolTableOfs];
 +        Stream_LoadVolume( volume_info, volume );
 +    }
 +
 +    /* if there's a local path, load it */
 +    n = loc->dwLocalPathOfs;
 +    if( n && (n < loc->dwTotalSize) )
 +        *path = Stream_LoadPath( &p[n], loc->dwTotalSize - n );
 +
 +    TRACE("type %d serial %08x name %s path %s\n", volume->type,
 +          volume->serial, debugstr_w(volume->label), debugstr_w(*path));
 +
 +    HeapFree( GetProcessHeap(), 0, p );
 +    return S_OK;
 +}
 +
 +/*
 + *  The format of the advertised shortcut info seems to be:
 + *
 + *  Offset     Description
 + *  ------     -----------
 + *
 + *    0          Length of the block (4 bytes, usually 0x314)
 + *    4          tag (dword)
 + *    8          string data in ASCII
 + *    8+0x104    string data in UNICODE
 + *
 + * In the original Win32 implementation the buffers are not initialized
 + *  to zero, so data trailing the string is random garbage.
 + */
 +static HRESULT Stream_LoadAdvertiseInfo( IStream* stm, LPWSTR *str )
 +{
 +    DWORD size;
 +    ULONG count;
 +    HRESULT r;
 +    EXP_DARWIN_LINK buffer;
 +
 +    TRACE("%p\n",stm);
 +
 +    r = IStream_Read( stm, &buffer.dbh.cbSize, sizeof (DWORD), &count );
 +    if( FAILED( r ) )
 +        return r;
 +
 +    /* make sure that we read the size of the structure even on error */
 +    size = sizeof buffer - sizeof (DWORD);
 +    if( buffer.dbh.cbSize != sizeof buffer )
 +    {
 +        ERR("Ooops.  This structure is not as expected...\n");
 +        return E_FAIL;
 +    }
 +
 +    r = IStream_Read( stm, &buffer.dbh.dwSignature, size, &count );
 +    if( FAILED( r ) )
 +        return r;
 +
 +    if( count != size )
 +        return E_FAIL;
 +
 +    TRACE("magic %08x  string = %s\n", buffer.dbh.dwSignature, debugstr_w(buffer.szwDarwinID));
 +
 +    if( (buffer.dbh.dwSignature&0xffff0000) != 0xa0000000 )
 +    {
 +        ERR("Unknown magic number %08x in advertised shortcut\n", buffer.dbh.dwSignature);
 +        return E_FAIL;
 +    }
 +
 +    *str = HeapAlloc( GetProcessHeap(), 0,
 +                     (wcslen(buffer.szwDarwinID)+1) * sizeof(WCHAR) );
 +    wcscpy( *str, buffer.szwDarwinID );
 +
 +    return S_OK;
 +}
 +
 +/************************************************************************
 + * IPersistStream_Load (IPersistStream)
 + */
 +static HRESULT WINAPI IPersistStream_fnLoad(
 +    IPersistStream*  iface,
 +    IStream*         stm)
 +{
 +    LINK_HEADER hdr;
 +    ULONG    dwBytesRead;
 +    BOOL     unicode;
 +    HRESULT  r;
 +    DWORD    zero;
 +
 +    IShellLinkImpl *This = impl_from_IPersistStream(iface);
 +
 +    TRACE("%p %p\n", This, stm);
 +
 +    if( !stm )
 +        return STG_E_INVALIDPOINTER;
 +
 +    dwBytesRead = 0;
 +    r = IStream_Read(stm, &hdr, sizeof(hdr), &dwBytesRead);
 +    if( FAILED( r ) )
 +        return r;
 +
 +    if( dwBytesRead != sizeof(hdr))
 +        return E_FAIL;
 +    if( hdr.dwSize != sizeof(hdr))
 +        return E_FAIL;
 +    if( !IsEqualIID(&hdr.MagicGuid, &CLSID_ShellLink) )
 +        return E_FAIL;
 +
 +    /* free all the old stuff */
 +    ILFree(This->pPidl);
 +    This->pPidl = NULL;
 +    memset( &This->volume, 0, sizeof This->volume );
 +    HeapFree(GetProcessHeap(), 0, This->sPath);
 +    This->sPath = NULL;
 +    HeapFree(GetProcessHeap(), 0, This->sDescription);
 +    This->sDescription = NULL;
 +    HeapFree(GetProcessHeap(), 0, This->sPathRel);
 +    This->sPathRel = NULL;
 +    HeapFree(GetProcessHeap(), 0, This->sWorkDir);
 +    This->sWorkDir = NULL;
 +    HeapFree(GetProcessHeap(), 0, This->sArgs);
 +    This->sArgs = NULL;
 +    HeapFree(GetProcessHeap(), 0, This->sIcoPath);
 +    This->sIcoPath = NULL;
 +    HeapFree(GetProcessHeap(), 0, This->sProduct);
 +    This->sProduct = NULL;
 +    HeapFree(GetProcessHeap(), 0, This->sComponent);
 +    This->sComponent = NULL;
 +
 +    This->wHotKey = (WORD)hdr.wHotKey;
 +    This->iIcoNdx = hdr.nIcon;
 +    FileTimeToSystemTime (&hdr.Time1, &This->time1);
 +    FileTimeToSystemTime (&hdr.Time2, &This->time2);
 +    FileTimeToSystemTime (&hdr.Time3, &This->time3);
 +    if (TRACE_ON(shell))
 +    {
 +        WCHAR sTemp[MAX_PATH];
 +        GetDateFormatW(LOCALE_USER_DEFAULT,DATE_SHORTDATE, &This->time1,
 +                       NULL, sTemp, sizeof(sTemp)/sizeof(*sTemp));
 +        TRACE("-- time1: %s\n", debugstr_w(sTemp) );
 +        GetDateFormatW(LOCALE_USER_DEFAULT,DATE_SHORTDATE, &This->time2,
 +                       NULL, sTemp, sizeof(sTemp)/sizeof(*sTemp));
 +        TRACE("-- time2: %s\n", debugstr_w(sTemp) );
 +        GetDateFormatW(LOCALE_USER_DEFAULT,DATE_SHORTDATE, &This->time3,
 +                       NULL, sTemp, sizeof(sTemp)/sizeof(*sTemp));
 +        TRACE("-- time3: %s\n", debugstr_w(sTemp) );
 +    }
 +
 +    /* load all the new stuff */
 +    if( hdr.dwFlags & SLDF_HAS_ID_LIST )
 +    {
 +        r = ILLoadFromStream( stm, &This->pPidl );
 +        if( FAILED( r ) )
 +            return r;
 +    }
 +    pdump(This->pPidl);
 +
 +    /* load the location information */
 +    if( hdr.dwFlags & SLDF_HAS_LINK_INFO )
 +        r = Stream_LoadLocation( stm, &This->volume, &This->sPath );
 +    if( FAILED( r ) )
 +        goto end;
 +
 +    unicode = hdr.dwFlags & SLDF_UNICODE;
 +    if( hdr.dwFlags & SLDF_HAS_NAME )
 +    {
 +        r = Stream_LoadString( stm, unicode, &This->sDescription );
 +        TRACE("Description  -> %s\n",debugstr_w(This->sDescription));
 +    }
 +    if( FAILED( r ) )
 +        goto end;
 +
 +    if( hdr.dwFlags & SLDF_HAS_RELPATH )
 +    {
 +        r = Stream_LoadString( stm, unicode, &This->sPathRel );
 +        TRACE("Relative Path-> %s\n",debugstr_w(This->sPathRel));
 +    }
 +    if( FAILED( r ) )
 +        goto end;
 +
 +    if( hdr.dwFlags & SLDF_HAS_WORKINGDIR )
 +    {
 +        r = Stream_LoadString( stm, unicode, &This->sWorkDir );
 +        TRACE("Working Dir  -> %s\n",debugstr_w(This->sWorkDir));
 +    }
 +    if( FAILED( r ) )
 +        goto end;
 +
 +    if( hdr.dwFlags & SLDF_HAS_ARGS )
 +    {
 +        r = Stream_LoadString( stm, unicode, &This->sArgs );
 +        TRACE("Working Dir  -> %s\n",debugstr_w(This->sArgs));
 +    }
 +    if( FAILED( r ) )
 +        goto end;
 +
 +    if( hdr.dwFlags & SLDF_HAS_ICONLOCATION )
 +    {
 +        r = Stream_LoadString( stm, unicode, &This->sIcoPath );
 +        TRACE("Icon file    -> %s\n",debugstr_w(This->sIcoPath));
 +    }
 +    if( FAILED( r ) )
 +        goto end;
 +
 +#if (NTDDI_VERSION < NTDDI_LONGHORN)
 +    if( hdr.dwFlags & SLDF_HAS_LOGO3ID )
 +    {
 +        r = Stream_LoadAdvertiseInfo( stm, &This->sProduct );
 +        TRACE("Product      -> %s\n",debugstr_w(This->sProduct));
 +    }
 +    if( FAILED( r ) )
 +        goto end;
 +#endif
 +
 +    if( hdr.dwFlags & SLDF_HAS_DARWINID )
 +    {
 +        r = Stream_LoadAdvertiseInfo( stm, &This->sComponent );
 +        TRACE("Component    -> %s\n",debugstr_w(This->sComponent));
 +    }
 +    if( hdr.dwFlags & SLDF_RUNAS_USER )
 +    {
 +       This->bRunAs = TRUE;
 +    }
 +    else
 +    {
 +       This->bRunAs = FALSE;
 +    }
 +
 +    if( FAILED( r ) )
 +        goto end;
 +
 +    r = IStream_Read(stm, &zero, sizeof zero, &dwBytesRead);
 +    if( FAILED( r ) || zero || dwBytesRead != sizeof zero )
 +        ERR("Last word was not zero\n");
 +
 +    TRACE("OK\n");
 +
 +    pdump (This->pPidl);
 +
 +    return S_OK;
 +end:
 +    return r;
 +}
 +
 +/************************************************************************
 + * Stream_WriteString
 + *
 + * Helper function for IPersistStream_Save. Writes a unicode string
 + *  with terminating nul byte to a stream, preceded by the its length.
 + */
 +static HRESULT Stream_WriteString( IStream* stm, LPCWSTR str )
 +{
 +    USHORT len = wcslen( str ) + 1;
 +    DWORD count;
 +    HRESULT r;
 +
 +    r = IStream_Write( stm, &len, sizeof(len), &count );
 +    if( FAILED( r ) )
 +        return r;
 +
 +    len *= sizeof(WCHAR);
 +
 +    r = IStream_Write( stm, str, len, &count );
 +    if( FAILED( r ) )
 +        return r;
 +
 +    return S_OK;
 +}
 +
 +/************************************************************************
 + * Stream_WriteLocationInfo
 + *
 + * Writes the location info to a stream
 + *
 + * FIXME: One day we might want to write the network volume information
 + *        and the final path.
 + *        Figure out how Windows deals with unicode paths here.
 + */
 +static HRESULT Stream_WriteLocationInfo( IStream* stm, LPCWSTR path,
 +                                         volume_info *volume )
 +{
 +    DWORD total_size, path_size, volume_info_size, label_size, final_path_size;
 +    LOCAL_VOLUME_INFO *vol;
 +    LOCATION_INFO *loc;
 +    LPSTR szLabel, szPath, szFinalPath;
 +    ULONG count = 0;
 +    HRESULT hr;
 +
 +    TRACE("%p %s %p\n", stm, debugstr_w(path), volume);
 +
 +    /* figure out the size of everything */
 +    label_size = WideCharToMultiByte( CP_ACP, 0, volume->label, -1,
 +                                      NULL, 0, NULL, NULL );
 +    path_size = WideCharToMultiByte( CP_ACP, 0, path, -1,
 +                                     NULL, 0, NULL, NULL );
 +    volume_info_size = sizeof *vol + label_size;
 +    final_path_size = 1;
 +    total_size = sizeof *loc + volume_info_size + path_size + final_path_size;
 +
 +    /* create pointers to everything */
 +    loc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, total_size);
 +    vol = (LOCAL_VOLUME_INFO*) &loc[1];
 +    szLabel = (LPSTR) &vol[1];
 +    szPath = &szLabel[label_size];
 +    szFinalPath = &szPath[path_size];
 +
 +    /* fill in the location information header */
 +    loc->dwTotalSize = total_size;
 +    loc->dwHeaderSize = sizeof (*loc);
 +    loc->dwFlags = 1;
 +    loc->dwVolTableOfs = sizeof (*loc);
 +    loc->dwLocalPathOfs = sizeof (*loc) + volume_info_size;
 +    loc->dwNetworkVolTableOfs = 0;
 +    loc->dwFinalPathOfs = sizeof (*loc) + volume_info_size + path_size;
 +
 +    /* fill in the volume information */
 +    vol->dwSize = volume_info_size;
 +    vol->dwType = volume->type;
 +    vol->dwVolSerial = volume->serial;
 +    vol->dwVolLabelOfs = sizeof (*vol);
 +
 +    /* copy in the strings */
 +    WideCharToMultiByte( CP_ACP, 0, volume->label, -1,
 +                         szLabel, label_size, NULL, NULL );
 +    WideCharToMultiByte( CP_ACP, 0, path, -1,
 +                         szPath, path_size, NULL, NULL );
 +    szFinalPath[0] = 0;
 +
 +    hr = IStream_Write( stm, loc, total_size, &count );
 +    HeapFree(GetProcessHeap(), 0, loc);
 +
 +    return hr;
 +}
 +
 +static EXP_DARWIN_LINK* shelllink_build_darwinid( LPCWSTR string, DWORD magic )
 +{
 +    EXP_DARWIN_LINK *buffer;
 +
 +    buffer = LocalAlloc( LMEM_ZEROINIT, sizeof *buffer );
 +    buffer->dbh.cbSize = sizeof *buffer;
 +    buffer->dbh.dwSignature = magic;
 +    lstrcpynW( buffer->szwDarwinID, string, MAX_PATH );
 +    WideCharToMultiByte(CP_ACP, 0, string, -1, buffer->szDarwinID, MAX_PATH, NULL, NULL );
 +
 +    return buffer;
 +}
 +
 +static HRESULT Stream_WriteAdvertiseInfo( IStream* stm, LPCWSTR string, DWORD magic )
 +{
 +    EXP_DARWIN_LINK *buffer;
 +    ULONG count;
 +
 +    TRACE("%p\n",stm);
 +
 +    buffer = shelllink_build_darwinid( string, magic );
 +
 +    return IStream_Write( stm, buffer, buffer->dbh.cbSize, &count );
 +}
 +
 +/************************************************************************
 + * IPersistStream_Save (IPersistStream)
 + *
 + * FIXME: makes assumptions about byte order
 + */
 +static HRESULT WINAPI IPersistStream_fnSave(
 +      IPersistStream*  iface,
 +      IStream*         stm,
 +      BOOL             fClearDirty)
 +{
 +    LINK_HEADER header;
 +    ULONG   count;
 +    DWORD   zero;
 +    HRESULT r;
 +
 +    IShellLinkImpl *This = impl_from_IPersistStream(iface);
 +
 +    TRACE("%p %p %x\n", This, stm, fClearDirty);
 +
 +    memset(&header, 0, sizeof(header));
 +    header.dwSize = sizeof(header);
 +    header.fStartup = This->iShowCmd;
 +    header.MagicGuid = CLSID_ShellLink;
 +
 +    header.wHotKey = This->wHotKey;
 +    header.nIcon = This->iIcoNdx;
 +    header.dwFlags = SLDF_UNICODE;   /* strings are in unicode */
 +    if( This->pPidl )
 +        header.dwFlags |= SLDF_HAS_ID_LIST;
 +    if( This->sPath )
 +        header.dwFlags |= SLDF_HAS_LINK_INFO;
 +    if( This->sDescription )
 +        header.dwFlags |= SLDF_HAS_NAME;
 +    if( This->sWorkDir )
 +        header.dwFlags |= SLDF_HAS_WORKINGDIR;
 +    if( This->sArgs )
 +        header.dwFlags |= SLDF_HAS_ARGS;
 +    if( This->sIcoPath )
 +        header.dwFlags |= SLDF_HAS_ICONLOCATION;
 +#if (NTDDI_VERSION < NTDDI_LONGHORN)
 +    if( This->sProduct )
 +        header.dwFlags |= SLDF_HAS_LOGO3ID;
 +#endif
 +    if( This->sComponent )
 +        header.dwFlags |= SLDF_HAS_DARWINID;
 +    if( This->bRunAs )
 +        header.dwFlags |= SLDF_RUNAS_USER;
 +
 +    SystemTimeToFileTime ( &This->time1, &header.Time1 );
 +    SystemTimeToFileTime ( &This->time2, &header.Time2 );
 +    SystemTimeToFileTime ( &This->time3, &header.Time3 );
 +
 +    /* write the Shortcut header */
 +    r = IStream_Write( stm, &header, sizeof(header), &count );
 +    if( FAILED( r ) )
 +    {
 +        ERR("Write failed at %d\n",__LINE__);
 +        return r;
 +    }
 +
 +    TRACE("Writing pidl\n");
 +
 +    /* write the PIDL to the shortcut */
 +    if( This->pPidl )
 +    {
 +        r = ILSaveToStream( stm, This->pPidl );
 +        if( FAILED( r ) )
 +        {
 +            ERR("Failed to write PIDL at %d\n",__LINE__);
 +            return r;
 +        }
 +    }
 +
 +    if( This->sPath )
 +        Stream_WriteLocationInfo( stm, This->sPath, &This->volume );
 +
 +    if( This->sDescription )
 +        r = Stream_WriteString( stm, This->sDescription );
 +
 +    if( This->sPathRel )
 +        r = Stream_WriteString( stm, This->sPathRel );
 +
 +    if( This->sWorkDir )
 +        r = Stream_WriteString( stm, This->sWorkDir );
 +
 +    if( This->sArgs )
 +        r = Stream_WriteString( stm, This->sArgs );
 +
 +    if( This->sIcoPath )
 +        r = Stream_WriteString( stm, This->sIcoPath );
 +
 +    if( This->sProduct )
 +        r = Stream_WriteAdvertiseInfo( stm, This->sProduct, EXP_SZ_ICON_SIG );
 +
 +    if( This->sComponent )
 +        r = Stream_WriteAdvertiseInfo( stm, This->sComponent, EXP_DARWIN_ID_SIG );
 +
 +    /* the last field is a single zero dword */
 +    zero = 0;
 +    r = IStream_Write( stm, &zero, sizeof zero, &count );
 +
 +    return S_OK;
 +}
 +
 +/************************************************************************
 + * IPersistStream_GetSizeMax (IPersistStream)
 + */
 +static HRESULT WINAPI IPersistStream_fnGetSizeMax(
 +      IPersistStream*  iface,
 +      ULARGE_INTEGER*  pcbSize)
 +{
 +      IShellLinkImpl *This = impl_from_IPersistStream(iface);
 +
 +      TRACE("(%p)\n", This);
 +
 +      return E_NOTIMPL;
 +}
 +
 +static const IPersistStreamVtbl psvt =
 +{
 +      IPersistStream_fnQueryInterface,
 +      IPersistStream_fnAddRef,
 +      IPersistStream_fnRelease,
 +      IPersistStream_fnGetClassID,
 +      IPersistStream_fnIsDirty,
 +      IPersistStream_fnLoad,
 +      IPersistStream_fnSave,
 +      IPersistStream_fnGetSizeMax
 +};
 +
 +/**************************************************************************
 + *      IShellLink_Constructor
 + */
 +HRESULT WINAPI IShellLink_Constructor( IUnknown *pUnkOuter,
 +               REFIID riid, LPVOID *ppv )
 +{
 +      IShellLinkImpl * sl;
 +      HRESULT r;
 +
 +      TRACE("unkOut=%p riid=%s\n",pUnkOuter, debugstr_guid(riid));
 +
 +      *ppv = NULL;
 +
 +      if (pUnkOuter)
 +            return CLASS_E_NOAGGREGATION;
 +      sl = LocalAlloc(LMEM_ZEROINIT,sizeof(IShellLinkImpl));
 +      if (!sl)
 +            return E_OUTOFMEMORY;
 +
 +      sl->ref = 1;
 +      sl->lpVtbl = &slvt;
 +      sl->lpvtblw = &slvtw;
 +      sl->lpvtblPersistFile = &pfvt;
 +      sl->lpvtblPersistStream = &psvt;
 +      sl->lpvtblShellLinkDataList = &dlvt;
 +      sl->lpvtblShellExtInit = &eivt;
 +      sl->lpvtblContextMenu = &cmvt;
 +      sl->lpvtblObjectWithSite = &owsvt;
 +      sl->lpvtblPropSheetExt = &pse;
 +      sl->iShowCmd = SW_SHOWNORMAL;
 +      sl->bDirty = FALSE;
 +      sl->iIdOpen = -1;
 +      sl->site = NULL;
 +    sl->bRunAs = FALSE;
 +
 +      TRACE("(%p)->()\n",sl);
 +
 +        r = ShellLink_QueryInterface( sl, riid, ppv );
 +        ShellLink_Release( sl );
 +        return r;
 +}
 +
 +
 +static BOOL SHELL_ExistsFileW(LPCWSTR path)
 +{
 +    if (INVALID_FILE_ATTRIBUTES == GetFileAttributesW(path))
 +        return FALSE;
 +    return TRUE;
 +}
 +
 +/**************************************************************************
 + *  ShellLink_UpdatePath
 + *    update absolute path in sPath using relative path in sPathRel
 + */
 +static HRESULT ShellLink_UpdatePath(LPCWSTR sPathRel, LPCWSTR path, LPCWSTR sWorkDir, LPWSTR* psPath)
 +{
 +    if (!path || !psPath)
 +      return E_INVALIDARG;
 +
 +    if (!*psPath && sPathRel) {
 +      WCHAR buffer[2*MAX_PATH], abs_path[2*MAX_PATH];
 +      LPWSTR final = NULL;
 +
 +      /* first try if [directory of link file] + [relative path] finds an existing file */
 +
 +        GetFullPathNameW( path, MAX_PATH*2, buffer, &final );
 +        if( !final )
 +            final = buffer;
 +      wcscpy(final, sPathRel);
 +
 +      *abs_path = '\0';
 +
 +      if (SHELL_ExistsFileW(buffer)) {
 +          if (!GetFullPathNameW(buffer, MAX_PATH, abs_path, &final))
 +              wcscpy(abs_path, buffer);
 +      } else {
 +          /* try if [working directory] + [relative path] finds an existing file */
 +          if (sWorkDir) {
 +              wcscpy(buffer, sWorkDir);
 +              wcscpy(PathAddBackslashW(buffer), sPathRel);
 +
 +              if (SHELL_ExistsFileW(buffer))
 +                  if (!GetFullPathNameW(buffer, MAX_PATH, abs_path, &final))
 +                      wcscpy(abs_path, buffer);
 +          }
 +      }
 +
 +      /* FIXME: This is even not enough - not all shell links can be resolved using this algorithm. */
 +      if (!*abs_path)
 +          wcscpy(abs_path, sPathRel);
 +
 +      *psPath = HeapAlloc(GetProcessHeap(), 0, (wcslen(abs_path)+1)*sizeof(WCHAR));
 +      if (!*psPath)
 +          return E_OUTOFMEMORY;
 +
 +      wcscpy(*psPath, abs_path);
 +    }
 +
 +    return S_OK;
 +}
 +
 +/**************************************************************************
 + *      IShellLink_ConstructFromFile
 + */
 +HRESULT WINAPI IShellLink_ConstructFromFile( IUnknown* pUnkOuter, REFIID riid,
 +               LPCITEMIDLIST pidl, LPVOID* ppv)
 +{
 +    IShellLinkW* psl;
 +
 +    HRESULT hr = IShellLink_Constructor(NULL, riid, (LPVOID*)&psl);
 +
 +    if (SUCCEEDED(hr)) {
 +      IPersistFile* ppf;
 +
 +      *ppv = NULL;
 +
 +      hr = IShellLinkW_QueryInterface(psl, &IID_IPersistFile, (LPVOID*)&ppf);
 +
 +      if (SUCCEEDED(hr)) {
 +          WCHAR path[MAX_PATH];
 +
 +          if (SHGetPathFromIDListW(pidl, path))
 +              hr = IPersistFile_Load(ppf, path, 0);
 +            else
 +                hr = E_FAIL;
 +
 +          if (SUCCEEDED(hr))
 +              *ppv = psl;
 +
 +          IPersistFile_Release(ppf);
 +      }
 +
 +      if (!*ppv)
 +          IShellLinkW_Release(psl);
 +    }
 +
 +    return hr;
 +}
 +
 +/**************************************************************************
 + *  IShellLinkA_QueryInterface
 + */
 +static HRESULT WINAPI IShellLinkA_fnQueryInterface( IShellLinkA * iface, REFIID riid,  LPVOID *ppvObj)
 +{
 +    IShellLinkImpl *This = (IShellLinkImpl *)iface;
 +    return ShellLink_QueryInterface( This, riid, ppvObj );
 +}
 +
 +/******************************************************************************
 + * IShellLinkA_AddRef
 + */
 +static ULONG WINAPI IShellLinkA_fnAddRef(IShellLinkA * iface)
 +{
 +    IShellLinkImpl *This = (IShellLinkImpl *)iface;
 +    return ShellLink_AddRef( This );
 +}
 +
 +/******************************************************************************
 + *    IShellLinkA_Release
 + */
 +static ULONG WINAPI IShellLinkA_fnRelease(IShellLinkA * iface)
 +{
 +    IShellLinkImpl *This = (IShellLinkImpl *)iface;
 +    return ShellLink_Release( This );
 +}
 +
 +static HRESULT WINAPI IShellLinkA_fnGetPath(IShellLinkA * iface, LPSTR pszFile,
 +                  INT cchMaxPath, WIN32_FIND_DATAA *pfd, DWORD fFlags)
 +{
 +    IShellLinkImpl *This = (IShellLinkImpl *)iface;
 +
 +    TRACE("(%p)->(pfile=%p len=%u find_data=%p flags=%u)(%s)\n",
 +          This, pszFile, cchMaxPath, pfd, fFlags, debugstr_w(This->sPath));
 +
-     This->sDescription = HEAP_strdupAtoW( GetProcessHeap(), 0, pszName);
-     if ( !This->sDescription )
-         return E_OUTOFMEMORY;
 +    if (cchMaxPath)
 +        pszFile[0] = 0;
 +    if (This->sPath)
 +        WideCharToMultiByte( CP_ACP, 0, This->sPath, -1,
 +                             pszFile, cchMaxPath, NULL, NULL);
 +
 +    if (pfd) FIXME("(%p): WIN32_FIND_DATA is not yet filled.\n", This);
 +
 +    return S_OK;
 +}
 +
 +static HRESULT WINAPI IShellLinkA_fnGetIDList(IShellLinkA * iface, LPITEMIDLIST * ppidl)
 +{
 +    IShellLinkImpl *This = (IShellLinkImpl *)iface;
 +
 +    TRACE("(%p)->(ppidl=%p)\n",This, ppidl);
 +
 +    return IShellLinkW_GetIDList((IShellLinkW*)&(This->lpvtblw), ppidl);
 +}
 +
 +static HRESULT WINAPI IShellLinkA_fnSetIDList(IShellLinkA * iface, LPCITEMIDLIST pidl)
 +{
 +    IShellLinkImpl *This = (IShellLinkImpl *)iface;
 +
 +    TRACE("(%p)->(pidl=%p)\n",This, pidl);
 +
 +    if (This->pPidl)
 +      ILFree(This->pPidl);
 +    This->pPidl = ILClone (pidl);
 +    This->bDirty = TRUE;
 +
 +    return S_OK;
 +}
 +
 +static HRESULT WINAPI IShellLinkA_fnGetDescription(IShellLinkA * iface, LPSTR pszName,INT cchMaxName)
 +{
 +    IShellLinkImpl *This = (IShellLinkImpl *)iface;
 +
 +    TRACE("(%p)->(%p len=%u)\n",This, pszName, cchMaxName);
 +
 +    if( cchMaxName )
 +        pszName[0] = 0;
 +    if( This->sDescription )
 +        WideCharToMultiByte( CP_ACP, 0, This->sDescription, -1,
 +            pszName, cchMaxName, NULL, NULL);
 +
 +    return S_OK;
 +}
 +
 +static HRESULT WINAPI IShellLinkA_fnSetDescription(IShellLinkA * iface, LPCSTR pszName)
 +{
 +    IShellLinkImpl *This = (IShellLinkImpl *)iface;
 +
 +    TRACE("(%p)->(pName=%s)\n", This, pszName);
 +
 +    HeapFree(GetProcessHeap(), 0, This->sDescription);
-     This->sWorkDir = HEAP_strdupAtoW( GetProcessHeap(), 0, pszDir);
-     if ( !This->sWorkDir )
-         return E_OUTOFMEMORY;
++    This->sDescription = NULL;
 +
++    if ( pszName ) {
++        This->sDescription = HEAP_strdupAtoW( GetProcessHeap(), 0, pszName);
++        if ( !This->sDescription )
++            return E_OUTOFMEMORY;
++    }
 +    This->bDirty = TRUE;
 +
 +    return S_OK;
 +}
 +
 +static HRESULT WINAPI IShellLinkA_fnGetWorkingDirectory(IShellLinkA * iface, LPSTR pszDir,INT cchMaxPath)
 +{
 +    IShellLinkImpl *This = (IShellLinkImpl *)iface;
 +
 +    TRACE("(%p)->(%p len=%u)\n", This, pszDir, cchMaxPath);
 +
 +    if( cchMaxPath )
 +        pszDir[0] = 0;
 +    if( This->sWorkDir )
 +        WideCharToMultiByte( CP_ACP, 0, This->sWorkDir, -1,
 +                             pszDir, cchMaxPath, NULL, NULL);
 +
 +    return S_OK;
 +}
 +
 +static HRESULT WINAPI IShellLinkA_fnSetWorkingDirectory(IShellLinkA * iface, LPCSTR pszDir)
 +{
 +    IShellLinkImpl *This = (IShellLinkImpl *)iface;
 +
 +    TRACE("(%p)->(dir=%s)\n",This, pszDir);
 +
 +    HeapFree(GetProcessHeap(), 0, This->sWorkDir);
-     This->sArgs = HEAP_strdupAtoW( GetProcessHeap(), 0, pszArgs);
-     if( !This->sArgs )
-         return E_OUTOFMEMORY;
++    This->sWorkDir = NULL;
 +
++    if ( pszDir ) {
++        This->sWorkDir = HEAP_strdupAtoW( GetProcessHeap(), 0, pszDir);
++        if ( !This->sWorkDir )
++            return E_OUTOFMEMORY;
++    }
 +    This->bDirty = TRUE;
 +
 +    return S_OK;
 +}
 +
 +static HRESULT WINAPI IShellLinkA_fnGetArguments(IShellLinkA * iface, LPSTR pszArgs,INT cchMaxPath)
 +{
 +    IShellLinkImpl *This = (IShellLinkImpl *)iface;
 +
 +    TRACE("(%p)->(%p len=%u)\n", This, pszArgs, cchMaxPath);
 +
 +    if( cchMaxPath )
 +        pszArgs[0] = 0;
 +    if( This->sArgs )
 +        WideCharToMultiByte( CP_ACP, 0, This->sArgs, -1,
 +                             pszArgs, cchMaxPath, NULL, NULL);
 +
 +    return S_OK;
 +}
 +
 +static HRESULT WINAPI IShellLinkA_fnSetArguments(IShellLinkA * iface, LPCSTR pszArgs)
 +{
 +    IShellLinkImpl *This = (IShellLinkImpl *)iface;
 +
 +    TRACE("(%p)->(args=%s)\n",This, pszArgs);
 +
 +    HeapFree(GetProcessHeap(), 0, This->sArgs);
-     This->sIcoPath = HEAP_strdupAtoW(GetProcessHeap(), 0, pszIconPath);
-     if ( !This->sIcoPath )
-         return E_OUTOFMEMORY;
++    This->sArgs = NULL;
++
++    if ( pszArgs ) {
++        This->sArgs = HEAP_strdupAtoW( GetProcessHeap(), 0, pszArgs);
++        if( !This->sArgs )
++            return E_OUTOFMEMORY;
++    }
 +
 +    This->bDirty = TRUE;
 +
 +    return S_OK;
 +}
 +
 +static HRESULT WINAPI IShellLinkA_fnGetHotkey(IShellLinkA * iface, WORD *pwHotkey)
 +{
 +    IShellLinkImpl *This = (IShellLinkImpl *)iface;
 +
 +    TRACE("(%p)->(%p)(0x%08x)\n",This, pwHotkey, This->wHotKey);
 +
 +    *pwHotkey = This->wHotKey;
 +
 +    return S_OK;
 +}
 +
 +static HRESULT WINAPI IShellLinkA_fnSetHotkey(IShellLinkA * iface, WORD wHotkey)
 +{
 +    IShellLinkImpl *This = (IShellLinkImpl *)iface;
 +
 +    TRACE("(%p)->(hotkey=%x)\n",This, wHotkey);
 +
 +    This->wHotKey = wHotkey;
 +    This->bDirty = TRUE;
 +
 +    return S_OK;
 +}
 +
 +static HRESULT WINAPI IShellLinkA_fnGetShowCmd(IShellLinkA * iface, INT *piShowCmd)
 +{
 +    IShellLinkImpl *This = (IShellLinkImpl *)iface;
 +
 +    TRACE("(%p)->(%p)\n",This, piShowCmd);
 +    *piShowCmd = This->iShowCmd;
 +    return S_OK;
 +}
 +
 +static HRESULT WINAPI IShellLinkA_fnSetShowCmd(IShellLinkA * iface, INT iShowCmd)
 +{
 +    IShellLinkImpl *This = (IShellLinkImpl *)iface;
 +
 +    TRACE("(%p) %d\n",This, iShowCmd);
 +
 +    This->iShowCmd = iShowCmd;
 +    This->bDirty = TRUE;
 +
 +    return NOERROR;
 +}
 +
 +static HRESULT SHELL_PidlGeticonLocationA(IShellFolder* psf, LPCITEMIDLIST pidl,
 +                                          LPSTR pszIconPath, int cchIconPath, int* piIcon)
 +{
 +    LPCITEMIDLIST pidlLast;
 +
 +    HRESULT hr = SHBindToParent(pidl, &IID_IShellFolder, (LPVOID*)&psf, &pidlLast);
 +
 +    if (SUCCEEDED(hr)) {
 +      IExtractIconA* pei;
 +
 +      hr = IShellFolder_GetUIObjectOf(psf, 0, 1, &pidlLast, &IID_IExtractIconA, NULL, (LPVOID*)&pei);
 +
 +      if (SUCCEEDED(hr)) {
 +          hr = IExtractIconA_GetIconLocation(pei, 0, pszIconPath, MAX_PATH, piIcon, NULL);
 +
 +          IExtractIconA_Release(pei);
 +      }
 +
 +      IShellFolder_Release(psf);
 +    }
 +
 +    return hr;
 +}
 +
 +static HRESULT WINAPI IShellLinkA_fnGetIconLocation(IShellLinkA * iface, LPSTR pszIconPath,INT cchIconPath,INT *piIcon)
 +{
 +    IShellLinkImpl *This = (IShellLinkImpl *)iface;
 +
 +    TRACE("(%p)->(%p len=%u iicon=%p)\n", This, pszIconPath, cchIconPath, piIcon);
 +
 +    pszIconPath[0] = 0;
 +    *piIcon = This->iIcoNdx;
 +
 +    if (This->sIcoPath)
 +    {
 +        WideCharToMultiByte(CP_ACP, 0, This->sIcoPath, -1, pszIconPath, cchIconPath, NULL, NULL);
 +      return S_OK;
 +    }
 +
 +    if (This->pPidl || This->sPath)
 +    {
 +      IShellFolder* pdsk;
 +
 +      HRESULT hr = SHGetDesktopFolder(&pdsk);
 +
 +      if (SUCCEEDED(hr))
 +        {
 +          /* first look for an icon using the PIDL (if present) */
 +          if (This->pPidl)
 +              hr = SHELL_PidlGeticonLocationA(pdsk, This->pPidl, pszIconPath, cchIconPath, piIcon);
 +          else
 +              hr = E_FAIL;
 +
 +          /* if we couldn't find an icon yet, look for it using the file system path */
 +          if (FAILED(hr) && This->sPath)
 +            {
 +              LPITEMIDLIST pidl;
 +
 +              hr = IShellFolder_ParseDisplayName(pdsk, 0, NULL, This->sPath, NULL, &pidl, NULL);
 +
 +              if (SUCCEEDED(hr)) {
 +                  hr = SHELL_PidlGeticonLocationA(pdsk, pidl, pszIconPath, cchIconPath, piIcon);
 +
 +                  SHFree(pidl);
 +              }
 +          }
 +
 +          IShellFolder_Release(pdsk);
 +      }
 +
 +      return hr;
 +    }
 +    return S_OK;
 +}
 +
 +static HRESULT WINAPI IShellLinkA_fnSetIconLocation(IShellLinkA * iface, LPCSTR pszIconPath,INT iIcon)
 +{
 +    IShellLinkImpl *This = (IShellLinkImpl *)iface;
 +
 +    TRACE("(%p)->(path=%s iicon=%u)\n",This, pszIconPath, iIcon);
 +
 +    HeapFree(GetProcessHeap(), 0, This->sIcoPath);
-     This->sPathRel = HEAP_strdupAtoW(GetProcessHeap(), 0, pszPathRel);
++    This->sIcoPath = NULL;
++
++    if ( pszIconPath ) {
++        This->sIcoPath = HEAP_strdupAtoW(GetProcessHeap(), 0, pszIconPath);
++        if ( !This->sIcoPath )
++            return E_OUTOFMEMORY;
++    }
 +
 +    This->iIcoNdx = iIcon;
 +    This->bDirty = TRUE;
 +
 +    return S_OK;
 +}
 +
 +static HRESULT WINAPI IShellLinkA_fnSetRelativePath(IShellLinkA * iface, LPCSTR pszPathRel, DWORD dwReserved)
 +{
 +    IShellLinkImpl *This = (IShellLinkImpl *)iface;
 +
 +    TRACE("(%p)->(path=%s %x)\n",This, pszPathRel, dwReserved);
 +
 +    HeapFree(GetProcessHeap(), 0, This->sPathRel);
++    This->sPathRel = NULL;
++
++    if ( pszPathRel ) {
++        This->sPathRel = HEAP_strdupAtoW(GetProcessHeap(), 0, pszPathRel);
++
++        if ( !This->sPathRel )
++            return E_OUTOFMEMORY;
++    }
++
 +    This->bDirty = TRUE;
 +
 +    return ShellLink_UpdatePath(This->sPathRel, This->sPath, This->sWorkDir, &This->sPath);
 +}
 +
 +static HRESULT WINAPI IShellLinkA_fnResolve(IShellLinkA * iface, HWND hwnd, DWORD fFlags)
 +{
 +    IShellLinkImpl *This = (IShellLinkImpl *)iface;
 +
 +    TRACE("(%p)->(hwnd=%p flags=%x)\n",This, hwnd, fFlags);
 +
 +    return IShellLinkW_Resolve( (IShellLinkW*)&(This->lpvtblw), hwnd, fFlags );
 +}
 +
 +static HRESULT WINAPI IShellLinkA_fnSetPath(IShellLinkA * iface, LPCSTR pszFile)
 +{
 +    HRESULT r;
 +    LPWSTR str;
 +    IShellLinkImpl *This = (IShellLinkImpl *)iface;
 +
 +    TRACE("(%p)->(path=%s)\n",This, pszFile);
 +
 +    if (!pszFile) return E_INVALIDARG;
 +
 +    str = HEAP_strdupAtoW(GetProcessHeap(), 0, pszFile);
 +    if( !str )
 +        return E_OUTOFMEMORY;
 +
 +    r = IShellLinkW_SetPath((IShellLinkW*)&(This->lpvtblw), str);
 +    HeapFree( GetProcessHeap(), 0, str );
 +
 +    return r;
 +}
 +
 +/**************************************************************************
 +* IShellLink Implementation
 +*/
 +
 +static const IShellLinkAVtbl slvt =
 +{
 +    IShellLinkA_fnQueryInterface,
 +    IShellLinkA_fnAddRef,
 +    IShellLinkA_fnRelease,
 +    IShellLinkA_fnGetPath,
 +    IShellLinkA_fnGetIDList,
 +    IShellLinkA_fnSetIDList,
 +    IShellLinkA_fnGetDescription,
 +    IShellLinkA_fnSetDescription,
 +    IShellLinkA_fnGetWorkingDirectory,
 +    IShellLinkA_fnSetWorkingDirectory,
 +    IShellLinkA_fnGetArguments,
 +    IShellLinkA_fnSetArguments,
 +    IShellLinkA_fnGetHotkey,
 +    IShellLinkA_fnSetHotkey,
 +    IShellLinkA_fnGetShowCmd,
 +    IShellLinkA_fnSetShowCmd,
 +    IShellLinkA_fnGetIconLocation,
 +    IShellLinkA_fnSetIconLocation,
 +    IShellLinkA_fnSetRelativePath,
 +    IShellLinkA_fnResolve,
 +    IShellLinkA_fnSetPath
 +};
 +
 +
 +/**************************************************************************
 + *  IShellLinkW_fnQueryInterface
 + */
 +static HRESULT WINAPI IShellLinkW_fnQueryInterface(
 +  IShellLinkW * iface, REFIID riid, LPVOID *ppvObj)
 +{
 +    IShellLinkImpl *This = impl_from_IShellLinkW(iface);
 +    return ShellLink_QueryInterface( This, riid, ppvObj );
 +}
 +
 +/******************************************************************************
 + * IShellLinkW_fnAddRef
 + */
 +static ULONG WINAPI IShellLinkW_fnAddRef(IShellLinkW * iface)
 +{
 +    IShellLinkImpl *This = impl_from_IShellLinkW(iface);
 +    return ShellLink_AddRef( This );
 +}
 +
 +/******************************************************************************
 + * IShellLinkW_fnRelease
 + */
 +static ULONG WINAPI IShellLinkW_fnRelease(IShellLinkW * iface)
 +{
 +    IShellLinkImpl *This = impl_from_IShellLinkW(iface);
 +    return ShellLink_Release( This );
 +}
 +
 +static HRESULT WINAPI IShellLinkW_fnGetPath(IShellLinkW * iface, LPWSTR pszFile,INT cchMaxPath, WIN32_FIND_DATAW *pfd, DWORD fFlags)
 +{
 +    IShellLinkImpl *This = impl_from_IShellLinkW(iface);
 +
 +    TRACE("(%p)->(pfile=%p len=%u find_data=%p flags=%u)(%s)\n",
 +          This, pszFile, cchMaxPath, pfd, fFlags, debugstr_w(This->sPath));
 +
 +    if (This->sComponent || This->sProduct)
 +        return S_FALSE;
 +
 +    if (cchMaxPath)
 +        pszFile[0] = 0;
 +    if (This->sPath)
 +        lstrcpynW( pszFile, This->sPath, cchMaxPath );
 +
 +    if (pfd) FIXME("(%p): WIN32_FIND_DATA is not yet filled.\n", This);
 +
 +    return S_OK;
 +}
 +
 +static HRESULT WINAPI IShellLinkW_fnGetIDList(IShellLinkW * iface, LPITEMIDLIST * ppidl)
 +{
 +    IShellLinkImpl *This = impl_from_IShellLinkW(iface);
 +
 +    TRACE("(%p)->(ppidl=%p)\n",This, ppidl);
 +
 +    if (!This->pPidl)
 +    {
 +      *ppidl = NULL;
 +        return S_FALSE;
 +    }
 +    *ppidl = ILClone(This->pPidl);
 +    return S_OK;
 +}
 +
 +static HRESULT WINAPI IShellLinkW_fnSetIDList(IShellLinkW * iface, LPCITEMIDLIST pidl)
 +{
 +    IShellLinkImpl *This = impl_from_IShellLinkW(iface);
 +
 +    TRACE("(%p)->(pidl=%p)\n",This, pidl);
 +
 +    if( This->pPidl )
 +        ILFree( This->pPidl );
 +    This->pPidl = ILClone( pidl );
 +    if( !This->pPidl )
 +        return E_FAIL;
 +
 +    This->bDirty = TRUE;
 +
 +    return S_OK;
 +}
 +
 +static HRESULT WINAPI IShellLinkW_fnGetDescription(IShellLinkW * iface, LPWSTR pszName,INT cchMaxName)
 +{
 +    IShellLinkImpl *This = impl_from_IShellLinkW(iface);
 +
 +    TRACE("(%p)->(%p len=%u)\n",This, pszName, cchMaxName);
 +
 +    pszName[0] = 0;
 +    if( This->sDescription )
 +        lstrcpynW( pszName, This->sDescription, cchMaxName );
 +
 +    return S_OK;
 +}
 +
 +static HRESULT WINAPI IShellLinkW_fnSetDescription(IShellLinkW * iface, LPCWSTR pszName)
 +{
 +    IShellLinkImpl *This = impl_from_IShellLinkW(iface);
 +
 +    TRACE("(%p)->(desc=%s)\n",This, debugstr_w(pszName));
 +
 +    HeapFree(GetProcessHeap(), 0, This->sDescription);
 +    This->sDescription = HeapAlloc( GetProcessHeap(), 0,
 +                                    (wcslen( pszName )+1)*sizeof(WCHAR) );
 +    if ( !This->sDescription )
 +        return E_OUTOFMEMORY;
 +
 +    wcscpy( This->sDescription, pszName );
 +    This->bDirty = TRUE;
 +
 +    return S_OK;
 +}
 +
 +static HRESULT WINAPI IShellLinkW_fnGetWorkingDirectory(IShellLinkW * iface, LPWSTR pszDir,INT cchMaxPath)
 +{
 +    IShellLinkImpl *This = impl_from_IShellLinkW(iface);
 +
 +    TRACE("(%p)->(%p len %u)\n", This, pszDir, cchMaxPath);
 +
 +    if( cchMaxPath )
 +        pszDir[0] = 0;
 +    if( This->sWorkDir )
 +        lstrcpynW( pszDir, This->sWorkDir, cchMaxPath );
 +
 +    return S_OK;
 +}
 +
 +static HRESULT WINAPI IShellLinkW_fnSetWorkingDirectory(IShellLinkW * iface, LPCWSTR pszDir)
 +{
 +    IShellLinkImpl *This = impl_from_IShellLinkW(iface);
 +
 +    TRACE("(%p)->(dir=%s)\n",This, debugstr_w(pszDir));
 +
 +    HeapFree(GetProcessHeap(), 0, This->sWorkDir);
 +    This->sWorkDir = HeapAlloc( GetProcessHeap(), 0,
 +                                (wcslen( pszDir )+1)*sizeof (WCHAR) );
 +    if ( !This->sWorkDir )
 +        return E_OUTOFMEMORY;
 +    wcscpy( This->sWorkDir, pszDir );
 +    This->bDirty = TRUE;
 +
 +    return S_OK;
 +}
 +
 +static HRESULT WINAPI IShellLinkW_fnGetArguments(IShellLinkW * iface, LPWSTR pszArgs,INT cchMaxPath)
 +{
 +    IShellLinkImpl *This = impl_from_IShellLinkW(iface);
 +
 +    TRACE("(%p)->(%p len=%u)\n", This, pszArgs, cchMaxPath);
 +
 +    if( cchMaxPath )
 +        pszArgs[0] = 0;
 +    if( This->sArgs )
 +        lstrcpynW( pszArgs, This->sArgs, cchMaxPath );
 +
 +    return NOERROR;
 +}
 +
 +static HRESULT WINAPI IShellLinkW_fnSetArguments(IShellLinkW * iface, LPCWSTR pszArgs)
 +{
 +    IShellLinkImpl *This = impl_from_IShellLinkW(iface);
 +
 +    TRACE("(%p)->(args=%s)\n",This, debugstr_w(pszArgs));
 +
 +    HeapFree(GetProcessHeap(), 0, This->sArgs);
 +    This->sArgs = HeapAlloc( GetProcessHeap(), 0,
 +                             (wcslen( pszArgs )+1)*sizeof (WCHAR) );
 +    if ( !This->sArgs )
 +        return E_OUTOFMEMORY;
 +    wcscpy( This->sArgs, pszArgs );
 +    This->bDirty = TRUE;
 +
 +    return S_OK;
 +}
 +
 +static HRESULT WINAPI IShellLinkW_fnGetHotkey(IShellLinkW * iface, WORD *pwHotkey)
 +{
 +    IShellLinkImpl *This = impl_from_IShellLinkW(iface);
 +
 +    TRACE("(%p)->(%p)\n",This, pwHotkey);
 +
 +    *pwHotkey=This->wHotKey;
 +
 +    return S_OK;
 +}
 +
 +static HRESULT WINAPI IShellLinkW_fnSetHotkey(IShellLinkW * iface, WORD wHotkey)
 +{
 +    IShellLinkImpl *This = impl_from_IShellLinkW(iface);
 +
 +    TRACE("(%p)->(hotkey=%x)\n",This, wHotkey);
 +
 +    This->wHotKey = wHotkey;
 +    This->bDirty = TRUE;
 +
 +    return S_OK;
 +}
 +
 +static HRESULT WINAPI IShellLinkW_fnGetShowCmd(IShellLinkW * iface, INT *piShowCmd)
 +{
 +    IShellLinkImpl *This = impl_from_IShellLinkW(iface);
 +
 +    TRACE("(%p)->(%p)\n",This, piShowCmd);
 +
 +    *piShowCmd = This->iShowCmd;
 +
 +    return S_OK;
 +}
 +
 +static HRESULT WINAPI IShellLinkW_fnSetShowCmd(IShellLinkW * iface, INT iShowCmd)
 +{
 +    IShellLinkImpl *This = impl_from_IShellLinkW(iface);
 +
 +    This->iShowCmd = iShowCmd;
 +    This->bDirty = TRUE;
 +
 +    return S_OK;
 +}
 +
 +static HRESULT SHELL_PidlGeticonLocationW(IShellFolder* psf, LPCITEMIDLIST pidl,
 +                                          LPWSTR pszIconPath, int cchIconPath, int* piIcon)
 +{
 +    LPCITEMIDLIST pidlLast;
 +    UINT wFlags;
 +
 +    HRESULT hr = SHBindToParent(pidl, &IID_IShellFolder, (LPVOID*)&psf, &pidlLast);
 +
 +    if (SUCCEEDED(hr)) {
 +      IExtractIconW* pei;
 +
 +      hr = IShellFolder_GetUIObjectOf(psf, 0, 1, &pidlLast, &IID_IExtractIconW, NULL, (LPVOID*)&pei);
 +
 +      if (SUCCEEDED(hr)) {
 +          hr = IExtractIconW_GetIconLocation(pei, 0, pszIconPath, MAX_PATH, piIcon, &wFlags);
 +
 +          IExtractIconW_Release(pei);
 +      }
 +
 +      IShellFolder_Release(psf);
 +    }
 +
 +    return hr;
 +}
 +
 +static HRESULT WINAPI IShellLinkW_fnGetIconLocation(IShellLinkW * iface, LPWSTR pszIconPath,INT cchIconPath,INT *piIcon)
 +{
 +    IShellLinkImpl *This = impl_from_IShellLinkW(iface);
 +
 +    TRACE("(%p)->(%p len=%u iicon=%p)\n", This, pszIconPath, cchIconPath, piIcon);
 +
 +    pszIconPath[0] = 0;
 +    *piIcon = This->iIcoNdx;
 +
 +    if (This->sIcoPath)
 +    {
 +      lstrcpynW(pszIconPath, This->sIcoPath, cchIconPath);
 +      return S_OK;
 +    }
 +
 +    if (This->pPidl || This->sPath)
 +    {
 +      IShellFolder* pdsk;
 +
 +      HRESULT hr = SHGetDesktopFolder(&pdsk);
 +
 +      if (SUCCEEDED(hr))
 +        {
 +          /* first look for an icon using the PIDL (if present) */
 +          if (This->pPidl)
 +              hr = SHELL_PidlGeticonLocationW(pdsk, This->pPidl, pszIconPath, cchIconPath, piIcon);
 +          else
 +              hr = E_FAIL;
 +
 +          /* if we couldn't find an icon yet, look for it using the file system path */
 +          if (FAILED(hr) && This->sPath)
 +            {
 +              LPITEMIDLIST pidl;
 +
 +              hr = IShellFolder_ParseDisplayName(pdsk, 0, NULL, This->sPath, NULL, &pidl, NULL);
 +
 +              if (SUCCEEDED(hr))
 +                {
 +                  hr = SHELL_PidlGeticonLocationW(pdsk, pidl, pszIconPath, cchIconPath, piIcon);
 +
 +                  SHFree(pidl);
 +              }
 +          }
 +
 +          IShellFolder_Release(pdsk);
 +      }
 +      return hr;
 +    }
 +    return S_OK;
 +}
 +
 +static HRESULT WINAPI IShellLinkW_fnSetIconLocation(IShellLinkW * iface, LPCWSTR pszIconPath,INT iIcon)
 +{
 +    IShellLinkImpl *This = impl_from_IShellLinkW(iface);
 +
 +    TRACE("(%p)->(path=%s iicon=%u)\n",This, debugstr_w(pszIconPath), iIcon);
 +
 +    HeapFree(GetProcessHeap(), 0, This->sIcoPath);
 +    This->sIcoPath = HeapAlloc( GetProcessHeap(), 0,
 +                                (wcslen( pszIconPath )+1)*sizeof (WCHAR) );
 +    if ( !This->sIcoPath )
 +        return E_OUTOFMEMORY;
 +    wcscpy( This->sIcoPath, pszIconPath );
 +
 +    This->iIcoNdx = iIcon;
 +    This->bDirty = TRUE;
 +
 +    return S_OK;
 +}
 +
 +static HRESULT WINAPI IShellLinkW_fnSetRelativePath(IShellLinkW * iface, LPCWSTR pszPathRel, DWORD dwReserved)
 +{
 +    IShellLinkImpl *This = impl_from_IShellLinkW(iface);
 +
 +    TRACE("(%p)->(path=%s %x)\n",This, debugstr_w(pszPathRel), dwReserved);
 +
 +    HeapFree(GetProcessHeap(), 0, This->sPathRel);
 +    This->sPathRel = HeapAlloc( GetProcessHeap(), 0,
 +                                (wcslen( pszPathRel )+1) * sizeof (WCHAR) );
 +    if ( !This->sPathRel )
 +        return E_OUTOFMEMORY;
 +    wcscpy( This->sPathRel, pszPathRel );
 +    This->bDirty = TRUE;
 +
 +    return ShellLink_UpdatePath(This->sPathRel, This->sPath, This->sWorkDir, &This->sPath);
 +}
 +
 +static HRESULT WINAPI IShellLinkW_fnResolve(IShellLinkW * iface, HWND hwnd, DWORD fFlags)
 +{
 +    HRESULT hr = S_OK;
 +    BOOL bSuccess;
 +
 +    IShellLinkImpl *This = impl_from_IShellLinkW(iface);
 +
 +    TRACE("(%p)->(hwnd=%p flags=%x)\n",This, hwnd, fFlags);
 +
 +    /*FIXME: use IResolveShellLink interface */
 +
 +    if (!This->sPath && This->pPidl) {
 +      WCHAR buffer[MAX_PATH];
 +
 +      bSuccess = SHGetPathFromIDListW(This->pPidl, buffer);
 +
 +      if (bSuccess && *buffer) {
 +          This->sPath = HeapAlloc(GetProcessHeap(), 0, (wcslen(buffer)+1)*sizeof(WCHAR));
 +          if (!This->sPath)
 +              return E_OUTOFMEMORY;
 +
 +          wcscpy(This->sPath, buffer);
 +
 +          This->bDirty = TRUE;
 +      } else
 +          hr = S_OK;    /* don't report an error occurred while just caching information */
 +    }
 +
 +    if (!This->sIcoPath && This->sPath) {
 +      This->sIcoPath = HeapAlloc(GetProcessHeap(), 0, (wcslen(This->sPath)+1)*sizeof(WCHAR));
 +      if (!This->sIcoPath)
 +          return E_OUTOFMEMORY;
 +
 +      wcscpy(This->sIcoPath, This->sPath);
 +      This->iIcoNdx = 0;
 +
 +      This->bDirty = TRUE;
 +    }
 +
 +    return hr;
 +}
 +
 +static LPWSTR ShellLink_GetAdvertisedArg(LPCWSTR str)
 +{
 +    LPWSTR ret;
 +    LPCWSTR p;
 +    DWORD len;
 +
 +    if( !str )
 +        return NULL;
 +
 +    p = wcschr( str, ':' );
 +    if( !p )
 +        return NULL;
 +    len = p - str;
 +    ret = HeapAlloc( GetProcessHeap(), 0, sizeof(WCHAR)*(len+1));
 +    if( !ret )
 +        return ret;
 +    memcpy( ret, str, sizeof(WCHAR)*len );
 +    ret[len] = 0;
 +    return ret;
 +}
 +
 +static HRESULT ShellLink_SetAdvertiseInfo(IShellLinkImpl *This, LPCWSTR str)
 +{
 +    LPCWSTR szComponent = NULL, szProduct = NULL, p;
 +    WCHAR szGuid[39];
 +    HRESULT r;
 +    GUID guid;
 +    int len;
 +
 +    while( str[0] )
 +    {
 +        /* each segment must start with two colons */
 +        if( str[0] != ':' || str[1] != ':' )
 +            return E_FAIL;
 +
 +        /* the last segment is just two colons */
 +        if( !str[2] )
 +            break;
 +        str += 2;
 +
 +        /* there must be a colon straight after a guid */
 +        p = wcschr( str, ':' );
 +        if( !p )
 +            return E_FAIL;
 +        len = p - str;
 +        if( len != 38 )
 +            return E_FAIL;
 +
 +        /* get the guid, and check it's validly formatted */
 +        memcpy( szGuid, str, sizeof(WCHAR)*len );
 +        szGuid[len] = 0;
 +        r = CLSIDFromString( szGuid, &guid );
 +        if( r != S_OK )
 +            return r;
 +        str = p + 1;
 +
 +        /* match it up to a guid that we care about */
 +        if( IsEqualGUID( &guid, &SHELL32_AdvtShortcutComponent ) && !szComponent )
 +            szComponent = str;
 +        else if( IsEqualGUID( &guid, &SHELL32_AdvtShortcutProduct ) && !szProduct )
 +            szProduct = str;
 +        else
 +            return E_FAIL;
 +
 +        /* skip to the next field */
 +        str = wcschr( str, ':' );
 +        if( !str )
 +            return E_FAIL;
 +    }
 +
 +    /* we have to have a component for an advertised shortcut */
 +    if( !szComponent )
 +        return E_FAIL;
 +
 +    This->sComponent = ShellLink_GetAdvertisedArg( szComponent );
 +    This->sProduct = ShellLink_GetAdvertisedArg( szProduct );
 +
 +    TRACE("Component = %s\n", debugstr_w(This->sComponent));
 +    TRACE("Product = %s\n", debugstr_w(This->sProduct));
 +
 +    return S_OK;
 +}
 +
 +static BOOL ShellLink_GetVolumeInfo(LPCWSTR path, volume_info *volume)
 +{
 +    const int label_sz = sizeof volume->label/sizeof volume->label[0];
 +    WCHAR drive[4] = { path[0], ':', '\\', 0 };
 +    BOOL r;
 +
 +    volume->type = GetDriveTypeW(drive);
 +    r = GetVolumeInformationW(drive, volume->label, label_sz,
 +                              &volume->serial, NULL, NULL, NULL, 0);
 +    TRACE("r = %d type %d serial %08x name %s\n", r,
 +          volume->type, volume->serial, debugstr_w(volume->label));
 +    return r;
 +}
 +
 +static HRESULT WINAPI IShellLinkW_fnSetPath(IShellLinkW * iface, LPCWSTR pszFile)
 +{
 +    IShellLinkImpl *This = impl_from_IShellLinkW(iface);
 +    WCHAR buffer[MAX_PATH];
 +    LPWSTR fname, unquoted = NULL;
 +    HRESULT hr = S_OK;
 +    UINT len;
 +
 +    TRACE("(%p)->(path=%s)\n",This, debugstr_w(pszFile));
 +
 +    if (!pszFile) return E_INVALIDARG;
 +
 +    /* quotes at the ends of the string are stripped */
 +    len = wcslen(pszFile);
 +    if (pszFile[0] == '"' && pszFile[len-1] == '"')
 +    {
 +        unquoted = strdupW(pszFile);
 +        PathUnquoteSpacesW(unquoted);
 +        pszFile = unquoted;
 +    }
 +
 +    /* any other quote marks are invalid */
 +    if (wcschr(pszFile, '"'))
 +    {
 +        HeapFree(GetProcessHeap(), 0, unquoted);
 +        return S_FALSE;
 +    }
 +
 +    HeapFree(GetProcessHeap(), 0, This->sPath);
 +    This->sPath = NULL;
 +
 +    HeapFree(GetProcessHeap(), 0, This->sComponent);
 +    This->sComponent = NULL;
 +
 +    if (This->pPidl)
 +        ILFree(This->pPidl);
 +    This->pPidl = NULL;
 +
 +    if (S_OK != ShellLink_SetAdvertiseInfo( This, pszFile ))
 +    {
 +        if (*pszFile == '\0')
 +            *buffer = '\0';
 +        else if (!GetFullPathNameW(pszFile, MAX_PATH, buffer, &fname))
 +          return E_FAIL;
 +        else if(!PathFileExistsW(buffer) &&
 +              !SearchPathW(NULL, pszFile, NULL, MAX_PATH, buffer, NULL))
 +        hr = S_FALSE;
 +
 +        This->pPidl = SHSimpleIDListFromPathW(pszFile);
 +        ShellLink_GetVolumeInfo(buffer, &This->volume);
 +
 +        This->sPath = HeapAlloc( GetProcessHeap(), 0,
 +                             (wcslen( buffer )+1) * sizeof (WCHAR) );
 +        if (!This->sPath)
 +            return E_OUTOFMEMORY;
 +
 +        wcscpy(This->sPath, buffer);
 +    }
 +    This->bDirty = TRUE;
 +    HeapFree(GetProcessHeap(), 0, unquoted);
 +
 +    return hr;
 +}
 +
 +/**************************************************************************
 +* IShellLinkW Implementation
 +*/
 +
 +static const IShellLinkWVtbl slvtw =
 +{
 +    IShellLinkW_fnQueryInterface,
 +    IShellLinkW_fnAddRef,
 +    IShellLinkW_fnRelease,
 +    IShellLinkW_fnGetPath,
 +    IShellLinkW_fnGetIDList,
 +    IShellLinkW_fnSetIDList,
 +    IShellLinkW_fnGetDescription,
 +    IShellLinkW_fnSetDescription,
 +    IShellLinkW_fnGetWorkingDirectory,
 +    IShellLinkW_fnSetWorkingDirectory,
 +    IShellLinkW_fnGetArguments,
 +    IShellLinkW_fnSetArguments,
 +    IShellLinkW_fnGetHotkey,
 +    IShellLinkW_fnSetHotkey,
 +    IShellLinkW_fnGetShowCmd,
 +    IShellLinkW_fnSetShowCmd,
 +    IShellLinkW_fnGetIconLocation,
 +    IShellLinkW_fnSetIconLocation,
 +    IShellLinkW_fnSetRelativePath,
 +    IShellLinkW_fnResolve,
 +    IShellLinkW_fnSetPath
 +};
 +
 +static HRESULT WINAPI
 +ShellLink_DataList_QueryInterface( IShellLinkDataList* iface, REFIID riid, void** ppvObject)
 +{
 +    IShellLinkImpl *This = impl_from_IShellLinkDataList(iface);
 +    return IShellLinkA_QueryInterface((IShellLinkA*)This, riid, ppvObject);
 +}
 +
 +static ULONG WINAPI
 +ShellLink_DataList_AddRef( IShellLinkDataList* iface )
 +{
 +    IShellLinkImpl *This = impl_from_IShellLinkDataList(iface);
 +    return IShellLinkA_AddRef((IShellLinkA*)This);
 +}
 +
 +static ULONG WINAPI
 +ShellLink_DataList_Release( IShellLinkDataList* iface )
 +{
 +    IShellLinkImpl *This = impl_from_IShellLinkDataList(iface);
 +    return ShellLink_Release( This );
 +}
 +
 +static HRESULT WINAPI
 +ShellLink_AddDataBlock( IShellLinkDataList* iface, void* pDataBlock )
 +{
 +    FIXME("\n");
 +    return E_NOTIMPL;
 +}
 +
 +static HRESULT WINAPI
 +ShellLink_CopyDataBlock( IShellLinkDataList* iface, DWORD dwSig, void** ppDataBlock )
 +{
 +    IShellLinkImpl *This = impl_from_IShellLinkDataList(iface);
 +    LPVOID block = NULL;
 +    HRESULT r = E_FAIL;
 +
 +    TRACE("%p %08x %p\n", iface, dwSig, ppDataBlock );
 +
 +    switch (dwSig)
 +    {
 +    case EXP_DARWIN_ID_SIG:
 +        if (!This->sComponent)
 +            break;
 +        block = shelllink_build_darwinid( This->sComponent, dwSig );
 +        r = S_OK;
 +        break;
 +    case EXP_SZ_LINK_SIG:
 +    case NT_CONSOLE_PROPS_SIG:
 +    case NT_FE_CONSOLE_PROPS_SIG:
 +    case EXP_SPECIAL_FOLDER_SIG:
 +    case EXP_SZ_ICON_SIG:
 +        FIXME("valid but unhandled datablock %08x\n", dwSig);
 +        break;
 +    default:
 +        ERR("unknown datablock %08x\n", dwSig);
 +    }
 +    *ppDataBlock = block;
 +    return r;
 +}
 +
 +static HRESULT WINAPI
 +ShellLink_RemoveDataBlock( IShellLinkDataList* iface, DWORD dwSig )
 +{
 +    FIXME("\n");
 +    return E_NOTIMPL;
 +}
 +
 +static HRESULT WINAPI
 +ShellLink_GetFlags( IShellLinkDataList* iface, DWORD* pdwFlags )
 +{
 +    IShellLinkImpl *This = impl_from_IShellLinkDataList(iface);
 +    DWORD flags = 0;
 +
 +    FIXME("%p %p\n", This, pdwFlags );
 +
 +    /* FIXME: add more */
 +    if (This->sArgs)
 +        flags |= SLDF_HAS_ARGS;
 +    if (This->sComponent)
 +        flags |= SLDF_HAS_DARWINID;
 +    if (This->sIcoPath)
 +        flags |= SLDF_HAS_ICONLOCATION;
 +#if (NTDDI_VERSION < NTDDI_LONGHORN)
 +    if (This->sProduct)
 +        flags |= SLDF_HAS_LOGO3ID;
 +#endif
 +    if (This->pPidl)
 +        flags |= SLDF_HAS_ID_LIST;
 +
 +    *pdwFlags = flags;
 +
 +    return S_OK;
 +}
 +
 +static HRESULT WINAPI
 +ShellLink_SetFlags( IShellLinkDataList* iface, DWORD dwFlags )
 +{
 +    FIXME("\n");
 +    return E_NOTIMPL;
 +}
 +
 +static const IShellLinkDataListVtbl dlvt =
 +{
 +    ShellLink_DataList_QueryInterface,
 +    ShellLink_DataList_AddRef,
 +    ShellLink_DataList_Release,
 +    ShellLink_AddDataBlock,
 +    ShellLink_CopyDataBlock,
 +    ShellLink_RemoveDataBlock,
 +    ShellLink_GetFlags,
 +    ShellLink_SetFlags
 +};
 +
 +static HRESULT WINAPI
 +ShellLink_ExtInit_QueryInterface( IShellExtInit* iface, REFIID riid, void** ppvObject )
 +{
 +    IShellLinkImpl *This = impl_from_IShellExtInit(iface);
 +    return IShellLinkA_QueryInterface((IShellLinkA*)This, riid, ppvObject);
 +}
 +
 +static ULONG WINAPI
 +ShellLink_ExtInit_AddRef( IShellExtInit* iface )
 +{
 +    IShellLinkImpl *This = impl_from_IShellExtInit(iface);
 +    return IShellLinkA_AddRef((IShellLinkA*)This);
 +}
 +
 +static ULONG WINAPI
 +ShellLink_ExtInit_Release( IShellExtInit* iface )
 +{
 +    IShellLinkImpl *This = impl_from_IShellExtInit(iface);
 +    return ShellLink_Release( This );
 +}
 +
 +/**************************************************************************
 + * ShellLink implementation of IShellExtInit::Initialize()
 + *
 + * Loads the shelllink from the dataobject the shell is pointing to.
 + */
 +static HRESULT WINAPI
 +ShellLink_ExtInit_Initialize( IShellExtInit* iface, LPCITEMIDLIST pidlFolder,
 +                              IDataObject *pdtobj, HKEY hkeyProgID )
 +{
 +    IShellLinkImpl *This = impl_from_IShellExtInit(iface);
 +    FORMATETC format;
 +    STGMEDIUM stgm;
 +    UINT count;
 +    HRESULT r = E_FAIL;
 +
 +    TRACE("%p %p %p %p\n", This, pidlFolder, pdtobj, hkeyProgID );
 +
 +    if( !pdtobj )
 +        return r;
 +
 +    format.cfFormat = CF_HDROP;
 +    format.ptd = NULL;
 +    format.dwAspect = DVASPECT_CONTENT;
 +    format.lindex = -1;
 +    format.tymed = TYMED_HGLOBAL;
 +
 +    if( FAILED( IDataObject_GetData( pdtobj, &format, &stgm ) ) )
 +        return r;
 +
 +    count = DragQueryFileW( stgm.u.hGlobal, -1, NULL, 0 );
 +    if( count == 1 )
 +    {
 +        LPWSTR path;
 +
 +        count = DragQueryFileW( stgm.u.hGlobal, 0, NULL, 0 );
 +        count++;
 +        path = HeapAlloc( GetProcessHeap(), 0, count*sizeof(WCHAR) );
 +        if( path )
 +        {
 +            IPersistFile *pf = (IPersistFile*) &This->lpvtblPersistFile;
 +
 +            count = DragQueryFileW( stgm.u.hGlobal, 0, path, count );
 +            r = IPersistFile_Load( pf, path, 0 );
 +            HeapFree( GetProcessHeap(), 0, path );
 +        }
 +    }
 +    ReleaseStgMedium( &stgm );
 +
 +    return r;
 +}
 +
 +static const IShellExtInitVtbl eivt =
 +{
 +    ShellLink_ExtInit_QueryInterface,
 +    ShellLink_ExtInit_AddRef,
 +    ShellLink_ExtInit_Release,
 +    ShellLink_ExtInit_Initialize
 +};
 +
 +static HRESULT WINAPI
 +ShellLink_ContextMenu_QueryInterface( IContextMenu* iface, REFIID riid, void** ppvObject )
 +{
 +    IShellLinkImpl *This = impl_from_IContextMenu(iface);
 +    return IShellLinkA_QueryInterface((IShellLinkA*)This, riid, ppvObject);
 +}
 +
 +static ULONG WINAPI
 +ShellLink_ContextMenu_AddRef( IContextMenu* iface )
 +{
 +    IShellLinkImpl *This = impl_from_IContextMenu(iface);
 +    return IShellLinkA_AddRef((IShellLinkA*)This);
 +}
 +
 +static ULONG WINAPI
 +ShellLink_ContextMenu_Release( IContextMenu* iface )
 +{
 +    IShellLinkImpl *This = impl_from_IContextMenu(iface);
 +    return ShellLink_Release( This );
 +}
 +
 +static HRESULT WINAPI
 +ShellLink_QueryContextMenu( IContextMenu* iface, HMENU hmenu, UINT indexMenu,
 +                            UINT idCmdFirst, UINT idCmdLast, UINT uFlags )
 +{
 +    IShellLinkImpl *This = impl_from_IContextMenu(iface);
 +    WCHAR szOpen[20];
 +    MENUITEMINFOW mii;
 +    int id = 1;
 +
 +    TRACE("%p %p %u %u %u %u\n", This,
 +          hmenu, indexMenu, idCmdFirst, idCmdLast, uFlags );
 +
 +    if ( !hmenu )
 +        return E_INVALIDARG;
 +
 +    if (!LoadStringW(shell32_hInstance, IDS_OPEN_VERB, szOpen, sizeof(szOpen)/sizeof(WCHAR)))
 +        szOpen[0] = L'\0';
 +    else
 +        szOpen[(sizeof(szOpen)/sizeof(WCHAR))-1] = L'\0';
 +
 +    memset( &mii, 0, sizeof(mii) );
 +    mii.cbSize = sizeof (mii);
 +    mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE;
 +    mii.dwTypeData = (LPWSTR)szOpen;
 +    mii.cch = wcslen( mii.dwTypeData );
 +    mii.wID = idCmdFirst + id++;
 +    mii.fState = MFS_DEFAULT | MFS_ENABLED;
 +    mii.fType = MFT_STRING;
 +    if (!InsertMenuItemW( hmenu, indexMenu, TRUE, &mii ))
 +        return E_FAIL;
 +    This->iIdOpen = 1;
 +
 +    return MAKE_HRESULT( SEVERITY_SUCCESS, 0, id );
 +}
 +
 +static LPWSTR
 +shelllink_get_msi_component_path( LPWSTR component )
 +{
 +    LPWSTR path;
 +    DWORD r, sz = 0;
 +
 +    r = CommandLineFromMsiDescriptor( component, NULL, &sz );
 +    if (r != ERROR_SUCCESS)
 +         return NULL;
 +
 +    sz++;
 +    path = HeapAlloc( GetProcessHeap(), 0, sz*sizeof(WCHAR) );
 +    r = CommandLineFromMsiDescriptor( component, path, &sz );
 +    if (r != ERROR_SUCCESS)
 +    {
 +        HeapFree( GetProcessHeap(), 0, path );
 +        path = NULL;
 +    }
 +
 +    TRACE("returning %s\n", debugstr_w( path ) );
 +
 +    return path;
 +}
 +
 +INT_PTR CALLBACK ExtendedShortcutProc(
 +    HWND hwndDlg,
 +    UINT uMsg,
 +    WPARAM wParam,
 +    LPARAM lParam
 +)
 +{
 +   HWND hDlgCtrl;
 +
 +   switch(uMsg)
 +   {
 +   case WM_INITDIALOG:
 +       if (lParam)
 +       {
 +            hDlgCtrl = GetDlgItem(hwndDlg, 14000);
 +            SendMessage(hDlgCtrl, BM_SETCHECK, BST_CHECKED, 0);
 +       }
 +       return TRUE;
 +   case WM_COMMAND:
 +        hDlgCtrl = GetDlgItem(hwndDlg, 14000);
 +              if (LOWORD(wParam) == IDOK)
 +        {
 +                 if ( SendMessage(hDlgCtrl, BM_GETCHECK, 0, 0) == BST_CHECKED )
 +                EndDialog(hwndDlg, 1);
 +           else
 +              EndDialog(hwndDlg, 0);
 +        }
 +        else if (LOWORD(wParam) == IDCANCEL)
 +        {
 +            EndDialog(hwndDlg, -1);
 +        }
 +        else if (LOWORD(wParam) == 14000)
 +        {
 +           if ( SendMessage(hDlgCtrl, BM_GETCHECK, 0, 0) == BST_CHECKED)
 +              SendMessage(hDlgCtrl, BM_SETCHECK, BST_UNCHECKED, 0);
 +           else
 +              SendMessage(hDlgCtrl, BM_SETCHECK, BST_CHECKED, 0);
 +
 +        }
 +   }
 +   return FALSE;
 +}
 +
 +/**************************************************************************
 + * SH_ShellLinkDlgProc
 + *
 + * dialog proc of the shortcut property dialog
 + */
 +
 +INT_PTR
 +CALLBACK
 +SH_ShellLinkDlgProc(
 +    HWND hwndDlg,
 +    UINT uMsg,
 +    WPARAM wParam,
 +    LPARAM lParam
 +)
 +{
 +    LPPROPSHEETPAGEW ppsp;
 +    LPPSHNOTIFY lppsn;
 +    IShellLinkImpl *This;
 +    HWND hDlgCtrl;
 +    WCHAR szBuffer[MAX_PATH];
 +    WCHAR * ptr;
 +    int IconIndex;
 +    INT_PTR result;
 +
 +    This = (IShellLinkImpl *)GetWindowLongPtr(hwndDlg, DWLP_USER);
 +
 +    switch(uMsg)
 +    {
 +    case WM_INITDIALOG:
 +        ppsp = (LPPROPSHEETPAGEW)lParam;
 +        if (ppsp == NULL)
 +            break;
 +
 +        TRACE("ShellLink_DlgProc (WM_INITDIALOG hwnd %p lParam %p ppsplParam %x)\n",hwndDlg, lParam, ppsp->lParam);
 +
 +        This = (IShellLinkImpl *)ppsp->lParam;
 +        SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)This);
 +
 +              TRACE("sArgs: %S sComponent: %S sDescription: %S sIcoPath: %S sPath: %S sPathRel: %S sProduct: %S sWorkDir: %S\n", This->sArgs, This->sComponent ,This->sDescription,
 +                      This->sIcoPath, This->sPath, This->sPathRel, This->sProduct, This->sWorkDir);
 +
 +        /* target path */
 +        hDlgCtrl = GetDlgItem( hwndDlg, 14009 );
 +        if ( hDlgCtrl != NULL )
 +            SendMessageW( hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)This->sPath );
 +
 +       /* working dir */
 +       hDlgCtrl = GetDlgItem( hwndDlg, 14011 );
 +       if ( hDlgCtrl != NULL )
 +            SendMessageW( hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)This->sWorkDir );
 +
 +         /* description */
 +       hDlgCtrl = GetDlgItem( hwndDlg, 14019 );
 +       if ( hDlgCtrl != NULL )
 +            SendMessageW( hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)This->sDescription );
 +        return TRUE;
 +    case WM_NOTIFY:
 +       lppsn = (LPPSHNOTIFY) lParam;
 +       if ( lppsn->hdr.code == PSN_APPLY )
 +       {
 +            /* set working directory */
 +            hDlgCtrl = GetDlgItem( hwndDlg, 14011 );
 +            SendMessageW( hDlgCtrl, WM_GETTEXT, (WPARAM)MAX_PATH, (LPARAM)szBuffer );
 +            IShellLinkW_fnSetWorkingDirectory((IShellLinkW*)&This->lpvtblw, szBuffer);
 +            /* set link destination */
 +            hDlgCtrl = GetDlgItem( hwndDlg, 14009 );
 +            SendMessageW( hDlgCtrl, WM_GETTEXT, (WPARAM)MAX_PATH, (LPARAM)szBuffer);
 +            if ( !SHELL_ExistsFileW(szBuffer) )
 +            {
 +                //FIXME load localized error msg
 +                MessageBoxW( hwndDlg, L"file not existing", szBuffer, MB_OK );
 +                SetWindowLongPtr( hwndDlg, DWL_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE );
 +                return TRUE;
 +            }
 +            ptr = wcsrchr(szBuffer, L'.');
 +            if (ptr && !_wcsnicmp(ptr, L".lnk", 4))
 +            {
 +                // FIXME load localized error msg
 +                MessageBoxW( hwndDlg, L"You cannot create a link to a shortcut", L"Error", MB_ICONERROR );
 +                SetWindowLongPtr( hwndDlg, DWL_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE );
 +                return TRUE;
 +            }
 +
 +            IShellLinkW_fnSetPath((IShellLinkW*)&This->lpvtblw, szBuffer);
 +
 +            TRACE("This %p sLinkPath %S\n", This, This->sLinkPath);
 +            IPersistFile_fnSave( (IPersistFile*)&This->lpvtblPersistFile, This->sLinkPath, TRUE );
 +            SetWindowLongPtr( hwndDlg, DWL_MSGRESULT, PSNRET_NOERROR );
 +            return TRUE;
 +       }
 +       break;
 +    case WM_COMMAND:
 +       switch(LOWORD(wParam))
 +       {
 +           case 14020:
 +               ///
 +               /// FIXME
 +               /// open target directory
 +               ///
 +               return TRUE;
 +           case 14021:
 +               if (This->sIcoPath)
 +                    wcscpy(szBuffer, This->sIcoPath);
 +               else
 +                    wcscpy(szBuffer, This->sPath);
 +
 +               IconIndex = This->iIcoNdx;
 +               if (PickIconDlg(hwndDlg, szBuffer, MAX_PATH, &IconIndex))
 +               {
 +                    IShellLinkW_fnSetIconLocation((IShellLinkW*)&This->lpvtblw, szBuffer, IconIndex);
 +                    ///
 +                    /// FIXME redraw icon
 +               }
 +               return TRUE;
 +           case 14022:
 +               result = DialogBoxParamW(shell32_hInstance, MAKEINTRESOURCEW(SHELL_EXTENDED_SHORTCUT_DLG), hwndDlg, ExtendedShortcutProc, (LPARAM)This->bRunAs);
 +               if (result == 1 || result == 0)
 +               {
 +                   if ( This->bRunAs != result )
 +                   {
 +                       PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
 +                   }
 +
 +                   This->bRunAs = result;
 +               }
 +               return TRUE;
 +       }
 +       switch(HIWORD(wParam))
 +       {
 +           case EN_CHANGE:
 +              PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
 +              break;
 +       }
 +       break;
 +    default:
 +        break;
 +   }
 +   return FALSE;
 +}
 +
 +/**************************************************************************
 + * ShellLink_IShellPropSheetExt interface
 + */
 +
 +static HRESULT WINAPI
 + ShellLink_IShellPropSheetExt_QueryInterface( IShellPropSheetExt* iface, REFIID riid, void** ppvObject )
 +{
 +    IShellLinkImpl *This = impl_from_IShellPropSheetExt(iface);
 +    return ShellLink_QueryInterface( This, riid, ppvObject );
 +}
 +
 +static ULONG WINAPI
 + ShellLink_IShellPropSheetExt_AddRef( IShellPropSheetExt* iface )
 +{
 +    IShellLinkImpl *This = impl_from_IShellPropSheetExt(iface);
 +    return ShellLink_AddRef( This );
 +}
 +
 +static ULONG WINAPI
 + ShellLink_IShellPropSheetExt_Release( IShellPropSheetExt* iface )
 +{
 +    IShellLinkImpl *This = impl_from_IShellPropSheetExt(iface);
 +    return ShellLink_Release( This );
 +}
 +
 +static HRESULT WINAPI
 + ShellLink_IShellPropSheetExt_AddPages( IShellPropSheetExt *iface, LPFNADDPROPSHEETPAGE pfnAddPage, LPARAM lParam)
 +{
 +    HPROPSHEETPAGE hPage;
 +    BOOL bRet;
 +    IShellLinkImpl *This = impl_from_IShellPropSheetExt(iface);
 +
 +    hPage = SH_CreatePropertySheetPage("SHELL_GENERAL_SHORTCUT_DLG", SH_ShellLinkDlgProc, (LPARAM)This, NULL);
 +    if (hPage == NULL)
 +    {
 +       ERR("failed to create property sheet page\n");
 +       return E_FAIL;
 +    }
 +
 +    bRet = pfnAddPage(hPage, lParam);
 +    if (bRet)
 +       return S_OK;
 +    else
 +       return E_FAIL;
 +}
 +
 +static HRESULT WINAPI
 + ShellLink_IShellPropSheetExt_ReplacePages( IShellPropSheetExt *iface, UINT uPageID, LPFNADDPROPSHEETPAGE pfnReplacePage, LPARAM lParam)
 +{
 +    IShellLinkImpl *This = impl_from_IShellPropSheetExt(iface);
 +    TRACE("(%p) (uPageID %u, pfnReplacePage %p lParam %p\n", This, uPageID, pfnReplacePage, lParam);
 +    return E_NOTIMPL;
 +}
 +
 +static const IShellPropSheetExtVtbl pse =
 +{
 +    ShellLink_IShellPropSheetExt_QueryInterface,
 +    ShellLink_IShellPropSheetExt_AddRef,
 +    ShellLink_IShellPropSheetExt_Release,
 +    ShellLink_IShellPropSheetExt_AddPages,
 +    ShellLink_IShellPropSheetExt_ReplacePages
 +};
 +
 +static HRESULT WINAPI
 +ShellLink_InvokeCommand( IContextMenu* iface, LPCMINVOKECOMMANDINFO lpici )
 +{
 +    IShellLinkImpl *This = impl_from_IContextMenu(iface);
 +    static const WCHAR szOpen[] = { 'o','p','e','n',0 };
 +    static const WCHAR szCplOpen[] = { 'c','p','l','o','p','e','n',0 };
 +    SHELLEXECUTEINFOW sei;
 +    HWND hwnd = NULL; /* FIXME: get using interface set from IObjectWithSite */
 +    LPWSTR args = NULL;
 +    LPWSTR path = NULL;
 +    HRESULT r;
 +
 +    TRACE("%p %p\n", This, lpici );
 +
 +    if ( lpici->cbSize < sizeof (CMINVOKECOMMANDINFO) )
 +        return E_INVALIDARG;
 +
 +    r = IShellLinkW_Resolve( (IShellLinkW*)&(This->lpvtblw), hwnd, 0 );
 +    if ( FAILED( r ) )
 +    {
 +        TRACE("failed to resolve component with error 0x%08x", r);
 +        return r;
 +    }
 +    if ( This->sComponent )
 +    {
 +        path = shelllink_get_msi_component_path( This->sComponent );
 +        if (!path)
 +            return E_FAIL;
 +    }
 +    else
 +        path = strdupW( This->sPath );
 +
 +    if ( lpici->cbSize == sizeof (CMINVOKECOMMANDINFOEX) &&
 +         ( lpici->fMask & CMIC_MASK_UNICODE ) )
 +    {
 +        LPCMINVOKECOMMANDINFOEX iciex = (LPCMINVOKECOMMANDINFOEX) lpici;
 +        DWORD len = 2;
 +
 +        if ( This->sArgs )
 +            len += wcslen( This->sArgs );
 +        if ( iciex->lpParametersW )
 +            len += wcslen( iciex->lpParametersW );
 +
 +        args = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
 +        args[0] = 0;
 +        if ( This->sArgs )
 +            wcscat( args, This->sArgs );
 +        if ( iciex->lpParametersW )
 +        {
 +            static const WCHAR space[] = { ' ', 0 };
 +            wcscat( args, space );
 +            wcscat( args, iciex->lpParametersW );
 +        }
 +    }
 +    else if (This->sArgs != NULL)
 +    {
 +        args = strdupW( This->sArgs );
 +    }
 +
 +    memset( &sei, 0, sizeof sei );
 +    sei.cbSize = sizeof sei;
 +    sei.fMask = SEE_MASK_UNICODE | (lpici->fMask & (SEE_MASK_NOASYNC|SEE_MASK_ASYNCOK|SEE_MASK_FLAG_NO_UI));
 +    sei.lpFile = path;
 +    sei.nShow = This->iShowCmd;
 +    sei.lpDirectory = This->sWorkDir;
 +    sei.lpParameters = args;
 +    sei.lpVerb = szOpen;
 +
 +    // HACK for ShellExecuteExW
 +    if (!wcsstr(This->sPath, L".cpl"))
 +        sei.lpVerb = szOpen;
 +    else
 +        sei.lpVerb = szCplOpen;
 +
 +    if( ShellExecuteExW( &sei ) )
 +        r = S_OK;
 +    else
 +        r = E_FAIL;
 +
 +    HeapFree( GetProcessHeap(), 0, args );
 +    HeapFree( GetProcessHeap(), 0, path );
 +
 +    return r;
 +}
 +
 +static HRESULT WINAPI
 +ShellLink_GetCommandString( IContextMenu* iface, UINT_PTR idCmd, UINT uType,
 +                            UINT* pwReserved, LPSTR pszName, UINT cchMax )
 +{
 +    IShellLinkImpl *This = impl_from_IContextMenu(iface);
 +
 +    FIXME("%p %lu %u %p %p %u\n", This,
 +          idCmd, uType, pwReserved, pszName, cchMax );
 +
 +    return E_NOTIMPL;
 +}
 +
 +static const IContextMenuVtbl cmvt =
 +{
 +    ShellLink_ContextMenu_QueryInterface,
 +    ShellLink_ContextMenu_AddRef,
 +    ShellLink_ContextMenu_Release,
 +    ShellLink_QueryContextMenu,
 +    ShellLink_InvokeCommand,
 +    ShellLink_GetCommandString
 +};
 +
 +static HRESULT WINAPI
 +ShellLink_ObjectWithSite_QueryInterface( IObjectWithSite* iface, REFIID riid, void** ppvObject )
 +{
 +    IShellLinkImpl *This = impl_from_IObjectWithSite(iface);
 +    return ShellLink_QueryInterface( This, riid, ppvObject );
 +}
 +
 +static ULONG WINAPI
 +ShellLink_ObjectWithSite_AddRef( IObjectWithSite* iface )
 +{
 +    IShellLinkImpl *This = impl_from_IObjectWithSite(iface);
 +    return ShellLink_AddRef( This );
 +}
 +
 +static ULONG WINAPI
 +ShellLink_ObjectWithSite_Release( IObjectWithSite* iface )
 +{
 +    IShellLinkImpl *This = impl_from_IObjectWithSite(iface);
 +    return ShellLink_Release( This );
 +}
 +
 +static HRESULT WINAPI
 +ShellLink_GetSite( IObjectWithSite *iface, REFIID iid, void ** ppvSite )
 +{
 +    IShellLinkImpl *This = impl_from_IObjectWithSite(iface);
 +
 +    TRACE("%p %s %p\n", This, debugstr_guid( iid ), ppvSite );
 +
 +    if ( !This->site )
 +        return E_FAIL;
 +    return IUnknown_QueryInterface( This->site, iid, ppvSite );
 +}
 +
 +static HRESULT WINAPI
 +ShellLink_SetSite( IObjectWithSite *iface, IUnknown *punk )
 +{
 +    IShellLinkImpl *This = impl_from_IObjectWithSite(iface);
 +
 +    TRACE("%p %p\n", iface, punk);
 +
 +    if ( punk )
 +        IUnknown_AddRef( punk );
 +    This->site = punk;
 +
 +    return S_OK;
 +}
 +
 +static const IObjectWithSiteVtbl owsvt =
 +{
 +    ShellLink_ObjectWithSite_QueryInterface,
 +    ShellLink_ObjectWithSite_AddRef,
 +    ShellLink_ObjectWithSite_Release,
 +    ShellLink_SetSite,
 +    ShellLink_GetSite,
 +};
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 0000000,75a4c03..75a4c03
mode 000000,100644..100644
--- /dev/null
index 0000000,7a4dcd7..7a4dcd7
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
diff --cc lib/lib.rbuild
Simple merge
index 445f38e,dd67502..dd67502
Binary files differ
index 78983c5,a9bd9f5..a9bd9f5
Binary files differ
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 0000000,839d6fe..839d6fe
mode 000000,100644..100644
--- /dev/null
index 0000000,c38aa3f..c38aa3f
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 7e48a4d,0000000..b924112
mode 100644,000000..100644
--- /dev/null
@@@ -1,480 -1,0 +1,477 @@@
-   int dx;
 +/*
 + * PROJECT:         Win32 subsystem
 + * LICENSE:         See COPYING in the top level directory
 + * FILE:            subsystems/win32/win32k/dib/dib1bpp.c
 + * PURPOSE:         Device Independant Bitmap functions, 1bpp
 + * PROGRAMMERS:     Jason Filby
 + */
 +
 +#include <win32k.h>
 +
 +#define NDEBUG
 +#include <debug.h>
 +
 +VOID
 +DIB_1BPP_PutPixel(SURFOBJ *SurfObj, LONG x, LONG y, ULONG c)
 +{
 +  PBYTE addr = (PBYTE)SurfObj->pvScan0 + y * SurfObj->lDelta + (x >> 3);
 +
 +  if (0 == (c & 0x01))
 +    *addr &= ~MASK1BPP(x);
 +  else
 +    *addr |= MASK1BPP(x);
 +}
 +
 +ULONG
 +DIB_1BPP_GetPixel(SURFOBJ *SurfObj, LONG x, LONG y)
 +{
 +  PBYTE addr = (PBYTE)SurfObj->pvScan0 + y * SurfObj->lDelta + (x >> 3);
 +
 +  return (*addr & MASK1BPP(x) ? 1 : 0);
 +}
 +
 +VOID
 +DIB_1BPP_HLine(SURFOBJ *SurfObj, LONG x1, LONG x2, LONG y, ULONG c)
 +{
 +  while(x1 < x2)
 +  {
 +    DIB_1BPP_PutPixel(SurfObj, x1, y, c);
 +    x1++;
 +  }
 +}
 +
 +VOID
 +DIB_1BPP_VLine(SURFOBJ *SurfObj, LONG x, LONG y1, LONG y2, ULONG c)
 +{
 +  while(y1 < y2)
 +  {
 +    DIB_1BPP_PutPixel(SurfObj, x, y1, c);
 +    y1++;
 +  }
 +}
 +
 +static
 +void
 +DIB_1BPP_BitBltSrcCopy_From1BPP (
 +                                 SURFOBJ* DestSurf,
 +                                 SURFOBJ* SourceSurf,
 +                                 XLATEOBJ* pxlo,
 +                                 PRECTL DestRect,
 +                                 POINTL *SourcePoint )
 +{
 +  // the 'window' in this sense is the x-position that corresponds
 +  // to the left-edge of the 8-pixel byte we are currently working with.
 +  // dwx is current x-window, dwx2 is the 'last' window we need to process
 +  int dwx, dwx2; // destination window x-position
 +  int swx; // source window y-position
 +
 +  // left and right edges of source and dest rectangles
 +  int dl = DestRect->left; // dest left
 +  int dr = DestRect->right-1; // dest right (inclusive)
 +  int sl = SourcePoint->x; // source left
 +  int sr = sl + dr - dl; // source right (inclusive)
 +
 +  // which direction are we going?
 +  int xinc;
 +  int yinc;
 +  int ySrcDelta, yDstDelta;
 +
 +  // following 4 variables are used for the y-sweep
 +  int dy; // dest y
 +  int dy1; // dest y start
 +  int dy2; // dest y end
 +  int sy1; // src y start
 +
-     dx = dwx; /* dest x for this pass */
 +  int shift;
 +  BYTE srcmask, dstmask, xormask;
 +
 +  // 'd' and 's' are the dest & src buffer pointers that I use on my x-sweep
 +  // 'pd' and 'ps' are the dest & src buffer pointers used on the inner y-sweep
 +  PBYTE d, pd; // dest ptrs
 +  PBYTE s, ps; // src ptrs
 +
 +  shift = (dl-sl)&7;
 +
 +  xormask = 0xFF * XLATEOBJ_iXlate(pxlo, 0);
 +
 +  if ( DestRect->top <= SourcePoint->y )
 +  {
 +    // moving up ( scan top -> bottom )
 +    dy1 = DestRect->top;
 +    dy2 = DestRect->bottom - 1;
 +    sy1 = SourcePoint->y;
 +    yinc = 1;
 +    ySrcDelta = SourceSurf->lDelta;
 +    yDstDelta = DestSurf->lDelta;
 +  }
 +  else
 +  {
 +    // moving down ( scan bottom -> top )
 +    dy1 = DestRect->bottom - 1;
 +    dy2 = DestRect->top;
 +    sy1 = SourcePoint->y + dy1 - dy2;
 +    yinc = -1;
 +    ySrcDelta = -SourceSurf->lDelta;
 +    yDstDelta = -DestSurf->lDelta;
 +  }
 +  if ( DestRect->left <= SourcePoint->x )
 +  {
 +    // moving left ( scan left->right )
 +    dwx = dl&~7;
 +    swx = (sl-(dl&7))&~7;
 +    dwx2 = dr&~7;
 +    xinc = 1;
 +  }
 +  else
 +  {
 +    // moving right ( scan right->left )
 +    dwx = dr&~7;
 +    swx = (sr-(dr&7))&~7; //(sr-7)&~7; // we need the left edge of this block... thus the -7
 +    dwx2 = dl&~7;
 +    xinc = -1;
 +  }
 +  d = &(((PBYTE)DestSurf->pvScan0)[dy1*DestSurf->lDelta + (dwx>>3)]);
 +  s = &(((PBYTE)SourceSurf->pvScan0)[sy1*SourceSurf->lDelta + (swx>>3)]);
 +  for ( ;; )
 +  {
 +    dy = dy1;
 +    pd = d;
 +    ps = s;
 +    srcmask = 0xff;
-       dx = dl;
 +    if ( dwx < dl )
 +    {
 +      int diff = dl-dwx;
 +      srcmask &= (1<<(8-diff))-1;
 +    }
 +    if ( dwx+7 > dr )
 +    {
 +      int diff = dr-dwx+1;
 +      srcmask &= ~((1<<(8-diff))-1);
 +    }
 +    dstmask = ~srcmask;
 +
 +    // we unfortunately *must* have 5 different versions of the inner
 +    // loop to be certain we don't try to read from memory that is not
 +    // needed and may in fact be invalid
 +    if ( !shift )
 +    {
 +      for ( ;; )
 +      {
 +        *pd = (BYTE)((*pd & dstmask) | ((ps[0]^xormask) & srcmask));
 +
 +        // this *must* be here, because we could be going up *or* down...
 +        if ( dy == dy2 )
 +          break;
 +        dy += yinc;
 +        pd += yDstDelta;
 +        ps += ySrcDelta;
 +      }
 +    }
 +    else if ( !(0xFF00 & (srcmask<<shift) ) ) // check if ps[0] not needed...
 +    {
 +      for ( ;; )
 +      {
 +        *pd = (BYTE)((*pd & dstmask)
 +          | ( ( (ps[1]^xormask) >> shift ) & srcmask ));
 +
 +        // this *must* be here, because we could be going up *or* down...
 +        if ( dy == dy2 )
 +          break;
 +        dy += yinc;
 +        pd += yDstDelta;
 +        ps += ySrcDelta;
 +      }
 +    }
 +    else if ( !(0xFF & (srcmask<<shift) ) ) // check if ps[1] not needed...
 +    {
 +      for ( ;; )
 +      {
 +        *pd = (*pd & dstmask)
 +          | ( ( (ps[0]^xormask) << ( 8 - shift ) ) & srcmask );
 +
 +        // this *must* be here, because we could be going up *or* down...
 +        if ( dy == dy2 )
 +          break;
 +        dy += yinc;
 +        pd += yDstDelta;
 +        ps += ySrcDelta;
 +      }
 +    }
 +    else // both ps[0] and ps[1] are needed
 +    {
 +      for ( ;; )
 +      {
 +        *pd = (*pd & dstmask)
 +          | ( ( ( ((ps[1]^xormask))|((ps[0]^xormask)<<8) ) >> shift ) & srcmask );
 +
 +        // this *must* be here, because we could be going up *or* down...
 +        if ( dy == dy2 )
 +          break;
 +        dy += yinc;
 +        pd += yDstDelta;
 +        ps += ySrcDelta;
 +      }
 +    }
 +
 +    // this *must* be here, because we could be going right *or* left...
 +    if ( dwx == dwx2 )
 +      break;
 +    d += xinc;
 +    s += xinc;
 +    dwx += xinc<<3;
 +    swx += xinc<<3;
 +  }
 +}
 +
 +BOOLEAN
 +DIB_1BPP_BitBltSrcCopy(PBLTINFO BltInfo)
 +{
 +  ULONG Color;
 +  LONG i, j, sx, sy = BltInfo->SourcePoint.y;
 +
 +  switch ( BltInfo->SourceSurface->iBitmapFormat )
 +  {
 +  case BMF_1BPP:
 +    DIB_1BPP_BitBltSrcCopy_From1BPP ( BltInfo->DestSurface, BltInfo->SourceSurface, BltInfo->XlateSourceToDest, &BltInfo->DestRect, &BltInfo->SourcePoint );
 +    break;
 +
 +  case BMF_4BPP:
 +    for (j=BltInfo->DestRect.top; j<BltInfo->DestRect.bottom; j++)
 +    {
 +      sx = BltInfo->SourcePoint.x;
 +      for (i=BltInfo->DestRect.left; i<BltInfo->DestRect.right; i++)
 +      {
 +        Color = XLATEOBJ_iXlate(BltInfo->XlateSourceToDest, DIB_4BPP_GetPixel(BltInfo->SourceSurface, sx, sy));
 +        DIB_1BPP_PutPixel(BltInfo->DestSurface, i, j, Color);
 +        sx++;
 +      }
 +      sy++;
 +    }
 +    break;
 +
 +  case BMF_8BPP:
 +    for (j=BltInfo->DestRect.top; j<BltInfo->DestRect.bottom; j++)
 +    {
 +      sx = BltInfo->SourcePoint.x;
 +      for (i=BltInfo->DestRect.left; i<BltInfo->DestRect.right; i++)
 +      {
 +        Color = XLATEOBJ_iXlate(BltInfo->XlateSourceToDest, DIB_8BPP_GetPixel(BltInfo->SourceSurface, sx, sy));
 +        DIB_1BPP_PutPixel(BltInfo->DestSurface, i, j, Color);
 +        sx++;
 +      }
 +      sy++;
 +    }
 +    break;
 +
 +  case BMF_16BPP:
 +    for (j=BltInfo->DestRect.top; j<BltInfo->DestRect.bottom; j++)
 +    {
 +      sx = BltInfo->SourcePoint.x;
 +      for (i=BltInfo->DestRect.left; i<BltInfo->DestRect.right; i++)
 +      {
 +        Color = XLATEOBJ_iXlate(BltInfo->XlateSourceToDest, DIB_16BPP_GetPixel(BltInfo->SourceSurface, sx, sy));
 +        DIB_1BPP_PutPixel(BltInfo->DestSurface, i, j, Color);
 +        sx++;
 +      }
 +      sy++;
 +    }
 +    break;
 +
 +  case BMF_24BPP:
 +    for (j=BltInfo->DestRect.top; j<BltInfo->DestRect.bottom; j++)
 +    {
 +      sx = BltInfo->SourcePoint.x;
 +      for (i=BltInfo->DestRect.left; i<BltInfo->DestRect.right; i++)
 +      {
 +        Color = XLATEOBJ_iXlate(BltInfo->XlateSourceToDest, DIB_24BPP_GetPixel(BltInfo->SourceSurface, sx, sy));
 +        DIB_1BPP_PutPixel(BltInfo->DestSurface, i, j, Color);
 +        sx++;
 +      }
 +      sy++;
 +    }
 +    break;
 +
 +  case BMF_32BPP:
 +    for (j=BltInfo->DestRect.top; j<BltInfo->DestRect.bottom; j++)
 +    {
 +      sx = BltInfo->SourcePoint.x;
 +      for (i=BltInfo->DestRect.left; i<BltInfo->DestRect.right; i++)
 +      {
 +        Color = XLATEOBJ_iXlate(BltInfo->XlateSourceToDest, DIB_32BPP_GetPixel(BltInfo->SourceSurface, sx, sy));
 +        DIB_1BPP_PutPixel(BltInfo->DestSurface, i, j, Color);
 +        sx++;
 +      }
 +      sy++;
 +    }
 +    break;
 +
 +  default:
 +    DbgPrint("DIB_1BPP_BitBlt: Unhandled Source BPP: %u\n", BitsPerFormat(BltInfo->SourceSurface->iBitmapFormat));
 +    return FALSE;
 +  }
 +
 +  return TRUE;
 +}
 +
 +BOOLEAN
 +DIB_1BPP_BitBlt(PBLTINFO BltInfo)
 +{
 +  ULONG DestX, DestY;
 +  ULONG SourceX, SourceY;
 +  ULONG PatternY = 0;
 +  ULONG Dest, Source = 0, Pattern = 0;
 +  ULONG Index;
 +  BOOLEAN UsesSource;
 +  BOOLEAN UsesPattern;
 +  PULONG DestBits;
 +  ULONG RoundedRight;
 +
 +  UsesSource = ROP4_USES_SOURCE(BltInfo->Rop4);
 +  UsesPattern = ROP4_USES_PATTERN(BltInfo->Rop4);
 +
 +  RoundedRight = BltInfo->DestRect.right -
 +    ((BltInfo->DestRect.right - BltInfo->DestRect.left) & 31);
 +  SourceY = BltInfo->SourcePoint.y;
 +
 +  if (UsesPattern)
 +  {
 +    if (BltInfo->PatternSurface)
 +    {
 +      PatternY = (BltInfo->DestRect.top + BltInfo->BrushOrigin.y) %
 +        BltInfo->PatternSurface->sizlBitmap.cy;
 +    }
 +    else
 +    {
 +      /* FIXME: Shouldn't it be expanded? */
 +      if (BltInfo->Brush)
 +        Pattern = BltInfo->Brush->iSolidColor;
 +    }
 +  }
 +
 +  for (DestY = BltInfo->DestRect.top; DestY < BltInfo->DestRect.bottom; DestY++)
 +  {
 +    DestX = BltInfo->DestRect.left;
 +    SourceX = BltInfo->SourcePoint.x;
 +    DestBits = (PULONG)(
 +      (PBYTE)BltInfo->DestSurface->pvScan0 +
 +      (BltInfo->DestRect.left >> 3) +
 +      DestY * BltInfo->DestSurface->lDelta);
 +
 +    if (DestX & 31)
 +    {
 +#if 0
 +      /* FIXME: This case is completely untested!!! */
 +
 +      Dest = *((PBYTE)DestBits);
 +      NoBits = 31 - (DestX & 31);
 +
 +      if (UsesSource)
 +      {
 +        Source = 0;
 +        /* FIXME: This is incorrect! */
 +        for (Index = 31 - NoBits; Index >= 0; Index++)
 +          Source |= (DIB_GetSource(SourceSurf, SourceX + Index, SourceY, ColorTranslation) << (31 - Index));
 +      }
 +
 +      if (BltInfo->PatternSurface)
 +      {
 +        Pattern = 0;
 +        for (k = 31 - NoBits; k >= 0; k++)
 +          Pattern |= (DIB_GetSourceIndex(PatternObj, (X + BrushOrigin.x + k) % PatternWidth, PatternY) << (31 - k));
 +      }
 +
 +      Dest = DIB_DoRop(Rop4, Dest, Source, Pattern);
 +      Dest &= ~((1 << (31 - NoBits)) - 1);
 +      Dest |= *((PBYTE)DestBits) & ((1 << (31 - NoBits)) - 1);
 +
 +      *DestBits = Dest;
 +
 +      DestX += NoBits;
 +      SourceX += NoBits;
 +#endif
 +    }
 +
 +    for (; DestX < RoundedRight; DestX += 32, DestBits++, SourceX += 32)
 +    {
 +      Dest = *DestBits;
 +
 +      if (UsesSource)
 +      {
 +        Source = 0;
 +        for (Index = 0; Index < 8; Index++)
 +        {
 +          Source |= DIB_GetSource(BltInfo->SourceSurface, SourceX + Index, SourceY, BltInfo->XlateSourceToDest) << (7 - Index);
 +          Source |= DIB_GetSource(BltInfo->SourceSurface, SourceX + Index + 8, SourceY, BltInfo->XlateSourceToDest) << (8 + (7 - Index));
 +          Source |= DIB_GetSource(BltInfo->SourceSurface, SourceX + Index + 16, SourceY, BltInfo->XlateSourceToDest) << (16 + (7 - Index));
 +          Source |= DIB_GetSource(BltInfo->SourceSurface, SourceX + Index + 24, SourceY, BltInfo->XlateSourceToDest) << (24 + (7 - Index));
 +        }
 +      }
 +
 +      if (BltInfo->PatternSurface)
 +      {
 +        Pattern = 0;
 +        for (Index = 0; Index < 8; Index++)
 +        {
 +          Pattern |= DIB_GetSourceIndex(BltInfo->PatternSurface, (DestX + BltInfo->BrushOrigin.x + Index) % BltInfo->PatternSurface->sizlBitmap.cx, PatternY) << (7 - Index);
 +          Pattern |= DIB_GetSourceIndex(BltInfo->PatternSurface, (DestX + BltInfo->BrushOrigin.x + Index + 8) % BltInfo->PatternSurface->sizlBitmap.cx, PatternY) << (8 + (7 - Index));
 +          Pattern |= DIB_GetSourceIndex(BltInfo->PatternSurface, (DestX + BltInfo->BrushOrigin.x + Index + 16) % BltInfo->PatternSurface->sizlBitmap.cx, PatternY) << (16 + (7 - Index));
 +          Pattern |= DIB_GetSourceIndex(BltInfo->PatternSurface, (DestX + BltInfo->BrushOrigin.x + Index + 24) % BltInfo->PatternSurface->sizlBitmap.cx, PatternY) << (24 + (7 - Index));
 +        }
 +      }
 +
 +      *DestBits = DIB_DoRop(BltInfo->Rop4, Dest, Source, Pattern);
 +    }
 +
 +    if (DestX < BltInfo->DestRect.right)
 +    {
 +      for (; DestX < BltInfo->DestRect.right; DestX++, SourceX++)
 +      {
 +        Dest = DIB_1BPP_GetPixel(BltInfo->DestSurface, DestX, DestY);
 +
 +        if (UsesSource)
 +        {
 +          Source = DIB_GetSource(BltInfo->SourceSurface, SourceX, SourceY, BltInfo->XlateSourceToDest);
 +        }
 +
 +        if (BltInfo->PatternSurface)
 +        {
 +          Pattern = DIB_GetSourceIndex(BltInfo->PatternSurface, (DestX + BltInfo->BrushOrigin.x) % BltInfo->PatternSurface->sizlBitmap.cx, PatternY);
 +        }
 +
 +        DIB_1BPP_PutPixel(BltInfo->DestSurface, DestX, DestY, DIB_DoRop(BltInfo->Rop4, Dest, Source, Pattern) & 0xF);
 +      }
 +    }
 +
 +    SourceY++;
 +    if (BltInfo->PatternSurface)
 +    {
 +      PatternY++;
 +      PatternY %= BltInfo->PatternSurface->sizlBitmap.cy;
 +    }
 +  }
 +
 +  return TRUE;
 +}
 +
 +/* BitBlt Optimize */
 +BOOLEAN
 +DIB_1BPP_ColorFill(SURFOBJ* DestSurface, RECTL* DestRect, ULONG color)
 +{
 +  ULONG DestY;
 +
 +  for (DestY = DestRect->top; DestY< DestRect->bottom; DestY++)
 +  {
 +    DIB_1BPP_HLine(DestSurface, DestRect->left, DestRect->right, DestY, color);
 +  }
 +  return TRUE;
 +}
 +
 +BOOLEAN
 +DIB_1BPP_TransparentBlt(SURFOBJ *DestSurf, SURFOBJ *SourceSurf,
 +                        RECTL*  DestRect,  RECTL *SourceRect,
 +                        XLATEOBJ *ColorTranslation, ULONG iTransColor)
 +{
 +  return FALSE;
 +}
 +
 +/* EOF */
index efe0f53,0000000..e13331c
mode 100644,000000..100644
--- /dev/null
@@@ -1,366 -1,0 +1,365 @@@
-   ULONG RoundedRight, X, Y, SourceX = 0, SourceY = 0, Source, wd, Dest;
 +/*
 + * PROJECT:         Win32 subsystem
 + * LICENSE:         See COPYING in the top level directory
 + * FILE:            subsystems/win32/win32k/dib/dib8bpp.c
 + * PURPOSE:         Device Independant Bitmap functions, 8bpp
 + * PROGRAMMERS:     Jason Filby
 + *                  Thomas Bluemel
 + *                  Gregor Anich
 + */
 +
 +#include <win32k.h>
 +
 +#define NDEBUG
 +#include <debug.h>
 +
 +VOID
 +DIB_8BPP_PutPixel(SURFOBJ *SurfObj, LONG x, LONG y, ULONG c)
 +{
 +  PBYTE byteaddr = (PBYTE)SurfObj->pvScan0 + y * SurfObj->lDelta + x;
 +
 +  *byteaddr = c;
 +}
 +
 +ULONG
 +DIB_8BPP_GetPixel(SURFOBJ *SurfObj, LONG x, LONG y)
 +{
 +  PBYTE byteaddr = (PBYTE)SurfObj->pvScan0 + y * SurfObj->lDelta + x;
 +
 +  return (ULONG)(*byteaddr);
 +}
 +
 +VOID
 +DIB_8BPP_HLine(SURFOBJ *SurfObj, LONG x1, LONG x2, LONG y, ULONG c)
 +{
 +  memset((PBYTE)SurfObj->pvScan0 + y * SurfObj->lDelta + x1, (BYTE) c, x2 - x1);
 +}
 +
 +VOID
 +DIB_8BPP_VLine(SURFOBJ *SurfObj, LONG x, LONG y1, LONG y2, ULONG c)
 +{
 +  PBYTE byteaddr = (PBYTE)SurfObj->pvScan0 + y1 * SurfObj->lDelta;
 +  PBYTE addr = byteaddr + x;
 +  LONG lDelta = SurfObj->lDelta;
 +
 +  byteaddr = addr;
 +  while(y1++ < y2)
 +  {
 +    *addr = c;
 +
 +    addr += lDelta;
 +  }
 +}
 +
 +BOOLEAN
 +DIB_8BPP_BitBltSrcCopy(PBLTINFO BltInfo)
 +{
 +  LONG     i, j, sx, sy, xColor, f1;
 +  PBYTE    SourceBits, DestBits, SourceLine, DestLine;
 +  PBYTE    SourceBits_4BPP, SourceLine_4BPP;
 +
 +  DestBits = (PBYTE)BltInfo->DestSurface->pvScan0 + (BltInfo->DestRect.top * BltInfo->DestSurface->lDelta) + BltInfo->DestRect.left;
 +
 +  switch(BltInfo->SourceSurface->iBitmapFormat)
 +  {
 +    case BMF_1BPP:
 +      sx = BltInfo->SourcePoint.x;
 +      sy = BltInfo->SourcePoint.y;
 +
 +      for (j=BltInfo->DestRect.top; j<BltInfo->DestRect.bottom; j++)
 +      {
 +        sx = BltInfo->SourcePoint.x;
 +        for (i=BltInfo->DestRect.left; i<BltInfo->DestRect.right; i++)
 +        {
 +          if(DIB_1BPP_GetPixel(BltInfo->SourceSurface, sx, sy) == 0)
 +          {
 +            DIB_8BPP_PutPixel(BltInfo->DestSurface, i, j, XLATEOBJ_iXlate(BltInfo->XlateSourceToDest, 0));
 +          }
 +          else
 +          {
 +            DIB_8BPP_PutPixel(BltInfo->DestSurface, i, j, XLATEOBJ_iXlate(BltInfo->XlateSourceToDest, 1));
 +          }
 +          sx++;
 +        }
 +        sy++;
 +      }
 +      break;
 +
 +    case BMF_4BPP:
 +      SourceBits_4BPP = (PBYTE)BltInfo->SourceSurface->pvScan0 + (BltInfo->SourcePoint.y * BltInfo->SourceSurface->lDelta) + (BltInfo->SourcePoint.x >> 1);
 +
 +      for (j=BltInfo->DestRect.top; j<BltInfo->DestRect.bottom; j++)
 +      {
 +        SourceLine_4BPP = SourceBits_4BPP;
 +        sx = BltInfo->SourcePoint.x;
 +        f1 = sx & 1;
 +
 +        for (i=BltInfo->DestRect.left; i<BltInfo->DestRect.right; i++)
 +        {
 +          xColor = XLATEOBJ_iXlate(BltInfo->XlateSourceToDest,
 +              (*SourceLine_4BPP & altnotmask[f1]) >> (4 * (1 - f1)));
 +          DIB_8BPP_PutPixel(BltInfo->DestSurface, i, j, xColor);
 +          if(f1 == 1) { SourceLine_4BPP++; f1 = 0; } else { f1 = 1; }
 +          sx++;
 +        }
 +
 +        SourceBits_4BPP += BltInfo->SourceSurface->lDelta;
 +      }
 +      break;
 +
 +    case BMF_8BPP:
 +      if (NULL == BltInfo->XlateSourceToDest || 0 != (BltInfo->XlateSourceToDest->flXlate & XO_TRIVIAL))
 +      {
 +        if (BltInfo->DestRect.top < BltInfo->SourcePoint.y)
 +        {
 +          SourceBits = (PBYTE)BltInfo->SourceSurface->pvScan0 + (BltInfo->SourcePoint.y * BltInfo->SourceSurface->lDelta) + BltInfo->SourcePoint.x;
 +          for (j = BltInfo->DestRect.top; j < BltInfo->DestRect.bottom; j++)
 +          {
 +            RtlMoveMemory(DestBits, SourceBits, BltInfo->DestRect.right - BltInfo->DestRect.left);
 +            SourceBits += BltInfo->SourceSurface->lDelta;
 +            DestBits += BltInfo->DestSurface->lDelta;
 +          }
 +        }
 +        else
 +        {
 +          SourceBits = (PBYTE)BltInfo->SourceSurface->pvScan0 + ((BltInfo->SourcePoint.y + BltInfo->DestRect.bottom - BltInfo->DestRect.top - 1) * BltInfo->SourceSurface->lDelta) + BltInfo->SourcePoint.x;
 +          DestBits = (PBYTE)BltInfo->DestSurface->pvScan0 + ((BltInfo->DestRect.bottom - 1) * BltInfo->DestSurface->lDelta) + BltInfo->DestRect.left;
 +          for (j = BltInfo->DestRect.bottom - 1; BltInfo->DestRect.top <= j; j--)
 +          {
 +            RtlMoveMemory(DestBits, SourceBits, BltInfo->DestRect.right - BltInfo->DestRect.left);
 +            SourceBits -= BltInfo->SourceSurface->lDelta;
 +            DestBits -= BltInfo->DestSurface->lDelta;
 +          }
 +        }
 +      }
 +      else
 +      {
 +        if (BltInfo->DestRect.top < BltInfo->SourcePoint.y)
 +        {
 +          SourceLine = (PBYTE)BltInfo->SourceSurface->pvScan0 + (BltInfo->SourcePoint.y * BltInfo->SourceSurface->lDelta) + BltInfo->SourcePoint.x;
 +          DestLine = DestBits;
 +          for (j = BltInfo->DestRect.top; j < BltInfo->DestRect.bottom; j++)
 +          {
 +            SourceBits = SourceLine;
 +            DestBits = DestLine;
 +            for (i=BltInfo->DestRect.left; i<BltInfo->DestRect.right; i++)
 +            {
 +              *DestBits++ = XLATEOBJ_iXlate(BltInfo->XlateSourceToDest, *SourceBits++);
 +            }
 +            SourceLine += BltInfo->SourceSurface->lDelta;
 +            DestLine += BltInfo->DestSurface->lDelta;
 +          }
 +        }
 +        else
 +        {
 +          SourceLine = (PBYTE)BltInfo->SourceSurface->pvScan0 + ((BltInfo->SourcePoint.y + BltInfo->DestRect.bottom - BltInfo->DestRect.top - 1) * BltInfo->SourceSurface->lDelta) + BltInfo->SourcePoint.x;
 +          DestLine = (PBYTE)BltInfo->DestSurface->pvScan0 + ((BltInfo->DestRect.bottom - 1) * BltInfo->DestSurface->lDelta) + BltInfo->DestRect.left;
 +          for (j = BltInfo->DestRect.bottom - 1; BltInfo->DestRect.top <= j; j--)
 +          {
 +            SourceBits = SourceLine;
 +            DestBits = DestLine;
 +            for (i=BltInfo->DestRect.left; i<BltInfo->DestRect.right; i++)
 +            {
 +              *DestBits++ = XLATEOBJ_iXlate(BltInfo->XlateSourceToDest, *SourceBits++);
 +            }
 +            SourceLine -= BltInfo->SourceSurface->lDelta;
 +            DestLine -= BltInfo->DestSurface->lDelta;
 +          }
 +        }
 +      }
 +      break;
 +
 +    case BMF_16BPP:
 +      SourceLine = (PBYTE)BltInfo->SourceSurface->pvScan0 + (BltInfo->SourcePoint.y * BltInfo->SourceSurface->lDelta) + 2 * BltInfo->SourcePoint.x;
 +      DestLine = DestBits;
 +
 +      for (j = BltInfo->DestRect.top; j < BltInfo->DestRect.bottom; j++)
 +      {
 +        SourceBits = SourceLine;
 +        DestBits = DestLine;
 +
 +        for (i = BltInfo->DestRect.left; i < BltInfo->DestRect.right; i++)
 +        {
 +          xColor = *((PWORD) SourceBits);
 +          *DestBits = XLATEOBJ_iXlate(BltInfo->XlateSourceToDest, xColor);
 +          SourceBits += 2;
 +          DestBits += 1;
 +        }
 +
 +        SourceLine += BltInfo->SourceSurface->lDelta;
 +        DestLine += BltInfo->DestSurface->lDelta;
 +      }
 +      break;
 +
 +    case BMF_24BPP:
 +      SourceLine = (PBYTE)BltInfo->SourceSurface->pvScan0 + (BltInfo->SourcePoint.y * BltInfo->SourceSurface->lDelta) + 3 * BltInfo->SourcePoint.x;
 +      DestLine = DestBits;
 +
 +      for (j = BltInfo->DestRect.top; j < BltInfo->DestRect.bottom; j++)
 +      {
 +        SourceBits = SourceLine;
 +        DestBits = DestLine;
 +
 +        for (i = BltInfo->DestRect.left; i < BltInfo->DestRect.right; i++)
 +        {
 +          xColor = (*(SourceBits + 2) << 0x10) +
 +             (*(SourceBits + 1) << 0x08) +
 +             (*(SourceBits));
 +          *DestBits = XLATEOBJ_iXlate(BltInfo->XlateSourceToDest, xColor);
 +          SourceBits += 3;
 +          DestBits += 1;
 +        }
 +
 +        SourceLine += BltInfo->SourceSurface->lDelta;
 +        DestLine += BltInfo->DestSurface->lDelta;
 +      }
 +      break;
 +
 +    case BMF_32BPP:
 +      SourceLine = (PBYTE)BltInfo->SourceSurface->pvScan0 + (BltInfo->SourcePoint.y * BltInfo->SourceSurface->lDelta) + 4 * BltInfo->SourcePoint.x;
 +      DestLine = DestBits;
 +
 +      for (j = BltInfo->DestRect.top; j < BltInfo->DestRect.bottom; j++)
 +      {
 +        SourceBits = SourceLine;
 +        DestBits = DestLine;
 +
 +        for (i = BltInfo->DestRect.left; i < BltInfo->DestRect.right; i++)
 +        {
 +          xColor = *((PDWORD) SourceBits);
 +          *DestBits = XLATEOBJ_iXlate(BltInfo->XlateSourceToDest, xColor);
 +          SourceBits += 4;
 +          DestBits += 1;
 +        }
 +
 +        SourceLine += BltInfo->SourceSurface->lDelta;
 +        DestLine += BltInfo->DestSurface->lDelta;
 +      }
 +      break;
 +
 +    default:
 +      DPRINT1("DIB_8BPP_Bitblt: Unhandled Source BPP: %u\n", BitsPerFormat(BltInfo->SourceSurface->iBitmapFormat));
 +      return FALSE;
 +  }
 +
 +  return TRUE;
 +}
 +
 +/* BitBlt Optimize */
 +BOOLEAN
 +DIB_8BPP_ColorFill(SURFOBJ* DestSurface, RECTL* DestRect, ULONG color)
 +{
 +  ULONG DestY;
 +  for (DestY = DestRect->top; DestY< DestRect->bottom; DestY++)
 +  {
 +    DIB_8BPP_HLine(DestSurface, DestRect->left, DestRect->right, DestY, color);
 +  }
 +  return TRUE;
 +}
 +
 +
 +BOOLEAN
 +DIB_8BPP_TransparentBlt(SURFOBJ *DestSurf, SURFOBJ *SourceSurf,
 +                        RECTL*  DestRect,  RECTL *SourceRect,
 +                        XLATEOBJ *ColorTranslation, ULONG iTransColor)
 +{
-   wd = DestSurf->lDelta - (DestRect->right - DestRect->left);
++  ULONG RoundedRight, X, Y, SourceX = 0, SourceY = 0, Source, Dest;
 +  ULONG *DestBits;
 +
 +  LONG DstHeight;
 +  LONG DstWidth;
 +  LONG SrcHeight;
 +  LONG SrcWidth;
 +
 +  DstHeight = DestRect->bottom - DestRect->top;
 +  DstWidth = DestRect->right - DestRect->left;
 +  SrcHeight = SourceRect->bottom - SourceRect->top;
 +  SrcWidth = SourceRect->right - SourceRect->left;
 +
 +  RoundedRight = DestRect->right - ((DestRect->right - DestRect->left) & 0x3);
 +  DestBits = (ULONG*)((PBYTE)DestSurf->pvScan0 + DestRect->left +
 +                      (DestRect->top * DestSurf->lDelta));
 +
 +  for(Y = DestRect->top; Y < DestRect->bottom; Y++)
 +  {
 +    DestBits = (ULONG*)((PBYTE)DestSurf->pvScan0 + DestRect->left +
 +                        (Y * DestSurf->lDelta));
 +    SourceY = SourceRect->top+(Y - DestRect->top) * SrcHeight / DstHeight;
 +    for (X = DestRect->left; X < RoundedRight; X += 4, DestBits++)
 +    {
 +      Dest = *DestBits;
 +
 +      SourceX = SourceRect->left+(X - DestRect->left) * SrcWidth / DstWidth;
 +      if (SourceX >= 0 && SourceY >= 0 &&
 +          SourceSurf->sizlBitmap.cx > SourceX && SourceSurf->sizlBitmap.cy > SourceY)
 +      {
 +        Source = DIB_GetSourceIndex(SourceSurf, SourceX, SourceY);
 +        if(Source != iTransColor)
 +        {
 +          Dest &= 0xFFFFFF00;
 +          Dest |= (XLATEOBJ_iXlate(ColorTranslation, Source) & 0xFF);
 +        }
 +      }
 +
 +      SourceX = SourceRect->left+(X+1 - DestRect->left) * SrcWidth / DstWidth;
 +      if (SourceX >= 0 && SourceY >= 0 &&
 +          SourceSurf->sizlBitmap.cx > SourceX && SourceSurf->sizlBitmap.cy > SourceY)
 +      {
 +        Source = DIB_GetSourceIndex(SourceSurf, SourceX, SourceY);
 +        if(Source != iTransColor)
 +        {
 +          Dest &= 0xFFFF00FF;
 +          Dest |= ((XLATEOBJ_iXlate(ColorTranslation, Source) << 8) & 0xFF00);
 +        }
 +      }
 +
 +      SourceX = SourceRect->left+(X+2 - DestRect->left) * SrcWidth / DstWidth;
 +      if (SourceX >= 0 && SourceY >= 0 &&
 +          SourceSurf->sizlBitmap.cx > SourceX && SourceSurf->sizlBitmap.cy > SourceY)
 +      {
 +        Source = DIB_GetSourceIndex(SourceSurf, SourceX, SourceY);
 +        if(Source != iTransColor)
 +        {
 +          Dest &= 0xFF00FFFF;
 +          Dest |= ((XLATEOBJ_iXlate(ColorTranslation, Source) << 16) & 0xFF0000);
 +        }
 +      }
 +
 +      SourceX = SourceRect->left+(X+3 - DestRect->left) * SrcWidth / DstWidth;
 +      if (SourceX >= 0 && SourceY >= 0 &&
 +          SourceSurf->sizlBitmap.cx > SourceX && SourceSurf->sizlBitmap.cy > SourceY)
 +      {
 +        Source = DIB_GetSourceIndex(SourceSurf, SourceX, SourceY);
 +        if(Source != iTransColor)
 +        {
 +          Dest &= 0x00FFFFFF;
 +          Dest |= ((XLATEOBJ_iXlate(ColorTranslation, Source) << 24) & 0xFF000000);
 +        }
 +      }
 +
 +      *DestBits = Dest;
 +    }
 +
 +    if(X < DestRect->right)
 +    {
 +      for (; X < DestRect->right; X++)
 +      {
 +        SourceX = SourceRect->left+(X - DestRect->left) * SrcWidth / DstWidth;
 +        if (SourceX >= 0 && SourceY >= 0 &&
 +            SourceSurf->sizlBitmap.cx > SourceX && SourceSurf->sizlBitmap.cy > SourceY)
 +        {
 +          Source = DIB_GetSourceIndex(SourceSurf, SourceX, SourceY);
 +          if(Source != iTransColor)
 +          {
 +            *((BYTE*)DestBits) = (BYTE)(XLATEOBJ_iXlate(ColorTranslation, Source) & 0xFF);
 +          }
 +        }
 +        DestBits = (PULONG)((ULONG_PTR)DestBits + 1);
 +      }
 +    }
 +  }
 +
 +  return TRUE;
 +}
 +
 +/* EOF */
index 92e9095,0000000..e6dd497
mode 100644,000000..100644
--- /dev/null
@@@ -1,973 -1,0 +1,971 @@@
-     BOOL               UsesPattern;
 +/*
 + * COPYRIGHT:        See COPYING in the top level directory
 + * PROJECT:          ReactOS kernel
 + * PURPOSE:          GDI BitBlt Functions
 + * FILE:             subsys/win32k/eng/bitblt.c
 + * PROGRAMER:        Jason Filby
 + *                   Timo Kreuzer
 + * REVISION HISTORY:
 + *        2/10/1999: Created
 + */
 +
 +#include <win32k.h>
 +
 +#define NDEBUG
 +#include <debug.h>
 +
 +typedef BOOLEAN (APIENTRY *PBLTRECTFUNC)(SURFOBJ* OutputObj,
 +                                        SURFOBJ* InputObj,
 +                                        SURFOBJ* Mask,
 +                                        XLATEOBJ* ColorTranslation,
 +                                        RECTL* OutputRect,
 +                                        POINTL* InputPoint,
 +                                        POINTL* MaskOrigin,
 +                                        BRUSHOBJ* pbo,
 +                                        POINTL* BrushOrigin,
 +                                        ROP4 Rop4);
 +
 +static BOOLEAN APIENTRY
 +BltMask(SURFOBJ* psoDest,
 +        SURFOBJ* psoSource, // unused
 +        SURFOBJ* psoMask,
 +        XLATEOBJ* ColorTranslation,  // unused
 +        RECTL* prclDest,
 +        POINTL* pptlSource, // unused
 +        POINTL* pptlMask,
 +        BRUSHOBJ* pbo,
 +        POINTL* pptlBrush,
 +        ROP4 Rop4)
 +{
 +    LONG x, y;
 +    BYTE *pjMskLine, *pjMskCurrent;
 +    BYTE fjMaskBit0, fjMaskBit;
 +    /* Pattern brushes */
 +    PEBRUSHOBJ pebo = NULL;
 +    SURFOBJ *psoPattern = NULL;
 +    PSURFACE psurfPattern;
 +    ULONG PatternWidth = 0, PatternHeight = 0;
 +    LONG PatternX0 = 0, PatternX = 0, PatternY = 0;
 +    PFN_DIB_PutPixel fnDest_PutPixel = NULL;
 +    PFN_DIB_GetPixel fnPattern_GetPixel = NULL;
 +    ULONG Pattern = 0;
 +    HBITMAP hbmPattern;
 +
 +    ASSERT(psoSource == NULL);
 +    ASSERT(pptlSource == NULL);
 +
 +    if (psoMask == NULL)
 +    {
 +        return FALSE;
 +    }
 +
 +    if (pbo && pbo->iSolidColor == 0xFFFFFFFF)
 +    {
 +        pebo = CONTAINING_RECORD(pbo, EBRUSHOBJ, BrushObject);
 +
 +        hbmPattern = EBRUSHOBJ_pvGetEngBrush(pebo);
 +        psurfPattern = SURFACE_LockSurface(hbmPattern);
 +        if (psurfPattern != NULL)
 +        {
 +            psoPattern = &psurfPattern->SurfObj;
 +            PatternWidth = psoPattern->sizlBitmap.cx;
 +            PatternHeight = psoPattern->sizlBitmap.cy;
 +            fnPattern_GetPixel = DibFunctionsForBitmapFormat[psoPattern->iBitmapFormat].DIB_GetPixel;
 +        }
 +    }
 +    else
 +        psurfPattern = NULL;
 +
 +    pjMskLine = (PBYTE)psoMask->pvScan0 + pptlMask->y * psoMask->lDelta + (pptlMask->x >> 3);
 +    fjMaskBit0 = 0x80 >> (pptlMask->x & 0x07);
 +
 +    fnDest_PutPixel = DibFunctionsForBitmapFormat[psoDest->iBitmapFormat].DIB_PutPixel;
 +    if (psurfPattern)
 +    {
 +        PatternY = (prclDest->top - pptlBrush->y) % PatternHeight;
 +        if (PatternY < 0)
 +        {
 +            PatternY += PatternHeight;
 +        }
 +        PatternX0 = (prclDest->left - pptlBrush->x) % PatternWidth;
 +        if (PatternX0 < 0)
 +        {
 +            PatternX0 += PatternWidth;
 +        }
 +
 +        for (y = prclDest->top; y < prclDest->bottom; y++)
 +        {
 +            pjMskCurrent = pjMskLine;
 +            fjMaskBit = fjMaskBit0;
 +            PatternX = PatternX0;
 +
 +            for (x = prclDest->left; x < prclDest->right; x++)
 +            {
 +                if (*pjMskCurrent & fjMaskBit)
 +                {
 +                    fnDest_PutPixel(psoDest, x, y,
 +                        fnPattern_GetPixel(psoPattern, PatternX, PatternY));
 +                }
 +                fjMaskBit = _rotr8(fjMaskBit, 1);
 +                pjMskCurrent += (fjMaskBit >> 7);
 +                PatternX++;
 +                PatternX %= PatternWidth;
 +            }
 +            pjMskLine += psoMask->lDelta;
 +            PatternY++;
 +            PatternY %= PatternHeight;
 +        }
 +    }
 +    else
 +    {
 +        Pattern = pbo ? pbo->iSolidColor : 0;
 +        for (y = prclDest->top; y < prclDest->bottom; y++)
 +        {
 +            pjMskCurrent = pjMskLine;
 +            fjMaskBit = fjMaskBit0;
 +
 +            for (x = prclDest->left; x < prclDest->right; x++)
 +            {
 +                if (*pjMskCurrent & fjMaskBit)
 +                {
 +                     fnDest_PutPixel(psoDest, x, y, Pattern);
 +                }
 +                fjMaskBit = _rotr8(fjMaskBit, 1);
 +                pjMskCurrent += (fjMaskBit >> 7);
 +            }
 +            pjMskLine += psoMask->lDelta;
 +        }
 +    }
 +
 +    if (psurfPattern)
 +        SURFACE_UnlockSurface(psurfPattern);
 +
 +    return TRUE;
 +}
 +
 +static BOOLEAN APIENTRY
 +BltPatCopy(SURFOBJ* Dest,
 +           SURFOBJ* Source,
 +           SURFOBJ* Mask,
 +           XLATEOBJ* ColorTranslation,
 +           RECTL* DestRect,
 +           POINTL* SourcePoint,
 +           POINTL* MaskPoint,
 +           BRUSHOBJ* pbo,
 +           POINTL* BrushPoint,
 +           ROP4 Rop4)
 +{
 +    // These functions are assigned if we're working with a DIB
 +    // The assigned functions depend on the bitsPerPixel of the DIB
 +
 +    DibFunctionsForBitmapFormat[Dest->iBitmapFormat].DIB_ColorFill(Dest, DestRect, pbo ? pbo->iSolidColor : 0);
 +
 +    return TRUE;
 +}
 +
 +static BOOLEAN APIENTRY
 +CallDibBitBlt(SURFOBJ* OutputObj,
 +              SURFOBJ* InputObj,
 +              SURFOBJ* Mask,
 +              XLATEOBJ* ColorTranslation,
 +              RECTL* OutputRect,
 +              POINTL* InputPoint,
 +              POINTL* MaskOrigin,
 +              BRUSHOBJ* pbo,
 +              POINTL* BrushOrigin,
 +              ROP4 Rop4)
 +{
 +    BLTINFO BltInfo;
 +    PEBRUSHOBJ GdiBrush = NULL;
 +    SURFACE *psurfPattern;
 +    BOOLEAN Result;
 +    HBITMAP hbmPattern;
 +
 +    BltInfo.DestSurface = OutputObj;
 +    BltInfo.SourceSurface = InputObj;
 +    BltInfo.PatternSurface = NULL;
 +    BltInfo.XlateSourceToDest = ColorTranslation;
 +    BltInfo.DestRect = *OutputRect;
 +    BltInfo.SourcePoint = *InputPoint;
 +
 +    if (ROP3_TO_ROP4(SRCCOPY) == Rop4)
 +        return DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_BitBltSrcCopy(&BltInfo);
 +
 +    BltInfo.Brush = pbo;
 +    BltInfo.BrushOrigin = *BrushOrigin;
 +    BltInfo.Rop4 = Rop4;
 +
 +    /* Pattern brush */
 +    if (ROP4_USES_PATTERN(Rop4) && pbo && pbo->iSolidColor == 0xFFFFFFFF)
 +    {
 +        GdiBrush = CONTAINING_RECORD(pbo, EBRUSHOBJ, BrushObject);
 +        hbmPattern = EBRUSHOBJ_pvGetEngBrush(GdiBrush);
 +        psurfPattern = SURFACE_LockSurface(hbmPattern);
 +        if (psurfPattern)
 +        {
 +            BltInfo.PatternSurface = &psurfPattern->SurfObj;
 +        }
 +        else
 +        {
 +            /* FIXME - What to do here? */
 +        }
 +    }
 +    else
 +    {
 +        psurfPattern = NULL;
 +    }
 +
 +    Result = DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_BitBlt(&BltInfo);
 +
 +    /* Pattern brush */
 +    if (psurfPattern)
 +    {
 +        SURFACE_UnlockSurface(psurfPattern);
 +    }
 +
 +    return Result;
 +}
 +
 +INT __cdecl abs(INT nm);
 +
 +
 +/*
 + * @implemented
 + */
 +BOOL APIENTRY
 +NtGdiEngBitBlt(
 +                IN SURFOBJ  *psoTrg,
 +                IN SURFOBJ  *psoSrc,
 +                IN SURFOBJ  *psoMask,
 +                IN CLIPOBJ  *pco,
 +                IN XLATEOBJ  *pxlo,
 +                IN RECTL  *prclTrg,
 +                IN POINTL  *pptlSrc,
 +                IN POINTL  *pptlMask,
 +                IN BRUSHOBJ  *pbo,
 +                IN POINTL  *pptlBrush,
 +                IN ROP4  rop4    )
 +{
 +    RECTL  rclTrg;
 +    POINTL ptlSrc;
 +    POINTL ptlMask;
 +    POINTL ptlBrush;
 +
 +    _SEH2_TRY
 +    {
 +        ProbeForRead(prclTrg, sizeof(RECTL), 1);
 +        RtlCopyMemory(&rclTrg,prclTrg, sizeof(RECTL));
 +
 +        ProbeForRead(pptlSrc, sizeof(POINTL), 1);
 +        RtlCopyMemory(&ptlSrc, pptlSrc, sizeof(POINTL));
 +
 +        ProbeForRead(pptlMask, sizeof(POINTL), 1);
 +        RtlCopyMemory(&ptlMask, pptlMask, sizeof(POINTL));
 +
 +        ProbeForRead(pptlBrush, sizeof(POINTL), 1);
 +        RtlCopyMemory(&ptlBrush, pptlBrush, sizeof(POINTL));
 +
 +    }
 +    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
 +    {
 +        _SEH2_YIELD(return FALSE);
 +    }
 +    _SEH2_END;
 +
 +    return  EngBitBlt(psoTrg, psoSrc, psoMask, pco, pxlo, &rclTrg, &ptlSrc, &ptlMask, pbo, &ptlBrush, rop4);
 +}
 +
 +/*
 + * @implemented
 + */
 +BOOL APIENTRY
 +EngBitBlt(SURFOBJ *DestObj,
 +          SURFOBJ *SourceObj,
 +          SURFOBJ *Mask,
 +          CLIPOBJ *ClipRegion,
 +          XLATEOBJ *ColorTranslation,
 +          RECTL *DestRect,
 +          POINTL *SourcePoint,
 +          POINTL *MaskOrigin,
 +          BRUSHOBJ *pbo,
 +          POINTL *BrushOrigin,
 +          ROP4 rop4)
 +{
 +    BYTE               clippingType;
 +    RECTL              CombinedRect;
 +    RECT_ENUM          RectEnum;
 +    BOOL               EnumMore;
 +    POINTL             InputPoint;
 +    RECTL              InputRect;
 +    RECTL              OutputRect;
 +    SURFOBJ*           InputObj = 0;
 +    SURFOBJ*           OutputObj;
 +    PBLTRECTFUNC       BltRectFunc;
 +    BOOLEAN            Ret = TRUE;
 +    RECTL              ClipRect;
 +    unsigned           i;
 +    POINTL             Pt;
 +    ULONG              Direction;
 +    BOOL               UsesSource;
-     UsesPattern = ROP4_USES_PATTERN(rop4);
 +    POINTL             AdjustedBrushOrigin;
 +
 +    UsesSource = ROP4_USES_SOURCE(rop4);
 +    if (R4_NOOP == rop4)
 +    {
 +        /* Copy destination onto itself: nop */
 +        return TRUE;
 +    }
 +
 +    OutputRect = *DestRect;
 +    if (OutputRect.right < OutputRect.left)
 +    {
 +        OutputRect.left = DestRect->right;
 +        OutputRect.right = DestRect->left;
 +    }
 +    if (OutputRect.bottom < OutputRect.top)
 +    {
 +        OutputRect.left = DestRect->right;
 +        OutputRect.right = DestRect->left;
 +    }
 +
 +    if (UsesSource)
 +    {
 +        if (NULL == SourcePoint)
 +        {
 +            return FALSE;
 +        }
 +
 +        /* Make sure we don't try to copy anything outside the valid source
 +           region */
 +        InputPoint = *SourcePoint;
 +        if (InputPoint.x < 0)
 +        {
 +            OutputRect.left -= InputPoint.x;
 +            InputPoint.x = 0;
 +        }
 +        if (InputPoint.y < 0)
 +        {
 +            OutputRect.top -= InputPoint.y;
 +            InputPoint.y = 0;
 +        }
 +        if (SourceObj->sizlBitmap.cx < InputPoint.x +
 +                OutputRect.right - OutputRect.left)
 +        {
 +            OutputRect.right = OutputRect.left +
 +                               SourceObj->sizlBitmap.cx - InputPoint.x;
 +        }
 +        if (SourceObj->sizlBitmap.cy < InputPoint.y +
 +                OutputRect.bottom - OutputRect.top)
 +        {
 +            OutputRect.bottom = OutputRect.top +
 +                                SourceObj->sizlBitmap.cy - InputPoint.y;
 +        }
 +
 +        InputRect.left = InputPoint.x;
 +        InputRect.right = InputPoint.x + (OutputRect.right - OutputRect.left);
 +        InputRect.top = InputPoint.y;
 +        InputRect.bottom = InputPoint.y + (OutputRect.bottom - OutputRect.top);
 +
 +        InputObj = SourceObj;
 +    }
 +    else
 +    {
 +        InputRect.left = 0;
 +        InputRect.right = DestRect->right - DestRect->left;
 +        InputRect.top = 0;
 +        InputRect.bottom = DestRect->bottom - DestRect->top;
 +    }
 +
 +    if (NULL != ClipRegion)
 +    {
 +        if (OutputRect.left < ClipRegion->rclBounds.left)
 +        {
 +            InputRect.left += ClipRegion->rclBounds.left - OutputRect.left;
 +            InputPoint.x += ClipRegion->rclBounds.left - OutputRect.left;
 +            OutputRect.left = ClipRegion->rclBounds.left;
 +        }
 +        if (ClipRegion->rclBounds.right < OutputRect.right)
 +        {
 +            InputRect.right -=  OutputRect.right - ClipRegion->rclBounds.right;
 +            OutputRect.right = ClipRegion->rclBounds.right;
 +        }
 +        if (OutputRect.top < ClipRegion->rclBounds.top)
 +        {
 +            InputRect.top += ClipRegion->rclBounds.top - OutputRect.top;
 +            InputPoint.y += ClipRegion->rclBounds.top - OutputRect.top;
 +            OutputRect.top = ClipRegion->rclBounds.top;
 +        }
 +        if (ClipRegion->rclBounds.bottom < OutputRect.bottom)
 +        {
 +            InputRect.bottom -=  OutputRect.bottom - ClipRegion->rclBounds.bottom;
 +            OutputRect.bottom = ClipRegion->rclBounds.bottom;
 +        }
 +    }
 +
 +    /* Check for degenerate case: if height or width of OutputRect is 0 pixels
 +       there's nothing to do */
 +    if (OutputRect.right <= OutputRect.left ||
 +            OutputRect.bottom <= OutputRect.top)
 +    {
 +        return TRUE;
 +    }
 +
 +    OutputObj = DestObj;
 +
 +    if (BrushOrigin)
 +    {
 +        AdjustedBrushOrigin.x = BrushOrigin->x;
 +        AdjustedBrushOrigin.y = BrushOrigin->y;
 +    }
 +    else
 +    {
 +        AdjustedBrushOrigin.x = 0;
 +        AdjustedBrushOrigin.y = 0;
 +    }
 +
 +    /* Determine clipping type */
 +    if (ClipRegion == (CLIPOBJ *) NULL)
 +    {
 +        clippingType = DC_TRIVIAL;
 +    }
 +    else
 +    {
 +        clippingType = ClipRegion->iDComplexity;
 +    }
 +
 +    if (R4_MASK == rop4)
 +    {
 +        BltRectFunc = BltMask;
 +    }
 +    else if (ROP3_TO_ROP4(PATCOPY) == rop4)
 +    {
 +        if (pbo && pbo->iSolidColor == 0xFFFFFFFF)
 +            BltRectFunc = CallDibBitBlt;
 +        else
 +            BltRectFunc = BltPatCopy;
 +    }
 +    else
 +    {
 +        BltRectFunc = CallDibBitBlt;
 +    }
 +
 +
 +    switch (clippingType)
 +    {
 +        case DC_TRIVIAL:
 +            Ret = (*BltRectFunc)(OutputObj, InputObj, Mask, ColorTranslation,
 +                                 &OutputRect, &InputPoint, MaskOrigin, pbo,
 +                                 &AdjustedBrushOrigin, rop4);
 +            break;
 +        case DC_RECT:
 +            /* Clip the blt to the clip rectangle */
 +            ClipRect.left = ClipRegion->rclBounds.left;
 +            ClipRect.right = ClipRegion->rclBounds.right;
 +            ClipRect.top = ClipRegion->rclBounds.top;
 +            ClipRect.bottom = ClipRegion->rclBounds.bottom;
 +            if (RECTL_bIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
 +            {
 +                Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
 +                Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
 +                Ret = (*BltRectFunc)(OutputObj, InputObj, Mask, ColorTranslation,
 +                                     &CombinedRect, &Pt, MaskOrigin, pbo,
 +                                     &AdjustedBrushOrigin, rop4);
 +            }
 +            break;
 +        case DC_COMPLEX:
 +            Ret = TRUE;
 +            if (OutputObj == InputObj)
 +            {
 +                if (OutputRect.top < InputPoint.y)
 +                {
 +                    Direction = OutputRect.left < InputPoint.x ?
 +                                CD_RIGHTDOWN : CD_LEFTDOWN;
 +                }
 +                else
 +                {
 +                    Direction = OutputRect.left < InputPoint.x ?
 +                                CD_RIGHTUP : CD_LEFTUP;
 +                }
 +            }
 +            else
 +            {
 +                Direction = CD_ANY;
 +            }
 +            CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, Direction, 0);
 +            do
 +            {
 +                EnumMore = CLIPOBJ_bEnum(ClipRegion,(ULONG) sizeof(RectEnum),
 +                                         (PVOID) &RectEnum);
 +
 +                for (i = 0; i < RectEnum.c; i++)
 +                {
 +                    ClipRect.left = RectEnum.arcl[i].left;
 +                    ClipRect.right = RectEnum.arcl[i].right;
 +                    ClipRect.top = RectEnum.arcl[i].top;
 +                    ClipRect.bottom = RectEnum.arcl[i].bottom;
 +                    if (RECTL_bIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
 +                    {
 +                        Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
 +                        Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
 +                        Ret = (*BltRectFunc)(OutputObj, InputObj, Mask,
 +                                             ColorTranslation, &CombinedRect, &Pt,
 +                                             MaskOrigin, pbo, &AdjustedBrushOrigin,
 +                                             rop4) && Ret;
 +                    }
 +                }
 +            }
 +            while (EnumMore);
 +            break;
 +    }
 +
 +    return Ret;
 +}
 +
 +BOOL APIENTRY
 +IntEngBitBlt(
 +    SURFOBJ *psoTrg,
 +    SURFOBJ *psoSrc,
 +    SURFOBJ *psoMask,
 +    CLIPOBJ *pco,
 +    XLATEOBJ *pxlo,
 +    RECTL *prclTrg,
 +    POINTL *pptlSrc,
 +    POINTL *pptlMask,
 +    BRUSHOBJ *pbo,
 +    POINTL *pptlBrush,
 +    ROP4 rop4)
 +{
 +    SURFACE *psurfTrg;
 +    SURFACE *psurfSrc = NULL;
 +    BOOL bResult;
 +    RECTL rclClipped;
 +    RECTL rclSrc;
 +//    INTENG_ENTER_LEAVE EnterLeaveSource;
 +//    INTENG_ENTER_LEAVE EnterLeaveDest;
 +    PFN_DrvBitBlt pfnBitBlt;
 +
 +    ASSERT(psoTrg);
 +    psurfTrg = CONTAINING_RECORD(psoTrg, SURFACE, SurfObj);
 +
 +    /* FIXME: Should we really allow to pass non-well-ordered rects? */
 +    rclClipped = *prclTrg;
 +    RECTL_vMakeWellOrdered(&rclClipped);
 +
 +    /* Clip target rect against the bounds of the clipping region */
 +    if (pco)
 +    {
 +        if (!RECTL_bIntersectRect(&rclClipped, &rclClipped, &pco->rclBounds))
 +        {
 +            /* Nothing left */
 +            return TRUE;
 +        }
 +
 +        /* Don't pass a clipobj with only a single rect */
 +        if (pco->iDComplexity == DC_RECT)
 +            pco = NULL;
 +    }
 +
 +    if (ROP4_USES_SOURCE(rop4))
 +    {
 +        ASSERT(psoSrc);
 +        psurfSrc = CONTAINING_RECORD(psoSrc, SURFACE, SurfObj);
 +
 +        /* Calculate source rect */
 +        rclSrc.left = pptlSrc->x + rclClipped.left - prclTrg->left;
 +        rclSrc.top = pptlSrc->y + rclClipped.top - prclTrg->top;
 +        rclSrc.right = rclSrc.left + rclClipped.right - rclClipped.left;
 +        rclSrc.bottom = rclSrc.top + rclClipped.bottom - rclClipped.top;
 +    }
 +    else
 +    {
 +        psoSrc = NULL;
 +        psurfSrc = NULL;
 +    }
 +
 +    /* Is the target surface device managed? */
 +    if (psurfTrg->flags & HOOK_BITBLT)
 +    {
 +        /* Is the source a different device managed surface? */
 +        if (psoSrc && psoSrc->hdev != psoTrg->hdev && psurfSrc->flags & HOOK_BITBLT)
 +        {
 +            DPRINT1("Need to copy to standard bitmap format!\n");
 +            ASSERT(FALSE);
 +        }
 +
 +        pfnBitBlt = GDIDEVFUNCS(psoTrg).BitBlt;
 +    }
 +
 +    /* Is the source surface device managed? */
 +    else if (psoSrc && psurfSrc->flags & HOOK_BITBLT)
 +    {
 +        pfnBitBlt = GDIDEVFUNCS(psoSrc).BitBlt;
 +    }
 +    else
 +    {
 +        pfnBitBlt = EngBitBlt;
 +    }
 +
 +    bResult = pfnBitBlt(psoTrg,
 +                        psoSrc,
 +                        psoMask,
 +                        pco,
 +                        pxlo,
 +                        &rclClipped,
 +                        (POINTL*)&rclSrc,
 +                        pptlMask,
 +                        pbo,
 +                        pptlBrush,
 +                        rop4);
 +
 +    // FIXME: cleanup temp surface!
 +
 +    return bResult;
 +}
 +
 +
 +/**** REACTOS FONT RENDERING CODE *********************************************/
 +
 +/* renders the alpha mask bitmap */
 +static BOOLEAN APIENTRY
 +AlphaBltMask(SURFOBJ* psoDest,
 +             SURFOBJ* psoSource, // unused
 +             SURFOBJ* psoMask,
 +             XLATEOBJ* pxloRGB2Dest,
 +             XLATEOBJ* pxloBrush,
 +             RECTL* prclDest,
 +             POINTL* pptlSource, // unused
 +             POINTL* pptlMask,
 +             BRUSHOBJ* pbo,
 +             POINTL* pptlBrush)
 +{
 +    LONG i, j, dx, dy;
 +    int r, g, b;
 +    ULONG Background, BrushColor, NewColor;
 +    BYTE *tMask, *lMask;
 +
 +    ASSERT(psoSource == NULL);
 +    ASSERT(pptlSource == NULL);
 +
 +    dx = prclDest->right  - prclDest->left;
 +    dy = prclDest->bottom - prclDest->top;
 +
 +    if (psoMask != NULL)
 +    {
 +        BrushColor = XLATEOBJ_iXlate(pxloBrush, pbo ? pbo->iSolidColor : 0);
 +        r = (int)GetRValue(BrushColor);
 +        g = (int)GetGValue(BrushColor);
 +        b = (int)GetBValue(BrushColor);
 +
 +        tMask = (PBYTE)psoMask->pvScan0 + (pptlMask->y * psoMask->lDelta) + pptlMask->x;
 +        for (j = 0; j < dy; j++)
 +        {
 +            lMask = tMask;
 +            for (i = 0; i < dx; i++)
 +            {
 +                if (*lMask > 0)
 +                {
 +                    if (*lMask == 0xff)
 +                    {
 +                        DibFunctionsForBitmapFormat[psoDest->iBitmapFormat].DIB_PutPixel(
 +                            psoDest, prclDest->left + i, prclDest->top + j, pbo ? pbo->iSolidColor : 0);
 +                    }
 +                    else
 +                    {
 +                        Background = DIB_GetSource(psoDest, prclDest->left + i, prclDest->top + j,
 +                                                   pxloBrush);
 +
 +                        NewColor =
 +                            RGB((*lMask * (r - GetRValue(Background)) >> 8) + GetRValue(Background),
 +                                (*lMask * (g - GetGValue(Background)) >> 8) + GetGValue(Background),
 +                                (*lMask * (b - GetBValue(Background)) >> 8) + GetBValue(Background));
 +
 +                        Background = XLATEOBJ_iXlate(pxloRGB2Dest, NewColor);
 +                        DibFunctionsForBitmapFormat[psoDest->iBitmapFormat].DIB_PutPixel(
 +                            psoDest, prclDest->left + i, prclDest->top + j, Background);
 +                    }
 +                }
 +                lMask++;
 +            }
 +            tMask += psoMask->lDelta;
 +        }
 +        return TRUE;
 +    }
 +    else
 +    {
 +        return FALSE;
 +    }
 +}
 +
 +static
 +BOOL APIENTRY
 +EngMaskBitBlt(SURFOBJ *psoDest,
 +              SURFOBJ *psoMask,
 +              CLIPOBJ *ClipRegion,
 +              XLATEOBJ *DestColorTranslation,
 +              XLATEOBJ *SourceColorTranslation,
 +              RECTL *DestRect,
 +              POINTL *pptlMask,
 +              BRUSHOBJ *pbo,
 +              POINTL *BrushOrigin)
 +{
 +    BYTE               clippingType;
 +    RECTL              CombinedRect;
 +    RECT_ENUM          RectEnum;
 +    BOOL               EnumMore;
 +    POINTL             InputPoint;
 +    RECTL              InputRect;
 +    RECTL              OutputRect;
 +    POINTL             Translate;
 +    INTENG_ENTER_LEAVE EnterLeaveSource;
 +    INTENG_ENTER_LEAVE EnterLeaveDest;
 +    SURFOBJ*           psoInput;
 +    SURFOBJ*           psoOutput;
 +    BOOLEAN            Ret = TRUE;
 +    RECTL              ClipRect;
 +    unsigned           i;
 +    POINTL             Pt;
 +    ULONG              Direction;
 +    POINTL             AdjustedBrushOrigin;
 +
 +    ASSERT(psoMask);
 +
 +    if (pptlMask)
 +    {
 +        InputRect.left = pptlMask->x;
 +        InputRect.right = pptlMask->x + (DestRect->right - DestRect->left);
 +        InputRect.top = pptlMask->y;
 +        InputRect.bottom = pptlMask->y + (DestRect->bottom - DestRect->top);
 +    }
 +    else
 +    {
 +        InputRect.left = 0;
 +        InputRect.right = DestRect->right - DestRect->left;
 +        InputRect.top = 0;
 +        InputRect.bottom = DestRect->bottom - DestRect->top;
 +    }
 +
 +    OutputRect = *DestRect;
 +    if (NULL != ClipRegion)
 +    {
 +        if (OutputRect.left < ClipRegion->rclBounds.left)
 +        {
 +            InputRect.left += ClipRegion->rclBounds.left - OutputRect.left;
 +            OutputRect.left = ClipRegion->rclBounds.left;
 +        }
 +        if (ClipRegion->rclBounds.right < OutputRect.right)
 +        {
 +            InputRect.right -=  OutputRect.right - ClipRegion->rclBounds.right;
 +            OutputRect.right = ClipRegion->rclBounds.right;
 +        }
 +        if (OutputRect.top < ClipRegion->rclBounds.top)
 +        {
 +            InputRect.top += ClipRegion->rclBounds.top - OutputRect.top;
 +            OutputRect.top = ClipRegion->rclBounds.top;
 +        }
 +        if (ClipRegion->rclBounds.bottom < OutputRect.bottom)
 +        {
 +            InputRect.bottom -=  OutputRect.bottom - ClipRegion->rclBounds.bottom;
 +            OutputRect.bottom = ClipRegion->rclBounds.bottom;
 +        }
 +    }
 +
 +    if (! IntEngEnter(&EnterLeaveSource, psoMask, &InputRect, TRUE, &Translate, &psoInput))
 +    {
 +        return FALSE;
 +    }
 +
 +    InputPoint.x = InputRect.left + Translate.x;
 +    InputPoint.y = InputRect.top + Translate.y;
 +
 +    /* Check for degenerate case: if height or width of OutputRect is 0 pixels there's
 +       nothing to do */
 +    if (OutputRect.right <= OutputRect.left || OutputRect.bottom <= OutputRect.top)
 +    {
 +        IntEngLeave(&EnterLeaveSource);
 +        return TRUE;
 +    }
 +
 +    if (! IntEngEnter(&EnterLeaveDest, psoDest, &OutputRect, FALSE, &Translate, &psoOutput))
 +    {
 +        IntEngLeave(&EnterLeaveSource);
 +        return FALSE;
 +    }
 +
 +    OutputRect.left = DestRect->left + Translate.x;
 +    OutputRect.right = DestRect->right + Translate.x;
 +    OutputRect.top = DestRect->top + Translate.y;
 +    OutputRect.bottom = DestRect->bottom + Translate.y;
 +
 +    if (BrushOrigin)
 +    {
 +        AdjustedBrushOrigin.x = BrushOrigin->x + Translate.x;
 +        AdjustedBrushOrigin.y = BrushOrigin->y + Translate.y;
 +    }
 +    else
 +        AdjustedBrushOrigin = Translate;
 +
 +    // Determine clipping type
 +    if (ClipRegion == (CLIPOBJ *) NULL)
 +    {
 +        clippingType = DC_TRIVIAL;
 +    } else {
 +        clippingType = ClipRegion->iDComplexity;
 +    }
 +
 +    switch (clippingType)
 +    {
 +        case DC_TRIVIAL:
 +            if (psoMask->iBitmapFormat == BMF_8BPP)
 +                Ret = AlphaBltMask(psoOutput, NULL , psoInput, DestColorTranslation, SourceColorTranslation,
 +                                   &OutputRect, NULL, &InputPoint, pbo, &AdjustedBrushOrigin);
 +            else
 +                Ret = BltMask(psoOutput, NULL, psoInput, DestColorTranslation,
 +                              &OutputRect, NULL, &InputPoint, pbo, &AdjustedBrushOrigin,
 +                              R4_MASK);
 +            break;
 +        case DC_RECT:
 +            // Clip the blt to the clip rectangle
 +            ClipRect.left = ClipRegion->rclBounds.left + Translate.x;
 +            ClipRect.right = ClipRegion->rclBounds.right + Translate.x;
 +            ClipRect.top = ClipRegion->rclBounds.top + Translate.y;
 +            ClipRect.bottom = ClipRegion->rclBounds.bottom + Translate.y;
 +            if (RECTL_bIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
 +            {
 +                Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
 +                Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
 +                if (psoMask->iBitmapFormat == BMF_8BPP)
 +                {
 +                    Ret = AlphaBltMask(psoOutput, NULL, psoInput, DestColorTranslation, SourceColorTranslation,
 +                                       &CombinedRect, NULL, &Pt, pbo, &AdjustedBrushOrigin);
 +                }
 +                else
 +                {
 +                    Ret = BltMask(psoOutput, NULL, psoInput, DestColorTranslation,
 +                                  &CombinedRect, NULL, &Pt, pbo, &AdjustedBrushOrigin, R4_MASK);
 +                }
 +            }
 +            break;
 +        case DC_COMPLEX:
 +            Ret = TRUE;
 +            if (psoOutput == psoInput)
 +            {
 +                if (OutputRect.top < InputPoint.y)
 +                {
 +                    Direction = OutputRect.left < InputPoint.x ? CD_RIGHTDOWN : CD_LEFTDOWN;
 +                }
 +                else
 +                {
 +                    Direction = OutputRect.left < InputPoint.x ? CD_RIGHTUP : CD_LEFTUP;
 +                }
 +            }
 +            else
 +            {
 +                Direction = CD_ANY;
 +            }
 +            CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, Direction, 0);
 +            do
 +            {
 +                EnumMore = CLIPOBJ_bEnum(ClipRegion,(ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
 +
 +                for (i = 0; i < RectEnum.c; i++)
 +                {
 +                    ClipRect.left = RectEnum.arcl[i].left + Translate.x;
 +                    ClipRect.right = RectEnum.arcl[i].right + Translate.x;
 +                    ClipRect.top = RectEnum.arcl[i].top + Translate.y;
 +                    ClipRect.bottom = RectEnum.arcl[i].bottom + Translate.y;
 +                    if (RECTL_bIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
 +                    {
 +                        Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
 +                        Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
 +                        if (psoMask->iBitmapFormat == BMF_8BPP)
 +                        {
 +                            Ret = AlphaBltMask(psoOutput, NULL, psoInput,
 +                                               DestColorTranslation,
 +                                               SourceColorTranslation,
 +                                               &CombinedRect, NULL, &Pt, pbo,
 +                                               &AdjustedBrushOrigin) && Ret;
 +                        }
 +                        else
 +                        {
 +                            Ret = BltMask(psoOutput, NULL, psoInput,
 +                                          DestColorTranslation, &CombinedRect, NULL,
 +                                          &Pt, pbo, &AdjustedBrushOrigin,
 +                                          R4_MASK) && Ret;
 +                        }
 +                    }
 +                }
 +            }
 +            while (EnumMore);
 +            break;
 +    }
 +
 +
 +    IntEngLeave(&EnterLeaveDest);
 +    IntEngLeave(&EnterLeaveSource);
 +
 +    return Ret;
 +}
 +
 +BOOL APIENTRY
 +IntEngMaskBlt(SURFOBJ *psoDest,
 +              SURFOBJ *psoMask,
 +              CLIPOBJ *ClipRegion,
 +              XLATEOBJ *DestColorTranslation,
 +              XLATEOBJ *SourceColorTranslation,
 +              RECTL *DestRect,
 +              POINTL *pptlMask,
 +              BRUSHOBJ *pbo,
 +              POINTL *BrushOrigin)
 +{
 +    BOOLEAN ret;
 +    RECTL OutputRect;
 +    POINTL InputPoint;
 +    SURFACE *psurfDest;
 +
 +    ASSERT(psoMask);
 +
 +    if (pptlMask)
 +    {
 +        InputPoint = *pptlMask;
 +    }
 +
 +    /* Clip against the bounds of the clipping region so we won't try to write
 +     * outside the surface */
 +    if (NULL != ClipRegion)
 +    {
 +        if (!RECTL_bIntersectRect(&OutputRect, DestRect, &ClipRegion->rclBounds))
 +        {
 +            return TRUE;
 +        }
 +        InputPoint.x += OutputRect.left - DestRect->left;
 +        InputPoint.y += OutputRect.top - DestRect->top;
 +    }
 +    else
 +    {
 +        OutputRect = *DestRect;
 +    }
 +
 +    /* No success yet */
 +    ret = FALSE;
 +    ASSERT(psoDest);
 +    psurfDest = CONTAINING_RECORD(psoDest, SURFACE, SurfObj);
 +
 +    /* Dummy BitBlt to let driver know that it should flush its changes.
 +       This should really be done using a call to DrvSynchronizeSurface,
 +       but the VMware driver doesn't hook that call. */
 +    IntEngBitBlt(psoDest, NULL, psoMask, ClipRegion, DestColorTranslation,
 +                   DestRect, pptlMask, pptlMask, pbo, BrushOrigin,
 +                   R4_NOOP);
 +
 +    ret = EngMaskBitBlt(psoDest, psoMask, ClipRegion, DestColorTranslation, SourceColorTranslation,
 +                        &OutputRect, &InputPoint, pbo, BrushOrigin);
 +
 +    /* Dummy BitBlt to let driver know that something has changed. */
 +    IntEngBitBlt(psoDest, NULL, psoMask, ClipRegion, DestColorTranslation,
 +                   DestRect, pptlMask, pptlMask, pbo, BrushOrigin,
 +                   R4_NOOP);
 +
 +    return ret;
 +}
 +
 +/* EOF */
index 31fd500,0000000..d59c4f2
mode 100644,000000..100644
--- /dev/null
@@@ -1,137 -1,0 +1,135 @@@
-   SURFACE *psurf;
 +/*
 + *  ReactOS W32 Subsystem
 + *  Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
 + *
 + *  This program is free software; you can redistribute it and/or modify
 + *  it under the terms of the GNU General Public License as published by
 + *  the Free Software Foundation; either version 2 of the License, or
 + *  (at your option) any later version.
 + *
 + *  This program 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 General Public License for more details.
 + *
 + *  You should have received a copy of the GNU General Public License along
 + *  with this program; if not, write to the Free Software Foundation, Inc.,
 + *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 + */
 +/* $Id$
 + *
 + * COPYRIGHT:         See COPYING in the top level directory
 + * PROJECT:           ReactOS kernel
 + * PURPOSE:           GDI Driver Paint Functions
 + * FILE:              subsys/win32k/eng/paint.c
 + * PROGRAMER:         Jason Filby
 + * REVISION HISTORY:
 + *                 3/7/1999: Created
 + */
 +
 +#include <win32k.h>
 +
 +#define NDEBUG
 +#include <debug.h>
 +
 +BOOL APIENTRY FillSolid(SURFOBJ *pso, PRECTL pRect, ULONG iColor)
 +{
 +  LONG y;
 +  ULONG LineWidth;
-   psurf = CONTAINING_RECORD(pso, SURFACE, SurfObj);
 +
 +  ASSERT(pso);
 +  ASSERT(pRect);
 +  LineWidth  = pRect->right - pRect->left;
 +  DPRINT(" LineWidth: %d, top: %d, bottom: %d\n", LineWidth, pRect->top, pRect->bottom);
 +  for (y = pRect->top; y < pRect->bottom; y++)
 +  {
 +    DibFunctionsForBitmapFormat[pso->iBitmapFormat].DIB_HLine(
 +      pso, pRect->left, pRect->right, y, iColor);
 +  }
 +  return TRUE;
 +}
 +
 +BOOL APIENTRY
 +EngPaintRgn(SURFOBJ *pso, CLIPOBJ *ClipRegion, ULONG iColor, MIX Mix,
 +            BRUSHOBJ *BrushObj, POINTL *BrushPoint)
 +{
 +  RECT_ENUM RectEnum;
 +  BOOL EnumMore;
 +  ULONG i;
 +
 +  ASSERT(pso);
 +  ASSERT(ClipRegion);
 +
 +  DPRINT("ClipRegion->iMode:%d, ClipRegion->iDComplexity: %d\n Color: %d", ClipRegion->iMode, ClipRegion->iDComplexity, iColor);
 +  switch(ClipRegion->iMode) {
 +
 +    case TC_RECTANGLES:
 +
 +    /* Rectangular clipping can be handled without enumeration.
 +       Note that trivial clipping is not possible, since the clipping
 +       region defines the area to fill */
 +
 +    if (ClipRegion->iDComplexity == DC_RECT)
 +    {
 +      FillSolid(pso, &(ClipRegion->rclBounds), iColor);
 +    } else {
 +
 +      /* Enumerate all the rectangles and draw them */
 +      CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, CD_ANY, 0);
 +
 +      do {
 +        EnumMore = CLIPOBJ_bEnum(ClipRegion, sizeof(RectEnum), (PVOID) &RectEnum);
 +        for (i = 0; i < RectEnum.c; i++) {
 +          FillSolid(pso, RectEnum.arcl + i, iColor);
 +        }
 +      } while (EnumMore);
 +    }
 +
 +    return(TRUE);
 +
 +    default:
 +       return(FALSE);
 +  }
 +}
 +
 +/*
 + * @unimplemented
 + */
 +BOOL APIENTRY
 +EngPaint(IN SURFOBJ *pso,
 +       IN CLIPOBJ *ClipRegion,
 +       IN BRUSHOBJ *Brush,
 +       IN POINTL *BrushOrigin,
 +       IN MIX  Mix)
 +{
 +  BOOLEAN ret;
 +
 +  // FIXME: We only support a brush's solid color attribute
 +  ret = EngPaintRgn(pso, ClipRegion, Brush->iSolidColor, Mix, Brush, BrushOrigin);
 +
 +  return ret;
 +}
 +
 +BOOL APIENTRY
 +IntEngPaint(IN SURFOBJ *pso,
 +            IN CLIPOBJ *ClipRegion,
 +            IN BRUSHOBJ *Brush,
 +            IN POINTL *BrushOrigin,
 +            IN MIX  Mix)
 +{
 +  SURFACE *psurf = CONTAINING_RECORD(pso, SURFACE, SurfObj);
 +  BOOL ret;
 +
 +  DPRINT("pso->iType == %d\n", pso->iType);
 +  /* Is the surface's Paint function hooked? */
 +  if((pso->iType!=STYPE_BITMAP) && (psurf->flags & HOOK_PAINT))
 +  {
 +    // Call the driver's DrvPaint
 +    ret = GDIDEVFUNCS(pso).Paint(
 +      pso, ClipRegion, Brush, BrushOrigin, Mix);
 +    return ret;
 +  }
 +  return EngPaint(pso, ClipRegion, Brush, BrushOrigin, Mix );
 +
 +}
 +/* EOF */
index f22af00,0000000..ce40048
mode 100644,000000..100644
--- /dev/null
@@@ -1,1231 -1,0 +1,1230 @@@
-                     INT ret;
 +/*
 + * COPYRIGHT:        See COPYING in the top level directory
 + * PROJECT:          ReactOS kernel
 + * PURPOSE:          Clipboard routines
 + * FILE:             subsys/win32k/ntuser/clipboard.c
 + * PROGRAMER:        Filip Navara <xnavara@volny.cz>
 + *                   Pablo Borobia <pborobia@gmail.com>
 + */
 +
 +#include <win32k.h>
 +
 +#define NDEBUG
 +#include <debug.h>
 +
 +#define DATA_DELAYED_RENDER  0
 +#define DATA_SYNTHESIZED_RENDER -1
 +
 +PTHREADINFO      ClipboardThread;
 +PTHREADINFO      ClipboardOwnerThread;
 +PWINDOW_OBJECT  ClipboardWindow;
 +PWINDOW_OBJECT  ClipboardViewerWindow;
 +PWINDOW_OBJECT  ClipboardOwnerWindow;
 +BOOL            sendDrawClipboardMsg;
 +BOOL            recentlySetClipboard;
 +BOOL            delayedRender;
 +UINT            lastEnumClipboardFormats;
 +DWORD           ClipboardSequenceNumber = 0;
 +
 +PCLIPBOARDCHAINELEMENT WindowsChain = NULL;
 +PCLIPBOARDELEMENT      ClipboardData = NULL;
 +
 +PCHAR synthesizedData;
 +DWORD synthesizedDataSize;
 +
 +
 +/*==============================================================*/
 +
 +/* return the pointer to the prev window of the finded window,
 +   if NULL does not exists in the chain */
 +PCLIPBOARDCHAINELEMENT FASTCALL
 +IntIsWindowInChain(PWINDOW_OBJECT window)
 +{
 +    PCLIPBOARDCHAINELEMENT wce = WindowsChain;
 +
 +    while (wce)
 +    {
 +        if (wce->window == window)
 +        {
 +            break;
 +        }
 +        wce = wce->next;
 +    }
 +
 +    return wce;
 +}
 +
 +VOID FASTCALL printChain(VOID)
 +{
 +    /*test*/
 +    PCLIPBOARDCHAINELEMENT wce2 = WindowsChain;
 +    while (wce2)
 +    {
 +        DPRINT1("chain: %p\n", wce2->window->hSelf);
 +        wce2 = wce2->next;
 +    }
 +}
 +
 +/* the new window always have to be the first in the chain */
 +PCLIPBOARDCHAINELEMENT FASTCALL
 +IntAddWindowToChain(PWINDOW_OBJECT window)
 +{
 +    PCLIPBOARDCHAINELEMENT wce = NULL;
 +
 +    if (!IntIsWindowInChain(window))
 +    {
 +        wce = WindowsChain;
 +
 +        wce = ExAllocatePoolWithTag(PagedPool, sizeof(CLIPBOARDCHAINELEMENT), USERTAG_CLIPBOARD);
 +        if (wce == NULL)
 +        {
 +            SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
 +            goto exit_addChain;
 +        }
 +
 +        wce->window = window;
 +        wce->next = WindowsChain;
 +
 +        WindowsChain = wce;
 +
 +        //printChain();
 +    }
 +exit_addChain:
 +
 +    /* return the next window to beremoved later */
 +    return wce;
 +}
 +
 +PCLIPBOARDCHAINELEMENT FASTCALL
 +IntRemoveWindowFromChain(PWINDOW_OBJECT window)
 +{
 +    PCLIPBOARDCHAINELEMENT wce = WindowsChain;
 +      PCLIPBOARDCHAINELEMENT *link = &WindowsChain;
 +
 +    if (IntIsWindowInChain(window))
 +    {
 +        while (wce != NULL)
 +        {
 +            if (wce->window == window)
 +            {
 +                *link = wce->next;
 +                break;
 +            }
 +
 +            link = &wce->next;
 +            wce = wce->next;
 +        }
 +
 +        //printChain();
 +
 +        return wce;
 +    }
 +    else
 +    {
 +        return NULL;
 +    }
 +}
 +
 +
 +/*==============================================================*/
 +/* if format exists, returns a non zero value (pointing to format object) */
 +PCLIPBOARDELEMENT FASTCALL
 +intIsFormatAvailable(UINT format)
 +{
 +    PCLIPBOARDELEMENT ret = NULL;
 +    PCLIPBOARDELEMENT ce = ClipboardData;
 +
 +    while(ce)
 +    {
 +          if (ce->format == format)
 +          {
 +              ret = ce;
 +              break;
 +          }
 +          ce = ce->next;
 +    }
 +    return ret;
 +}
 +
 +/* counts how many distinct format were are in the clipboard */
 +DWORD FASTCALL
 +IntCountClipboardFormats(VOID)
 +{
 +    DWORD ret = 0;
 +    PCLIPBOARDELEMENT ce = ClipboardData;
 +
 +    while(ce)
 +    {
 +        ret++;
 +          ce = ce->next;
 +    }
 +    return ret;
 +}
 +
 +/* adds a new format and data to the clipboard */
 +PCLIPBOARDELEMENT FASTCALL
 +intAddFormatedData(UINT format, HANDLE hData, DWORD size)
 +{
 +    PCLIPBOARDELEMENT ce = NULL;
 +
 +    ce = ExAllocatePoolWithTag(PagedPool, sizeof(CLIPBOARDELEMENT), USERTAG_CLIPBOARD);
 +    if (ce == NULL)
 +    {
 +        SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
 +    }
 +    else
 +    {
 +        ce->format = format;
 +        ce->size = size;
 +        ce->hData = hData;
 +        ce->next = ClipboardData;
 +
 +        ClipboardData = ce;
 +
 +        IntIncrementSequenceNumber();
 +    }
 +
 +    return ce;
 +}
 +
 +/* removes a format and its data from the clipboard */
 +BOOL FASTCALL
 +intRemoveFormatedData(UINT format)
 +{
 +    BOOL ret = FALSE;
 +    PCLIPBOARDELEMENT ce = ClipboardData;
 +    PCLIPBOARDELEMENT *link = &ClipboardData;
 +
 +    if (intIsFormatAvailable(format))
 +    {
 +        while (ce != NULL)
 +        {
 +            if (ce->format == format)
 +            {
 +                *link = ce->next;
 +                break;
 +            }
 +
 +            link = &ce->next;
 +            ce = ce->next;
 +        }
 +
 +        if (ce->hData)
 +        {
 +            ExFreePool(ce->hData);
 +        }
 +        ExFreePool(ce);
 +        ret = TRUE;
 +    }
 +
 +    return ret;
 +}
 +
 +VOID FASTCALL
 +IntEmptyClipboardData(VOID)
 +{
 +    PCLIPBOARDELEMENT ce = ClipboardData;
 +    PCLIPBOARDELEMENT tmp;
 +
 +    while(ce)
 +    {
 +        tmp = ce->next;
 +              if (ce->hData)
 +              {
 +            ExFreePool(ce->hData);
 +        }
 +          ExFreePool(ce);
 +          ce = tmp;
 +    }
 +
 +    ClipboardData = NULL;
 +}
 +
 +/*==============================================================*/
 +
 +HANDLE FASTCALL
 +renderBITMAPfromDIB(LPBYTE pDIB)
 +{
 +    HDC hdc;
 +    HBITMAP hbitmap;
 +    PBITMAPINFO pBmi, pConvertedBmi = NULL;
 +    NTSTATUS Status ;
 +      UINT offset = 0; /* Stupid compiler */
 +
 +      pBmi = (BITMAPINFO*)pDIB;
 +
 +    //hdc = UserGetDCEx(NULL, NULL, DCX_USESTYLE);
 +    hdc = UserGetDCEx(ClipboardWindow, NULL, DCX_USESTYLE);
 +
 +    /* Probe it */
 +    _SEH2_TRY
 +    {
 +        ProbeForRead(&pBmi->bmiHeader.biSize, sizeof(DWORD), 1);
 +              ProbeForRead(pBmi, pBmi->bmiHeader.biSize, 1);
 +              ProbeForRead(pBmi, DIB_BitmapInfoSize(pBmi, DIB_RGB_COLORS), 1);
 +              pConvertedBmi = DIB_ConvertBitmapInfo(pBmi, DIB_RGB_COLORS);
 +              if(!pConvertedBmi)
 +              {
 +                      Status = STATUS_INVALID_PARAMETER;
 +              }
 +              else
 +              {
 +                      offset = DIB_BitmapInfoSize((BITMAPINFO*)pBmi, DIB_RGB_COLORS);
 +                      ProbeForRead(pDIB + offset, pConvertedBmi->bmiHeader.biSizeImage, 1);
 +              }
 +    }
 +    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
 +    {
 +        Status = _SEH2_GetExceptionCode();
 +    }
 +    _SEH2_END
 +
 +    if(!NT_SUCCESS(Status))
 +    {
 +        UserReleaseDC(ClipboardWindow, hdc, FALSE);
 +        return NULL;
 +    }
 +
 +    hbitmap = GreCreateDIBitmapInternal(hdc,
 +                                        pConvertedBmi->bmiHeader.biWidth,
 +                                        pConvertedBmi->bmiHeader.biHeight,
 +                                        CBM_INIT,
 +                                        pDIB+offset,
 +                                        pConvertedBmi,
 +                                        DIB_RGB_COLORS,
 +                                        0,
 +                                        0);
 +    //UserReleaseDC(NULL, hdc, FALSE);
 +    UserReleaseDC(ClipboardWindow, hdc, FALSE);
 +
 +      DIB_FreeConvertedBitmapInfo(pConvertedBmi, pBmi);
 +
 +    return hbitmap;
 +}
 +
 +BOOL FASTCALL
 +canSinthesize(UINT format)
 +{
 +    BOOL ret = FALSE;
 +
 +    switch(format)
 +    {
 +        case CF_BITMAP:
 +        case CF_METAFILEPICT:
 +            ret = TRUE;
 +    }
 +
 +    return ret;
 +}
 +
 +/* returns the size of the sinthesized data */
 +DWORD FASTCALL
 +synthesizeData(UINT format)
 +{
 +    DWORD ret = 0;
 +
 +    synthesizedData = NULL;
 +    synthesizedDataSize = 0;
 +
 +    if (!canSinthesize(format))
 +    {
 +        return 0;
 +    }
 +
 +    switch (format)
 +    {
 +        case CF_BITMAP:
 +        {
 +            break;
 +        }
 +
 +        case CF_METAFILEPICT:
 +        {
 +            break;
 +        }
 +    }
 +
 +    ret = 1;
 +
 +    return ret;
 +}
 +
 +VOID FASTCALL
 +freeSynthesizedData(VOID)
 +{
 +    ExFreePool(synthesizedData);
 +}
 +
 +/*==============================================================*/
 +
 +BOOL FASTCALL
 +intIsClipboardOpenByMe(VOID)
 +{
 +    /* check if we open the clipboard */
 +    if (ClipboardThread && ClipboardThread == PsGetCurrentThreadWin32Thread())
 +    {
 +        /* yes, we got a thread and its the same that opens the clipboard */
 +        return TRUE;
 +
 +    }
 +    /* will fail if not thread (closed) or not open by me*/
 +    return FALSE;
 +}
 +
 +/* IntClipboardFreeWindow it's called when a window was destroyed */
 +VOID FASTCALL
 +IntClipboardFreeWindow(PWINDOW_OBJECT window)
 +{
 +    /* called from co_UserFreeWindow in window.c */
 +    /* check if clipboard is not locked by this window, if yes, unlock it */
 +    if (ClipboardThread == PsGetCurrentThreadWin32Thread())
 +    {
 +        /* the window that opens the clipboard was destroyed */
 +        ClipboardThread = NULL;
 +        ClipboardWindow = NULL;
 +        //TODO: free clipboard
 +    }
 +    if (window == ClipboardOwnerWindow)
 +    {
 +        /* the owner window was destroyed */
 +        ClipboardOwnerWindow = NULL;
 +        ClipboardOwnerThread = NULL;
 +    }
 +    /* remove window from window chain */
 +    if (IntIsWindowInChain(window))
 +    {
 +              PCLIPBOARDCHAINELEMENT w = IntRemoveWindowFromChain(window);
 +              if (w)
 +              {
 +            ExFreePool(w);
 +              }
 +    }
 +}
 +
 +BOOL APIENTRY
 +NtUserOpenClipboard(HWND hWnd, DWORD Unknown1)
 +{
 +
 +    PWINDOW_OBJECT Window;
 +    BOOL ret = FALSE;
 +
 +    UserEnterExclusive();
 +
 +    sendDrawClipboardMsg = FALSE;
 +    recentlySetClipboard = FALSE;
 +
 +    if (ClipboardThread)
 +    {
 +        /* clipboard is already open */
 +        if (ClipboardThread == PsGetCurrentThreadWin32Thread())
 +        {
 +            if  (ClipboardOwnerWindow)
 +            {
 +                if (ClipboardOwnerWindow->hSelf == hWnd)
 +                {
 +                    ret = TRUE;
 +                }
 +            }
 +            else
 +            {
 +                 if (hWnd == NULL)
 +                 {
 +                    ret = TRUE;
 +                 }
 +            }
 +        }
 +    }
 +    else
 +    {
 +
 +        if (hWnd != NULL)
 +        {
 +            Window = UserGetWindowObject(hWnd);
 +
 +            if (Window != NULL)
 +            {
 +                ClipboardWindow =  Window;
 +                ClipboardThread = PsGetCurrentThreadWin32Thread();
 +                ret = TRUE;
 +            }
 +            else
 +            {
 +                ClipboardWindow = NULL;
 +                ClipboardThread = NULL;
 +                ClipboardOwnerWindow = NULL;
 +                ClipboardOwnerThread = NULL;
 +            }
 +        }
 +        else
 +        {
 +            ClipboardWindow =  NULL;
 +            ClipboardThread = PsGetCurrentThreadWin32Thread();
 +            ret = TRUE;
 +        }
 +    }
 +
 +    UserLeave();
 +
 +    return ret;
 +}
 +
 +BOOL APIENTRY
 +NtUserCloseClipboard(VOID)
 +{
 +    BOOL ret = FALSE;
 +
 +    UserEnterExclusive();
 +
 +    if (intIsClipboardOpenByMe())
 +    {
 +        ClipboardWindow = NULL;
 +        ClipboardThread = NULL;
 +        ret = TRUE;
 +    }
 +    else
 +    {
 +        SetLastWin32Error(ERROR_CLIPBOARD_NOT_OPEN);
 +    }
 +
 +    recentlySetClipboard = FALSE;
 +
 +    UserLeave();
 +
 +    if (sendDrawClipboardMsg && WindowsChain)
 +    {
 +        /* only send message to the first window in the chain, then they'll do the chain */
 +        /* commented because it makes a crash in co_MsqSendMessage
 +        ASSERT(WindowsChain->window);
 +        ASSERT(WindowsChain->window->hSelf);
 +        DPRINT1("Clipboard: sending WM_DRAWCLIPBOARD to %p\n", WindowsChain->window->hSelf);
 +        co_IntSendMessage(WindowsChain->window->hSelf, WM_DRAWCLIPBOARD, 0, 0);
 +        */
 +    }
 +
 +    return ret;
 +}
 +
 +HWND APIENTRY
 +NtUserGetOpenClipboardWindow(VOID)
 +{
 +    HWND ret = NULL;
 +
 +    UserEnterShared();
 +
 +    if (ClipboardWindow)
 +    {
 +        ret = ClipboardWindow->hSelf;
 +    }
 +
 +    UserLeave();
 +
 +    return ret;
 +}
 +
 +BOOL APIENTRY
 +NtUserChangeClipboardChain(HWND hWndRemove, HWND hWndNewNext)
 +{
 +    BOOL ret = FALSE;
 +    PCLIPBOARDCHAINELEMENT w = NULL;
 +    PWINDOW_OBJECT removeWindow;
 +    UserEnterExclusive();
 +
 +    removeWindow = UserGetWindowObject(hWndRemove);
 +
 +    if (removeWindow)
 +    {
 +        if ((ret = !!IntIsWindowInChain(removeWindow)))
 +        {
 +            w = IntRemoveWindowFromChain(removeWindow);
 +            if (w)
 +            {
 +                ExFreePool(w);
 +            }
 +        }
 +    }
 +
 +    if (ret && WindowsChain)
 +    {
 +        // only send message to the first window in the chain,
 +        // then they do the chain
 +
 +        /* WindowsChain->window may be NULL */
 +        LPARAM lparam = WindowsChain->window == NULL ? 0 : (LPARAM)WindowsChain->window->hSelf;
 +        DPRINT1("Message: WM_CHANGECBCHAIN to %p", WindowsChain->window->hSelf);
 +        co_IntSendMessage(WindowsChain->window->hSelf, WM_CHANGECBCHAIN, (WPARAM)hWndRemove, lparam);
 +    }
 +
 +    UserLeave();
 +
 +    return ret;
 +}
 +
 +DWORD APIENTRY
 +NtUserCountClipboardFormats(VOID)
 +{
 +    DWORD ret = 0;
 +
 +    if (ClipboardData)
 +    {
 +       ret = IntCountClipboardFormats();
 +    }
 +
 +    return ret;
 +}
 +
 +DWORD APIENTRY
 +NtUserEmptyClipboard(VOID)
 +{
 +    BOOL ret = FALSE;
 +
 +    UserEnterExclusive();
 +
 +    if (intIsClipboardOpenByMe())
 +    {
 +        if (ClipboardData)
 +        {
 +            IntEmptyClipboardData();
 +        }
 +
 +        ClipboardOwnerWindow = ClipboardWindow;
 +        ClipboardOwnerThread = ClipboardThread;
 +
 +        IntIncrementSequenceNumber();
 +
 +        ret = TRUE;
 +    }
 +    else
 +    {
 +        SetLastWin32Error(ERROR_CLIPBOARD_NOT_OPEN);
 +    }
 +
 +    if (ret && ClipboardOwnerWindow)
 +    {
 +        DPRINT("Clipboard: WM_DESTROYCLIPBOARD to %p", ClipboardOwnerWindow->hSelf);
 +        co_IntSendMessage( ClipboardOwnerWindow->hSelf, WM_DESTROYCLIPBOARD, 0, 0);
 +    }
 +
 +    UserLeave();
 +
 +    return ret;
 +}
 +
 +HANDLE APIENTRY
 +NtUserGetClipboardData(UINT uFormat, PVOID pBuffer)
 +{
 +    HANDLE ret = NULL;
 +
 +    UserEnterShared();
 +
 +    if (intIsClipboardOpenByMe())
 +    {
 +        /* when Unknown1 is zero, we returns to user32 the data size */
 +        if (!pBuffer)
 +        {
 +            PCLIPBOARDELEMENT data = intIsFormatAvailable(uFormat);
 +
 +            if (data)
 +            {
 +                /* format exists in clipboard */
 +                if (data->size == DATA_DELAYED_RENDER)
 +                {
 +                    /* tell owner what data needs to be rendered */
 +                    if (ClipboardOwnerWindow)
 +                    {
 +                        ASSERT(ClipboardOwnerWindow->hSelf);
 +                        co_IntSendMessage(ClipboardOwnerWindow->hSelf, WM_RENDERFORMAT, (WPARAM)uFormat, 0);
 +                        data = intIsFormatAvailable(uFormat);
 +                        ASSERT(data->size);
 +                        ret = (HANDLE)(ULONG_PTR)data->size;
 +                    }
 +                }
 +                else
 +                {
 +                    if (data->size == DATA_SYNTHESIZED_RENDER)
 +                    {
 +                        data->size = synthesizeData(uFormat);
 +                    }
 +
 +                }
 +                ret = (HANDLE)(ULONG_PTR)data->size;
 +            }
 +            else
 +            {
 +                /* there is no data in this format */
 +                //ret = (HANDLE)FALSE;
 +            }
 +        }
 +        else
 +        {
 +            PCLIPBOARDELEMENT data = intIsFormatAvailable(uFormat);
 +
 +            if (data)
 +            {
 +                if (data->size == DATA_DELAYED_RENDER)
 +                {
 +                    // we rendered it in 1st call of getclipboard data
 +                }
 +                else
 +                {
 +                    if (data->size == DATA_SYNTHESIZED_RENDER)
 +                    {
 +                        if (uFormat == CF_BITMAP)
 +                        {
 +                            /* BITMAP & METAFILEs returns a GDI handle */
 +                            PCLIPBOARDELEMENT data = intIsFormatAvailable(CF_DIB);
 +                            if (data)
 +                            {
 +                                ret = renderBITMAPfromDIB(data->hData);
 +                            }
 +                        }
 +                        else
 +                        {
 +                            ret = (HANDLE)pBuffer;
 +
 +                            _SEH2_TRY
 +                            {
 +                                ProbeForWrite(pBuffer, synthesizedDataSize, 1);
 +                                memcpy(pBuffer, (PCHAR)synthesizedData, synthesizedDataSize);
 +                            }
 +                            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
 +                            {
 +                                ret = NULL;
 +                            }
 +                            _SEH2_END
 +
 +                            freeSynthesizedData();
 +                        }
 +                    }
 +                    else
 +                    {
 +                        ret = (HANDLE)pBuffer;
 +
 +                        _SEH2_TRY
 +                        {
 +                            ProbeForWrite(pBuffer, data->size, 1);
 +                            memcpy(pBuffer, (PCHAR)data->hData, data->size);
 +                        }
 +                        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
 +                        {
 +                            ret = NULL;
 +                        }
 +                        _SEH2_END
 +                    }
 +                }
 +
 +            }
 +
 +        }
 +    }
 +    else
 +    {
 +        SetLastWin32Error(ERROR_CLIPBOARD_NOT_OPEN);
 +    }
 +
 +    UserLeave();
 +
 +    return ret;
 +}
 +
 +INT APIENTRY
 +NtUserGetClipboardFormatName(UINT format, PUNICODE_STRING FormatName,
 +                             INT cchMaxCount)
 +{
 +    UNICODE_STRING sFormatName;
 +    INT ret = 0;
 +
 +    /* if the format is built-in we fail */
 +    if (format < 0xc000)
 +    {
 +        /* registetrated formats are >= 0xc000 */
 +        return 0;
 +    }
 +
 +    if((cchMaxCount < 1) || !FormatName)
 +    {
 +        SetLastWin32Error(ERROR_INVALID_PARAMETER);
 +        return 0;
 +    }
 +
 +    _SEH2_TRY
 +    {
 +        ProbeForWriteUnicodeString(FormatName);
 +        sFormatName = *(volatile UNICODE_STRING *)FormatName;
 +        ProbeForWrite(sFormatName.Buffer, sFormatName.MaximumLength, 1);
 +
 +        ret = IntGetAtomName((RTL_ATOM)format, sFormatName.Buffer, cchMaxCount * sizeof(WCHAR));
 +
 +        if (ret >= 0)
 +        {
 +            ret = ret / sizeof(WCHAR);
 +            sFormatName.Length = ret;
 +        }
 +        else
 +        {
 +            ret = 0;
 +        }
 +    }
 +    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
 +    {
 +        SetLastNtError(_SEH2_GetExceptionCode());
 +    }
 +    _SEH2_END;
 +
 +    return ret;
 +}
 +
 +HWND APIENTRY
 +NtUserGetClipboardOwner(VOID)
 +{
 +    HWND ret = NULL;
 +
 +    UserEnterShared();
 +
 +    if (ClipboardOwnerWindow)
 +    {
 +        ret = ClipboardOwnerWindow->hSelf;
 +    }
 +
 +    UserLeave();
 +
 +    return ret;
 +}
 +
 +HWND APIENTRY
 +NtUserGetClipboardViewer(VOID)
 +{
 +    HWND ret = NULL;
 +
 +    UserEnterShared();
 +
 +    if (WindowsChain)
 +    {
 +        ret = WindowsChain->window->hSelf;
 +    }
 +
 +    UserLeave();
 +
 +    return ret;
 +}
 +
 +INT APIENTRY
 +NtUserGetPriorityClipboardFormat(UINT *paFormatPriorityList, INT cFormats)
 +{
 +    INT i;
 +    UINT *priorityList;
 +    INT ret = 0;
 +
 +    UserEnterExclusive();
 +
 +    _SEH2_TRY
 +    {
 +        if (IntCountClipboardFormats() == 0)
 +        {
 +            ret = 0;
 +        }
 +        else
 +        {
 +            ProbeForRead(paFormatPriorityList, cFormats, sizeof(UINT));
 +
 +            priorityList = paFormatPriorityList;
 +
 +            ret = -1;
 +
 +            for (i = 0; i < cFormats; i++)
 +            {
 +                if (intIsFormatAvailable(priorityList[i]))
 +                {
 +                    ret = priorityList[i];
 +                    break;
 +                }
 +            }
 +
 +        }
 +    }
 +    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
 +    {
 +        SetLastNtError(_SEH2_GetExceptionCode());
 +    }
 +    _SEH2_END;
 +
 +    UserLeave();
 +
 +    return ret;
 +
 +}
 +
 +BOOL APIENTRY
 +NtUserIsClipboardFormatAvailable(UINT format)
 +{
 +    BOOL ret = FALSE;
 +
 +    UserEnterShared();
 +
 +    ret = (intIsFormatAvailable(format) != NULL);
 +
 +    UserLeave();
 +
 +    return ret;
 +}
 +
 +
 +
 +HANDLE APIENTRY
 +NtUserSetClipboardData(UINT uFormat, HANDLE hMem, DWORD size)
 +{
 +    HANDLE hCBData = NULL;
 +    UNICODE_STRING unicodeString;
 +    OEM_STRING oemString;
 +    ANSI_STRING ansiString;
 +
 +    UserEnterExclusive();
 +
 +    /* to place data here the we need to be the owner */
 +    if (ClipboardOwnerThread == PsGetCurrentThreadWin32Thread())
 +    {
 +        PCLIPBOARDELEMENT data = intIsFormatAvailable(uFormat);
 +        if (data)
 +        {
 +
 +            if (data->size == DATA_DELAYED_RENDER)
 +            {
 +                intRemoveFormatedData(uFormat);
 +            }
 +            else
 +            {
 +                // we already have this format on clipboard
 +                goto exit_setCB;
 +            }
 +        }
 +
 +        if (hMem)
 +        {
 +            _SEH2_TRY
 +            {
 +                ProbeForRead(hMem, size, 1);
 +            }
 +            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
 +            {
 +                SetLastNtError(_SEH2_GetExceptionCode());
 +                _SEH2_YIELD(goto exit_setCB);
 +            }
 +            _SEH2_END;
 +
 +            if (intIsClipboardOpenByMe())
 +            {
 +                delayedRender = FALSE;
 +            }
 +
 +            if (!canSinthesize(uFormat))
 +            {
 +                hCBData = ExAllocatePoolWithTag(PagedPool, size, USERTAG_CLIPBOARD);
 +                memcpy(hCBData, hMem, size);
 +                intAddFormatedData(uFormat, hCBData, size);
 +                DPRINT1("Data stored\n");
 +            }
 +
 +            sendDrawClipboardMsg = TRUE;
 +            recentlySetClipboard = TRUE;
 +            lastEnumClipboardFormats = uFormat;
 +
 +            /* conversions */
 +            switch (uFormat)
 +            {
 +                case CF_TEXT:
 +                    {
 +                        //TODO : sinthesize CF_UNICODETEXT & CF_OEMTEXT
 +                        // CF_TEXT -> CF_UNICODETEXT
 +                        ansiString.Buffer = hCBData;
 +                        ansiString.Length = size;
 +                        RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, TRUE);
 +                        intAddFormatedData(CF_UNICODETEXT, unicodeString.Buffer, unicodeString.Length * sizeof(WCHAR));
 +                        // CF_TEXT -> CF_OEMTEXT
 +                        RtlUnicodeStringToOemString(&oemString, &unicodeString, TRUE);
 +                        intAddFormatedData(CF_OEMTEXT, oemString.Buffer, oemString.Length);
 +                        //HKCU\Control Panel\International\Locale
 +                        //intAddFormatedData(CF_LOCALE, oemString.Buffer, oemString.Length);
 +                        break;
 +                    }
 +                case CF_UNICODETEXT:
 +                {
 +                    //TODO : sinthesize CF_TEXT & CF_OEMTEXT
 +                    //CF_UNICODETEXT -> CF_TEXT
 +                    unicodeString.Buffer = hCBData;
 +                    unicodeString.Length = size;
 +                    RtlUnicodeStringToAnsiString(&ansiString, &unicodeString, TRUE);
 +                    intAddFormatedData(CF_TEXT, ansiString.Buffer, ansiString.Length);
 +                    //CF_UNICODETEXT -> CF_OEMTEXT
 +                    RtlUnicodeStringToOemString(&oemString, &unicodeString, TRUE);
 +                    intAddFormatedData(CF_OEMTEXT, oemString.Buffer, oemString.Length);
 +                    break;
 +                }
 +                case CF_OEMTEXT:
 +                {
 +                    //TODO : sinthesize CF_TEXT & CF_UNICODETEXT
 +                    //CF_OEMTEXT -> CF_UNICODETEXT
 +                    oemString.Buffer = hCBData;
 +                    oemString.Length = size;
 +                    RtlOemStringToUnicodeString(&unicodeString, &oemString, TRUE);
 +                    intAddFormatedData(CF_UNICODETEXT, unicodeString.Buffer, unicodeString.Length * sizeof(WCHAR));
 +                    //CF_OEMTEXT -> CF_TEXT
 +                    RtlUnicodeStringToAnsiString(&ansiString, &unicodeString, TRUE);
 +                    intAddFormatedData(CF_TEXT, ansiString.Buffer, ansiString.Length);
 +                    break;
 +                }
 +                case CF_BITMAP:
 +                {
 +                    // we need to render the DIB or DIBV5 format as soon as possible
 +                    // because pallette information may change
 +
 +                    HDC hdc;
-                     ret = NtGdiGetDIBitsInternal(hdc, hMem, 0, bm.bmHeight,  NULL, &bi, DIB_RGB_COLORS, 0, 0);
 +                    BITMAP bm;
 +                    BITMAPINFO bi;
 +                    SURFACE *psurf;
 +
 +                    hdc = UserGetDCEx(NULL, NULL, DCX_USESTYLE);
 +
 +
 +                    psurf = SURFACE_LockSurface(hMem);
 +                    BITMAP_GetObject(psurf, sizeof(BITMAP), (PVOID)&bm);
 +                    if(psurf)
 +                    {
 +                        SURFACE_UnlockSurface(psurf);
 +                    }
 +
 +                    bi.bmiHeader.biSize       = sizeof(BITMAPINFOHEADER);
 +                    bi.bmiHeader.biWidth = bm.bmWidth;
 +                    bi.bmiHeader.biHeight = bm.bmHeight;
 +                    bi.bmiHeader.biPlanes = 1;
 +                    bi.bmiHeader.biBitCount   = bm.bmPlanes * bm.bmBitsPixel;
 +                    bi.bmiHeader.biCompression = BI_RGB;
 +                    bi.bmiHeader.biSizeImage = 0;
 +                    bi.bmiHeader.biXPelsPerMeter = 0;
 +                    bi.bmiHeader.biYPelsPerMeter = 0;
 +                    bi.bmiHeader.biClrUsed = 0;
 +
-                     ret = NtGdiGetDIBitsInternal(hdc, hMem, 0, bm.bmHeight, (LPBYTE)hCBData + sizeof(BITMAPINFOHEADER), &bi, DIB_RGB_COLORS, 0, 0);
++                    NtGdiGetDIBitsInternal(hdc, hMem, 0, bm.bmHeight,  NULL, &bi, DIB_RGB_COLORS, 0, 0);
 +
 +                    size = bi.bmiHeader.biSizeImage + sizeof(BITMAPINFOHEADER);
 +
 +                    hCBData = ExAllocatePoolWithTag(PagedPool, size, USERTAG_CLIPBOARD);
 +                    memcpy(hCBData, &bi, sizeof(BITMAPINFOHEADER));
 +
++                    NtGdiGetDIBitsInternal(hdc, hMem, 0, bm.bmHeight, (LPBYTE)hCBData + sizeof(BITMAPINFOHEADER), &bi, DIB_RGB_COLORS, 0, 0);
 +
 +                    UserReleaseDC(NULL, hdc, FALSE);
 +
 +                    intAddFormatedData(CF_DIB, hCBData, size);
 +                    intAddFormatedData(CF_BITMAP, 0, DATA_SYNTHESIZED_RENDER);
 +                    // intAddFormatedData(CF_DIBV5, hCBData, size);
 +
 +                    break;
 +                }
 +                case CF_DIB:
 +                {
 +                    intAddFormatedData(CF_BITMAP, 0, DATA_SYNTHESIZED_RENDER);
 +                    // intAddFormatedData(CF_DIBV5, hCBData, size);
 +                    /* investigate */
 +                    // intAddFormatedData(CF_PALETTE, hCBData, size);
 +                    break;
 +                }
 +                case CF_DIBV5:
 +                    // intAddFormatedData(CF_BITMAP, hCBData, size);
 +                    // intAddFormatedData(CF_PALETTE, hCBData, size);
 +                    // intAddFormatedData(CF_DIB, hCBData, size);
 +                    break;
 +                case CF_ENHMETAFILE:
 +                    // intAddFormatedData(CF_METAFILEPICT, hCBData, size);
 +                    break;
 +                case CF_METAFILEPICT:
 +                    // intAddFormatedData(CF_ENHMETAFILE, hCBData, size);
 +                    break;
 +            }
 +
 +        }
 +        else
 +        {
 +            // the window provides data in the specified format
 +            delayedRender = TRUE;
 +            sendDrawClipboardMsg = TRUE;
 +            intAddFormatedData(uFormat, NULL, 0);
 +            DPRINT1("SetClipboardData delayed format: %d\n", uFormat);
 +        }
 +
 +
 +    }
 +
 +exit_setCB:
 +
 +    UserLeave();
 +
 +    return hMem;
 +}
 +
 +HWND APIENTRY
 +NtUserSetClipboardViewer(HWND hWndNewViewer)
 +{
 +    HWND ret = NULL;
 +    PCLIPBOARDCHAINELEMENT newWC = NULL;
 +    PWINDOW_OBJECT window;
 +
 +    UserEnterExclusive();
 +
 +    window = UserGetWindowObject(hWndNewViewer);
 +
 +    if (window)
 +    {
 +        if ((newWC = IntAddWindowToChain(window)))
 +        {
 +            if (newWC)
 +            {
 +                // newWC->next may be NULL if we are the first window in the chain
 +                if (newWC->next)
 +                {
 +                    // return the next HWND available window in the chain
 +                    ret = newWC->next->window->hSelf;
 +                }
 +            }
 +        }
 +    }
 +
 +    UserLeave();
 +
 +    return ret;
 +}
 +
 +UINT APIENTRY
 +IntEnumClipboardFormats(UINT uFormat)
 +{
 +    UINT ret = 0;
 +
 +    if (intIsClipboardOpenByMe())
 +    {
 +            if (uFormat == 0)
 +            {
 +                if (recentlySetClipboard)
 +                {
 +                    ret = lastEnumClipboardFormats;
 +                }
 +                else
 +                {
 +                    /* return the first available format */
 +                    if (ClipboardData)
 +                    {
 +                        ret = ClipboardData->format;
 +                    }
 +                }
 +            }
 +            else
 +            {
 +                if (recentlySetClipboard)
 +                {
 +                    ret = 0;
 +                }
 +                else
 +                {
 +                    /* querying nextt available format */
 +                    PCLIPBOARDELEMENT data = intIsFormatAvailable(uFormat);
 +
 +                    if (data)
 +                    {
 +                        if (data->next)
 +                        {
 +                            ret = data->next->format;
 +                        }
 +                        else
 +                        {
 +                            /* reached the end */
 +                            ret = 0;
 +                        }
 +                    }
 +                }
 +
 +            }
 +    }
 +    else
 +    {
 +        SetLastWin32Error(ERROR_CLIPBOARD_NOT_OPEN);
 +    }
 +
 +    return ret;
 +}
 +
 +// This number is incremented whenever the contents of the clipboard change
 +// or the clipboard is emptied.
 +// If clipboard rendering is delayed,
 +// the sequence number is not incremented until the changes are rendered.
 +VOID FASTCALL
 +IntIncrementSequenceNumber(VOID)
 +{
 +    PTHREADINFO pti;
 +    PWINSTATION_OBJECT WinStaObj;
 +
 +    pti = PsGetCurrentThreadWin32Thread();
 +    WinStaObj = pti->rpdesk->rpwinstaParent;
 +
 +    WinStaObj->Clipboard->ClipboardSequenceNumber++;
 +}
 +
 +DWORD APIENTRY
 +NtUserGetClipboardSequenceNumber(VOID)
 +{
 +    //windowstation sequence number
 +    //if no WINSTA_ACCESSCLIPBOARD access to the window station,
 +    //the function returns zero.
 +    DWORD sn;
 +
 +    HWINSTA WinSta;
 +    PWINSTATION_OBJECT WinStaObj;
 +    NTSTATUS Status;
 +
 +    WinSta = UserGetProcessWindowStation();
 +
 +    Status = IntValidateWindowStationHandle(WinSta, KernelMode, WINSTA_ACCESSCLIPBOARD, &WinStaObj);
 +
 +    if (!NT_SUCCESS(Status))
 +    {
 +        DPRINT1("No WINSTA_ACCESSCLIPBOARD access\n");
 +        SetLastNtError(Status);
 +        return 0;
 +    }
 +
 +    sn = WinStaObj->ClipboardSequenceNumber;
 +
 +    ObDereferenceObject(WinStaObj);
 +
 +    //local copy
 +    //sn = ClipboardSequenceNumber;
 +
 +    return sn;
 +}
 +
 +
 +/**************** VISTA FUNCTIONS******************/
 +
 +BOOL APIENTRY NtUserAddClipboardFormatListener(
 +    HWND hwnd
 +)
 +{
 +    UNIMPLEMENTED;
 +    return FALSE;
 +}
 +
 +BOOL APIENTRY NtUserRemoveClipboardFormatListener(
 +    HWND hwnd
 +)
 +{
 +    UNIMPLEMENTED;
 +    return FALSE;
 +}
 +
 +BOOL APIENTRY NtUserGetUpdatedClipboardFormats(
 +    PUINT lpuiFormats,
 +    UINT cFormats,
 +    PUINT pcFormatsOut
 +)
 +{
 +    UNIMPLEMENTED;
 +    return FALSE;
 +}
 +
 +/* EOF */
index a1650bd,0000000..33df687
mode 100644,000000..100644
--- /dev/null
@@@ -1,1514 -1,0 +1,1513 @@@
-     BOOL bResult;
 +/*
 + *  ReactOS W32 Subsystem
 + *  Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
 + *
 + *  This program is free software; you can redistribute it and/or modify
 + *  it under the terms of the GNU General Public License as published by
 + *  the Free Software Foundation; either version 2 of the License, or
 + *  (at your option) any later version.
 + *
 + *  This program 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 General Public License for more details.
 + *
 + *  You should have received a copy of the GNU General Public License along
 + *  with this program; if not, write to the Free Software Foundation, Inc.,
 + *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 + */
 +
 +/*
 + * We handle two types of cursors/icons:
 + * - Private
 + *   Loaded without LR_SHARED flag
 + *   Private to a process
 + *   Can be deleted by calling NtDestroyCursorIcon()
 + *   CurIcon->hModule, CurIcon->hRsrc and CurIcon->hGroupRsrc set to NULL
 + * - Shared
 + *   Loaded with LR_SHARED flag
 + *   Possibly shared by multiple processes
 + *   Immune to NtDestroyCursorIcon()
 + *   CurIcon->hModule, CurIcon->hRsrc and CurIcon->hGroupRsrc are valid
 + * There's a M:N relationship between processes and (shared) cursor/icons.
 + * A process can have multiple cursor/icons and a cursor/icon can be used
 + * by multiple processes. To keep track of this we keep a list of all
 + * cursor/icons (CurIconList) and per cursor/icon we keep a list of
 + * CURICON_PROCESS structs starting at CurIcon->ProcessList.
 + */
 +
 +#include <win32k.h>
 +
 +#define NDEBUG
 +#include <debug.h>
 +
 +static PAGED_LOOKASIDE_LIST gProcessLookasideList;
 +static LIST_ENTRY gCurIconList;
 +
 +SYSTEM_CURSORINFO gSysCursorInfo;
 +
 +BOOL
 +InitCursorImpl()
 +{
 +    ExInitializePagedLookasideList(&gProcessLookasideList,
 +                                   NULL,
 +                                   NULL,
 +                                   0,
 +                                   sizeof(CURICON_PROCESS),
 +                                   TAG_DIB,
 +                                   128);
 +    InitializeListHead(&gCurIconList);
 +
 +     gSysCursorInfo.Enabled = FALSE;
 +     gSysCursorInfo.ButtonsDown = 0;
 +     gSysCursorInfo.CursorClipInfo.IsClipped = FALSE;
 +     gSysCursorInfo.LastBtnDown = 0;
 +     gSysCursorInfo.CurrentCursorObject = NULL;
 +     gSysCursorInfo.ShowingCursor = 0;
 +     gSysCursorInfo.ClickLockActive = FALSE;
 +     gSysCursorInfo.ClickLockTime = 0;
 +
 +    return TRUE;
 +}
 +
 +PSYSTEM_CURSORINFO
 +IntGetSysCursorInfo()
 +{
 +    return &gSysCursorInfo;
 +}
 +
 +/* This function creates a reference for the object! */
 +PCURICON_OBJECT FASTCALL UserGetCurIconObject(HCURSOR hCurIcon)
 +{
 +    PCURICON_OBJECT CurIcon;
 +
 +    if (!hCurIcon)
 +    {
 +        SetLastWin32Error(ERROR_INVALID_CURSOR_HANDLE);
 +        return NULL;
 +    }
 +
 +    CurIcon = (PCURICON_OBJECT)UserReferenceObjectByHandle(hCurIcon, otCursorIcon);
 +    if (!CurIcon)
 +    {
 +        /* we never set ERROR_INVALID_ICON_HANDLE. lets hope noone ever checks for it */
 +        SetLastWin32Error(ERROR_INVALID_CURSOR_HANDLE);
 +        return NULL;
 +    }
 +
 +    ASSERT(CurIcon->head.cLockObj >= 1);
 +    return CurIcon;
 +}
 +
 +HCURSOR
 +FASTCALL
 +UserSetCursor(
 +    PCURICON_OBJECT NewCursor,
 +    BOOL ForceChange)
 +{
 +    PSYSTEM_CURSORINFO CurInfo;
 +    PCURICON_OBJECT OldCursor;
 +    HCURSOR hOldCursor = (HCURSOR)0;
 +    HDC hdcScreen;
-         bResult = GreSetPointerShape(hdcScreen,
-                                      NewCursor->IconInfo.hbmMask,
-                                      NewCursor->IconInfo.hbmColor,
-                                      NewCursor->IconInfo.xHotspot,
-                                      NewCursor->IconInfo.yHotspot,
-                                      gpsi->ptCursor.x,
-                                      gpsi->ptCursor.y);
 +
 +      CurInfo = IntGetSysCursorInfo();
 +
 +    OldCursor = CurInfo->CurrentCursorObject;
 +    if (OldCursor)
 +    {
 +        hOldCursor = (HCURSOR)OldCursor->Self;
 +    }
 +
 +    /* Is the new cursor the same as the old cursor? */
 +    if (OldCursor == NewCursor)
 +    {
 +        /* Nothing to to do in this case */
 +        return hOldCursor;
 +    }
 +
 +    /* Get the screen DC */
 +    if(!(hdcScreen = IntGetScreenDC()))
 +    {
 +        return (HCURSOR)0;
 +    }
 +
 +    /* Do we have a new cursor? */
 +    if (NewCursor)
 +    {
 +        UserReferenceObject(NewCursor);
 +
 +        CurInfo->ShowingCursor = 1;
 +        CurInfo->CurrentCursorObject = NewCursor;
 +
 +        /* Call GDI to set the new screen cursor */
++        GreSetPointerShape(hdcScreen,
++                           NewCursor->IconInfo.hbmMask,
++                           NewCursor->IconInfo.hbmColor,
++                           NewCursor->IconInfo.xHotspot,
++                           NewCursor->IconInfo.yHotspot,
++                           gpsi->ptCursor.x,
++                           gpsi->ptCursor.y);
 +
 +
 +    }
 +    else
 +    {
 +        /* Check if were diplaying a cursor */
 +        if (OldCursor && CurInfo->ShowingCursor)
 +        {
 +            /* Remove the cursor */
 +            GreMovePointer(hdcScreen, -1, -1);
 +            DPRINT("Removing pointer!\n");
 +        }
 +
 +        CurInfo->CurrentCursorObject = NULL;
 +        CurInfo->ShowingCursor = 0;
 +    }
 +
 +    /* OldCursor is not in use anymore */
 +    if (OldCursor)
 +    {
 +        UserDereferenceObject(OldCursor);
 +    }
 +
 +    /* Return handle of the old cursor */
 +    return hOldCursor;
 +}
 +
 +BOOL UserSetCursorPos( INT x, INT y, BOOL SendMouseMoveMsg)
 +{
 +    PWINDOW_OBJECT DesktopWindow;
 +    PSYSTEM_CURSORINFO CurInfo;
 +    HDC hDC;
 +    MSG Msg;
 +
 +    if(!(hDC = IntGetScreenDC()))
 +    {
 +        return FALSE;
 +    }
 +
 +    CurInfo = IntGetSysCursorInfo();
 +
 +    DesktopWindow = UserGetDesktopWindow();
 +
 +    if (DesktopWindow)
 +    {
 +        if(x >= DesktopWindow->Wnd->rcClient.right)
 +            x = DesktopWindow->Wnd->rcClient.right - 1;
 +        if(y >= DesktopWindow->Wnd->rcClient.bottom)
 +            y = DesktopWindow->Wnd->rcClient.bottom - 1;
 +    }
 +
 +    if(x < 0)
 +        x = 0;
 +    if(y < 0)
 +        y = 0;
 +
 +    //Clip cursor position
 +    if(CurInfo->CursorClipInfo.IsClipped)
 +    {
 +       if(x >= (LONG)CurInfo->CursorClipInfo.Right)
 +           x = (LONG)CurInfo->CursorClipInfo.Right - 1;
 +       if(x < (LONG)CurInfo->CursorClipInfo.Left)
 +           x = (LONG)CurInfo->CursorClipInfo.Left;
 +       if(y >= (LONG)CurInfo->CursorClipInfo.Bottom)
 +           y = (LONG)CurInfo->CursorClipInfo.Bottom - 1;
 +       if(y < (LONG)CurInfo->CursorClipInfo.Top)
 +           y = (LONG)CurInfo->CursorClipInfo.Top;
 +    }
 +
 +    //Store the new cursor position
 +    gpsi->ptCursor.x = x;
 +    gpsi->ptCursor.y = y;
 +
 +    //Move the mouse pointer
 +    GreMovePointer(hDC, x, y);
 +
 +    if (!SendMouseMoveMsg)
 +       return TRUE;
 +
 +    //Generate a mouse move message
 +    Msg.message = WM_MOUSEMOVE;
 +    Msg.wParam = CurInfo->ButtonsDown;
 +    Msg.lParam = MAKELPARAM(x, y);
 +    Msg.pt = gpsi->ptCursor;
 +    MsqInsertSystemMessage(&Msg);
 +
 +    return TRUE;
 +}
 +
 +/* Called from NtUserCallOneParam with Routine ONEPARAM_ROUTINE_SHOWCURSOR
 + * User32 macro NtUserShowCursor */
 +int UserShowCursor(BOOL bShow)
 +{
 +    PSYSTEM_CURSORINFO CurInfo = IntGetSysCursorInfo();
 +    HDC hdcScreen;
 +
 +    if (!(hdcScreen = IntGetScreenDC()))
 +    {
 +        return 0; /* No mouse */
 +    }
 +
 +    if (bShow == FALSE)
 +    {
 +        /* Check if were diplaying a cursor */
 +        if (CurInfo->ShowingCursor == 1)
 +        {
 +            /* Remove the pointer */
 +            GreMovePointer(hdcScreen, -1, -1);
 +            DPRINT("Removing pointer!\n");
 +        }
 +        CurInfo->ShowingCursor--;
 +    }
 +    else
 +    {
 +        if (CurInfo->ShowingCursor == 0)
 +        {
 +            /*Show the pointer*/
 +            GreMovePointer(hdcScreen, gpsi->ptCursor.x, gpsi->ptCursor.y);
 +        }
 +        CurInfo->ShowingCursor++;
 +    }
 +
 +    return CurInfo->ShowingCursor;
 +}
 +
 +/*
 + * We have to register that this object is in use by the current
 + * process. The only way to do that seems to be to walk the list
 + * of cursor/icon objects starting at W32Process->CursorIconListHead.
 + * If the object is already present in the list, we don't have to do
 + * anything, if it's not present we add it and inc the ProcessCount
 + * in the object. Having to walk the list kind of sucks, but that's
 + * life...
 + */
 +static BOOLEAN FASTCALL
 +ReferenceCurIconByProcess(PCURICON_OBJECT CurIcon)
 +{
 +    PPROCESSINFO Win32Process;
 +    PCURICON_PROCESS Current;
 +
 +    Win32Process = PsGetCurrentProcessWin32Process();
 +
 +    LIST_FOR_EACH(Current, &CurIcon->ProcessList, CURICON_PROCESS, ListEntry)
 +    {
 +        if (Current->Process == Win32Process)
 +        {
 +            /* Already registered for this process */
 +            return TRUE;
 +        }
 +    }
 +
 +    /* Not registered yet */
 +    Current = ExAllocateFromPagedLookasideList(&gProcessLookasideList);
 +    if (NULL == Current)
 +    {
 +        return FALSE;
 +    }
 +    InsertHeadList(&CurIcon->ProcessList, &Current->ListEntry);
 +    Current->Process = Win32Process;
 +
 +    return TRUE;
 +}
 +
 +PCURICON_OBJECT FASTCALL
 +IntFindExistingCurIconObject(HMODULE hModule,
 +                             HRSRC hRsrc, LONG cx, LONG cy)
 +{
 +    PCURICON_OBJECT CurIcon;
 +
 +    LIST_FOR_EACH(CurIcon, &gCurIconList, CURICON_OBJECT, ListEntry)
 +    {
 +
 +        //    if(NT_SUCCESS(UserReferenceObjectByPointer(Object, otCursorIcon))) //<- huh????
 +//      UserReferenceObject(  CurIcon);
 +//      {
 +        if ((CurIcon->hModule == hModule) && (CurIcon->hRsrc == hRsrc))
 +        {
 +            if (cx && ((cx != CurIcon->Size.cx) || (cy != CurIcon->Size.cy)))
 +            {
 +//               UserDereferenceObject(CurIcon);
 +                continue;
 +            }
 +            if (! ReferenceCurIconByProcess(CurIcon))
 +            {
 +                return NULL;
 +            }
 +
 +            return CurIcon;
 +        }
 +//      }
 +//      UserDereferenceObject(CurIcon);
 +
 +    }
 +
 +    return NULL;
 +}
 +
 +PCURICON_OBJECT
 +IntCreateCurIconHandle()
 +{
 +    PCURICON_OBJECT CurIcon;
 +    HANDLE hCurIcon;
 +
 +    CurIcon = UserCreateObject(gHandleTable, NULL, &hCurIcon, otCursorIcon, sizeof(CURICON_OBJECT));
 +
 +    if (!CurIcon)
 +    {
 +        SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
 +        return FALSE;
 +    }
 +
 +    CurIcon->Self = hCurIcon;
 +    InitializeListHead(&CurIcon->ProcessList);
 +
 +    if (! ReferenceCurIconByProcess(CurIcon))
 +    {
 +        DPRINT1("Failed to add process\n");
 +        UserDeleteObject(hCurIcon, otCursorIcon);
 +        UserDereferenceObject(CurIcon);
 +        return NULL;
 +    }
 +
 +    InsertHeadList(&gCurIconList, &CurIcon->ListEntry);
 +
 +    return CurIcon;
 +}
 +
 +BOOLEAN FASTCALL
 +IntDestroyCurIconObject(PCURICON_OBJECT CurIcon, BOOL ProcessCleanup)
 +{
 +    PSYSTEM_CURSORINFO CurInfo;
 +    HBITMAP bmpMask, bmpColor;
 +    BOOLEAN Ret;
 +    PCURICON_PROCESS Current = NULL;
 +    PPROCESSINFO W32Process = PsGetCurrentProcessWin32Process();
 +
 +    /* Private objects can only be destroyed by their own process */
 +    if (NULL == CurIcon->hModule)
 +    {
 +        ASSERT(CurIcon->ProcessList.Flink->Flink == &CurIcon->ProcessList);
 +        Current = CONTAINING_RECORD(CurIcon->ProcessList.Flink, CURICON_PROCESS, ListEntry);
 +        if (Current->Process != W32Process)
 +        {
 +            DPRINT1("Trying to destroy private icon/cursor of another process\n");
 +            return FALSE;
 +        }
 +    }
 +    else if (! ProcessCleanup)
 +    {
 +        DPRINT("Trying to destroy shared icon/cursor\n");
 +        return FALSE;
 +    }
 +
 +    /* Now find this process in the list of processes referencing this object and
 +       remove it from that list */
 +    LIST_FOR_EACH(Current, &CurIcon->ProcessList, CURICON_PROCESS, ListEntry)
 +    {
 +        if (Current->Process == W32Process)
 +        {
 +            RemoveEntryList(&Current->ListEntry);
 +            break;
 +        }
 +    }
 +
 +    ExFreeToPagedLookasideList(&gProcessLookasideList, Current);
 +
 +    /* If there are still processes referencing this object we can't destroy it yet */
 +    if (! IsListEmpty(&CurIcon->ProcessList))
 +    {
 +        return TRUE;
 +    }
 +
 +
 +    if (! ProcessCleanup)
 +    {
 +        RemoveEntryList(&CurIcon->ListEntry);
 +    }
 +
 +    CurInfo = IntGetSysCursorInfo();
 +
 +    if (CurInfo->CurrentCursorObject == CurIcon)
 +    {
 +        /* Hide the cursor if we're destroying the current cursor */
 +        UserSetCursor(NULL, TRUE);
 +    }
 +
 +    bmpMask = CurIcon->IconInfo.hbmMask;
 +    bmpColor = CurIcon->IconInfo.hbmColor;
 +
 +    /* delete bitmaps */
 +    if (bmpMask)
 +    {
 +        GDIOBJ_SetOwnership(bmpMask, PsGetCurrentProcess());
 +        GreDeleteObject(bmpMask);
 +        CurIcon->IconInfo.hbmMask = NULL;
 +    }
 +    if (bmpColor)
 +    {
 +        GDIOBJ_SetOwnership(bmpColor, PsGetCurrentProcess());
 +        GreDeleteObject(bmpColor);
 +        CurIcon->IconInfo.hbmColor = NULL;
 +    }
 +
 +    /* We were given a pointer, no need to keep the reference anylonger! */
 +    UserDereferenceObject(CurIcon);
 +    Ret = UserDeleteObject(CurIcon->Self, otCursorIcon);
 +
 +    return Ret;
 +}
 +
 +VOID FASTCALL
 +IntCleanupCurIcons(struct _EPROCESS *Process, PPROCESSINFO Win32Process)
 +{
 +    PCURICON_OBJECT CurIcon, tmp;
 +    PCURICON_PROCESS ProcessData;
 +
 +    LIST_FOR_EACH_SAFE(CurIcon, tmp, &gCurIconList, CURICON_OBJECT, ListEntry)
 +    {
 +        UserReferenceObject(CurIcon);
 +        //    if(NT_SUCCESS(UserReferenceObjectByPointer(Object, otCursorIcon)))
 +        {
 +            LIST_FOR_EACH(ProcessData, &CurIcon->ProcessList, CURICON_PROCESS, ListEntry)
 +            {
 +                if (Win32Process == ProcessData->Process)
 +                {
 +                    RemoveEntryList(&CurIcon->ListEntry);
 +                    IntDestroyCurIconObject(CurIcon, TRUE);
 +                    CurIcon = NULL;
 +                    break;
 +                }
 +            }
 +
 +//         UserDereferenceObject(Object);
 +        }
 +
 +        if (CurIcon)
 +        {
 +            UserDereferenceObject(CurIcon);
 +        }
 +    }
 +
 +}
 +
 +
 +/*
 + * @implemented
 + */
 +BOOL
 +APIENTRY
 +NtUserGetIconInfo(
 +    HANDLE hCurIcon,
 +    PICONINFO IconInfo,
 +    PUNICODE_STRING lpInstName, // optional
 +    PUNICODE_STRING lpResName,  // optional
 +    LPDWORD pbpp,               // optional
 +    BOOL bInternal)
 +{
 +    ICONINFO ii;
 +    PCURICON_OBJECT CurIcon;
 +    NTSTATUS Status = STATUS_SUCCESS;
 +    BOOL Ret = FALSE;
 +    DWORD colorBpp = 0;
 +
 +    DPRINT("Enter NtUserGetIconInfo\n");
 +    UserEnterExclusive();
 +
 +    if (!IconInfo)
 +    {
 +        SetLastWin32Error(ERROR_INVALID_PARAMETER);
 +        goto leave;
 +    }
 +
 +    if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
 +    {
 +        goto leave;
 +    }
 +
 +    RtlCopyMemory(&ii, &CurIcon->IconInfo, sizeof(ICONINFO));
 +
 +    /* Copy bitmaps */
 +    ii.hbmMask = BITMAP_CopyBitmap(CurIcon->IconInfo.hbmMask);
 +    ii.hbmColor = BITMAP_CopyBitmap(CurIcon->IconInfo.hbmColor);
 +
 +    if (pbpp)
 +    {
 +        PSURFACE psurfBmp;
 +
 +        psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmColor);
 +        if (psurfBmp)
 +        {
 +            colorBpp = BitsPerFormat(psurfBmp->SurfObj.iBitmapFormat);
 +            SURFACE_UnlockSurface(psurfBmp);
 +        }
 +    }
 +
 +    /* Copy fields */
 +    _SEH2_TRY
 +    {
 +        ProbeForWrite(IconInfo, sizeof(ICONINFO), 1);
 +        RtlCopyMemory(IconInfo, &ii, sizeof(ICONINFO));
 +
 +        if (pbpp)
 +        {
 +            ProbeForWrite(pbpp, sizeof(DWORD), 1);
 +            *pbpp = colorBpp;
 +        }
 +    }
 +    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
 +    {
 +        Status = _SEH2_GetExceptionCode();
 +    }
 +    _SEH2_END
 +
 +    if (NT_SUCCESS(Status))
 +        Ret = TRUE;
 +    else
 +        SetLastNtError(Status);
 +
 +    UserDereferenceObject(CurIcon);
 +
 +leave:
 +    DPRINT("Leave NtUserGetIconInfo, ret=%i\n", Ret);
 +    UserLeave();
 +
 +    return Ret;
 +}
 +
 +
 +/*
 + * @implemented
 + */
 +BOOL
 +APIENTRY
 +NtUserGetIconSize(
 +    HANDLE hCurIcon,
 +    UINT istepIfAniCur,
 +    PLONG plcx,       // &size.cx
 +    PLONG plcy)       // &size.cy
 +{
 +    PCURICON_OBJECT CurIcon;
 +    NTSTATUS Status = STATUS_SUCCESS;
 +    BOOL bRet = FALSE;
 +
 +    DPRINT("Enter NtUserGetIconSize\n");
 +    UserEnterExclusive();
 +
 +    if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
 +    {
 +        goto cleanup;
 +    }
 +
 +    _SEH2_TRY
 +    {
 +        ProbeForWrite(plcx, sizeof(LONG), 1);
 +        RtlCopyMemory(plcx, &CurIcon->Size.cx, sizeof(LONG));
 +        ProbeForWrite(plcy, sizeof(LONG), 1);
 +        RtlCopyMemory(plcy, &CurIcon->Size.cy, sizeof(LONG));
 +    }
 +    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
 +    {
 +        Status = _SEH2_GetExceptionCode();
 +    }
 +    _SEH2_END
 +
 +    if (NT_SUCCESS(Status))
 +        bRet = TRUE;
 +    else
 +        SetLastNtError(Status); // maybe not, test this
 +
 +    UserDereferenceObject(CurIcon);
 +
 +cleanup:
 +    DPRINT("Leave NtUserGetIconSize, ret=%i\n", bRet);
 +    UserLeave();
 +    return bRet;
 +}
 +
 +
 +/*
 + * @unimplemented
 + */
 +DWORD
 +APIENTRY
 +NtUserGetCursorFrameInfo(
 +    DWORD Unknown0,
 +    DWORD Unknown1,
 +    DWORD Unknown2,
 +    DWORD Unknown3)
 +{
 +    UNIMPLEMENTED
 +
 +    return 0;
 +}
 +
 +
 +/*
 + * @implemented
 + */
 +BOOL
 +APIENTRY
 +NtUserGetCursorInfo(
 +    PCURSORINFO pci)
 +{
 +    CURSORINFO SafeCi;
 +    PSYSTEM_CURSORINFO CurInfo;
 +    NTSTATUS Status = STATUS_SUCCESS;
 +    PCURICON_OBJECT CurIcon;
 +    BOOL Ret = FALSE;
 +    DECLARE_RETURN(BOOL);
 +
 +    DPRINT("Enter NtUserGetCursorInfo\n");
 +    UserEnterExclusive();
 +
 +    CurInfo = IntGetSysCursorInfo();
 +    CurIcon = (PCURICON_OBJECT)CurInfo->CurrentCursorObject;
 +
 +    SafeCi.cbSize = sizeof(CURSORINFO);
 +    SafeCi.flags = ((CurInfo->ShowingCursor && CurIcon) ? CURSOR_SHOWING : 0);
 +    SafeCi.hCursor = (CurIcon ? (HCURSOR)CurIcon->Self : (HCURSOR)0);
 +
 +    SafeCi.ptScreenPos = gpsi->ptCursor;
 +
 +    _SEH2_TRY
 +    {
 +        if (pci->cbSize == sizeof(CURSORINFO))
 +        {
 +            ProbeForWrite(pci, sizeof(CURSORINFO), 1);
 +            RtlCopyMemory(pci, &SafeCi, sizeof(CURSORINFO));
 +            Ret = TRUE;
 +        }
 +        else
 +        {
 +            SetLastWin32Error(ERROR_INVALID_PARAMETER);
 +        }
 +    }
 +    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
 +    {
 +        Status = _SEH2_GetExceptionCode();
 +    }
 +    _SEH2_END;
 +    if (!NT_SUCCESS(Status))
 +    {
 +        SetLastNtError(Status);
 +    }
 +
 +    RETURN(Ret);
 +
 +CLEANUP:
 +    DPRINT("Leave NtUserGetCursorInfo, ret=%i\n",_ret_);
 +    UserLeave();
 +    END_CLEANUP;
 +}
 +
 +BOOL
 +APIENTRY
 +UserClipCursor(
 +    RECTL *prcl)
 +{
 +    /* FIXME - check if process has WINSTA_WRITEATTRIBUTES */
 +    PSYSTEM_CURSORINFO CurInfo;
 +    PWINDOW_OBJECT DesktopWindow = NULL;
 +
 +    CurInfo = IntGetSysCursorInfo();
 +
 +    DesktopWindow = UserGetDesktopWindow();
 +
 +    if (prcl != NULL &&
 +       (prcl->right > prcl->left) &&
 +       (prcl->bottom > prcl->top) &&
 +        DesktopWindow != NULL)
 +    {
 +        CurInfo->CursorClipInfo.IsClipped = TRUE;
 +        CurInfo->CursorClipInfo.Left = max(prcl->left, DesktopWindow->Wnd->rcWindow.left);
 +        CurInfo->CursorClipInfo.Top = max(prcl->top, DesktopWindow->Wnd->rcWindow.top);
 +        CurInfo->CursorClipInfo.Right = min(prcl->right, DesktopWindow->Wnd->rcWindow.right);
 +        CurInfo->CursorClipInfo.Bottom = min(prcl->bottom, DesktopWindow->Wnd->rcWindow.bottom);
 +
 +        UserSetCursorPos(gpsi->ptCursor.x, gpsi->ptCursor.y, FALSE);
 +    }
 +    else
 +    {
 +        CurInfo->CursorClipInfo.IsClipped = FALSE;
 +    }
 +
 +    return TRUE;
 +}
 +
 +/*
 + * @implemented
 + */
 +BOOL
 +APIENTRY
 +NtUserClipCursor(
 +    RECTL *prcl)
 +{
 +    /* FIXME - check if process has WINSTA_WRITEATTRIBUTES */
 +    RECTL rclLocal;
 +    BOOL bResult;
 +
 +    if (prcl)
 +    {
 +        _SEH2_TRY
 +        {
 +            /* Probe and copy rect */
 +            ProbeForRead(prcl, sizeof(RECTL), 1);
 +            rclLocal = *prcl;
 +        }
 +        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
 +        {
 +            SetLastWin32Error(ERROR_INVALID_PARAMETER);
 +            _SEH2_YIELD(return FALSE;)
 +        }
 +        _SEH2_END
 +
 +        prcl = &rclLocal;
 +    }
 +
 +    UserEnterExclusive();
 +
 +    /* Call the internal function */
 +    bResult = UserClipCursor(prcl);
 +
 +    UserLeave();
 +
 +    return bResult;
 +}
 +
 +
 +/*
 + * @implemented
 + */
 +BOOL
 +APIENTRY
 +NtUserDestroyCursor(
 +    HANDLE hCurIcon,
 +    DWORD Unknown)
 +{
 +    PCURICON_OBJECT CurIcon;
 +    BOOL ret;
 +    DECLARE_RETURN(BOOL);
 +
 +    DPRINT("Enter NtUserDestroyCursorIcon\n");
 +    UserEnterExclusive();
 +
 +    if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
 +    {
 +        RETURN(FALSE);
 +    }
 +
 +    ret = IntDestroyCurIconObject(CurIcon, FALSE);
 +    /* Note: IntDestroyCurIconObject will remove our reference for us! */
 +
 +    RETURN(ret);
 +
 +CLEANUP:
 +    DPRINT("Leave NtUserDestroyCursorIcon, ret=%i\n",_ret_);
 +    UserLeave();
 +    END_CLEANUP;
 +}
 +
 +
 +/*
 + * @implemented
 + */
 +HICON
 +APIENTRY
 +NtUserFindExistingCursorIcon(
 +    HMODULE hModule,
 +    HRSRC hRsrc,
 +    LONG cx,
 +    LONG cy)
 +{
 +    PCURICON_OBJECT CurIcon;
 +    HANDLE Ret = (HANDLE)0;
 +    DECLARE_RETURN(HICON);
 +
 +    DPRINT("Enter NtUserFindExistingCursorIcon\n");
 +    UserEnterExclusive();
 +
 +    CurIcon = IntFindExistingCurIconObject(hModule, hRsrc, cx, cy);
 +    if (CurIcon)
 +    {
 +        Ret = CurIcon->Self;
 +
 +//      IntReleaseCurIconObject(CurIcon);//faxme: is this correct? does IntFindExistingCurIconObject add a ref?
 +        RETURN(Ret);
 +    }
 +
 +    SetLastWin32Error(ERROR_INVALID_CURSOR_HANDLE);
 +    RETURN((HANDLE)0);
 +
 +CLEANUP:
 +    DPRINT("Leave NtUserFindExistingCursorIcon, ret=%i\n",_ret_);
 +    UserLeave();
 +    END_CLEANUP;
 +}
 +
 +
 +/*
 + * @implemented
 + */
 +BOOL
 +APIENTRY
 +NtUserGetClipCursor(
 +    RECTL *lpRect)
 +{
 +    /* FIXME - check if process has WINSTA_READATTRIBUTES */
 +    PSYSTEM_CURSORINFO CurInfo;
 +    RECTL Rect;
 +    NTSTATUS Status;
 +    DECLARE_RETURN(BOOL);
 +
 +    DPRINT("Enter NtUserGetClipCursor\n");
 +    UserEnterExclusive();
 +
 +    if (!lpRect)
 +        RETURN(FALSE);
 +
 +    CurInfo = IntGetSysCursorInfo();
 +    if (CurInfo->CursorClipInfo.IsClipped)
 +    {
 +        Rect.left = CurInfo->CursorClipInfo.Left;
 +        Rect.top = CurInfo->CursorClipInfo.Top;
 +        Rect.right = CurInfo->CursorClipInfo.Right;
 +        Rect.bottom = CurInfo->CursorClipInfo.Bottom;
 +    }
 +    else
 +    {
 +        Rect.left = 0;
 +        Rect.top = 0;
 +        Rect.right = UserGetSystemMetrics(SM_CXSCREEN);
 +        Rect.bottom = UserGetSystemMetrics(SM_CYSCREEN);
 +    }
 +
 +    Status = MmCopyToCaller(lpRect, &Rect, sizeof(RECT));
 +    if (!NT_SUCCESS(Status))
 +    {
 +        SetLastNtError(Status);
 +        RETURN(FALSE);
 +    }
 +
 +    RETURN(TRUE);
 +
 +CLEANUP:
 +    DPRINT("Leave NtUserGetClipCursor, ret=%i\n",_ret_);
 +    UserLeave();
 +    END_CLEANUP;
 +}
 +
 +
 +/*
 + * @implemented
 + */
 +HCURSOR
 +APIENTRY
 +NtUserSetCursor(
 +    HCURSOR hCursor)
 +{
 +    PCURICON_OBJECT CurIcon;
 +    HICON OldCursor;
 +    DECLARE_RETURN(HCURSOR);
 +
 +    DPRINT("Enter NtUserSetCursor\n");
 +    UserEnterExclusive();
 +
 +    if (hCursor)
 +    {
 +        if (!(CurIcon = UserGetCurIconObject(hCursor)))
 +        {
 +            RETURN(NULL);
 +        }
 +    }
 +    else
 +    {
 +        CurIcon = NULL;
 +    }
 +
 +    OldCursor = UserSetCursor(CurIcon, FALSE);
 +
 +    if (CurIcon)
 +    {
 +        UserDereferenceObject(CurIcon);
 +    }
 +
 +    RETURN(OldCursor);
 +
 +CLEANUP:
 +    DPRINT("Leave NtUserSetCursor, ret=%i\n",_ret_);
 +    UserLeave();
 +    END_CLEANUP;
 +}
 +
 +
 +/*
 + * @implemented
 + */
 +BOOL
 +APIENTRY
 +NtUserSetCursorContents(
 +    HANDLE hCurIcon,
 +    PICONINFO UnsafeIconInfo)
 +{
 +    PCURICON_OBJECT CurIcon;
 +    ICONINFO IconInfo;
 +    PSURFACE psurfBmp;
 +    NTSTATUS Status;
 +    BOOL Ret = FALSE;
 +    DECLARE_RETURN(BOOL);
 +
 +    DPRINT("Enter NtUserSetCursorContents\n");
 +    UserEnterExclusive();
 +
 +    if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
 +    {
 +        RETURN(FALSE);
 +    }
 +
 +    /* Copy fields */
 +    Status = MmCopyFromCaller(&IconInfo, UnsafeIconInfo, sizeof(ICONINFO));
 +    if (!NT_SUCCESS(Status))
 +    {
 +        SetLastNtError(Status);
 +        goto done;
 +    }
 +
 +    /* Delete old bitmaps */
 +    if ((CurIcon->IconInfo.hbmColor)
 +                      && (CurIcon->IconInfo.hbmColor != IconInfo.hbmColor))
 +    {
 +        GreDeleteObject(CurIcon->IconInfo.hbmColor);
 +    }
 +    if ((CurIcon->IconInfo.hbmMask)
 +                      && CurIcon->IconInfo.hbmMask != IconInfo.hbmMask)
 +    {
 +        GreDeleteObject(CurIcon->IconInfo.hbmMask);
 +    }
 +
 +    /* Copy new IconInfo field */
 +    CurIcon->IconInfo = IconInfo;
 +
 +    psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmColor);
 +    if (psurfBmp)
 +    {
 +        CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
 +        CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy;
 +        SURFACE_UnlockSurface(psurfBmp);
 +        GDIOBJ_SetOwnership(CurIcon->IconInfo.hbmColor, NULL);
 +    }
 +    else
 +    {
 +        psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmMask);
 +        if (!psurfBmp)
 +            goto done;
 +
 +        CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
 +        CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy / 2;
 +
 +        SURFACE_UnlockSurface(psurfBmp);
 +    }
 +      GDIOBJ_SetOwnership(CurIcon->IconInfo.hbmMask, NULL);
 +
 +    Ret = TRUE;
 +
 +done:
 +
 +    if (CurIcon)
 +    {
 +        UserDereferenceObject(CurIcon);
 +    }
 +    RETURN(Ret);
 +
 +CLEANUP:
 +    DPRINT("Leave NtUserSetCursorContents, ret=%i\n",_ret_);
 +    UserLeave();
 +    END_CLEANUP;
 +}
 +
 +
 +/*
 + * @implemented
 + */
 +#if 0
 +BOOL
 +APIENTRY
 +NtUserSetCursorIconData(
 +    HANDLE Handle,
 +    HMODULE hModule,
 +    PUNICODE_STRING pstrResName,
 +    PICONINFO pIconInfo)
 +{
 +    PCURICON_OBJECT CurIcon;
 +    PSURFACE psurfBmp;
 +    NTSTATUS Status = STATUS_SUCCESS;
 +    BOOL Ret = FALSE;
 +    DECLARE_RETURN(BOOL);
 +
 +    DPRINT("Enter NtUserSetCursorIconData\n");
 +    UserEnterExclusive();
 +
 +    if (!(CurIcon = UserGetCurIconObject(Handle)))
 +    {
 +        RETURN(FALSE);
 +    }
 +
 +    CurIcon->hModule = hModule;
 +    CurIcon->hRsrc = NULL; //hRsrc;
 +    CurIcon->hGroupRsrc = NULL; //hGroupRsrc;
 +
 +    _SEH2_TRY
 +    {
 +        ProbeForRead(pIconInfo, sizeof(ICONINFO), 1);
 +        RtlCopyMemory(&CurIcon->IconInfo, pIconInfo, sizeof(ICONINFO));
 +
 +        CurIcon->IconInfo.hbmMask = BITMAP_CopyBitmap(pIconInfo->hbmMask);
 +        CurIcon->IconInfo.hbmColor = BITMAP_CopyBitmap(pIconInfo->hbmColor);
 +
 +        if (CurIcon->IconInfo.hbmColor)
 +        {
 +            if ((psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmColor)))
 +            {
 +                CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
 +                CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy;
 +                SURFACE_UnlockSurface(psurfBmp);
 +                GDIOBJ_SetOwnership(GdiHandleTable, CurIcon->IconInfo.hbmMask, NULL);
 +            }
 +        }
 +        if (CurIcon->IconInfo.hbmMask)
 +        {
 +            if (CurIcon->IconInfo.hbmColor == NULL)
 +            {
 +                if ((psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmMask)))
 +                {
 +                    CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
 +                    CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy;
 +                    SURFACE_UnlockSurface(psurfBmp);
 +                }
 +            }
 +            GDIOBJ_SetOwnership(GdiHandleTable, CurIcon->IconInfo.hbmMask, NULL);
 +        }
 +    }
 +    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
 +    {
 +        Status = _SEH2_GetExceptionCode();
 +    }
 +    _SEH2_END
 +
 +    if (!NT_SUCCESS(Status))
 +        SetLastNtError(Status);
 +    else
 +        Ret = TRUE;
 +
 +    UserDereferenceObject(CurIcon);
 +    RETURN(Ret);
 +
 +CLEANUP:
 +    DPRINT("Leave NtUserSetCursorIconData, ret=%i\n",_ret_);
 +    UserLeave();
 +    END_CLEANUP;
 +}
 +#else
 +BOOL
 +APIENTRY
 +NtUserSetCursorIconData(
 +    HANDLE hCurIcon,
 +    PBOOL fIcon,
 +    POINT *Hotspot,
 +    HMODULE hModule,
 +    HRSRC hRsrc,
 +    HRSRC hGroupRsrc)
 +{
 +    PCURICON_OBJECT CurIcon;
 +    NTSTATUS Status;
 +    POINT SafeHotspot;
 +    BOOL Ret = FALSE;
 +    DECLARE_RETURN(BOOL);
 +
 +    DPRINT("Enter NtUserSetCursorIconData\n");
 +    UserEnterExclusive();
 +
 +    if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
 +    {
 +        RETURN(FALSE);
 +    }
 +
 +    CurIcon->hModule = hModule;
 +    CurIcon->hRsrc = hRsrc;
 +    CurIcon->hGroupRsrc = hGroupRsrc;
 +
 +    /* Copy fields */
 +    if (fIcon)
 +    {
 +        Status = MmCopyFromCaller(&CurIcon->IconInfo.fIcon, fIcon, sizeof(BOOL));
 +        if (!NT_SUCCESS(Status))
 +        {
 +            SetLastNtError(Status);
 +            goto done;
 +        }
 +    }
 +    else
 +    {
 +        if (!Hotspot)
 +            Ret = TRUE;
 +    }
 +
 +    if (Hotspot)
 +    {
 +        Status = MmCopyFromCaller(&SafeHotspot, Hotspot, sizeof(POINT));
 +        if (NT_SUCCESS(Status))
 +        {
 +            CurIcon->IconInfo.xHotspot = SafeHotspot.x;
 +            CurIcon->IconInfo.yHotspot = SafeHotspot.y;
 +
 +            Ret = TRUE;
 +        }
 +        else
 +            SetLastNtError(Status);
 +    }
 +
 +    if (!fIcon && !Hotspot)
 +    {
 +        Ret = TRUE;
 +    }
 +
 +done:
 +      if(Ret)
 +      {
 +              /* This icon is shared now */
 +              GDIOBJ_SetOwnership(CurIcon->IconInfo.hbmMask, NULL);
 +              if(CurIcon->IconInfo.hbmColor)
 +              {
 +                      GDIOBJ_SetOwnership(CurIcon->IconInfo.hbmColor, NULL);
 +              }
 +      }
 +    UserDereferenceObject(CurIcon);
 +    RETURN(Ret);
 +
 +
 +CLEANUP:
 +    DPRINT("Leave NtUserSetCursorIconData, ret=%i\n",_ret_);
 +    UserLeave();
 +    END_CLEANUP;
 +}
 +#endif
 +
 +/*
 + * @unimplemented
 + */
 +BOOL
 +APIENTRY
 +NtUserSetSystemCursor(
 +    HCURSOR hcur,
 +    DWORD id)
 +{
 +    return FALSE;
 +}
 +
 +/* Mostly inspired from wine code */
 +BOOL
 +UserDrawIconEx(
 +    HDC hDc,
 +    INT xLeft,
 +    INT yTop,
 +    PCURICON_OBJECT pIcon,
 +    INT cxWidth,
 +    INT cyHeight,
 +    UINT istepIfAniCur,
 +    HBRUSH hbrFlickerFreeDraw,
 +    UINT diFlags)
 +{
 +    BOOL Ret = FALSE;
 +    HBITMAP hbmMask, hbmColor;
 +    BITMAP bmpColor, bm;
 +    BOOL DoFlickerFree;
 +    INT iOldBkColor = 0, iOldTxtColor = 0;
 +
 +    HDC hMemDC, hDestDC = hDc;
 +    HGDIOBJ hOldOffBrush = 0;
 +    HGDIOBJ hOldOffBmp = 0;
 +    HBITMAP hTmpBmp = 0, hOffBmp = 0;
 +    BOOL bAlpha = FALSE;
 +    INT x=xLeft, y=yTop;
 +
 +    hbmMask = pIcon->IconInfo.hbmMask;
 +    hbmColor = pIcon->IconInfo.hbmColor;
 +
 +    if (istepIfAniCur)
 +        DPRINT1("NtUserDrawIconEx: istepIfAniCur is not supported!\n");
 +
 +    if (!hbmMask || !IntGdiGetObject(hbmMask, sizeof(BITMAP), (PVOID)&bm))
 +    {
 +        return FALSE;
 +    }
 +
 +    if (hbmColor && !IntGdiGetObject(hbmColor, sizeof(BITMAP), (PVOID)&bmpColor))
 +    {
 +        return FALSE;
 +    }
 +
 +    if(!(hMemDC = NtGdiCreateCompatibleDC(hDc)))
 +    {
 +        DPRINT1("NtGdiCreateCompatibleDC failed!\n");
 +        return FALSE;
 +    }
 +
 +    /* Check for alpha */
 +    if (hbmColor
 +            && (bmpColor.bmBitsPixel == 32)
 +            && (diFlags & DI_IMAGE))
 +    {
 +        SURFACE *psurfOff = NULL;
 +        PFN_DIB_GetPixel fnSource_GetPixel = NULL;
 +        INT i, j;
 +
 +        /* In order to correctly display 32 bit icons Windows first scans the image,
 +           because information about transparency is not stored in any image's headers */
 +        psurfOff = SURFACE_LockSurface(hbmColor);
 +        if (psurfOff)
 +        {
 +            fnSource_GetPixel = DibFunctionsForBitmapFormat[psurfOff->SurfObj.iBitmapFormat].DIB_GetPixel;
 +            if (fnSource_GetPixel)
 +            {
 +                for (i = 0; i < psurfOff->SurfObj.sizlBitmap.cx; i++)
 +                {
 +                    for (j = 0; j < psurfOff->SurfObj.sizlBitmap.cy; j++)
 +                    {
 +                        bAlpha = ((BYTE)(fnSource_GetPixel(&psurfOff->SurfObj, i, j) >> 24) & 0xff);
 +                        if (bAlpha)
 +                            break;
 +                    }
 +                    if (bAlpha)
 +                        break;
 +                }
 +            }
 +            SURFACE_UnlockSurface(psurfOff);
 +        }
 +    }
 +
 +    if (!cxWidth)
 +        cxWidth = ((diFlags & DI_DEFAULTSIZE) ?
 +                   UserGetSystemMetrics(SM_CXICON) : pIcon->Size.cx);
 +
 +    if (!cyHeight)
 +        cyHeight = ((diFlags & DI_DEFAULTSIZE) ?
 +                    UserGetSystemMetrics(SM_CYICON) : pIcon->Size.cy);
 +
 +    DoFlickerFree = (hbrFlickerFreeDraw &&
 +                     (GDI_HANDLE_GET_TYPE(hbrFlickerFreeDraw) == GDI_OBJECT_TYPE_BRUSH));
 +
 +    if (DoFlickerFree)
 +    {
 +        hDestDC = NtGdiCreateCompatibleDC(hDc);
 +        if(!hDestDC)
 +        {
 +            DPRINT1("NtGdiCreateCompatibleDC failed!\n");
 +            Ret = FALSE;
 +            goto Cleanup ;
 +        }
 +        hOffBmp = NtGdiCreateCompatibleBitmap(hDc, cxWidth, cyHeight);
 +        if(!hOffBmp)
 +        {
 +            DPRINT1("NtGdiCreateCompatibleBitmap failed!\n");
 +            goto Cleanup ;
 +        }
 +        hOldOffBmp = NtGdiSelectBitmap(hDestDC, hOffBmp);
 +        hOldOffBrush = NtGdiSelectBrush(hDestDC, hbrFlickerFreeDraw);
 +        NtGdiPatBlt(hDestDC, 0, 0, cxWidth, cyHeight, PATCOPY);
 +        NtGdiSelectBrush(hDestDC, hOldOffBrush);
 +        x=y=0;
 +    }
 +
 +    /* Set Background/foreground colors */
 +    iOldTxtColor = IntGdiSetTextColor(hDc, 0); //black
 +    iOldBkColor = IntGdiSetBkColor(hDc, 0x00FFFFFF); //white
 +
 +      if(bAlpha && (diFlags & DI_IMAGE))
 +      {
 +              BLENDFUNCTION pixelblend = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
 +        BYTE Alpha;
 +        INT i, j;
 +        PSURFACE psurf;
 +        PBYTE ptr ;
 +        HBITMAP hMemBmp = NULL;
 +
 +        hMemBmp = BITMAP_CopyBitmap(hbmColor);
 +        if(!hMemBmp)
 +        {
 +            DPRINT1("BITMAP_CopyBitmap failed!");
 +            goto CleanupAlpha;
 +        }
 +
 +        psurf = SURFACE_LockSurface(hMemBmp);
 +        if(!psurf)
 +        {
 +            DPRINT1("SURFACE_LockSurface failed!\n");
 +            goto CleanupAlpha;
 +        }
 +
 +        /* premultiply with the alpha channel value */
 +        for (i = 0; i < psurf->SurfObj.sizlBitmap.cy; i++)
 +        {
 +                      ptr = (PBYTE)psurf->SurfObj.pvScan0 + i*psurf->SurfObj.lDelta;
 +            for (j = 0; j < psurf->SurfObj.sizlBitmap.cx; j++)
 +            {
 +                Alpha = ptr[3];
 +                ptr[0] = (ptr[0] * Alpha) / 0xff;
 +                ptr[1] = (ptr[1] * Alpha) / 0xff;
 +                ptr[2] = (ptr[2] * Alpha) / 0xff;
 +
 +                              ptr += 4;
 +          &n