shell32: SHSimpleIDListFromPath

Rolf Kalbermatter rolf.kalbermatter at citeng.com
Sun May 4 15:29:57 CDT 2003


This is the first part of a patch to get SHChangeNotify working properly on
deleted and moved/renamed files. There needs to be another change in all
shlfldr_xx.c to actually make it work as desired.
As it is now with this patch SHSimpleIDListFromPath still does what it is
supposed to do for existing paths, which is already a lot more than the
function did until now and SHChangeNotify does work exactly as it did
already until now.

dlls\shell32\shlfsbind.h and dlls\shell32\shlfsbind.c are new files added
to the tree

Changelog
  * dlls/shell32/changenotify.c
    Make SHChangeNotify use SHSimpleIDListFromPath as it is supposed to do
  * dlls/shell32/pidl.c
    Fix SHSimpleIDListFromPath to create fully qualified ItemIDLists and
    passing a bindcontext to IShellFolder_ParseDisplayName for conversion
    of a path to an ItemIDList.
  * dlls\shell32\shlfsbind.h
    New header file for the FileSystemBindContext
  * dlls\shell32\shlfsbind.c
    New source file for the FileSystemBindContext

License: X11/LGPL

Rolf Kalbermatter

Index: dlls/shell32/changenotify.c
===================================================================
RCS file: /home/wine/wine/dlls/shell32/changenotify.c,v
retrieving revision 1.20
diff -u -r1.20 changenotify.c
--- dlls/shell32/changenotify.c	21 Jan 2003 19:36:24 -0000	1.20
+++ dlls/shell32/changenotify.c	4 May 2003 19:23:08 -0000
@@ -18,8 +18,17 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#include "config.h"
+
 #include <string.h>
 
+#define NONAMELESSUNION
+#define NONAMELESSSTRUCT
+#include "winerror.h"
+#include "winbase.h"
+#include "winreg.h"
+
+#include "shlwapi.h"
 #include "wine/debug.h"
 #include "pidl.h"
 #include "shell32_main.h"
