Skip to content

Commit

Permalink
Merge pull request #80 from Dijji/ProfileOnly
Browse files Browse the repository at this point in the history
Profile only
  • Loading branch information
Dijji authored Jan 16, 2020
2 parents e1a7ec8 + 0ba6cb6 commit 97a08d9
Show file tree
Hide file tree
Showing 33 changed files with 1,087 additions and 179 deletions.
27 changes: 27 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,30 @@
/PropertyHandler/x64/Release
/x64/Release
/Setup/obj/x64/Release
/TestDriver/TestDriver.suo
/AssociationManager/bin/Debug
/CommandLine/Debug
/CommandLineAssociationManager/bin/Debug
/ContextMenuHandler/Debug
/Debug
/PropertyHandler/Debug
/Setup/bin
/Setup/obj/x86/Debug
/Setup/msi/Debug
/AssociationManager/bin/Release
/CommandLine/Release
/CommandLineAssociationManager/bin/Release
/ContextMenuHandler/Release
/PropertyHandler/Release
/Release
/Setup/msi/Release
/Setup/obj/x86/Release
/CommandLine/FileMeta.aps
/ContextMenuHandler/ContextMenuHandler.aps
/PropertyHandler/FileMetaPropertyHandler.aps
/TestDriverAssoc/.vs/TestDriverAssoc/v15
/TestSandbox
/TestDriver/bin/Debug
/TestDriverAssoc/bin/Debug
/TestSandbox32
/CommandLineAssociationManager/CommandLineAssociationManager.csproj.user
220 changes: 174 additions & 46 deletions AssociationManager/Extension.cs

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions AssociationManager/FileMetaAssociationManager.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@
<Compile Include="Extensions.cs" />
<Compile Include="ObservableCollectionWithReset.cs" />
<Compile Include="Profile.cs" />
<Compile Include="PropertyHandlerTest.cs" />
<Compile Include="PropertyListEntry.cs" />
<Compile Include="Code Pack\PropertyKey.cs" />
<Compile Include="Code Pack\PropertySystemNativeMethods.cs" />
Expand Down
8 changes: 7 additions & 1 deletion AssociationManager/MainView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,10 @@ public void AddHandlers()
foreach (Extension ext in SelectedExtensions)
{
ext.SetupHandlerForExtension(SelectedProfile, true);

if (ext.PropertyHandlerState == HandlerState.ProfileOnly)
MessageBox.Show(string.Format(LocalizedMessages.WindowsWontExtendHandler, ext.Name),
LocalizedMessages.SetupHandler);
}
}

Expand Down Expand Up @@ -242,7 +246,9 @@ private void DeterminePossibleActions()
break;
}
}
else if (e.PropertyHandlerState == HandlerState.Ours || e.PropertyHandlerState == HandlerState.Chained)
else if (e.PropertyHandlerState == HandlerState.Ours ||
e.PropertyHandlerState == HandlerState.Chained ||
e.PropertyHandlerState == HandlerState.ProfileOnly)
{
if (handlersSelected == null)
handlersSelected = HandlerSet.Ours;
Expand Down
24 changes: 24 additions & 0 deletions AssociationManager/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,32 @@ private void profiles_Click(object sender, RoutedEventArgs e)
view.SelectedProfile = state.SelectedProfile;
}

// Temporary code to enumerate extensions for which Add Handler fails
//private void CheckForBlockedExtensions()
//{
// using (var w = new System.IO.StreamWriter(@"D:\TestProperties\Results\Extensions.csv"))
// {
// foreach (var ext in state.Extensions.Where(x => x.PropertyHandlerState == HandlerState.Foreign))
// {
// string result = "Exception";
// try
// {
// result = ext.IsPropertyHandlerBlocked() ? "Blocked" : "Ok";
// }
// catch (System.Exception ex)
// {
// }
// w.WriteLine(String.Format("{0}, {1}, {2}", ext.Name, result, ext.PropertyHandlerDisplay));
// }
// }
//}

