--- /dev/null
- {
+/*
+ *
+ * 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,
+};
--- /dev/null
- 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 */
--- /dev/null
- 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 */
--- /dev/null
- 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 */
--- /dev/null
- 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 */
--- /dev/null
- 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 */
--- /dev/null
- 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