├── .gitignore ├── Installer ├── config.txt ├── installer.sfx ├── make.cmd └── tools │ └── upx.exe ├── ShellExtension ├── ClassFactory.cpp ├── ClassFactory.hpp ├── Debug.cpp ├── Debug.h ├── EnumIDList.cpp ├── EnumIDList.hpp ├── Group.cpp ├── Group.hpp ├── Macros.h ├── Main.cpp ├── Main.h ├── PIDL.cpp ├── PIDL.h ├── Registration.cpp ├── Registration.h ├── ShellExtension.vcxproj ├── ShellExtension.vcxproj.filters ├── ShellFolder.cpp ├── ShellFolder.hpp ├── ShellView.cpp ├── ShellView.hpp ├── WinUnionFS.def ├── WinUnionFS.ico └── WinUnionFS.rc └── WinUnionFS.sln /.gitignore: -------------------------------------------------------------------------------- 1 | /*.sdf 2 | /bin 3 | /ShellExtension/bin 4 | /*.opensdf 5 | 6 | /*.suo 7 | -------------------------------------------------------------------------------- /Installer/config.txt: -------------------------------------------------------------------------------- 1 | ;!@Install@!UTF-8! 2 | BeginPrompt="Click OK to install WinUnionFS." 3 | ExtractDialogText="Installing WinUnionFS..." 4 | ExtractPathText="WinUnionFS will be installed to:" 5 | FinishMessage="WinUnionFS was installed succesfully." 6 | GUIFlags="32+64+256+2048+4096" 7 | GUIMode="1" 8 | InstallPath="%ProgramFiles%\\WinUnionFS" 9 | InstallPath64="%ProgramW6432%\\WinUnionFS" 10 | MiscFlags="4" 11 | SetEnvironment="uninstallkey=HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{313f9e44-11ba-45de-8ecf-4a8ba0424d26}" 12 | RunProgram="x86:regsvr32 /s WinUnionFS32.dll" 13 | RunProgram="x64:regsvr32 /s WinUnionFS64.dll" 14 | RunProgram="x86:hidcon:cmd /c DEL /F /S /Q \"%%T\\WinUnionFS64.dll\"" 15 | RunProgram="x64:hidcon:cmd /c DEL /F /S /Q \"%%T\\WinUnionFS32.dll\"" 16 | RunProgram="x86:hidcon:cmd /c REG ADD %uninstallkey% /V DisplayIcon /D \"%%T\\WinUnionFS32.dll\" /f" 17 | RunProgram="x64:hidcon:cmd /c REG ADD %uninstallkey% /V DisplayIcon /D \"%%T\\WinUnionFS64.dll\" /f" 18 | RunProgram="hidcon:cmd /c REG ADD %uninstallkey% /V DisplayName /D WinUnionFS /f" 19 | RunProgram="hidcon:cmd /c REG ADD %uninstallkey% /V DisplayVersion /D 1.0 /f" 20 | RunProgram="x86:hidcon:cmd /c REG ADD %uninstallkey% /V EstimatedSize /T REG_DWORD /D 105 /f" 21 | RunProgram="x64:hidcon:cmd /c REG ADD %uninstallkey% /V EstimatedSize /T REG_DWORD /D 117 /f" 22 | RunProgram="hidcon:cmd /c REG ADD %uninstallkey% /V Language /T REG_DWORD /D 0x0409 /f" 23 | RunProgram="hidcon:cmd /c REG ADD %uninstallkey% /V NoModify /T REG_DWORD /D 0x1 /f" 24 | RunProgram="hidcon:cmd /c REG ADD %uninstallkey% /V NoRepair /T REG_DWORD /D 0x1 /f" 25 | RunProgram="hidcon:cmd /c REG ADD %uninstallkey% /V Publisher /D \"Erik Welander\" /f" 26 | RunProgram="x86:hidcon:cmd /c REG ADD %uninstallkey% /V UninstallString /D \"cmd /c regsvr32 /s /u \\\"%%T\\WinUnionFS32.dll\\\" & rmdir /S /Q \\\"%%T\\\" & REG DELETE %uninstallkey% /f\" /f" 27 | RunProgram="x64:hidcon:cmd /c REG ADD %uninstallkey% /V UninstallString /D \"cmd /c regsvr32 /s /u \\\"%%T\\WinUnionFS64.dll\\\" & rmdir /S /Q \\\"%%T\\\" & REG DELETE %uninstallkey% /f\" /f" 28 | RunProgram="hidcon:cmd /c REG ADD %uninstallkey% /V VersionMajor /T REG_DWORD /D 0x01 /f" 29 | RunProgram="hidcon:cmd /c REG ADD %uninstallkey% /V VersionMinor /T REG_DWORD /D 0x00 /f" 30 | Title="WinUnionFS Installer" 31 | ;!@InstallEnd@! -------------------------------------------------------------------------------- /Installer/installer.sfx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alur/WinUnionFS/4c812376e82cb6c200d55dbb5f0aa6d14e05c3f1/Installer/installer.sfx -------------------------------------------------------------------------------- /Installer/make.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | REM Paths 4 | set BuildPath=%temp%\WinUnionFS_Install 5 | set Output=WinUnionFS_Installer.exe 6 | 7 | REM Tools 8 | set SevenZip="%ProgramFiles%\7-Zip\7z.exe" 9 | 10 | if exist %BuildPath% rmdir /S /Q %BuildPath% 11 | mkdir %BuildPath% 12 | 13 | copy /V ..\bin\Release_x64\WinUnionFS.dll %BuildPath%\WinUnionFS64.dll 14 | copy /V ..\bin\Release_Win32\WinUnionFS.dll %BuildPath%\WinUnionFS32.dll 15 | copy /V installer.sfx %BuildPath%\installer.sfx 16 | copy /V config.txt %BuildPath%\config.txt 17 | 18 | pushd %BuildPath% 19 | %SevenZip% a -t7z -mx=9 -m9=LZMA2 "Files.7z" WinUnionFS64.dll WinUnionFS32.dll 20 | upx --ultra-brute installer.sfx 21 | copy /b installer.sfx + config.txt + Files.7z Installer.exe 22 | popd 23 | 24 | move %BuildPath%\Installer.exe %Output% 25 | 26 | rmdir /S /Q %BuildPath% 27 | -------------------------------------------------------------------------------- /Installer/tools/upx.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alur/WinUnionFS/4c812376e82cb6c200d55dbb5f0aa6d14e05c3f1/Installer/tools/upx.exe -------------------------------------------------------------------------------- /ShellExtension/ClassFactory.cpp: -------------------------------------------------------------------------------- 1 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2 | * ClassFactory.cpp 3 | * The WinUnionFS Project 4 | * 5 | * Implementation of IClassFactory. 6 | * 7 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 8 | #include 9 | #include 10 | 11 | #include "ClassFactory.hpp" 12 | #include "ShellFolder.hpp" 13 | 14 | 15 | // The number of in-use objects. 16 | extern long objectCounter; 17 | 18 | 19 | /// 20 | /// Constructor. 21 | /// 22 | ClassFactory::ClassFactory() { 23 | this->refCount = 1; 24 | InterlockedIncrement(&::objectCounter); 25 | } 26 | 27 | 28 | /// 29 | /// Destructor. 30 | /// 31 | ClassFactory::~ClassFactory() { 32 | InterlockedDecrement(&::objectCounter); 33 | } 34 | 35 | 36 | /// 37 | /// IUnknown::AddRef 38 | /// Increments the reference count for an interface on an object. 39 | /// 40 | ULONG ClassFactory::AddRef() { 41 | return InterlockedIncrement(&this->refCount); 42 | } 43 | 44 | 45 | /// 46 | /// IUnknown::Release 47 | /// Decrements the reference count for an interface on an object. 48 | /// 49 | ULONG ClassFactory::Release() { 50 | if (InterlockedDecrement(&this->refCount) == 0) { 51 | delete this; 52 | return 0; 53 | } 54 | 55 | return this->refCount; 56 | } 57 | 58 | 59 | /// 60 | /// IUnknown::QueryInterface 61 | /// Retrieves pointers to the supported interfaces on an object. 62 | /// 63 | HRESULT ClassFactory::QueryInterface(REFIID riid, void **ppvObject) { 64 | if (ppvObject == NULL) { 65 | return E_POINTER; 66 | } 67 | 68 | if (riid == IID_IUnknown) { 69 | *ppvObject = (IUnknown*)this; 70 | } 71 | else if (riid == IID_IClassFactory) { 72 | *ppvObject = (IClassFactory*)this; 73 | } 74 | else { 75 | *ppvObject = NULL; 76 | return E_NOINTERFACE; 77 | } 78 | 79 | ++this->refCount; 80 | return S_OK; 81 | } 82 | 83 | 84 | /// 85 | /// IClassFactory::CreateInstance 86 | /// 87 | /// 88 | HRESULT ClassFactory::CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppvObject) { 89 | if (ppvObject == NULL) { 90 | return E_POINTER; 91 | } 92 | 93 | // TODO::Aggregate? 94 | if (pUnkOuter != NULL) { 95 | return CLASS_E_NOAGGREGATION; 96 | } 97 | 98 | if (riid == IID_IShellFolder) { 99 | *ppvObject = (IShellFolder*)(new ShellFolder(NULL)); 100 | } 101 | else if (riid == IID_IPersistFolder) { 102 | *ppvObject = (IPersistFolder*)(new ShellFolder(NULL)); 103 | } 104 | else { 105 | *ppvObject = NULL; 106 | return E_NOINTERFACE; 107 | } 108 | 109 | // We failed to create the object. 110 | if (*ppvObject == NULL) { 111 | return E_OUTOFMEMORY; 112 | } 113 | 114 | return S_OK; 115 | } 116 | 117 | 118 | /// 119 | /// IClassFactory::LockServer 120 | /// 121 | /// 122 | HRESULT ClassFactory::LockServer(BOOL fLock) { 123 | return S_OK; 124 | } 125 | 126 | 127 | /// 128 | /// IClassFactory::IsLocked 129 | /// 130 | /// 131 | bool ClassFactory::IsLocked() { 132 | return false; 133 | } 134 | -------------------------------------------------------------------------------- /ShellExtension/ClassFactory.hpp: -------------------------------------------------------------------------------- 1 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2 | * ClassFactory.hpp 3 | * The WinUnionFS Project 4 | * 5 | * Implementation of IClassFactory. 6 | * 7 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 8 | #pragma once 9 | 10 | class ClassFactory : public IClassFactory 11 | { 12 | public: 13 | // Constructor/Destructor 14 | explicit ClassFactory(); 15 | 16 | // IUnknown 17 | ULONG STDMETHODCALLTYPE AddRef(); 18 | STDMETHOD(QueryInterface) (REFIID, void**); 19 | ULONG STDMETHODCALLTYPE Release(); 20 | 21 | // IClassFactory 22 | STDMETHOD(CreateInstance) (IUnknown*, REFIID, void**); 23 | STDMETHOD(LockServer) (BOOL); 24 | 25 | // Utility 26 | bool IsLocked(); 27 | 28 | private: 29 | virtual ~ClassFactory(); 30 | 31 | ULONG refCount; // 32 | }; 33 | -------------------------------------------------------------------------------- /ShellExtension/Debug.cpp: -------------------------------------------------------------------------------- 1 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2 | * Debug.cpp 3 | * The WinUnionFS Project 4 | * 5 | * Debugging functions. 6 | * 7 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 8 | #if defined(_DEBUG) 9 | #define _CRT_SECURE_NO_WARNINGS 10 | 11 | #include 12 | #include 13 | #include "Debug.h" 14 | 15 | #include 16 | #include 17 | 18 | 19 | // 20 | std::ofstream outStream; 21 | 22 | 23 | /// 24 | /// Sends a formatted (printf-style) message to the debug output window. 25 | /// Automatically inserts \n at the end of the string. 26 | /// 27 | void DbgTraceMessage(LPCWSTR format, ...) { 28 | if (!outStream.is_open()) { 29 | outStream.open("c:\\debug.txt", std::ios::out | std::ios::app); 30 | } 31 | 32 | va_list args; 33 | WCHAR buffer[512]; 34 | char wcBuffer[512]; 35 | 36 | va_start(args, format); 37 | StringCchVPrintfExW(buffer, 512, NULL, NULL, STRSAFE_NULL_ON_FAILURE, format, args); 38 | va_end(args); 39 | 40 | OutputDebugStringW(buffer); 41 | OutputDebugStringW(L"\n"); 42 | 43 | wcstombs(wcBuffer, buffer, 512); 44 | 45 | outStream << std::string(wcBuffer) << std::endl; 46 | 47 | outStream.flush(); 48 | } 49 | #endif 50 | -------------------------------------------------------------------------------- /ShellExtension/Debug.h: -------------------------------------------------------------------------------- 1 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2 | * Debug.h 3 | * The WinUnionFS Project 4 | * 5 | * Debugging macros and functions. Taken from the LiteStep core. 6 | * 7 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 8 | #pragma once 9 | 10 | #if defined(_DEBUG) 11 | #define TRACE DbgTraceMessage 12 | void DbgTraceMessage(LPCWSTR format, ...); 13 | #else 14 | #define TRACE 15 | #endif 16 | -------------------------------------------------------------------------------- /ShellExtension/EnumIDList.cpp: -------------------------------------------------------------------------------- 1 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2 | * EnumIDList.cpp 3 | * The WinUnionFS Project 4 | * 5 | * Enumerates over a collection of PIDLs. 6 | * 7 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 8 | #include 9 | #include 10 | 11 | #include "EnumIDList.hpp" 12 | #include "Macros.h" 13 | #include "PIDL.h" 14 | 15 | 16 | // The number of in-use objects. 17 | extern long objectCounter; 18 | 19 | 20 | /// 21 | /// Constructor. 22 | /// 23 | EnumIDList::EnumIDList() { 24 | this->refCount = 1; 25 | this->position = 0; 26 | 27 | InterlockedIncrement(&::objectCounter); 28 | } 29 | 30 | 31 | /// 32 | /// Destructor. 33 | /// 34 | EnumIDList::~EnumIDList() { 35 | for (std::vector::iterator iter = this->items.begin(); iter != this->items.end(); ++iter) { 36 | CoTaskMemFree(*iter); 37 | } 38 | this->items.clear(); 39 | 40 | InterlockedDecrement(&::objectCounter); 41 | } 42 | 43 | 44 | /// 45 | /// IUnknown::AddRef 46 | /// Increments the reference count for an interface on an object. 47 | /// 48 | ULONG EnumIDList::AddRef() { 49 | return InterlockedIncrement(&this->refCount); 50 | } 51 | 52 | 53 | /// 54 | /// IUnknown::Release 55 | /// Decrements the reference count for an interface on an object. 56 | /// 57 | ULONG EnumIDList::Release() { 58 | if (InterlockedDecrement(&this->refCount) == 0) { 59 | delete this; 60 | return 0; 61 | } 62 | 63 | return this->refCount; 64 | } 65 | 66 | 67 | /// 68 | /// IUnknown::QueryInterface 69 | /// Retrieves pointers to the supported interfaces on an object. 70 | /// 71 | HRESULT EnumIDList::QueryInterface(REFIID riid, void **ppvObject) { 72 | if (ppvObject == NULL) { 73 | return E_POINTER; 74 | } 75 | 76 | if (riid == IID_IEnumIDList) { 77 | *ppvObject = (IEnumIDList*)this; 78 | } 79 | else { 80 | *ppvObject = NULL; 81 | return E_NOINTERFACE; 82 | } 83 | 84 | AddRef(); 85 | return S_OK; 86 | } 87 | 88 | 89 | /// 90 | /// IEnumIDList::Clone 91 | /// Creates a new item enumeration object with the same contents and state as the current one. 92 | /// 93 | HRESULT EnumIDList::Clone(IEnumIDList **ppenum) { 94 | EnumIDList* clone = new EnumIDList(); 95 | 96 | for (std::vector::iterator iter = this->items.begin(); iter != this->items.end(); ++iter) { 97 | clone->AddItem(PIDL::Copy(*iter)); 98 | } 99 | clone->position = this->position; 100 | 101 | *ppenum = clone; 102 | 103 | return S_OK; 104 | } 105 | 106 | 107 | /// 108 | /// IEnumIDList::Next 109 | /// Retrieves the specified number of item identifiers in the enumeration sequence and advances 110 | /// the current position by the number of items retrieved. 111 | /// 112 | HRESULT EnumIDList::Next(ULONG celt, LPITEMIDLIST *rgelt, ULONG *pceltFetched) { 113 | ULONG fetched = 0; 114 | 115 | for (ULONG i = 0; this->position != this->items.size() && fetched < celt; ++i) { 116 | rgelt[i] = PIDL::Copy(this->items[this->position++]); 117 | ++fetched; 118 | } 119 | 120 | if (pceltFetched != NULL) { 121 | *pceltFetched = fetched; 122 | } 123 | 124 | return fetched == celt ? S_OK : S_FALSE; 125 | } 126 | 127 | 128 | /// 129 | /// IEnumIDList::Reset 130 | /// Returns to the beginning of the enumeration sequence. 131 | /// 132 | HRESULT EnumIDList::Reset() { 133 | this->position = 0; 134 | return S_OK; 135 | } 136 | 137 | 138 | /// 139 | /// IEnumIDList::Skip 140 | /// Skips the specified number of elements in the enumeration sequence. 141 | /// 142 | HRESULT EnumIDList::Skip(ULONG celt) { 143 | this->position = max((ULONG)this->items.size(), this->position + celt); 144 | return S_OK; 145 | } 146 | 147 | 148 | /// 149 | /// EnumIDList::AddItem 150 | /// Skips the specified number of elements in the enumeration sequence. 151 | /// 152 | void EnumIDList::AddItem(LPITEMIDLIST item) { 153 | // Remove duplicate folders. 154 | if (FLAGSET(PIDL::Item(item)->attributes, SFGAO_FOLDER)) { 155 | LPCWSTR name = PIDL::Item(item)->name; 156 | for (std::vector::const_iterator iter = this->items.begin(); iter != this->items.end(); ++iter) { 157 | PIDL::PIDLItem* p = PIDL::Item(*iter); 158 | if (FLAGSET(p->attributes, SFGAO_FOLDER) && wcscmp(name, p->name) == 0) { 159 | return; 160 | } 161 | } 162 | } 163 | this->items.push_back(item); 164 | } 165 | -------------------------------------------------------------------------------- /ShellExtension/EnumIDList.hpp: -------------------------------------------------------------------------------- 1 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2 | * EnumIDList.hpp 3 | * The WinUnionFS Project 4 | * 5 | * Enumerates over a collection of PIDLs. 6 | * 7 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 8 | #pragma once 9 | 10 | #include 11 | 12 | class EnumIDList : public IEnumIDList { 13 | public: 14 | explicit EnumIDList(); 15 | virtual ~EnumIDList(); 16 | 17 | // IUnknown 18 | ULONG STDMETHODCALLTYPE AddRef(); 19 | STDMETHOD(QueryInterface) (REFIID, void**); 20 | ULONG STDMETHODCALLTYPE Release(); 21 | 22 | // IEnumIDList 23 | STDMETHOD(Clone) (IEnumIDList**); 24 | STDMETHOD(Next) (ULONG, LPITEMIDLIST*, ULONG*); 25 | STDMETHOD(Reset) (); 26 | STDMETHOD(Skip) (ULONG); 27 | 28 | // 29 | void AddItem(LPITEMIDLIST item); 30 | 31 | private: 32 | std::vector items; 33 | ULONG position; 34 | ULONG refCount; 35 | }; 36 | -------------------------------------------------------------------------------- /ShellExtension/Group.cpp: -------------------------------------------------------------------------------- 1 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2 | * Group.cpp 3 | * The WinUnionFS Project 4 | * 5 | * 6 | * 7 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 8 | #include 9 | #include 10 | #include 11 | 12 | #include "Group.hpp" 13 | 14 | 15 | // The number of live objects which use this class 16 | ULONG Group::userCount = 0; 17 | 18 | // The currently loaded groups 19 | std::vector Group::groups; 20 | 21 | 22 | /// 23 | /// Should be called when a new object which uses groups is created. 24 | /// 25 | void Group::AddUser() { 26 | if (InterlockedIncrement(&Group::userCount) == 1) { 27 | Load(); 28 | } 29 | } 30 | 31 | 32 | /// 33 | /// Should be called when a object which uses groups is deleted. 34 | /// 35 | void Group::RemoveUser() { 36 | if (InterlockedDecrement(&Group::userCount) == 0) { 37 | // Erase all groups 38 | for (std::vector::const_iterator group = Group::groups.begin(); group != Group::groups.end(); ++group) { 39 | delete *group; 40 | } 41 | Group::groups.clear(); 42 | } 43 | } 44 | 45 | 46 | /// 47 | /// Loads the groups from the registry. 48 | /// 49 | HRESULT Group::Load() { 50 | // HKCU/Software/WinUnionFS/Groups 51 | HKEY groupsKey, groupKey, foldersKey; 52 | 53 | if (RegCreateKeyW(HKEY_CURRENT_USER, L"SOFTWARE\\WinUnionFS\\Groups", &groupsKey) != ERROR_SUCCESS) { 54 | return E_UNEXPECTED; 55 | } 56 | 57 | DWORD groupIndex = 0, cchName = MAX_PATH; 58 | WCHAR name[MAX_PATH]; 59 | while (RegEnumKeyExW(groupsKey, groupIndex++, name, &cchName, NULL, NULL, NULL, NULL) != ERROR_NO_MORE_ITEMS) { 60 | Group* group = new Group(name); 61 | 62 | RegCreateKeyW(groupsKey, name, &groupKey); 63 | 64 | RegCreateKeyW(groupKey, L"Folders", &foldersKey); 65 | 66 | // Enumerate the folders 67 | DWORD folderIndex = 0, cchFolderKeyName = MAX_PATH; 68 | WCHAR folderKeyName[MAX_PATH]; 69 | while (RegEnumKeyExW(foldersKey, folderIndex++, folderKeyName, &cchFolderKeyName, NULL, NULL, NULL, NULL) != ERROR_NO_MORE_ITEMS) { 70 | DWORD cbFolderPath = MAX_PATH*sizeof(WCHAR); 71 | WCHAR folderPath[MAX_PATH]; 72 | 73 | RegGetValueW(foldersKey, folderKeyName, L"Path", RRF_RT_REG_SZ, NULL, &folderPath, &cbFolderPath); 74 | 75 | group->AddPath(folderPath); 76 | 77 | cchFolderKeyName = MAX_PATH; 78 | } 79 | 80 | RegCloseKey(foldersKey); 81 | 82 | RegCloseKey(groupKey); 83 | 84 | Group::groups.push_back(group); 85 | cchName = MAX_PATH; 86 | } 87 | 88 | RegCloseKey(groupsKey); 89 | 90 | return S_OK; 91 | } 92 | 93 | 94 | /// 95 | /// Constructor. 96 | /// 97 | Group::Group(LPCWSTR name) { 98 | this->name = _wcsdup(name); 99 | } 100 | 101 | 102 | /// 103 | /// Destructor. 104 | /// 105 | Group::~Group() { 106 | for (std::vector::const_iterator folder = this->folders.begin(); folder != this->folders.end(); ++folder) { 107 | (*folder)->Release(); 108 | } 109 | free((LPVOID)this->name); 110 | } 111 | 112 | 113 | /// 114 | /// Adds a folder to this group. 115 | /// 116 | HRESULT Group::AddPath(LPCWSTR path) { 117 | IShellFolder *desktopFolder = NULL, *folder; 118 | PIDLIST_ABSOLUTE idList = NULL; 119 | HRESULT hr; 120 | 121 | hr = SHGetDesktopFolder(&desktopFolder); 122 | 123 | if (SUCCEEDED(hr)) { 124 | hr = desktopFolder->ParseDisplayName(NULL, NULL, (LPWSTR)path, NULL, &idList, NULL); 125 | } 126 | 127 | if (SUCCEEDED(hr)) { 128 | hr = desktopFolder->BindToObject(idList, NULL, IID_IShellFolder, reinterpret_cast(&folder)); 129 | } 130 | 131 | if (SUCCEEDED(hr)) { 132 | this->folders.push_back(folder); 133 | } 134 | 135 | if (idList != NULL) { 136 | CoTaskMemFree(idList); 137 | } 138 | 139 | if (desktopFolder != NULL) { 140 | desktopFolder->Release(); 141 | } 142 | 143 | return hr; 144 | } 145 | 146 | 147 | /// 148 | /// Retrives IShellFolder pointers for all folders in this group. 149 | /// 150 | void Group::GetShellFoldersFor(LPCWSTR path, std::vector *out) { 151 | PIDLIST_ABSOLUTE idList = NULL; 152 | IShellFolder *targetFolder; 153 | 154 | for (std::vector::const_iterator folder = this->folders.begin(); folder != this->folders.end(); ++folder) { 155 | if (path[0] == '\0') { 156 | out->push_back(*folder); 157 | (*folder)->AddRef(); 158 | } 159 | else { 160 | if (SUCCEEDED((*folder)->ParseDisplayName(NULL, NULL, (LPWSTR)path, NULL, &idList, NULL))) { 161 | if (SUCCEEDED((*folder)->BindToObject(idList, NULL, IID_IShellFolder, reinterpret_cast(&targetFolder)))) { 162 | out->push_back(targetFolder); 163 | } 164 | CoTaskMemFree(idList); 165 | } 166 | } 167 | } 168 | } 169 | 170 | 171 | /// 172 | /// Finds an existing group with the specified name. 173 | /// 174 | Group* Group::Find(LPCWSTR name) { 175 | int index = 0; 176 | Group* group; 177 | while ((group = Find(index++)) != NULL) { 178 | if (wcscmp(name, group->name) == 0) { 179 | break; 180 | } 181 | } 182 | 183 | return group; 184 | } 185 | 186 | 187 | /// 188 | /// Returns group # index if it exists, otherwise NULL. 189 | /// 190 | Group* Group::Find(int index) { 191 | return index < Group::groups.size() ? Group::groups[index] : NULL; 192 | } 193 | -------------------------------------------------------------------------------- /ShellExtension/Group.hpp: -------------------------------------------------------------------------------- 1 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2 | * Group.hpp 3 | * The WinUnionFS Project 4 | * 5 | * Represents one of 6 | * 7 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 8 | #pragma once 9 | 10 | #include 11 | 12 | class Group 13 | { 14 | public: 15 | // Static methods 16 | static void AddUser(); 17 | static void RemoveUser(); 18 | 19 | static Group* Create(LPCWSTR name); 20 | static void Delete(LPCWSTR name); 21 | static Group* Find(LPCWSTR name); 22 | static Group* Find(int index); 23 | 24 | // Instance methods 25 | void GetShellFoldersFor(LPCWSTR path, std::vector *out); 26 | 27 | // The name of the group 28 | LPCWSTR name; 29 | 30 | private: 31 | // 32 | static HRESULT Load(); 33 | 34 | // The number of live objects which use this class 35 | static ULONG userCount; 36 | 37 | // The currently loaded groups 38 | static std::vector groups; 39 | 40 | 41 | // Constructor/Destructor 42 | explicit Group(LPCWSTR name); 43 | virtual ~Group(); 44 | 45 | // Instance methods 46 | HRESULT AddPath(LPCWSTR path); 47 | 48 | // The IShellFolders which make up this group 49 | std::vector folders; 50 | }; 51 | -------------------------------------------------------------------------------- /ShellExtension/Macros.h: -------------------------------------------------------------------------------- 1 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2 | * Macros.h 3 | * The WinUnionFS Project 4 | * 5 | * Macros. 6 | * 7 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 8 | #pragma once 9 | 10 | #define FLAGSET(var,flag) (((var) & (flag)) == (flag)) 11 | -------------------------------------------------------------------------------- /ShellExtension/Main.cpp: -------------------------------------------------------------------------------- 1 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2 | * Main.cpp 3 | * The WinUnionFS Project 4 | * 5 | * Exported functions. 6 | * 7 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 8 | #include 9 | #include 10 | #include 11 | 12 | #include "ClassFactory.hpp" 13 | #include "Debug.h" 14 | #include "Main.h" 15 | #include "Registration.h" 16 | 17 | 18 | // The handle to this DLL. 19 | HMODULE module; 20 | 21 | // The number of in-use objects. 22 | long objectCounter; 23 | 24 | // The CLSID of WinUnionFS, {313f9e44-11ba-45de-8ecf-4a8ba0424d26}. 25 | extern const CLSID CLSID_WinUnionFS = {0x313f9e44, 0x11ba, 0x45de, {0x8e, 0xcf, 0x4a, 0x8b, 0xa0, 0x42, 0x4d, 0x26}}; 26 | 27 | 28 | /// 29 | /// The main entry point for this DLL. 30 | /// 31 | /// A handle to the DLL module. 32 | /// The reason code that indicates why the DLL entry-point function is being called. 33 | /// TRUE on success, FALSE on failure. 34 | BOOL APIENTRY DllMain(HMODULE module, DWORD reasonForCall, LPVOID /* reserved */) { 35 | switch (reasonForCall) { 36 | case DLL_PROCESS_DETACH: 37 | { 38 | } 39 | break; 40 | 41 | case DLL_PROCESS_ATTACH: 42 | { 43 | DisableThreadLibraryCalls(module); 44 | ::module = module; 45 | ::objectCounter = 0; 46 | } 47 | break; 48 | } 49 | 50 | return TRUE; 51 | } 52 | 53 | 54 | /// 55 | /// Determines whether the DLL that implements this function is in use. 56 | /// 57 | STDAPI DllCanUnloadNow() { 58 | return ::objectCounter == 0 ? S_OK : S_FALSE; 59 | } 60 | 61 | 62 | /// 63 | /// Retrieves the class object from a DLL object handler or object application. 64 | /// 65 | STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) { 66 | // Wait for the debugger to attach... 67 | //while (!IsDebuggerPresent()) { 68 | // Sleep(100); 69 | //} 70 | 71 | if (riid == IID_IClassFactory) { 72 | *ppv = (IClassFactory*)(new ClassFactory()); 73 | } 74 | else { 75 | *ppv = NULL; 76 | return CLASS_E_CLASSNOTAVAILABLE; 77 | } 78 | return S_OK; 79 | } 80 | -------------------------------------------------------------------------------- /ShellExtension/Main.h: -------------------------------------------------------------------------------- 1 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2 | * Main.h 3 | * The WinUnionFS Project 4 | * 5 | * Exported functions. 6 | * 7 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 8 | #pragma once 9 | 10 | BOOL APIENTRY DllMain(HMODULE, DWORD, LPVOID); 11 | STDAPI DllCanUnloadNow(); 12 | STDAPI DllGetClassObject(REFCLSID, REFIID, LPVOID*); 13 | -------------------------------------------------------------------------------- /ShellExtension/PIDL.cpp: -------------------------------------------------------------------------------- 1 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2 | * PIDL.cpp 3 | * The WinUnionFS Project 4 | * 5 | * Functions for managing WinUnionFS PIDLs. 6 | * 7 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "Group.hpp" 14 | #include "PIDL.h" 15 | 16 | 17 | /// 18 | /// 19 | /// 20 | LPITEMIDLIST PIDL::Concatenate(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2) { 21 | if (pidl1 == NULL) { 22 | return Copy(pidl2); 23 | } 24 | if (pidl2 == NULL) { 25 | return Copy(pidl1); 26 | } 27 | 28 | ULONG size1 = Size(pidl1); 29 | ULONG size2 = Size(pidl2); 30 | 31 | LPBYTE copy = (LPBYTE)CoTaskMemAlloc(size1 + size2 - sizeof(ITEMIDLIST)); 32 | memcpy(copy, pidl1, size1); 33 | memcpy(copy + size1 - sizeof(ITEMIDLIST), pidl2, size2); 34 | 35 | return LPITEMIDLIST(copy); 36 | } 37 | 38 | 39 | /// 40 | /// 41 | /// 42 | LPITEMIDLIST PIDL::Create(LPCITEMIDLIST parent, LPWSTR path, SFGAOF attributes, USHORT folder) { 43 | // Size of the path. 44 | USHORT cbName = USHORT(sizeof(WCHAR)*wcslen(path)); 45 | ULONG parentSize = 0; 46 | 47 | if (parent != NULL) { 48 | parentSize = Size(parent); 49 | } 50 | 51 | // 52 | LPITEMIDLIST ret = (LPITEMIDLIST)CoTaskMemAlloc(parentSize + cbName + sizeof(PIDLItem) + sizeof(ITEMIDLIST)); 53 | PIDLItem* item = Item(ret); 54 | 55 | if (parent != NULL) { 56 | memcpy(ret, parent, parentSize); 57 | item = Item(End(ret)); 58 | } 59 | 60 | cbName += sizeof(WCHAR); // The terminating NULL. 61 | 62 | item->cb = USHORT(cbName + sizeof(PIDLItem)); 63 | item->attributes = attributes; 64 | item->folder = folder; 65 | item->cbName = cbName; 66 | memcpy(item->name, path, cbName); 67 | 68 | Next(ret)->mkid.cb = 0; 69 | 70 | return ret; 71 | } 72 | 73 | 74 | /// 75 | /// 76 | /// 77 | LPITEMIDLIST PIDL::Copy(LPCITEMIDLIST source) { 78 | if (source == NULL) { 79 | return NULL; 80 | } 81 | 82 | ULONG size = Size(source); 83 | LPITEMIDLIST copy = (LPITEMIDLIST)CoTaskMemAlloc(size); 84 | memcpy(copy, source, size); 85 | 86 | return copy; 87 | } 88 | 89 | 90 | /// 91 | /// Returns an empty PIDL. 92 | /// 93 | LPITEMIDLIST PIDL::Empty() { 94 | LPITEMIDLIST ret = (LPITEMIDLIST)CoTaskMemAlloc(sizeof(ITEMIDLIST)); 95 | ZeroMemory(ret, sizeof(ITEMIDLIST)); 96 | 97 | return ret; 98 | } 99 | 100 | 101 | /// 102 | /// 103 | /// 104 | LPITEMIDLIST PIDL::End(LPCITEMIDLIST pidl){ 105 | LPCITEMIDLIST last = pidl; 106 | while (last->mkid.cb != 0) { 107 | last = Next(last); 108 | } 109 | return (LPITEMIDLIST)last; 110 | } 111 | 112 | 113 | /// 114 | /// 115 | /// 116 | void PIDL::Free(LPITEMIDLIST pidl) { 117 | if (pidl != NULL) { 118 | CoTaskMemFree(pidl); 119 | } 120 | } 121 | 122 | 123 | /// 124 | /// 125 | /// 126 | SFGAOF PIDL::GetAttributes(PCITEMID_CHILD pidl) { 127 | return Item(pidl)->attributes; 128 | } 129 | 130 | 131 | /// 132 | /// 133 | /// 134 | LPWSTR PIDL::GetDisplayName(PCITEMID_CHILD pidl) { 135 | PIDLItem* item = Item(pidl); 136 | LPWSTR ret = (LPWSTR)CoTaskMemAlloc(Item(pidl)->cbName); 137 | memcpy(ret, Item(pidl)->name, Item(pidl)->cbName); 138 | 139 | return ret; 140 | } 141 | 142 | 143 | /// 144 | /// Returns the full parse path of the item. Folder1\Folder2\File 145 | /// 146 | void PIDL::GetFullPath(LPCITEMIDLIST parent, PCITEMID_CHILD pidl, LPWSTR path, UINT cchPath) { 147 | LPCITEMIDLIST iter = Next(parent); 148 | path[0] = '\0'; 149 | 150 | while (iter->mkid.cb != 0) { 151 | StringCchCatW(path, cchPath, Item(iter)->name); 152 | StringCchCatW(path, cchPath, L"\\"); 153 | iter = Next(iter); 154 | } 155 | if (pidl != NULL) { 156 | StringCchCatW(path, cchPath, Item(pidl)->name); 157 | } 158 | else if(Next(parent)->mkid.cb != 0) { 159 | // Should drop that last backslash 160 | path[wcslen(path)-1] = '\0'; 161 | } 162 | } 163 | 164 | 165 | /// 166 | /// Returns the full parse path of the item. Folder1\Folder2\File 167 | /// 168 | LPWSTR PIDL::GetFullPath(LPCITEMIDLIST parent, PCITEMID_CHILD pidl) { 169 | WCHAR path[MAX_PATH] = L""; 170 | 171 | GetFullPath(parent, pidl, path, MAX_PATH); 172 | 173 | size_t size = (wcslen(path)+1)*sizeof(WCHAR); 174 | LPWSTR ret = (LPWSTR)CoTaskMemAlloc(size); 175 | memcpy(ret, path, size); 176 | 177 | return ret; 178 | } 179 | 180 | 181 | /// 182 | /// Returns the size, in bytes, of the entire ITEMIDLIST. 183 | /// 184 | HRESULT PIDL::GetShellFoldersFor(LPCITEMIDLIST pidl, std::vector *out) { 185 | // ShellFolder will have to deal with the top-level folder. 186 | if (Next(pidl)->mkid.cb != 0) { 187 | // This is the group level, we should get IShellFolder interfaces for all folders included in the group. 188 | 189 | // The first PIDL is the group. 190 | Group* group = Group::Find(Item(Next(pidl))->name); 191 | 192 | if (group != NULL) { 193 | WCHAR path[MAX_PATH]; 194 | LPCITEMIDLIST pathStart = Next(pidl); 195 | 196 | GetFullPath(pathStart, NULL, path, MAX_PATH); 197 | group->GetShellFoldersFor(path, out); 198 | } 199 | } 200 | 201 | return S_OK; 202 | } 203 | 204 | 205 | /// 206 | /// Returns the "item" of the PIDL. 207 | /// 208 | PIDL::PIDLItem* PIDL::Item(LPCITEMIDLIST pidl) { 209 | return (PIDLItem*)&pidl->mkid; 210 | } 211 | 212 | 213 | /// 214 | /// Returns the "item" of the PIDL. 215 | /// 216 | ULONG PIDL::ItemCount(LPCITEMIDLIST pidl) { 217 | ULONG count = 0; 218 | for (LPCITEMIDLIST iter = pidl; iter->mkid.cb != 0; iter = Next(iter)) { 219 | ++count; 220 | } 221 | 222 | return count; 223 | } 224 | 225 | 226 | /// 227 | /// Returns last id in the PIDL. 228 | /// 229 | LPITEMIDLIST PIDL::Last(LPCITEMIDLIST pidl) { 230 | while (Next(pidl)->mkid.cb != 0) { 231 | pidl = Next(pidl); 232 | } 233 | 234 | return LPITEMIDLIST(pidl); 235 | } 236 | 237 | 238 | /// 239 | /// Returns the next item in the ITEMIDLIST. 240 | /// 241 | LPITEMIDLIST PIDL::Next(LPCITEMIDLIST pidl) { 242 | return LPITEMIDLIST(((LPBYTE)pidl)+pidl->mkid.cb); 243 | } 244 | 245 | 246 | /// 247 | /// Returns the size, in bytes, of the entire ITEMIDLIST. 248 | /// 249 | ULONG PIDL::Size(LPCITEMIDLIST pidl) { 250 | ULONG size = sizeof(ITEMIDLIST); // Terminating item ID 251 | for (LPCITEMIDLIST iter = pidl; iter->mkid.cb != 0; iter = Next(iter)) { 252 | size += iter->mkid.cb; 253 | } 254 | 255 | return size; 256 | } 257 | -------------------------------------------------------------------------------- /ShellExtension/PIDL.h: -------------------------------------------------------------------------------- 1 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2 | * PIDL.hpp 3 | * The WinUnionFS Project 4 | * 5 | * Functions for managing WinUnionFS PIDLs. 6 | * 7 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 8 | #pragma once 9 | 10 | #include 11 | 12 | namespace PIDL { 13 | typedef struct { 14 | USHORT cb; 15 | USHORT folder; 16 | SFGAOF attributes; 17 | USHORT cbName; 18 | WCHAR name[1]; 19 | } PIDLItem; 20 | 21 | LPITEMIDLIST Concatenate(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2); 22 | LPITEMIDLIST Create(LPCITEMIDLIST parent, LPWSTR path, SFGAOF attributes, USHORT folder); 23 | LPITEMIDLIST CreateFromPath(LPCWSTR path); 24 | LPITEMIDLIST Copy(LPCITEMIDLIST source); 25 | LPITEMIDLIST Empty(); 26 | LPITEMIDLIST End(LPCITEMIDLIST pidl); 27 | void Free(LPITEMIDLIST pidl); 28 | SFGAOF GetAttributes(PCITEMID_CHILD pidl); 29 | LPWSTR GetDisplayName(PCITEMID_CHILD pidl); 30 | void GetFullPath(LPCITEMIDLIST parent, PCITEMID_CHILD pidl, LPWSTR path, UINT cchPath); 31 | LPWSTR GetFullPath(LPCITEMIDLIST parent, PCITEMID_CHILD pidl); 32 | HRESULT GetShellFoldersFor(LPCITEMIDLIST pidl, std::vector *out); 33 | PIDLItem* Item(LPCITEMIDLIST pidl); 34 | ULONG ItemCount(LPCITEMIDLIST pidl); 35 | LPITEMIDLIST Last(LPCITEMIDLIST pidl); 36 | LPITEMIDLIST Next(LPCITEMIDLIST pidl); 37 | ULONG Size(LPCITEMIDLIST pidl); 38 | } 39 | -------------------------------------------------------------------------------- /ShellExtension/Registration.cpp: -------------------------------------------------------------------------------- 1 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2 | * Registration.cpp 3 | * The WinUnionFS Project 4 | * 5 | * Handles registration and unregistration of this DLL. 6 | * 7 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 8 | #include 9 | #include 10 | #include 11 | 12 | #include "Debug.h" 13 | #include "Registration.h" 14 | 15 | 16 | // The handle to this DLL. 17 | extern HMODULE module; 18 | 19 | // The CLSID of WinUnionFS. 20 | extern const CLSID CLSID_WinUnionFS; 21 | 22 | // The keys used for registration. 23 | #define CLSIDKEY L"CLSID\\%s" 24 | #define NAMESPACEKEY L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Desktop\\NameSpace\\%s" 25 | 26 | 27 | /// 28 | /// Sets a registry string value. 29 | /// 30 | inline LSTATUS RegSetString(HKEY key, LPCWSTR value, LPCWSTR data) { 31 | return RegSetValueEx(key, value, NULL, REG_SZ, (const BYTE*)data, DWORD(sizeof(WCHAR)*(wcslen(data)+1))); 32 | } 33 | 34 | 35 | /// 36 | /// Sets a formatted registry value. 37 | /// 38 | LSTATUS RegPrintf(HKEY key, LPCWSTR value, LPCWSTR format, ...) { 39 | WCHAR data[4096]; 40 | va_list args; 41 | 42 | va_start(args, format); 43 | StringCchVPrintf(data, 4096, format, args); 44 | va_end(args); 45 | 46 | return RegSetString(key, value, data); 47 | } 48 | 49 | 50 | /// 51 | /// Checks if the current process is elevated. 52 | /// 53 | bool IsElevated() { 54 | BOOL fIsRunAsAdmin = FALSE; 55 | PSID pAdministratorsGroup = NULL; 56 | 57 | // Allocate and initialize a SID of the administrators group. 58 | SID_IDENTIFIER_AUTHORITY ntAuthority = SECURITY_NT_AUTHORITY; 59 | if (!AllocateAndInitializeSid(&ntAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &pAdministratorsGroup)) { 60 | return false; 61 | } 62 | 63 | // Determine whether the SID of administrators group is enabled in the primary access token of the process. 64 | CheckTokenMembership(NULL, pAdministratorsGroup, &fIsRunAsAdmin); 65 | 66 | FreeSid(pAdministratorsGroup); 67 | 68 | return fIsRunAsAdmin != FALSE; 69 | } 70 | 71 | 72 | /// 73 | /// Attempts to run the specified function in elevated mode. 74 | /// We do that by calling rundll32 with runas. 75 | /// 76 | HRESULT RunElevated(LPCWSTR func) { 77 | WCHAR dllPath[MAX_PATH], commandLine[1024], workingDirectory[MAX_PATH]; 78 | HRESULT hr = E_UNEXPECTED; 79 | HRESULT* pResult = (HRESULT*)malloc(sizeof(pResult)); 80 | 81 | // 82 | GetModuleFileNameW(::module, dllPath, MAX_PATH); 83 | StringCchPrintfW(commandLine, 1024, L"%s,DllElevatedEntry %s %x %x", dllPath, func, pResult, GetCurrentProcessId()); 84 | GetCurrentDirectoryW(MAX_PATH, workingDirectory); 85 | 86 | SHELLEXECUTEINFOW info; 87 | info.cbSize = sizeof(SHELLEXECUTEINFOW); 88 | info.fMask = SEE_MASK_NOCLOSEPROCESS; 89 | info.lpDirectory = workingDirectory; 90 | info.lpFile = L"rundll32"; 91 | info.lpParameters = commandLine; 92 | info.lpVerb = L"runas"; 93 | info.nShow = SW_SHOW; 94 | 95 | ShellExecuteExW(&info); 96 | 97 | if (info.hProcess != NULL) { 98 | WaitForSingleObject(info.hProcess, INFINITE); 99 | CloseHandle(info.hProcess); 100 | 101 | hr = *pResult; 102 | } 103 | 104 | free(pResult); 105 | 106 | return hr; 107 | } 108 | 109 | 110 | /// 111 | /// Called by rundll32 when we are "elevating" the process. 112 | /// 113 | void CALLBACK DllElevatedEntry(HWND hwnd, HINSTANCE instance, LPSTR cmdLine, int cmdShow) { 114 | char *context, *token, *endPtr; 115 | char func[64]; 116 | DWORD processID; 117 | HRESULT* pResult; 118 | 119 | HANDLE hProcess; 120 | HRESULT hr; 121 | 122 | // Get the function to execute 123 | token = strtok_s(cmdLine, " ", &context); 124 | StringCchCopyA(func, 64, token); 125 | 126 | // Get the address to store the result in 127 | token = strtok_s(NULL, " ", &context); 128 | pResult = (HRESULT*)strtoul(token, &endPtr, 16); 129 | 130 | // Get the process ID 131 | token = strtok_s(NULL, " ", &context); 132 | processID = (DWORD)strtoul(token, &endPtr, 16); 133 | 134 | // Execute the function 135 | if (strcmp(func, "DllRegisterServer") == 0) { 136 | hr = DllRegisterServer(); 137 | } 138 | else if (strcmp(func, "DllUnregisterServer") == 0) { 139 | hr = DllUnregisterServer(); 140 | } 141 | else { 142 | hr = E_UNEXPECTED; 143 | } 144 | 145 | // Store the result in the callers memory 146 | if ((hProcess = OpenProcess(PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION, false, processID)) == NULL) { 147 | WriteProcessMemory(hProcess, pResult, &hr, sizeof(HRESULT), NULL); 148 | CloseHandle(hProcess); 149 | } 150 | } 151 | 152 | 153 | /// 154 | /// Retrives the path to the registry keys used. 155 | /// 156 | HRESULT GetKeyPath(KEY_TYPE type, LPWSTR path, UINT cchPath) { 157 | HRESULT hr = S_OK; 158 | LPWSTR clsidString; 159 | 160 | hr = StringFromCLSID(CLSID_WinUnionFS, &clsidString); 161 | 162 | if (SUCCEEDED(hr)) { 163 | switch (type) { 164 | case KEY_CLSID: 165 | { 166 | hr = StringCchPrintfW(path, cchPath, CLSIDKEY, clsidString); 167 | } 168 | break; 169 | 170 | case KEY_NAMESPACE: 171 | { 172 | hr = StringCchPrintfW(path, cchPath, NAMESPACEKEY, clsidString); 173 | } 174 | break; 175 | 176 | default: 177 | { 178 | hr = E_UNEXPECTED; 179 | } 180 | break; 181 | } 182 | 183 | CoTaskMemFree(clsidString); 184 | } 185 | 186 | return hr; 187 | } 188 | 189 | 190 | /// 191 | /// Deletes all registration-related registry keys. 192 | /// 193 | HRESULT DeleteRegKeys() { 194 | WCHAR key[MAX_PATH]; 195 | HRESULT hr; 196 | LSTATUS ls; 197 | 198 | // Drop the CLSID key 199 | hr = GetKeyPath(KEY_CLSID, key, MAX_PATH); 200 | if (SUCCEEDED(hr)) { 201 | ls = RegDeleteTreeW(HKEY_CLASSES_ROOT, key); 202 | hr = ls == ERROR_SUCCESS || ls == ERROR_FILE_NOT_FOUND ? S_OK : HRESULT_FROM_WIN32(ls); 203 | } 204 | 205 | // Drop the namespace key 206 | if (SUCCEEDED(hr)) { 207 | hr = GetKeyPath(KEY_NAMESPACE, key, MAX_PATH); 208 | } 209 | if (SUCCEEDED(hr)) { 210 | ls = RegDeleteTreeW(HKEY_LOCAL_MACHINE, key); 211 | hr = ls == ERROR_SUCCESS || ls == ERROR_FILE_NOT_FOUND ? S_OK : HRESULT_FROM_WIN32(ls); 212 | } 213 | 214 | return hr; 215 | } 216 | 217 | 218 | /// 219 | /// Registers this DLL. 220 | /// 221 | HRESULT RegisterDLL() { 222 | HKEY baseKey, subKey; 223 | WCHAR dllPath[MAX_PATH], key[MAX_PATH]; 224 | 225 | // Get the path to this DLL. 226 | GetModuleFileName(::module, dllPath, MAX_PATH); 227 | 228 | // 229 | GetKeyPath(KEY_CLSID, key, MAX_PATH); 230 | 231 | // Configure the top-level key. 232 | if (RegCreateKey(HKEY_CLASSES_ROOT, key, &baseKey) != ERROR_SUCCESS) { 233 | return E_UNEXPECTED; 234 | } 235 | RegSetValue(baseKey, NULL, REG_SZ, L"WinUnionFS", NULL); 236 | RegSetString(baseKey, L"InfoTip", L"WinUnionFS InfoTip"); 237 | 238 | // Create a DefaultIcon subkey. 239 | RegSetValue(baseKey, L"DefaultIcon", REG_SZ, L"%SystemRoot%\\system32\\imageres.dll,-1023", NULL); 240 | 241 | // Configure the InprocServer32 subkey. 242 | if (RegCreateKey(baseKey, L"InprocServer32", &subKey) != ERROR_SUCCESS) { 243 | RegCloseKey(baseKey); 244 | return E_UNEXPECTED; 245 | } 246 | RegSetValue(subKey, NULL, REG_SZ, dllPath, NULL); 247 | RegSetString(subKey, L"ThreadingModel", L"Apartment"); 248 | RegCloseKey(subKey); 249 | 250 | // Configure the ShellFolder subkey. 251 | if (RegCreateKey(baseKey, L"ShellFolder", &subKey) != ERROR_SUCCESS) { 252 | RegCloseKey(baseKey); 253 | return E_UNEXPECTED; 254 | } 255 | DWORD attributes = 0x20000000 | 0x80000000 | 0x00000010; 256 | RegSetValueEx(subKey, L"Attributes", NULL, REG_DWORD, (const BYTE*)&attributes, sizeof(DWORD)); 257 | RegPrintf(subKey, L"DefaultIcon", L"%s,1", dllPath); 258 | RegCloseKey(subKey); 259 | 260 | // Close the top-level key. 261 | RegCloseKey(baseKey); 262 | 263 | return S_OK; 264 | } 265 | 266 | 267 | /// 268 | /// Register a system-wide namespace below the desktop. 269 | /// 270 | HRESULT RegisterNamespace() { 271 | HKEY baseKey; 272 | WCHAR key[MAX_PATH]; 273 | 274 | GetKeyPath(KEY_NAMESPACE, key, MAX_PATH); 275 | if (RegCreateKey(HKEY_LOCAL_MACHINE, key, &baseKey) != ERROR_SUCCESS) { 276 | return E_UNEXPECTED; 277 | } 278 | RegSetValue(baseKey, NULL, REG_SZ, L"WinUnionFS", NULL); 279 | RegCloseKey(baseKey); 280 | 281 | return S_OK; 282 | } 283 | 284 | 285 | /// 286 | /// Registers this DLL. 287 | /// 288 | STDAPI DllRegisterServer() { 289 | HRESULT hr; 290 | 291 | // Check if we are elevated. 292 | if (!IsElevated()) { 293 | return RunElevated(L"DllRegisterServer"); 294 | } 295 | 296 | // Delete old registry keys 297 | hr = DeleteRegKeys(); 298 | 299 | // Register this DLL 300 | if (SUCCEEDED(hr)) { 301 | RegisterDLL(); 302 | } 303 | 304 | // Register a system-wide namespace below the desktop 305 | if (SUCCEEDED(hr)) { 306 | RegisterNamespace(); 307 | } 308 | 309 | // Refresh Desktop 310 | if (SUCCEEDED(hr)) { 311 | //SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL); 312 | } 313 | 314 | return hr; 315 | } 316 | 317 | 318 | /// 319 | /// Unregisters this DLL. 320 | /// 321 | STDAPI DllUnregisterServer() { 322 | HRESULT hr; 323 | 324 | // Check if we are elevated. 325 | if (!IsElevated()) { 326 | return RunElevated(L"DllUnregisterServer"); 327 | } 328 | 329 | // Delete registry keys 330 | hr = DeleteRegKeys(); 331 | 332 | // Refresh Desktop 333 | if (SUCCEEDED(hr)) { 334 | //SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL); 335 | } 336 | 337 | return hr; 338 | } 339 | -------------------------------------------------------------------------------- /ShellExtension/Registration.h: -------------------------------------------------------------------------------- 1 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2 | * Registration.h 3 | * The WinUnionFS Project 4 | * 5 | * Handles registration and unregistration of this DLL. 6 | * 7 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 8 | #pragma once 9 | 10 | // Helper functions 11 | LSTATUS RegSetString(HKEY key, LPCWSTR value, LPCWSTR data); 12 | LSTATUS RegPrintf(HKEY key, LPCWSTR value, LPCWSTR format, ...); 13 | 14 | // Elevation stuff 15 | bool IsElevated(); 16 | HRESULT RunElevated(LPCWSTR func); 17 | void CALLBACK DllElevatedEntry(HWND hwnd, HINSTANCE instance, LPSTR cmdLine, int cmdShow); 18 | 19 | // The various registry keys used 20 | typedef enum { 21 | KEY_CLSID, 22 | KEY_NAMESPACE 23 | } KEY_TYPE; 24 | 25 | // Registration/Unregistration 26 | HRESULT GetKeyPath(KEY_TYPE type); 27 | HRESULT DeleteRegKeys(); 28 | HRESULT RegisterDLL(); 29 | HRESULT RegisterNamespace(); 30 | 31 | // Exports 32 | STDAPI DllRegisterServer(); 33 | STDAPI DllUnregisterServer(); 34 | -------------------------------------------------------------------------------- /ShellExtension/ShellExtension.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {E0C5A5DE-429C-48E1-832F-D8D692514F85} 23 | ShellExtension 24 | 25 | 26 | 27 | DynamicLibrary 28 | true 29 | v120 30 | Unicode 31 | 32 | 33 | DynamicLibrary 34 | true 35 | v120 36 | Unicode 37 | 38 | 39 | DynamicLibrary 40 | false 41 | v120 42 | true 43 | Unicode 44 | 45 | 46 | DynamicLibrary 47 | false 48 | v120 49 | true 50 | Unicode 51 | false 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | $(SolutionDir)bin\$(Configuration)_$(Platform)\ 71 | bin\$(Configuration)_$(Platform)\ 72 | WinUnionFS 73 | 74 | 75 | $(SolutionDir)bin\$(Configuration)_$(Platform)\ 76 | bin\$(Configuration)_$(Platform)\ 77 | WinUnionFS 78 | 79 | 80 | $(SolutionDir)bin\$(Configuration)_$(Platform)\ 81 | bin\$(Configuration)_$(Platform)\ 82 | WinUnionFS 83 | 84 | 85 | $(SolutionDir)bin\$(Configuration)_$(Platform)\ 86 | bin\$(Configuration)_$(Platform)\ 87 | WinUnionFS 88 | 89 | 90 | 91 | Level3 92 | Disabled 93 | true 94 | false 95 | 96 | 97 | true 98 | WinUnionFS.def 99 | advapi32.lib;ole32.lib;shell32.lib;shlwapi.lib;Oleaut32.lib 100 | 101 | 102 | 103 | 104 | Level3 105 | Disabled 106 | true 107 | false 108 | 109 | 110 | true 111 | WinUnionFS.def 112 | advapi32.lib;ole32.lib;shell32.lib;shlwapi.lib;Oleaut32.lib 113 | 114 | 115 | 116 | 117 | Level3 118 | MaxSpeed 119 | true 120 | true 121 | MultiThreaded 122 | true 123 | 124 | 125 | true 126 | true 127 | true 128 | WinUnionFS.def 129 | advapi32.lib;ole32.lib;shell32.lib;shlwapi.lib;Oleaut32.lib 130 | 131 | 132 | 133 | 134 | Level3 135 | MaxSpeed 136 | true 137 | true 138 | MultiThreaded 139 | true 140 | 141 | 142 | true 143 | true 144 | true 145 | WinUnionFS.def 146 | advapi32.lib;ole32.lib;shell32.lib;shlwapi.lib;Oleaut32.lib 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | -------------------------------------------------------------------------------- /ShellExtension/ShellExtension.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | Source Files 32 | 33 | 34 | Source Files 35 | 36 | 37 | Source Files 38 | 39 | 40 | Source Files 41 | 42 | 43 | Source Files 44 | 45 | 46 | 47 | 48 | Header Files 49 | 50 | 51 | Header Files 52 | 53 | 54 | Header Files 55 | 56 | 57 | Header Files 58 | 59 | 60 | Header Files 61 | 62 | 63 | Header Files 64 | 65 | 66 | Header Files 67 | 68 | 69 | Header Files 70 | 71 | 72 | Header Files 73 | 74 | 75 | Header Files 76 | 77 | 78 | 79 | 80 | Resource Files 81 | 82 | 83 | 84 | 85 | Resource Files 86 | 87 | 88 | 89 | 90 | Resource Files 91 | 92 | 93 | -------------------------------------------------------------------------------- /ShellExtension/ShellFolder.cpp: -------------------------------------------------------------------------------- 1 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2 | * ShellFolder.cpp 3 | * The WinUnionFS Project 4 | * 5 | * Implementation of IShellFolder (and related interfaces). 6 | * 7 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "Debug.h" 16 | #include "EnumIDList.hpp" 17 | #include "Group.hpp" 18 | #include "Macros.h" 19 | #include "PIDL.h" 20 | #include "ShellFolder.hpp" 21 | #include "ShellView.hpp" 22 | 23 | 24 | // The number of in-use objects. 25 | extern long objectCounter; 26 | 27 | // The CLSID of WinUnionFS. 28 | extern const CLSID CLSID_WinUnionFS; 29 | 30 | 31 | /// 32 | /// Constructor. 33 | /// 34 | ShellFolder::ShellFolder(LPCITEMIDLIST path) { 35 | this->refCount = 1; 36 | InterlockedIncrement(&::objectCounter); 37 | Group::AddUser(); 38 | this->folder = PIDL::Copy(path); 39 | 40 | if (path != NULL) { 41 | PIDL::GetShellFoldersFor(path, &this->folders); 42 | } 43 | } 44 | 45 | 46 | /// 47 | /// Destructor. 48 | /// 49 | ShellFolder::~ShellFolder() { 50 | Group::RemoveUser(); 51 | InterlockedDecrement(&::objectCounter); 52 | PIDL::Free(this->folder); 53 | 54 | for (std::vector::const_iterator folder = this->folders.begin(); folder != this->folders.end(); ++folder) { 55 | (*folder)->Release(); 56 | } 57 | } 58 | 59 | 60 | /// 61 | /// IUnknown::AddRef 62 | /// Increments the reference count for an interface on an object. 63 | /// 64 | ULONG ShellFolder::AddRef() { 65 | return InterlockedIncrement(&this->refCount); 66 | } 67 | 68 | 69 | /// 70 | /// IUnknown::Release 71 | /// Decrements the reference count for an interface on an object. 72 | /// 73 | ULONG ShellFolder::Release() { 74 | if (InterlockedDecrement(&this->refCount) == 0) { 75 | delete this; 76 | return 0; 77 | } 78 | 79 | return this->refCount; 80 | } 81 | 82 | 83 | /// 84 | /// IUnknown::QueryInterface 85 | /// Retrieves pointers to the supported interfaces on an object. 86 | /// 87 | HRESULT ShellFolder::QueryInterface(REFIID riid, void **ppvObject) { 88 | if (ppvObject == NULL) { 89 | return E_POINTER; 90 | } 91 | 92 | if (riid == IID_IUnknown) { 93 | *ppvObject = (IUnknown*)(IShellFolder*)this; 94 | } 95 | else if (riid == IID_IPersist) { 96 | *ppvObject = (IPersist*)(IPersistFolder*)this; 97 | } 98 | else if (riid == IID_IPersistIDList) { 99 | *ppvObject = (IPersistIDList*)this; 100 | } 101 | else if (riid == IID_IShellFolder) { 102 | *ppvObject = (IShellFolder*)this; 103 | } 104 | else if (riid == IID_IShellFolder2) { 105 | *ppvObject = (IShellFolder2*)this; 106 | } 107 | else if (riid == IID_IPersistFolder) { 108 | *ppvObject = (IPersistFolder*)this; 109 | } 110 | else if (riid == IID_IPersistFolder2) { 111 | *ppvObject = (IPersistFolder2*)this; 112 | } 113 | /*else if (riid == IID_IPersistFolder3) { 114 | *ppvObject = (IPersistFolder3*)this; 115 | }*/ 116 | else { 117 | *ppvObject = NULL; 118 | return E_NOINTERFACE; 119 | } 120 | 121 | AddRef(); 122 | return S_OK; 123 | } 124 | 125 | 126 | /// 127 | /// IShellFolder::BindToObject 128 | /// Retrieves a handler, typically the Shell folder object that implements IShellFolder for a particular item. 129 | /// 130 | HRESULT ShellFolder::BindToObject(PCUIDLIST_RELATIVE pidl, IBindCtx *pbc, REFIID riid, void **ppvOut) { 131 | if (ppvOut == NULL) { 132 | return E_POINTER; 133 | } 134 | 135 | if (riid == IID_IShellFolder) { 136 | LPITEMIDLIST newPidl = PIDL::Concatenate(this->folder, pidl); 137 | *ppvOut = (IShellFolder*)(new ShellFolder(newPidl)); 138 | PIDL::Free(newPidl); 139 | return S_OK; 140 | } 141 | 142 | return E_NOINTERFACE; 143 | } 144 | 145 | 146 | /// 147 | /// IShellFolder::BindToStorage 148 | /// Requests a pointer to an object's storage interface. 149 | /// 150 | HRESULT ShellFolder::BindToStorage(PCUIDLIST_RELATIVE pidl, IBindCtx *pbc, REFIID riid, void **ppvOut) { 151 | return E_NOTIMPL; 152 | } 153 | 154 | 155 | /// 156 | /// IShellFolder::CompareIDs 157 | /// Determines the relative order of two file objects or folders, given their item identifier lists. 158 | /// 159 | HRESULT ShellFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2) { 160 | return MAKE_HRESULT(0, 0, (USHORT)wcscmp(PIDL::Item(pidl1)->name, PIDL::Item(pidl2)->name)); 161 | } 162 | 163 | 164 | /// 165 | /// IShellFolder::CreateViewObject 166 | /// Requests an object that can be used to obtain information from or interact with a folder object. 167 | /// 168 | HRESULT ShellFolder::CreateViewObject(HWND hwndOwner, REFIID riid, void **ppv) { 169 | HRESULT hr; 170 | 171 | if (ppv == NULL) { 172 | return E_POINTER; 173 | } 174 | 175 | if (riid == IID_IShellView) { 176 | *ppv = NULL; 177 | hr = E_NOINTERFACE; 178 | 179 | SFV_CREATE c; 180 | c.cbSize = sizeof(SFV_CREATE); 181 | c.psvOuter = NULL; 182 | c.psfvcb = NULL; 183 | QueryInterface(IID_IShellFolder, reinterpret_cast(&c.pshf)); 184 | 185 | hr = SHCreateShellFolderView(&c, reinterpret_cast(ppv)); 186 | } 187 | else { 188 | *ppv = NULL; 189 | hr = E_NOINTERFACE; 190 | } 191 | 192 | return hr; 193 | } 194 | 195 | 196 | /// 197 | /// IShellFolder::EnumObjects 198 | /// Enables a client to determine the contents of a folder by creating an item identifier enumeration 199 | /// object and returning its IEnumIDList interface. The methods supported by that interface can then be 200 | /// used to enumerate the folder's contents. 201 | /// 202 | HRESULT ShellFolder::EnumObjects(HWND hwndOwner, SHCONTF grfFlags, IEnumIDList **ppenumIDList) { 203 | if (ppenumIDList == NULL) { 204 | return E_POINTER; 205 | } 206 | 207 | EnumIDList* list = new EnumIDList(); 208 | 209 | if (PIDL::ItemCount(this->folder) == 1) { 210 | // This is the root folder, we should list the groups 211 | if (FLAGSET(grfFlags, SHCONTF_CHECKING_FOR_CHILDREN) || FLAGSET(grfFlags, SHCONTF_FOLDERS)) { 212 | int groupIndex = 0; 213 | Group* group; 214 | while ((group = Group::Find(groupIndex++)) != NULL) { 215 | list->AddItem(PIDL::Create(NULL, (LPWSTR)group->name, SFGAO_FOLDER | SFGAO_BROWSABLE | SFGAO_HASSUBFOLDER, 0)); 216 | } 217 | } 218 | } 219 | else { 220 | // Enumerate the contents of all the shell folders 221 | int f = 0; 222 | for (std::vector::const_iterator folder = this->folders.begin(); folder != this->folders.end(); ++folder) { 223 | IEnumIDList* enumIDList; 224 | PIDLIST_RELATIVE idNext = NULL; 225 | 226 | (*folder)->EnumObjects(hwndOwner, grfFlags, &enumIDList); 227 | 228 | while (enumIDList->Next(1, &idNext, NULL) != S_FALSE) { 229 | WCHAR fileName[MAX_PATH]; 230 | STRRET name; 231 | SFGAOF attributes = SFGAOF(-1); 232 | 233 | (*folder)->GetAttributesOf(1, (LPCITEMIDLIST *)&idNext, &attributes); 234 | (*folder)->GetDisplayNameOf(idNext, SHGDN_NORMAL, &name); 235 | StrRetToBufW(&name, idNext, fileName, MAX_PATH); 236 | list->AddItem(PIDL::Create(NULL, fileName, SFGAO_FOLDER | SFGAO_BROWSABLE | SFGAO_HASSUBFOLDER, f)); 237 | 238 | ILFree(idNext); 239 | } 240 | ++f; 241 | enumIDList->Release(); 242 | } 243 | } 244 | 245 | list->QueryInterface(IID_IEnumIDList, reinterpret_cast(ppenumIDList)); 246 | list->Release(); 247 | 248 | return S_OK; 249 | } 250 | 251 | 252 | /// 253 | /// IShellFolder::GetAttributesOf 254 | /// Gets the attributes of one or more file or folder objects contained in the object represented by IShellFolder. 255 | /// 256 | HRESULT ShellFolder::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, SFGAOF *rgfInOut) { 257 | SFGAOF attributes = SFGAOF(-1); 258 | 259 | if (cidl == 0 || apidl[0]->mkid.cb == 0) { 260 | // Top level folder. 261 | attributes = SFGAO_BROWSABLE | SFGAO_FOLDER | SFGAO_HASSUBFOLDER; 262 | } 263 | else { 264 | for (UINT i = 0; i < cidl; ++i) { 265 | attributes &= PIDL::GetAttributes(apidl[i]); 266 | } 267 | } 268 | 269 | *rgfInOut &= attributes; 270 | 271 | return S_OK; 272 | } 273 | 274 | 275 | /// 276 | /// IShellFolder::GetDisplayNameOf 277 | /// Retrieves the display name for the specified file object or subfolder. 278 | /// 279 | HRESULT ShellFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, SHGDNF uFlags, STRRET *pName) { 280 | pName->uType = STRRET_WSTR; 281 | 282 | if ((uFlags & SHGDN_INFOLDER) == SHGDN_INFOLDER) { 283 | pName->pOleStr = PIDL::GetDisplayName(pidl); 284 | } 285 | else { 286 | pName->pOleStr = PIDL::GetFullPath(this->folder, pidl); 287 | } 288 | 289 | return S_OK; 290 | } 291 | 292 | 293 | /// 294 | /// IShellFolder::GetUIObjectOf 295 | /// Gets an object that can be used to carry out actions on the specified file objects or folders. 296 | /// 297 | HRESULT ShellFolder::GetUIObjectOf(HWND hwndOwner, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, REFIID riid, UINT *rgfReserved, void **ppv) { 298 | HRESULT hr; 299 | *ppv = NULL; 300 | 301 | if (ppv == NULL) { 302 | return E_POINTER; 303 | } 304 | 305 | // TODO::We need to override some things to make navigation work properly... 306 | if (PIDL::ItemCount(this->folder) > 1) { 307 | PIDLIST_ABSOLUTE idList = NULL; 308 | PIDL::PIDLItem* item = PIDL::Item(apidl[0]); 309 | 310 | if (item->folder >= this->folders.size()) { 311 | return E_FAIL; 312 | } 313 | 314 | hr = this->folders[item->folder]->ParseDisplayName(hwndOwner, NULL, item->name, NULL, &idList, NULL); 315 | hr = this->folders[item->folder]->GetUIObjectOf(hwndOwner, 1, (LPCITEMIDLIST *)&idList, riid, rgfReserved, ppv); 316 | ILFree(idList); 317 | } 318 | else { 319 | // These are pure virtual folders... 320 | if (riid == IID_IExtractIconA || riid == IID_IExtractIconW) { 321 | hr = SHCreateFileExtractIconW(L"C:\\WinUnionFSTest", FILE_ATTRIBUTE_DIRECTORY, riid, ppv); 322 | } 323 | else { 324 | *ppv = NULL; 325 | hr = E_NOINTERFACE; 326 | } 327 | } 328 | 329 | return hr; 330 | } 331 | 332 | 333 | /// 334 | /// IShellFolder::ParseDisplayName 335 | /// Translates the display name of a file object or a folder into an item identifier list. 336 | /// 337 | HRESULT ShellFolder::ParseDisplayName(HWND hwnd, IBindCtx *pbc, LPWSTR pszDisplayName, ULONG *pchEaten, PIDLIST_RELATIVE *ppidl, ULONG *pdwAttributes) { 338 | HRESULT hr = E_FAIL; 339 | 340 | ULONG attributes = ULONG(-1); 341 | 342 | PIDLIST_ABSOLUTE idList = NULL; 343 | int i; 344 | for (i = 0; i < this->folders.size(); ++i) { 345 | if (SUCCEEDED(hr = this->folders[i]->ParseDisplayName(hwnd, NULL, pszDisplayName, pchEaten, &idList, &attributes))) { 346 | ILFree(idList); 347 | break; 348 | } 349 | } 350 | 351 | if (SUCCEEDED(hr)) { 352 | WCHAR path[MAX_PATH]; 353 | WCHAR *context, *token; 354 | LPITEMIDLIST pidl, temp; 355 | 356 | StringCchCopyW(path, MAX_PATH, pszDisplayName); 357 | 358 | token = wcstok_s(path, L"/", &context); 359 | pidl = PIDL::Create(NULL, token, SFGAO_BROWSABLE | SFGAO_FOLDER | SFGAO_HASSUBFOLDER, i); 360 | 361 | while ((token = wcstok_s(NULL, L"/", &context)) != NULL) { 362 | temp = PIDL::Create(pidl, token, SFGAO_BROWSABLE | SFGAO_FOLDER | SFGAO_HASSUBFOLDER, i); 363 | PIDL::Free(pidl); 364 | pidl = temp; 365 | } 366 | 367 | PIDL::Item(PIDL::Last(pidl))->attributes = attributes; 368 | *ppidl = pidl; 369 | 370 | if (pdwAttributes != NULL) { 371 | *pdwAttributes &= attributes; 372 | } 373 | } 374 | 375 | return hr; 376 | } 377 | 378 | 379 | /// 380 | /// IShellFolder::SetNameOf 381 | /// Sets the display name of a file object or subfolder, changing the item identifier in the process. 382 | /// 383 | HRESULT ShellFolder::SetNameOf(HWND hwndOwner, PCUITEMID_CHILD pidl, LPCWSTR pszName, SHGDNF uFlags, PITEMID_CHILD *ppidlOut) { 384 | return E_NOTIMPL; 385 | } 386 | 387 | 388 | /// 389 | /// IShellFolder2::EnumSearches 390 | /// Requests a pointer to an interface that allows a client to enumerate the available search objects. 391 | /// 392 | /// The address of a pointer to an enumerator object's IEnumExtraSearch interface. 393 | HRESULT ShellFolder::EnumSearches(IEnumExtraSearch **ppEnum) { 394 | *ppEnum = NULL; 395 | return E_NOTIMPL; 396 | } 397 | 398 | 399 | /// 400 | /// IShellFolder2::GetDefaultColumn 401 | /// Gets the default sorting and display columns. 402 | /// 403 | HRESULT ShellFolder::GetDefaultColumn(DWORD, ULONG *pSort, ULONG *pDisplay) { 404 | *pSort = 0; 405 | *pDisplay = 0; 406 | return S_OK; 407 | } 408 | 409 | 410 | /// 411 | /// IShellFolder2::GetDefaultColumnState 412 | /// Gets the default state for a specified column. 413 | /// 414 | HRESULT ShellFolder::GetDefaultColumnState(UINT iColumn, SHCOLSTATEF *pcsFlags) { 415 | switch (iColumn) { 416 | case 0: 417 | *pcsFlags = SHCOLSTATE_TYPE_STR; 418 | break; 419 | case 1: 420 | *pcsFlags = SHCOLSTATE_TYPE_STR; 421 | break; 422 | case 2: 423 | *pcsFlags = SHCOLSTATE_TYPE_STR; 424 | break; 425 | case 3: 426 | *pcsFlags = SHCOLSTATE_TYPE_DATE; 427 | break; 428 | default: 429 | return E_INVALIDARG; 430 | } 431 | 432 | return S_OK; 433 | } 434 | 435 | 436 | /// 437 | /// IShellFolder2::GetDefaultSearchGUID 438 | /// Returns the globally unique identifier (GUID) of the default search object for the folder. 439 | /// 440 | HRESULT ShellFolder::GetDefaultSearchGUID(GUID *pGuid) { 441 | *pGuid = CLSID_WinUnionFS; 442 | return E_NOTIMPL; 443 | } 444 | 445 | 446 | /// 447 | /// IShellFolder2::GetDetailsEx 448 | /// Gets detailed information, identified by a property set identifier (FMTID) and a property 449 | /// identifier (PID), on an item in a Shell folder. 450 | /// 451 | HRESULT ShellFolder::GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID *pscid, VARIANT *pv) { 452 | if (pscid->fmtid == FMTID_Storage) { 453 | switch (pscid->pid) { 454 | case PID_STG_NAME: 455 | { 456 | LPWSTR name = PIDL::GetDisplayName(pidl); 457 | pv->bstrVal = SysAllocString(name); 458 | CoTaskMemFree(name); 459 | } 460 | break; 461 | 462 | case PID_STG_SIZE: 463 | { 464 | pv->bstrVal = SysAllocString(L"Size"); 465 | } 466 | break; 467 | 468 | case PID_STG_WRITETIME: 469 | { 470 | pv->bstrVal = SysAllocString(L"Type"); 471 | } 472 | break; 473 | 474 | case PID_STG_STORAGETYPE: 475 | { 476 | pv->bstrVal = SysAllocString(L"Date Modified"); 477 | } 478 | break; 479 | 480 | default: 481 | return E_INVALIDARG; 482 | } 483 | } 484 | else { 485 | return E_FAIL; 486 | } 487 | 488 | return S_OK; 489 | } 490 | 491 | 492 | /// 493 | /// IShellFolder2::GetDetailsOf 494 | /// Gets detailed information, identified by a column index, on an item in a Shell folder. 495 | /// 496 | HRESULT ShellFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *psd) { 497 | switch (iColumn) { 498 | case 0: 499 | { 500 | psd->fmt = LVCFMT_LEFT; 501 | psd->cxChar = 20; 502 | psd->str.uType = STRRET_WSTR; 503 | if (pidl == NULL) { 504 | SHStrDupW(L"Name", &psd->str.pOleStr); 505 | } 506 | else { 507 | psd->str.pOleStr = PIDL::GetDisplayName(pidl); 508 | } 509 | } 510 | break; 511 | 512 | case 1: 513 | { 514 | psd->fmt = LVCFMT_RIGHT; 515 | psd->cxChar = 20; 516 | psd->str.uType = STRRET_WSTR; 517 | SHStrDupW(L"Size", &psd->str.pOleStr); 518 | } 519 | break; 520 | 521 | case 2: 522 | { 523 | psd->fmt = LVCFMT_LEFT; 524 | psd->cxChar = 20; 525 | psd->str.uType = STRRET_WSTR; 526 | SHStrDupW(L"Type", &psd->str.pOleStr); 527 | } 528 | break; 529 | 530 | case 3: 531 | { 532 | psd->fmt = LVCFMT_LEFT; 533 | psd->cxChar = 20; 534 | psd->str.uType = STRRET_WSTR; 535 | SHStrDupW(L"Date Modified", &psd->str.pOleStr); 536 | } 537 | break; 538 | 539 | default: 540 | return E_INVALIDARG; 541 | } 542 | return S_OK; 543 | } 544 | 545 | 546 | /// 547 | /// IShellFolder2::MapColumnToSCID 548 | /// Converts a column to the appropriate property set ID (FMTID) and property ID (PID). 549 | /// 550 | HRESULT ShellFolder::MapColumnToSCID(UINT iColumn, SHCOLUMNID *pscid) { 551 | switch (iColumn) { 552 | case 0: 553 | { 554 | pscid->fmtid = FMTID_Storage; 555 | pscid->pid = PID_STG_NAME; 556 | } 557 | break; 558 | 559 | case 1: 560 | { 561 | pscid->fmtid = FMTID_Storage; 562 | pscid->pid = PID_STG_SIZE; 563 | } 564 | break; 565 | 566 | case 2: 567 | { 568 | pscid->fmtid = FMTID_Storage; 569 | pscid->pid = PID_STG_STORAGETYPE; 570 | } 571 | break; 572 | 573 | case 3: 574 | { 575 | pscid->fmtid = FMTID_Storage; 576 | pscid->pid = PID_STG_WRITETIME; 577 | } 578 | break; 579 | 580 | default: 581 | return E_INVALIDARG; 582 | } 583 | return S_OK; 584 | } 585 | 586 | 587 | /// 588 | /// IPersist::GetClassID 589 | /// Retrieves the class identifier (CLSID) of the object. 590 | /// 591 | HRESULT ShellFolder::GetClassID(CLSID *pClassID) { 592 | *pClassID = CLSID_WinUnionFS; 593 | 594 | return S_OK; 595 | } 596 | 597 | 598 | /// 599 | /// IPersistIDList::GetIDList 600 | /// Gets an item identifier list. 601 | /// 602 | HRESULT ShellFolder::GetIDList(LPITEMIDLIST *ppidl) { 603 | return GetCurFolder(ppidl); 604 | } 605 | 606 | 607 | /// 608 | /// IPersistIDList::SetIDList 609 | /// Sets a persisted item identifier list. 610 | /// 611 | HRESULT ShellFolder::SetIDList(LPCITEMIDLIST pidl) { 612 | return Initialize(pidl); 613 | } 614 | 615 | 616 | /// 617 | /// IPersistFolder::Initialize 618 | /// Instructs a Shell folder object to initialize itself based on the information passed. 619 | /// 620 | HRESULT ShellFolder::Initialize(LPCITEMIDLIST pidl) { 621 | PIDL::Free(this->folder); 622 | this->folder = PIDL::Copy(pidl); 623 | 624 | for (std::vector::const_iterator folder = this->folders.begin(); folder != this->folders.end(); ++folder) { 625 | (*folder)->Release(); 626 | } 627 | 628 | PIDL::GetShellFoldersFor(this->folder, &this->folders); 629 | 630 | return S_OK; 631 | } 632 | 633 | 634 | /// 635 | /// IPersistFolder2::GetCurFolder 636 | /// Gets the ITEMIDLIST for the folder object. 637 | /// 638 | HRESULT ShellFolder::GetCurFolder(LPITEMIDLIST *ppidl) { 639 | *ppidl = PIDL::Copy(this->folder); 640 | return S_OK; 641 | } 642 | 643 | 644 | /// 645 | /// IPersistFolder3::GetFolderTargetInfo 646 | /// Provides the location and attributes of a folder shortcut's target folder. 647 | /// 648 | HRESULT ShellFolder::GetFolderTargetInfo(PERSIST_FOLDER_TARGET_INFO *ppfti) { 649 | ppfti->pidlTargetFolder = PIDL::Copy(this->folder); 650 | //PIDL::GetFullPath(this->folder, , 651 | 652 | return E_NOTIMPL; 653 | } 654 | 655 | 656 | /// 657 | /// IPersistFolder3::InitializeEx 658 | /// Initializes a folder and specifies its location in the namespace. If the folder is a shortcut, 659 | /// this method also specifies the location of the target folder. 660 | /// 661 | HRESULT ShellFolder::InitializeEx(IBindCtx *pbc, LPCITEMIDLIST pidlRoot, const PERSIST_FOLDER_TARGET_INFO *ppfti) { 662 | Initialize(pidlRoot); 663 | 664 | return E_NOTIMPL; 665 | } 666 | -------------------------------------------------------------------------------- /ShellExtension/ShellFolder.hpp: -------------------------------------------------------------------------------- 1 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2 | * ShellFolder.hpp 3 | * The WinUnionFS Project 4 | * 5 | * Implementation of IShellFolder (and related interfaces). 6 | * 7 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 8 | #pragma once 9 | 10 | #include 11 | 12 | class ShellFolder : 13 | public IShellFolder2, 14 | public IPersistIDList, 15 | public IPersistFolder3 16 | { 17 | public: 18 | // Constructor 19 | explicit ShellFolder(LPCITEMIDLIST path); 20 | 21 | // IUnknown 22 | ULONG STDMETHODCALLTYPE AddRef(); 23 | STDMETHOD(QueryInterface) (REFIID, void**); 24 | ULONG STDMETHODCALLTYPE Release(); 25 | 26 | // IShellFolder 27 | STDMETHOD(BindToObject) (PCUIDLIST_RELATIVE, IBindCtx*, REFIID, void**); 28 | STDMETHOD(BindToStorage) (PCUIDLIST_RELATIVE, IBindCtx*, REFIID, void**); 29 | STDMETHOD(CompareIDs) (LPARAM, PCUIDLIST_RELATIVE, PCUIDLIST_RELATIVE); 30 | STDMETHOD(CreateViewObject) (HWND, REFIID, void**); 31 | STDMETHOD(EnumObjects) (HWND, SHCONTF, IEnumIDList**); 32 | STDMETHOD(GetAttributesOf) (UINT, PCUITEMID_CHILD_ARRAY, SFGAOF*); 33 | STDMETHOD(GetDisplayNameOf) (PCUITEMID_CHILD, SHGDNF, STRRET*); 34 | STDMETHOD(GetUIObjectOf) (HWND, UINT, PCUITEMID_CHILD_ARRAY, REFIID, UINT*, void**); 35 | STDMETHOD(ParseDisplayName) (HWND, IBindCtx*, LPWSTR, ULONG*, PIDLIST_RELATIVE*, ULONG*); 36 | STDMETHOD(SetNameOf) (HWND, PCUITEMID_CHILD, LPCWSTR, SHGDNF, PITEMID_CHILD*); 37 | 38 | // IShellFolder2 39 | STDMETHOD(EnumSearches) (IEnumExtraSearch**); 40 | STDMETHOD(GetDefaultColumn) (DWORD, ULONG*, ULONG*); 41 | STDMETHOD(GetDefaultColumnState) (UINT, SHCOLSTATEF*); 42 | STDMETHOD(GetDefaultSearchGUID) (GUID*); 43 | STDMETHOD(GetDetailsEx) (PCUITEMID_CHILD, const SHCOLUMNID*, VARIANT*); 44 | STDMETHOD(GetDetailsOf) (PCUITEMID_CHILD, UINT, SHELLDETAILS*); 45 | STDMETHOD(MapColumnToSCID) (UINT, SHCOLUMNID*); 46 | 47 | // IPersist 48 | STDMETHOD(GetClassID) (CLSID*); 49 | 50 | // IPersistIDList 51 | STDMETHOD(GetIDList) (LPITEMIDLIST*); 52 | STDMETHOD(SetIDList) (LPCITEMIDLIST); 53 | 54 | // IPersistFolder 55 | STDMETHOD(Initialize) (LPCITEMIDLIST); 56 | 57 | // IPersistFolder2 58 | STDMETHOD(GetCurFolder) (LPITEMIDLIST*); 59 | 60 | // IPersistFolder3 61 | STDMETHOD(GetFolderTargetInfo) (PERSIST_FOLDER_TARGET_INFO*); 62 | STDMETHOD(InitializeEx) (IBindCtx*, LPCITEMIDLIST, const PERSIST_FOLDER_TARGET_INFO*); 63 | 64 | private: 65 | // Destructor 66 | virtual ~ShellFolder(); 67 | 68 | ULONG refCount; 69 | 70 | LPITEMIDLIST folder; 71 | 72 | std::vector folders; 73 | 74 | PERSIST_FOLDER_TARGET_INFO folderTargetInfo; 75 | }; 76 | -------------------------------------------------------------------------------- /ShellExtension/ShellView.cpp: -------------------------------------------------------------------------------- 1 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2 | * ShellView.cpp 3 | * The WinUnionFS Project 4 | * 5 | * Implementation of IShellView. 6 | * 7 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "Debug.h" 14 | #include "Macros.h" 15 | #include "ShellFolder.hpp" 16 | #include "ShellView.hpp" 17 | 18 | 19 | // The number of in-use objects. 20 | extern long objectCounter; 21 | 22 | // The CLSID of WinUnionFS. 23 | extern const CLSID CLSID_WinUnionFS; 24 | 25 | 26 | /// 27 | /// Constructor. 28 | /// 29 | ShellView::ShellView(IShellFolder* folder) { 30 | this->refCount = 1; 31 | InterlockedIncrement(&::objectCounter); 32 | this->folder = folder; 33 | } 34 | 35 | 36 | /// 37 | /// Destructor. 38 | /// 39 | ShellView::~ShellView() { 40 | this->folder->Release(); 41 | InterlockedDecrement(&::objectCounter); 42 | } 43 | 44 | 45 | /// 46 | /// IUnknown::AddRef 47 | /// Increments the reference count for an interface on an object. 48 | /// 49 | ULONG ShellView::AddRef() { 50 | return InterlockedIncrement(&this->refCount); 51 | } 52 | 53 | 54 | /// 55 | /// IUnknown::Release 56 | /// Decrements the reference count for an interface on an object. 57 | /// 58 | ULONG ShellView::Release() { 59 | if (InterlockedDecrement(&this->refCount) == 0) { 60 | delete this; 61 | return 0; 62 | } 63 | 64 | return this->refCount; 65 | } 66 | 67 | 68 | /// 69 | /// IUnknown::QueryInterface 70 | /// Retrieves pointers to the supported interfaces on an object. 71 | /// 72 | HRESULT ShellView::QueryInterface(REFIID riid, void **ppvObject) { 73 | if (ppvObject == NULL) { 74 | return E_POINTER; 75 | } 76 | 77 | if (riid == IID_IShellView) { 78 | *ppvObject = (IShellView*)this; 79 | } 80 | /*else if (riid == IID_IShellView2) { 81 | *ppvObject = (IShellView2*)this; 82 | } 83 | else if (riid == IID_IShellView3) { 84 | *ppvObject = (IShellView3*)this; 85 | }*/ 86 | else { 87 | *ppvObject = NULL; 88 | return E_NOINTERFACE; 89 | } 90 | 91 | AddRef(); 92 | return S_OK; 93 | } 94 | 95 | 96 | /// 97 | /// IShellView::AddPropertySheetPages 98 | /// Allows the view to add pages to the Options property sheet from the View menu. 99 | /// 100 | HRESULT ShellView::AddPropertySheetPages(DWORD, LPFNADDPROPSHEETPAGE lpfn, LPARAM lparam) { 101 | 102 | return S_OK; 103 | } 104 | 105 | 106 | /// 107 | /// IShellView::CreateViewWindow 108 | /// Creates a view window. This can be either the right pane of Windows Explorer or the client window of a folder window. 109 | /// 110 | HRESULT ShellView::CreateViewWindow(IShellView *pszPrevious, LPCFOLDERSETTINGS pfs, IShellBrowser *psb, RECT *prcView, HWND *phWnd) { 111 | if (this->hwnd != NULL) { 112 | return E_FAIL; 113 | *phWnd = NULL; 114 | } 115 | 116 | this->folderSettings = *pfs; 117 | this->previousView = pszPrevious; 118 | this->browser = psb; 119 | 120 | return E_NOTIMPL; 121 | } 122 | 123 | 124 | /// 125 | /// IShellView::DestroyViewWindow 126 | /// Destroys the view window. 127 | /// 128 | HRESULT ShellView::DestroyViewWindow() { 129 | if (this->hwnd == NULL) { 130 | return E_FAIL; 131 | } 132 | 133 | //DestroyWindow(this->hwnd); 134 | this->hwnd = NULL; 135 | return S_OK; 136 | } 137 | 138 | 139 | /// 140 | /// IShellView::EnableModeless 141 | /// Enables or disables modeless dialog boxes. 142 | /// 143 | HRESULT ShellView::EnableModeless(BOOL) { 144 | return S_OK; 145 | } 146 | 147 | 148 | /// 149 | /// IShellView::EnableModelessSV 150 | /// This method is not implemented. 151 | /// 152 | HRESULT ShellView::EnableModelessSV() { 153 | return E_NOTIMPL; 154 | } 155 | 156 | 157 | /// 158 | /// IShellView::GetCurrentInfo 159 | /// Gets the current folder settings. 160 | /// 161 | HRESULT ShellView::GetCurrentInfo(LPFOLDERSETTINGS lpfs) { 162 | *lpfs = this->folderSettings; 163 | return S_OK; 164 | } 165 | 166 | 167 | /// 168 | /// IShellView::GetItemObject 169 | /// Gets an interface that refers to data presented in the view. 170 | /// 171 | HRESULT ShellView::GetItemObject(UINT uItem, REFIID riid, LPVOID *ppv) { 172 | HRESULT hr = S_OK; 173 | *ppv = NULL; 174 | bool useViewOrder = FLAGSET(uItem, SVGIO_FLAG_VIEWORDER); 175 | UINT type = uItem & SVGIO_TYPE_MASK; 176 | 177 | 178 | if (riid == IID_IContextMenu) { 179 | switch (type) { 180 | case SVGIO_BACKGROUND: 181 | { 182 | } 183 | break; 184 | 185 | default: 186 | { 187 | hr = E_FAIL; 188 | } 189 | break; 190 | } 191 | } 192 | else if (riid == IID_IDispatch) { 193 | switch (type) { 194 | case SVGIO_SELECTION: 195 | { 196 | } 197 | break; 198 | 199 | case SVGIO_ALLVIEW: 200 | { 201 | } 202 | break; 203 | 204 | case SVGIO_CHECKED: 205 | { 206 | } 207 | break; 208 | 209 | default: 210 | { 211 | hr = E_FAIL; 212 | } 213 | break; 214 | } 215 | } 216 | else if (riid == IID_IDataObject) { 217 | switch (type) { 218 | case SVGIO_SELECTION: 219 | { 220 | } 221 | break; 222 | 223 | case SVGIO_ALLVIEW: 224 | { 225 | } 226 | break; 227 | 228 | case SVGIO_CHECKED: 229 | { 230 | } 231 | break; 232 | 233 | default: 234 | { 235 | hr = E_FAIL; 236 | } 237 | break; 238 | } 239 | } 240 | else { 241 | hr = E_NOINTERFACE; 242 | } 243 | 244 | hr = E_NOINTERFACE; 245 | 246 | return hr; 247 | } 248 | 249 | 250 | /// 251 | /// IShellView::Refresh 252 | /// Refreshes the view's contents in response to user input. 253 | /// 254 | HRESULT ShellView::Refresh() { 255 | return S_OK; 256 | } 257 | 258 | 259 | /// 260 | /// IShellView::SaveViewState 261 | /// Saves the Shell's view settings so the current state can be restored during a subsequent browsing session. 262 | /// 263 | HRESULT ShellView::SaveViewState() { 264 | return S_OK; 265 | } 266 | 267 | 268 | /// 269 | /// IShellView::SelectItem 270 | /// Changes the selection state of one or more items within the Shell view window. 271 | /// 272 | HRESULT ShellView::SelectItem(PCUITEMID_CHILD pidlItem, UINT uFlags) { 273 | return S_OK; 274 | } 275 | 276 | 277 | /// 278 | /// IShellView::TranslateAccelerator 279 | /// Translates keyboard shortcut (accelerator) key strokes when a namespace extension's view has the focus. 280 | /// 281 | HRESULT ShellView::TranslateAccelerator(LPMSG lpmsg) { 282 | return S_FALSE; 283 | } 284 | 285 | 286 | /// 287 | /// IShellView::UIActivate 288 | /// Called when the activation state of the view window is changed by an event that is not caused by the Shell view itself. 289 | /// 290 | HRESULT ShellView::UIActivate(UINT uState) { 291 | return S_OK; 292 | } 293 | 294 | 295 | /// 296 | /// IShellView2::CreateViewWindow2 297 | /// Used to request the creation of a new Shell view window. 298 | /// 299 | HRESULT ShellView::CreateViewWindow2(LPSV2CVW2_PARAMS) { 300 | return E_NOTIMPL; 301 | } 302 | 303 | 304 | /// 305 | /// IShellView2::GetView 306 | /// Requests the current or default Shell view, together with all other valid view identifiers (VIDs) supported by this implementation of IShellView2. 307 | /// 308 | HRESULT ShellView::GetView(SHELLVIEWID*, ULONG) { 309 | return E_NOTIMPL; 310 | } 311 | 312 | 313 | /// 314 | /// IShellView2::HandleRename 315 | /// Used to change an item's identifier. 316 | /// 317 | HRESULT ShellView::HandleRename(PCUITEMID_CHILD) { 318 | return E_NOTIMPL; 319 | } 320 | 321 | 322 | /// 323 | /// IShellView2::SelectAndPositionItem 324 | /// Selects and positions an item in a Shell View. 325 | /// 326 | HRESULT ShellView::SelectAndPositionItem(PCUITEMID_CHILD pidlItem, UINT uFlags, POINT *point) { 327 | return E_NOTIMPL; 328 | } 329 | 330 | 331 | /// 332 | /// IShellView3::CreateViewWindow3 333 | /// Requests the creation of a new Shell view window. 334 | /// 335 | HRESULT ShellView::CreateViewWindow3(IShellBrowser*, IShellView*, SV3CVW3_FLAGS, FOLDERFLAGS, FOLDERFLAGS, FOLDERVIEWMODE, const SHELLVIEWID*, const RECT*, HWND*) { 336 | return E_NOTIMPL; 337 | } -------------------------------------------------------------------------------- /ShellExtension/ShellView.hpp: -------------------------------------------------------------------------------- 1 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2 | * ShellView.hpp 3 | * The WinUnionFS Project 4 | * 5 | * Implementation of IShellView. 6 | * 7 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 8 | #pragma once 9 | 10 | class ShellView : public IShellView3 11 | { 12 | public: 13 | // Constructor 14 | explicit ShellView(IShellFolder* folder); 15 | 16 | // IUnknown 17 | ULONG STDMETHODCALLTYPE AddRef(); 18 | STDMETHOD(QueryInterface) (REFIID, void**); 19 | ULONG STDMETHODCALLTYPE Release(); 20 | 21 | // IShellView 22 | STDMETHOD(AddPropertySheetPages) (DWORD, LPFNADDPROPSHEETPAGE, LPARAM); 23 | STDMETHOD(CreateViewWindow) (IShellView*, LPCFOLDERSETTINGS, IShellBrowser*, RECT*, HWND*); 24 | STDMETHOD(DestroyViewWindow) (); 25 | STDMETHOD(EnableModeless) (BOOL); 26 | STDMETHOD(EnableModelessSV) (); 27 | STDMETHOD(GetCurrentInfo) (LPFOLDERSETTINGS); 28 | STDMETHOD(GetItemObject) (UINT, REFIID, LPVOID*); 29 | STDMETHOD(Refresh) (); 30 | STDMETHOD(SaveViewState) (); 31 | STDMETHOD(SelectItem) (PCUITEMID_CHILD, UINT); 32 | STDMETHOD(TranslateAccelerator) (LPMSG); 33 | STDMETHOD(UIActivate) (UINT); 34 | 35 | // IShellView2 36 | STDMETHOD(CreateViewWindow2) (LPSV2CVW2_PARAMS); 37 | STDMETHOD(GetView) (SHELLVIEWID*, ULONG); 38 | STDMETHOD(HandleRename) (PCUITEMID_CHILD); 39 | STDMETHOD(SelectAndPositionItem) (PCUITEMID_CHILD, UINT, POINT*); 40 | 41 | // IShellView3 42 | STDMETHOD(CreateViewWindow3) (IShellBrowser*, IShellView*, SV3CVW3_FLAGS, FOLDERFLAGS, FOLDERFLAGS, FOLDERVIEWMODE, const SHELLVIEWID*, const RECT*, HWND*); 43 | 44 | // Creates the class for our view window 45 | bool CreateWindowClass(); 46 | 47 | private: 48 | // Destructor 49 | virtual ~ShellView(); 50 | 51 | ULONG refCount; // 52 | 53 | IShellFolder* folder; // The IShellFolder 54 | IShellView* previousView; // 55 | IShellBrowser* browser; // 56 | 57 | FOLDERSETTINGS folderSettings; // 58 | 59 | HWND hwnd; // 60 | }; 61 | 62 | 63 | -------------------------------------------------------------------------------- /ShellExtension/WinUnionFS.def: -------------------------------------------------------------------------------- 1 | LIBRARY WinUnionFS 2 | EXPORTS 3 | DllCanUnloadNow PRIVATE 4 | DllGetClassObject PRIVATE 5 | DllRegisterServer PRIVATE 6 | DllUnregisterServer PRIVATE 7 | DllElevatedEntry PRIVATE 8 | -------------------------------------------------------------------------------- /ShellExtension/WinUnionFS.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alur/WinUnionFS/4c812376e82cb6c200d55dbb5f0aa6d14e05c3f1/ShellExtension/WinUnionFS.ico -------------------------------------------------------------------------------- /ShellExtension/WinUnionFS.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alur/WinUnionFS/4c812376e82cb6c200d55dbb5f0aa6d14e05c3f1/ShellExtension/WinUnionFS.rc -------------------------------------------------------------------------------- /WinUnionFS.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ShellExtension", "ShellExtension\ShellExtension.vcxproj", "{E0C5A5DE-429C-48E1-832F-D8D692514F85}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Debug|x64 = Debug|x64 10 | Release|Win32 = Release|Win32 11 | Release|x64 = Release|x64 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {E0C5A5DE-429C-48E1-832F-D8D692514F85}.Debug|Win32.ActiveCfg = Debug|Win32 15 | {E0C5A5DE-429C-48E1-832F-D8D692514F85}.Debug|Win32.Build.0 = Debug|Win32 16 | {E0C5A5DE-429C-48E1-832F-D8D692514F85}.Debug|x64.ActiveCfg = Debug|x64 17 | {E0C5A5DE-429C-48E1-832F-D8D692514F85}.Debug|x64.Build.0 = Debug|x64 18 | {E0C5A5DE-429C-48E1-832F-D8D692514F85}.Release|Win32.ActiveCfg = Release|Win32 19 | {E0C5A5DE-429C-48E1-832F-D8D692514F85}.Release|Win32.Build.0 = Release|Win32 20 | {E0C5A5DE-429C-48E1-832F-D8D692514F85}.Release|x64.ActiveCfg = Release|x64 21 | {E0C5A5DE-429C-48E1-832F-D8D692514F85}.Release|x64.Build.0 = Release|x64 22 | EndGlobalSection 23 | GlobalSection(SolutionProperties) = preSolution 24 | HideSolutionNode = FALSE 25 | EndGlobalSection 26 | EndGlobal 27 | --------------------------------------------------------------------------------