private void restartExplorer_Click(object sender, RoutedEventArgs e)
{
// Temporary code to enumerate extensions for which Add Handler fails
//CheckForBlockedExtensions();
//return;

bool failed = false;
try
{
Expand Down
114 changes: 114 additions & 0 deletions AssociationManager/PropertyHandlerTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;

namespace FileMetadataAssociationManager
{
static class PropertyHandlerTest
{
private static Guid IPropertyStoreGuid = new Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99");

public static bool WindowsIgnoresOurPropertyHandler(string extension)
{
// Create a temporary file with the right extension
string fileFullName = Path.ChangeExtension(
Path.GetTempPath() + Guid.NewGuid().ToString(), extension);
using (var fs = File.Create(fileFullName)) { }

// Get the property store that Explorer would use
IPropertyStore ps;
bool result = true;
HResult hr = (HResult)SHGetPropertyStoreFromParsingName(fileFullName, IntPtr.Zero,
GETPROPERTYSTOREFLAGS.GPS_NO_OPLOCK | GETPROPERTYSTOREFLAGS.GPS_HANDLERPROPERTIESONLY, ref IPropertyStoreGuid, out ps);
if (hr == HResult.Ok)
{
// Look for the signature property value that marks the handler as ours
PropertyKey key;
PropVariant pv = new PropVariant();
PropertySystemNativeMethods.PSGetPropertyKeyFromName("System.Software.ProductName", out key);
hr = ps.GetValue(key, pv);
if (hr == HResult.Ok && !pv.IsNullOrEmpty)
{
if ((pv.Value as string) == "FileMetadata")
result = false;
}
Marshal.ReleaseComObject(ps); // This release frees up the file for deletion
}

File.Delete(fileFullName);

return result;
}

[DllImport("shell32.dll", SetLastError = true)]
public static extern int SHGetPropertyStoreFromParsingName(
[In][MarshalAs(UnmanagedType.LPWStr)] string pszPath,
IntPtr zeroWorks,
GETPROPERTYSTOREFLAGS flags,
ref Guid iIdPropStore,
[Out] out IPropertyStore propertyStore);
}

public enum GETPROPERTYSTOREFLAGS
{
// If no flags are specified (GPS_DEFAULT), a read-only property store is returned that includes properties for the file or item.
// In the case that the shell item is a file, the property store contains:
// 1. properties about the file from the file system
// 2. properties from the file itself provided by the file's property handler, unless that file is offline,
// see GPS_OPENSLOWITEM
// 3. if requested by the file's property handler and supported by the file system, properties stored in the
// alternate property store.
//
// Non-file shell items should return a similar read-only store
//
// Specifying other GPS_ flags modifies the store that is returned
GPS_DEFAULT = 0x00000000,
GPS_HANDLERPROPERTIESONLY = 0x00000001, // only include properties directly from the file's property handler
GPS_READWRITE = 0x00000002, // Writable stores will only include handler properties
GPS_TEMPORARY = 0x00000004, // A read/write store that only holds properties for the lifetime of the IShellItem object
GPS_FASTPROPERTIESONLY = 0x00000008, // do not include any properties from the file's property handler (because the file's property handler will hit the disk)
GPS_OPENSLOWITEM = 0x00000010, // include properties from a file's property handler, even if it means retrieving the file from offline storage.
GPS_DELAYCREATION = 0x00000020, // delay the creation of the file's property handler until those properties are read, written, or enumerated
GPS_BESTEFFORT = 0x00000040, // For readonly stores, succeed and return all available properties, even if one or more sources of properties fails. Not valid with GPS_READWRITE.
GPS_NO_OPLOCK = 0x00000080, // some data sources protect the read property store with an oplock, this disables that
GPS_MASK_VALID = 0x000000FF,
}

/// <summary>
/// A property store
/// </summary>
[ComImport]
[Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IPropertyStore
{
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
HResult GetCount([Out] out uint propertyCount);

[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
HResult GetAt([In] uint propertyIndex, out PropertyKey key);

[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
HResult GetValue([In] ref PropertyKey key, [Out] PropVariant pv);

[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), PreserveSig]
HResult SetValue([In] ref PropertyKey key, [In] PropVariant pv);

[PreserveSig]
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
HResult Commit();
}

[ComImport]
[Guid("C8E2D566-186E-4D49-BF41-6909EAD56ACC")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IPropertyStoreCapabilities
{
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
HResult IsPropertyWritable([In]ref PropertyKey propertyKey);
}
}
9 changes: 6 additions & 3 deletions AssociationManager/State.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ public void Populate(string savedStateFile = null)

public void SortExtensions()
{
// Sort by file extension, but group by our handler, chained handlers, other handlers, and finally no handler
// Sort by file extension, but group by our handler, chained handlers, profile only,
// other handlers, and finally no handler
// This uses a Sort extension to ObservableCollection
extensions.Sort((e, f) =>
{
Expand All @@ -82,6 +83,10 @@ public void SortExtensions()
return -1;
else if (f.PropertyHandlerState == HandlerState.Chained)
return 1;
else if (e.PropertyHandlerState == HandlerState.ProfileOnly)
return -1;
else if (f.PropertyHandlerState == HandlerState.ProfileOnly)
return 1;
else if (e.PropertyHandlerState == HandlerState.Foreign)
return -1;
else if (f.PropertyHandlerState == HandlerState.Foreign)
Expand Down Expand Up @@ -409,8 +414,6 @@ private void PopulateExtensions()
if (dictExtensions.TryGetValue(name.ToLower(), out e))
{
e.RecordPropertyHandler(handlerGuid, handlerChainedGuid);

e.IdentifyCurrentProfile();
}
}
}
Expand Down
9 changes: 9 additions & 0 deletions AssociationMessages/LocalizedMessages.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions AssociationMessages/LocalizedMessages.resx
Original file line number Diff line number Diff line change
Expand Up @@ -279,4 +279,7 @@
<data name="AtLeastOneExtension" xml:space="preserve">
<value>-add and -remove commands require at least one extension to be specified</value>
</data>
<data name="WindowsWontExtendHandler" xml:space="preserve">
<value>Windows will not allow the handler for {0} to be extended. Using profile with Windows handler.</value>
</data>
</root>
17 changes: 14 additions & 3 deletions CommandLine/FileMeta.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ int wmain(int argc, WCHAR* argv[])
SwitchArg promptSwitch(L"p",L"prompt",L"After execution, prompt to continue", false);
cmd.add(promptSwitch);

// Define Explorer view of meta data switch
SwitchArg explorerSwitch(L"v", L"explorer", L"Export metadata thisExplorer sees", false);
cmd.add(explorerSwitch);

// Define XML file name override
ValueArg<wstring> xmlFileArg(L"x",L"xml",L"Name of XML file (only valid if one target file)",false,L"",L"file name");
cmd.add( xmlFileArg );
Expand Down Expand Up @@ -83,6 +87,11 @@ int wmain(int argc, WCHAR* argv[])
if (!exportSwitch.isSet())
throw ArgException(L"-c can only be used with -e", L"console");
}
else if (explorerSwitch.isSet())
{
if (!exportSwitch.isSet())
throw ArgException(L"-v can only be used with -e", L"explorer");
}

for (auto pos = targetFiles.begin(); pos != targetFiles.end(); ++pos)
{
Expand All @@ -94,9 +103,11 @@ int wmain(int argc, WCHAR* argv[])
result = ERROR_FILE_NOT_FOUND;
break;
}
else if (!checker.HasOurPropertyHandler(targetFile))
else if (0 == checker.HasPropertyHandler(targetFile) ||
(-1 == checker.HasPropertyHandler(targetFile) && !explorerSwitch.isSet()))
{
// Skip files that do not have our property handler
// Skip files that do not have our property handler,
// unless we were asked for the Explorer view
continue;
}
else if (deleteSwitch.isSet())
Expand Down Expand Up @@ -139,7 +150,7 @@ int wmain(int argc, WCHAR* argv[])
if (exportSwitch.isSet())
{
xml_document<WCHAR> doc;
ExportMetadata(&doc, targetFile);
ExportMetadata(&doc, targetFile, explorerSwitch.isSet());

// writing to a string rather than directly to the stream is odd, but writing directly does not compile
// (trying to access a private constructor on traits - a typically arcane template issue)
Expand Down
Binary file modified CommandLine/FileMeta.rc
Binary file not shown.
Loading

0 comments on commit 97a08d9

Please sign in to comment.