@@ -212,24 +221,25 @@
 {
 	LPITEMIDLIST Pidls[2];
 	LPNOTIFICATIONLIST ptr;
-	DWORD dummy;
 	UINT typeFlag = uFlags & SHCNF_TYPE;
 
 	Pidls[0] = (LPITEMIDLIST)dwItem1;
 	Pidls[1] = (LPITEMIDLIST)dwItem2;
 
-	TRACE("(0x%08lx,0x%08x,%p,%p):stub.\n", wEventId, uFlags, dwItem1, dwItem2);
+	TRACE("(0x%08lx,0x%08x,%p,%p)\n", wEventId, uFlags, dwItem1, dwItem2);
 
 	/* convert paths in IDLists*/
 	switch (typeFlag)
 	{
+	  case SHCNF_IDLIST:
+	    break;
 	  case SHCNF_PATHA:
-	    if (dwItem1) SHILCreateFromPathA((LPCSTR)dwItem1, &Pidls[0], &dummy);
-	    if (dwItem2) SHILCreateFromPathA((LPCSTR)dwItem2, &Pidls[1], &dummy);
+	    if (dwItem1) Pidls[0] = SHSimpleIDListFromPathA((LPCSTR)dwItem1);
+	    if (dwItem2) Pidls[1] = SHSimpleIDListFromPathA((LPCSTR)dwItem2);
 	    break;
 	  case SHCNF_PATHW:
-	    if (dwItem1) SHILCreateFromPathW((LPCWSTR)dwItem1, &Pidls[0], &dummy);
-	    if (dwItem2) SHILCreateFromPathW((LPCWSTR)dwItem2, &Pidls[1], &dummy);
+	    if (dwItem1) Pidls[0] = SHSimpleIDListFromPathW((LPCWSTR)dwItem1);
+	    if (dwItem2) Pidls[1] = SHSimpleIDListFromPathW((LPCWSTR)dwItem2);
 	    break;
 	  case SHCNF_PRINTERA:
 	  case SHCNF_PRINTERW:
@@ -255,8 +265,8 @@
 
 	LeaveCriticalSection(&SHELL32_ChangenotifyCS);
 
-	/* if we allocated it, free it */
-	if ((typeFlag == SHCNF_PATHA) || (typeFlag == SHCNF_PATHW))
+	/* if we allocated it, free it. The ANSI flag is also set in its Unicode sibling. */
+	if ((typeFlag & SHCNF_PATHA) /* || (typeFlag & SHCNF_PRINTERA) */ )
 	{
 	  if (Pidls[0]) SHFree(Pidls[0]);
 	  if (Pidls[1]) SHFree(Pidls[1]);

Index: dlls/shell32/pidl.c
===================================================================
RCS file: /home/wine/wine/dlls/shell32/pidl.c,v
retrieving revision 1.83
diff -u -r1.83 pidl.c
--- dlls/shell32/pidl.c	17 Apr 2003 02:18:33 -0000	1.83
+++ dlls/shell32/pidl.c	4 May 2003 19:25:30 -0000
@@ -39,6 +39,7 @@
 #include "shlwapi.h"
 
 #include "pidl.h"
+#include "shlfsbind.h"
 #include "debughlp.h"
 #include "wine/debug.h"
 
@@ -794,46 +795,115 @@
 	return ILCreateFromPathA (path);
 }
 /*************************************************************************
- *  SHSimpleIDListFromPath [SHELL32.162]
+ * _ILParsePathW             [internal]
+ *
+ * Creates an ItemIDList from a path and returns it.
+ *
+ * PARAMS
+ *  path         [I]   path to parse and convert into an ItemIDList
+ *  lpFindFile   [I]   pointer to buffer to initialize the FileSystem
+ *                     Bind Data object with
+ *  bBindCtx     [I]   indicates to create a BindContext and assign a
+ *                     FileSystem Bind Data object
+ *  ppidl        [O]   the newly create ItemIDList
+ *  prgfInOut    [I/O] requested attributes on input and actual
+ *                     attributes on return
+ *
+ * RETURNS
+ *  NO_ERROR on success or an OLE error code
+ *
+ * NOTES
+ *  If either lpFindFile is non-NULL or bBindCtx is TRUE, this function
+ *  creates a BindContext object and assigns a FileSystem Bind Data object
+ *  to it, passing the BindContext to IShellFolder_ParseDisplayName. Each
+ *  IShellFolder uses that FileSystem Bind Data object of the BindContext
+ *  to pass data about the current path element to the next object. This
+ *  is used to avoid having to verify the current path element on disk, so
+ *  that creating an ItemIDList from a non existing path still can work.
  */
-LPITEMIDLIST WINAPI SHSimpleIDListFromPathA (LPCSTR lpszPath)
+HRESULT WINAPI _ILParsePathW(LPCWSTR path, LPWIN32_FIND_DATAW lpFindFile,
+                             BOOL bBindCtx, LPITEMIDLIST *ppidl, LPDWORD prgfInOut)
 {
-	LPITEMIDLIST	pidl=NULL;
-	HANDLE	hFile;
-	WIN32_FIND_DATAA	stffile;
+	LPSHELLFOLDER pSF = NULL;
+	LPBC pBC = NULL;
+	HRESULT ret;
 
-	TRACE("path=%s\n", lpszPath);
+	TRACE("%s %p %ld %p %p %p 0x%lx\n", debugstr_w(path), lpFindFile, bBindCtx,
+	                                    ppidl, ppidl ? *ppidl : NULL,
+	                                    prgfInOut, prgfInOut ? *prgfInOut : 0);
 
-	if (!lpszPath) return NULL;
+	ret = SHGetDesktopFolder(&pSF);
+	if (FAILED(ret))
+	{
+	  return ret;
+	}
 
-	hFile = FindFirstFileA(lpszPath, &stffile);
+	if (lpFindFile || bBindCtx)
+	  ret = FSBindData_Constructor(lpFindFile, &pBC);
 
-	if ( hFile != INVALID_HANDLE_VALUE )
+	if (SUCCEEDED(ret))
 	{
-	  if (stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
-	  {
-	    pidl = _ILCreateFolder (&stffile);
-	  }
-	  else
-	  {
-	    pidl = _ILCreateValue (&stffile);
-	  }
-	  FindClose (hFile);
+	  ret = IShellFolder_ParseDisplayName(pSF, 0, pBC, (LPOLESTR)path, NULL, ppidl, prgfInOut);
+	  IUnknown_Release(pBC);
 	}
+
+	if (pBC)
+	  IBindCtx_Release(pBC);
+
+	IShellFolder_Release(pSF);
+
+	if (!SUCCEEDED(ret) && ppidl)
+	  *ppidl = NULL;
+
+	TRACE("%s %p 0x%lx\n", debugstr_w(path), ppidl ? *ppidl : NULL, prgfInOut ? *prgfInOut : 0);
+
+	return ret;
+}
+
+/*************************************************************************
+ * SHSimpleIDListFromPath    [SHELL32.162]
+ *
+ * Creates a simple ItemIDList from a path and returns it. This function
+ * does not fail on non-existing paths.
+ *
+ * PARAMS
+ *  path         [I]   path to parse and convert into an ItemIDList
+ *
+ * RETURNS
+ *  the newly created simple ItemIDList
+ *
+ * NOTES
+ *  Simple in the name does not mean a relative ItemIDList but rather a
+ *  fully qualified list, where only the file name is filled in and the
+ *  directory flag for those ItemID elements this is known about, eg.
+ *  it is not the last element in the ItemIDList or the actual directory
+ *  exists on disk.
+ *  exported by ordinal.
+ */
+LPITEMIDLIST WINAPI SHSimpleIDListFromPathA(LPCSTR path)
+{
+	LPITEMIDLIST pidl = NULL;
+	WCHAR wPath[MAX_PATH];
+
+	TRACE("%s\n", debugstr_a(path));
+
+	MultiByteToWideChar(CP_ACP, 0, path, -1, wPath, MAX_PATH);
+	_ILParsePathW(wPath, NULL, TRUE, &pidl, NULL);
 	return pidl;
 }
-LPITEMIDLIST WINAPI SHSimpleIDListFromPathW (LPCWSTR lpszPath)
+
+LPITEMIDLIST WINAPI SHSimpleIDListFromPathW(LPCWSTR path)
 {
-	char	lpszTemp[MAX_PATH];
-	TRACE("path=%s\n",debugstr_w(lpszPath));
+	LPITEMIDLIST pidl = NULL;
 
-        if (!WideCharToMultiByte( CP_ACP, 0, lpszPath, -1, lpszTemp, sizeof(lpszTemp), NULL, NULL ))
-            lpszTemp[sizeof(lpszTemp)-1] = 0;
+	TRACE("%s\n", debugstr_w(path));
 
-	return SHSimpleIDListFromPathA (lpszTemp);
+	_ILParsePathW(path, NULL, TRUE, &pidl, NULL);
+	TRACE("%s %p\n", debugstr_w(path), pidl);
+	return pidl;
 }
 
-LPITEMIDLIST WINAPI SHSimpleIDListFromPathAW (LPCVOID lpszPath)
+LPITEMIDLIST WINAPI SHSimpleIDListFromPathAW(LPCVOID lpszPath)
 {
 	if ( SHELL_OsIsUnicode())
 	  return SHSimpleIDListFromPathW (lpszPath);

--- /dev/nul	Sun May 04 19:15:26 2003
+++ dlls/shell32/shlfsbind.h	Sun May 04 20:08:32 2003
@@ -0,0 +1,64 @@
+/*
+ * File System Bind Data object to use as parameter for the bind context to
+ * IShellFolder_ParseDisplayName
+ *
+ * Copyright 2003 Rolf Kalbermatter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/***********************************************************************
+*   FSBindData declarations
+*/
+#ifndef __WINE_SHELL_FS_BINDDATA_H
+#define __WINE_SHELL_FS_BINDDATA_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* defined(__cplusplus) */
+
+typedef struct IFSBindData IFSBindData, *LPFSBINDDATA;
+
+#define INTERFACE IFSBindData
+#define IFSBindData_METHODS \
+    IUnknown_METHODS \
+    STDMETHOD(PutData)(THIS_ LPWIN32_FIND_DATAW lpFindFile) PURE; \
+    STDMETHOD(GetData)(THIS_ LPWIN32_FIND_DATAW lpFindFile) PURE;
+ICOM_DEFINE(IFSBindData,IUnknown)
+#undef INTERFACE
+
+DEFINE_GUID(IID_IFSBindData, 0x01E18D10,0x4D8B,0x11D2,0x85,0x5D,0x00,0x60,0x08,0x05,0x93,0x67);
+
+
+/*** IUnknown methods ***/
+#define IFSBindData_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b)
+#define IFSBindData_AddRef(p)             (p)->lpVtbl->AddRef(p)
+#define IFSBindData_Release(p)            (p)->lpVtbl->Release(p)
+/*** IFSBindData methods ***/
+#define IFSBindData_PutData(p,a)          (p)->lpVtbl->PutData(p,a)
+#define IFSBindData_GetData(p,a)          (p)->lpVtbl->GetData(p,a)
+
+HRESULT WINAPI FSBindData_Constructor(LPWIN32_FIND_DATAW lpFindFile, LPBC *ppV);
+
+HRESULT WINAPI FSBindData_QueryData(LPBC pbc, LPWIN32_FIND_DATAW lpFindFile);
+
+HRESULT WINAPI FSBindData_StoreData(LPBC pbc, LPWIN32_FIND_DATAW lpFindFile);
+
+#ifdef __cplusplus
+extern }
+#endif /* defined(__cplusplus) */
+
+#endif

--- /dev/nul	Sun May 04 19:15:26 2003
+++ dlls/shell32/shlfsbind.c	Sun May 04 19:19:00 2003
@@ -0,0 +1,203 @@
+/*
+ * File System Bind Data object to use as parameter for the bind context to
+ * IShellFolder_ParseDisplayName
+ *
+ * Copyright 2003	Rolf Kalbermatter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include "config.h"
+#include "wine/port.h"
+
+#include "winbase.h"
+#include "shell32_main.h"
+#include "shlfsbind.h"
+
+#include "debughlp.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(pidl);
+
+/***********************************************************************
+ * FSBindData implementation
+ */
+typedef struct
+{
+	ICOM_VFIELD(IFSBindData);
+	DWORD              ref;
+	LPWIN32_FIND_DATAW lpFindFile;
+} IFSBindDataImpl;
+
+static HRESULT WINAPI IFSBindData_fnQueryInterface(LPFSBINDDATA iface, REFIID riid, LPVOID* ppvObj);
+static ULONG WINAPI IFSBindData_fnAddRef(LPFSBINDDATA iface);
+static ULONG WINAPI IFSBindData_fnRelease(LPFSBINDDATA iface);
+static HRESULT WINAPI IFSBindData_fnPutData(LPFSBINDDATA iface, LPWIN32_FIND_DATAW lpFindFile);
+static HRESULT WINAPI IFSBindData_fnGetData(LPFSBINDDATA iface, LPWIN32_FIND_DATAW lpFindFile);
+
+static struct ICOM_VTABLE(IFSBindData) sbvt =
+{
+    ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+    IFSBindData_fnQueryInterface,
+    IFSBindData_fnAddRef,
+    IFSBindData_fnRelease,
+    IFSBindData_fnPutData,
+    IFSBindData_fnGetData,
+};
+
+static WCHAR lpFileSystemBindData[] = {'F','i','l','e',' ','S','y','s','t','e','m',' ','B','i','n','d','D','a','t','a',0};
+
+HRESULT WINAPI FSBindData_Constructor(LPWIN32_FIND_DATAW lpFindFile, LPBC *ppV)
+{
+	IFSBindDataImpl *sb = (IFSBindDataImpl*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IFSBindDataImpl));
+	HRESULT ret = E_OUTOFMEMORY;
+
+	*ppV = NULL;
+	if (!sb)
+	  return ret;
+
+	sb->lpVtbl = &sbvt;
+	sb->ref = 1;
+	if (lpFindFile)
+	  memcpy(sb->lpFindFile, lpFindFile, sizeof(LPWIN32_FIND_DATAW));
+	else
+	  memset(sb->lpFindFile, 0, sizeof(LPWIN32_FIND_DATAW));
+
+	ret = CreateBindCtx(0, ppV);
+	if (SUCCEEDED(ret))
+	{
+	  BIND_OPTS bindOpts;
+	  bindOpts.cbStruct = sizeof(BIND_OPTS);
+	  bindOpts.grfFlags = 0;
+	  bindOpts.grfMode = STGM_CREATE;
+	  bindOpts.dwTickCountDeadline = 0;
+	  IBindCtx_SetBindOptions(*ppV, &bindOpts);
+	  IBindCtx_RegisterObjectParam(*ppV, lpFileSystemBindData, (LPUNKNOWN)sb);
+
+	  IFSBindData_Release((LPFSBINDDATA)sb);
+	}
+	return ret;
+}
+
+HRESULT WINAPI FSBindData_QueryData(LPBC pbc, LPWIN32_FIND_DATAW lpFindFile)
+{
+	LPUNKNOWN pUnk;
+	LPFSBINDDATA pFSBindData = NULL;
+	HRESULT ret;
+	
+	ret = IBindCtx_GetObjectParam(pbc, lpFileSystemBindData, &pUnk);
+	if (SUCCEEDED(ret))
+	{
+	  ret = IUnknown_QueryInterface(pUnk, &IID_IFSBindData, &pFSBindData);
+	  if (SUCCEEDED(ret))
+	  {
+	    ret = IFSBindData_GetData(pFSBindData, lpFindFile);
+	    IFSBindData_Release(pFSBindData);  
+	  }
+	  IUnknown_Release(pUnk);
+	}
+	return ret;
+}
+
+HRESULT WINAPI FSBindData_StoreData(LPBC pbc, LPWIN32_FIND_DATAW lpFindFile)
+{
+	LPUNKNOWN pUnk;
+	LPFSBINDDATA pFSBindData = NULL;
+	HRESULT ret;
+	
+	ret = IBindCtx_GetObjectParam(pbc, lpFileSystemBindData, &pUnk);
+	if (SUCCEEDED(ret))
+	{
+	  ret = IUnknown_QueryInterface(pUnk, &IID_IFSBindData, &pFSBindData);
+	  if (SUCCEEDED(ret))
+	  {
+		ret = IFSBindData_PutData(pFSBindData, lpFindFile);
+	    IFSBindData_Release(pFSBindData);  
+	  }
+	  IUnknown_Release(pUnk);
+	}
+	return ret;}
+
+HRESULT WINAPI IFSBindData_fnQueryInterface(LPFSBINDDATA iface, REFIID riid, LPVOID *ppV)
+{
+	ICOM_THIS(IFSBindDataImpl, iface);
+	TRACE("(%p)->(\n\tIID:\t%s,%p)\n", This, debugstr_guid(riid), ppV);
+
+	*ppV = NULL;
+
+	if (IsEqualIID(riid, &IID_IUnknown))
+	{
+	  *ppV = This;
+	}
+	else if (IsEqualIID(riid, &IID_IFSBindData))
+	{
+	  *ppV = (IFSBindData*)This;
+	}
+
+	if(*ppV)
+	{
+	  IUnknown_AddRef((IUnknown*)(*ppV));
+	  TRACE("-- Interface: (%p)->(%p)\n", ppV, *ppV);
+	  return S_OK;
+	}
+	TRACE("-- Interface: E_NOINTERFACE\n");
+	return E_NOINTERFACE;
+}
+
+ULONG WINAPI IFSBindData_fnAddRef(LPFSBINDDATA iface)
+{
+	ICOM_THIS(IFSBindDataImpl, iface);
+	TRACE("(%p)\n", This);
+	return InterlockedIncrement(&This->ref);
+}
+
+ULONG WINAPI IFSBindData_fnRelease(LPFSBINDDATA iface)
+{
+	ICOM_THIS(IFSBindDataImpl, iface);
+	TRACE("(%p)\n", This);
+
+	if (!InterlockedDecrement(&This->ref))
+	{
+	  TRACE(" destroying ISFBindPidl(%p)\n",This);
+	  HeapFree(GetProcessHeap(), 0, This);
+	  return 0;
+	}
+	return This->ref;
+}
+
+HRESULT WINAPI IFSBindData_fnPutData(LPFSBINDDATA iface, LPWIN32_FIND_DATAW lpFindFile)
+{
+	ICOM_THIS(IFSBindDataImpl, iface);
+	TRACE("(%p %p)\n", This, lpFindFile);
+
+	if (!lpFindFile)
+	  memcpy(This->lpFindFile, lpFindFile, sizeof(LPWIN32_FIND_DATAW));
+	else
+	  memset(This->lpFindFile, 0, sizeof(LPWIN32_FIND_DATAW));
+	return NOERROR;
+}
+
+HRESULT WINAPI IFSBindData_fnGetData(LPFSBINDDATA iface, LPWIN32_FIND_DATAW lpFindFile)
+{
+	ICOM_THIS(IFSBindDataImpl, iface);
+	TRACE("(%p %p)\n", This, lpFindFile);
+
+	if (!lpFindFile)
+	  return E_INVALIDARG;
+
+	memcpy(lpFindFile, This->lpFindFile, sizeof(LPWIN32_FIND_DATAW));
+	return NOERROR;
+}





More information about the wine-patches mailing list