integrate replacement function for SHBindToParent()
Modified: trunk/reactos/subsys/system/explorer/shell/entries.cpp

Modified: trunk/reactos/subsys/system/explorer/shell/entries.cpp
--- trunk/reactos/subsys/system/explorer/shell/entries.cpp	2005-11-29 13:34:24 UTC (rev 19750)
+++ trunk/reactos/subsys/system/explorer/shell/entries.cpp	2005-11-29 13:35:11 UTC (rev 19751)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003, 2004 Martin Fuchs
+ * Copyright 2003, 2004, 2005 Martin Fuchs
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -334,7 +334,7 @@
 			unsigned flags;
 			int idx;
 
-			if (SUCCEEDED(pExtract->GetIconLocation(GIL_FORSHELL, path, MAX_PATH, &idx, &flags))) {
+			if (SUCCEEDED(pExtract->GetIconLocation(GIL_FORSHELL, path, COUNTOF(path), &idx, &flags))) {
 				if (flags & GIL_NOTFILENAME)
 					icon_id = g_Globals._icon_cache.extract(pExtract, path, idx, big_icons);
 				else {
@@ -403,6 +403,67 @@
 }
 
 
+ // local replacement implementation for SHBindToParent()
+ // (derived from http://www.geocities.com/SiliconValley/2060/articles/shell-helpers.html)
+static HRESULT my_SHBindToParent(LPCITEMIDLIST pidl, REFIID riid, VOID** ppv, LPCITEMIDLIST* ppidlLast)
+{
+	HRESULT hr;
+
+	if (!ppv)
+		return E_POINTER;
+
+	// There must be at least one item ID.
+	if (!pidl || !pidl->mkid.cb)
+		return E_INVALIDARG;
+
+	 // Get the desktop folder as root.
+	ShellFolder desktop;
+/*	IShellFolderPtr desktop;
+	hr = SHGetDesktopFolder(&desktop);
+	if (FAILED(hr))
+		return hr; */
+
+	// Walk to the penultimate item ID.
+	LPCITEMIDLIST marker = pidl;
+	for (;;)
+	{
+		LPCITEMIDLIST next = reinterpret_cast<LPCITEMIDLIST>(
+			marker->mkid.abID - sizeof(marker->mkid.cb) + marker->mkid.cb);
+		if (!next->mkid.cb)
+			break;
+		marker = next;
+	}
+
+	if (marker == pidl)
+	{
+		// There was only a single item ID, so bind to the root folder.
+		hr = desktop->QueryInterface(riid, ppv);
+	}
+	else
+	{
+		// Copy the ID list, truncating the last item.
+		int length = marker->mkid.abID - pidl->mkid.abID;
+		if (LPITEMIDLIST parent_id = reinterpret_cast<LPITEMIDLIST>(
+			malloc(length + sizeof(pidl->mkid.cb))))
+		{
+			LPBYTE raw_data = reinterpret_cast<LPBYTE>(parent_id);
+			memcpy(raw_data, pidl, length);
+			memset(raw_data + length, 0, sizeof(pidl->mkid.cb));
+			hr = desktop->BindToObject(parent_id, 0, riid, ppv);
+			free(parent_id);
+		}
+		else
+			return E_OUTOFMEMORY;
+	}
+
+	// Return a pointer to the last item ID.
+	if (ppidlLast)
+		*ppidlLast = marker;
+
+	return hr;
+}
+#define USE_MY_SHBINDTOPARENT
+
 HRESULT Entry::do_context_menu(HWND hwnd, const POINT& pos, CtxMenuInterfaces& cm_ifs)
 {
 	ShellPath shell_path = create_absolute_pidl();
@@ -411,6 +472,21 @@
 	if (!pidl_abs)
 		return S_FALSE;	// no action for registry entries, etc.
 
+#ifdef USE_MY_SHBINDTOPARENT
+	IShellFolder* parentFolder;
+	LPCITEMIDLIST pidlLast;
+
+	 // get and use the parent folder to display correct context menu in all cases -> correct "Properties" dialog for directories, ...
+	HRESULT hr = my_SHBindToParent(pidl_abs, IID_IShellFolder, (LPVOID*)&parentFolder, &pidlLast);
+
+	if (SUCCEEDED(hr)) {
+		hr = ShellFolderContextMenu(parentFolder, hwnd, 1, &pidlLast, pos.x, pos.y, cm_ifs);
+
+		parentFolder->Release();
+	}
+
+	return hr;
+#else
 	static DynamicFct<HRESULT(WINAPI*)(LPCITEMIDLIST, REFIID, LPVOID*, LPCITEMIDLIST*)> SHBindToParent(TEXT("SHELL32"), "SHBindToParent");
 
 	if (SHBindToParent) {
@@ -446,6 +522,7 @@
 		*/
 		return ShellFolderContextMenu(GetDesktopFolder(), hwnd, 1, &pidl_abs, pos.x, pos.y, cm_ifs);
 	}
+#endif
 }
 
 
@@ -489,7 +566,7 @@
 	LPWSTR wname = _data.cFileName;
 #else
 	WCHAR wname[MAX_PATH];
-	MultiByteToWideChar(CP_ACP, 0, _data.cFileName, -1, wname, MAX_PATH);
+	MultiByteToWideChar(CP_ACP, 0, _data.cFileName, -1, wname, COUNTOF(wname));
 #endif
 
 	LPITEMIDLIST pidl_last = NULL;