Click or drag to resize

IEngineGetMenuCommandAsync Method

IT Hit User File System
Gets context menu command.

Namespace:  ITHit.FileSystem
Assembly:  ITHit.FileSystem (in ITHit.FileSystem.dll) Version: 8.1.26224.0-Beta2
Syntax
Task<IMenuCommand> GetMenuCommandAsync(
	Guid menuGuid,
	IOperationContext operationContext = null
)

Parameters

menuGuid
Type: SystemGuid
Context menu command GUID.
operationContext (Optional)
Type: ITHit.FileSystemIOperationContext
Provides information about the environment.

Return Value

Type: TaskIMenuCommand
Menu implemntation.
Remarks

To show context menu in Windows Explorer for your virtual drive follow these steps:

  1. Derive your class from one of the [!:CloudFilesContextMenuVerbBase] class descendants. Add the GuidAttribute, ProgIdAttribute and ComVisibleAttribute attributes to your class. You do not need to implement any methods in your class. On Windows 11 your module that contains menu class requires package or application identity (be signed with a trusted certificate).
  2. Add the desktop3:CloudFilesContextMenus tag to your Package.appxmanifest (in case of packaged app) or appxmanifest.xml (in case of a sparse package) that references your class.
  3. Implement the IMenuCommand interface to return the menu data.
  4. Return your object that implements IMenuCommand from the GetMenuCommandAsync(Guid, IOperationContext) method.

Examples

The code below is part of 'VirtualDrive' C# sample provided with the SDK.

C#
[ComVisible(true)]
[ProgId("VirtualDrive.ContextMenuVerb")]
[Guid("9C923BF3-3A4B-487B-AB4E-B4CF87FD1C25")]
public class ContextMenuVerbRpc : CloudFilesContextMenuVerbRpcBase
{

}

The code below is part of 'VirtualDrive' C# sample provided with the SDK.

XML
<Extensions>
  <desktop3:Extension Category="windows.cloudFiles">
    <desktop3:CloudFiles>
      <desktop3:CustomStateHandler Clsid="000562AA-2879-4CF1-89E8-0AEC9596FE19"/>
      <desktop3:ThumbnailProviderHandler Clsid="05CF065E-E135-4B2B-9D4D-CFB3FBAC73A4"/>

      <desktop3:ExtendedPropertyHandler Clsid="20000000-0000-0000-0000-000000000001"/>
      <desktop3:BannersHandler Clsid="20000000-0000-0000-0000-000000000001"/>

      <desktop3:CloudFilesContextMenus>
        <desktop3:Verb Id="LockCommand" Clsid="9C923BF3-3A4B-487B-AB4E-B4CF87FD1C25" />
      </desktop3:CloudFilesContextMenus>

      <desktop4:ContentUriSource Clsid="6D45BC7A-D0B7-4913-8984-FD7261550C08"/>

    </desktop3:CloudFiles>
  </desktop3:Extension>
  <com:Extension Category="windows.comServer">
    <com:ComServer>
      <com:ExeServer DisplayName="VirtualDrive.ShellExtension" Executable="VirtualDrive.ShellExtension\VirtualDrive.ShellExtension.exe">
        <com:Class Id="05CF065E-E135-4B2B-9D4D-CFB3FBAC73A4" />
      </com:ExeServer>

      <com:ExeServer DisplayName="VirtualDrive.ShellExtension" Executable="VirtualDrive.ShellExtension\VirtualDrive.ShellExtension.exe">
        <com:Class Id="9C923BF3-3A4B-487B-AB4E-B4CF87FD1C25" />
      </com:ExeServer>

      <com:ExeServer DisplayName="VirtualDrive.ShellExtension" Executable="VirtualDrive.ShellExtension\VirtualDrive.ShellExtension.exe">
          <com:Class Id="000562AA-2879-4CF1-89E8-0AEC9596FE19" />
      </com:ExeServer>

      <com:ExeServer DisplayName="VirtualDrive.ShellExtension" Executable="VirtualDrive.ShellExtension\VirtualDrive.ShellExtension.exe">
          <com:Class Id="6D45BC7A-D0B7-4913-8984-FD7261550C08" />
      </com:ExeServer>

<com:ExeServer DisplayName="VirtualDrive.ShellExtension" Executable="VirtualDrive.ShellExtension\VirtualDrive.ShellExtension.exe">
  <com:Class Id="4E813313-2227-42AE-BDC9-53C17A9CF812" />
</com:ExeServer>

</com:ComServer>
  </com:Extension>
</Extensions>

The code below is part of 'Common' C# sample provided with the SDK.

C#
public class MenuCommandLock : IMenuCommandWindows
{
    private readonly VirtualEngineBase engine;
    private readonly ILogger logger;

    private const string lockCommandIcon = @"Images\Locked.ico";
    private const string unlockCommandIcon = @"Images\Unlocked.ico";

    public MenuCommandLock(VirtualEngineBase engine, ILogger logger)
    {
        this.engine = engine;
        this.logger = logger.CreateLogger("Lock Menu Command");
    }

    public async Task<string> GetTitleAsync(IEnumerable<string> filesPath)
    {
        bool isLocked = await IsLockedAsync(filesPath) == true;
        return isLocked ? "Unlock" : "Lock";
    }

    public async Task<string> GetIconAsync(IEnumerable<string> filesPath)
    {
        string iconName = await IsLockedAsync(filesPath) == false ? lockCommandIcon : unlockCommandIcon;
        string iconPath = Path.Combine(Path.GetDirectoryName(typeof(MenuCommandLock).Assembly.Location), iconName);
        return iconPath;
    }

    public async Task<MenuState> GetStateAsync(IEnumerable<string> filesPath)
    {
        // This sample can not lock folders.
        // Hide menu if any folders are selected.
        foreach (string userFileSystemPath in filesPath)
        {
            FileAttributes attr = File.GetAttributes(userFileSystemPath);
            if ((attr & FileAttributes.Directory) == FileAttributes.Directory)
                return MenuState.Hidden;
        }

        bool? isLocked = await IsLockedAsync(filesPath);
        return isLocked.HasValue ? MenuState.Enabled : MenuState.Hidden;
    }

    public async Task InvokeAsync(IEnumerable<string> filesPath, IEnumerable<byte[]> remoteStorageItemIds = null, CancellationToken cancellationToken = default)
    {
        // If you need a remote storage ID for each item use the following code:
        //foreach (string userFileSystemPath in filesPath)
        //{
        //    if(engine.Placeholders.TryGetItem(userFileSystemPath, out PlaceholderItem placeholder))
        //    {
        //        byte[] remoteStorageId = placeholder.GetRemoteStorageItemId();
        //    }
        //}

        bool isLocked = await IsLockedAsync(filesPath) == true;
        foreach (string userFileSystemPath in filesPath)
        {
            try
            {
                IClientNotifications clientNotifications = engine.ClientNotifications(userFileSystemPath, logger);
                if (isLocked)
                    await clientNotifications.UnlockAsync();
                else
                    await clientNotifications.LockAsync();
            }
            catch (Exception ex)
            {
                string actionName = isLocked ? "Unlock" : "Lock";
                logger.LogError($"Failed to {actionName} item", userFileSystemPath, null, ex);
            }
        }
    }

    public async Task<string> GetToolTipAsync(IEnumerable<string> filesPath)
    {
        bool isLocked = await IsLockedAsync(filesPath) == true;
        return isLocked ? "Unlock item(s)" : "Lock item(s)";
    }

    private async Task<bool?> IsLockedAsync(IEnumerable<string> filesPath, CancellationToken cancellationToken = default)
    {
        bool? allLocked = null;
        foreach (string userFileSystemPath in filesPath)
        {
            try
            {
                bool isLocked = false;
                if (engine.Placeholders.TryGetItem(userFileSystemPath, out PlaceholderItem placeholder))
                {
                    if (placeholder.Properties.TryGetLockInfo(out ServerLockInfo lockInfo))
                    {
                        // Detect if locked by this user.
                        if (!engine.IsCurrentUser(lockInfo.Owner))
                        {
                            // Typically we can not unlock items locked by other users.
                            // We must hide or disable menu in this case.
                            return null;
                        }
                        isLocked = true;
                    }
                }

                if (allLocked.HasValue && (allLocked != isLocked))
                {
                    return null;
                }

                allLocked = isLocked;
            }
            catch (Exception ex)
            {
                logger.LogError("Failed to get lock state", userFileSystemPath, null, ex);
            }
        }

        return allLocked;
    }
}

The code below is part of 'VirtualDrive' C# sample provided with the SDK.

C#
public override async Task<IMenuCommand> GetMenuCommandAsync(Guid menuGuid, IOperationContext operationContext = null)
{
    // For this method to be called you need to register a menu command handler.
    // See method description for more details.

    Logger.LogDebug($"{nameof(IEngine)}.{nameof(GetMenuCommandAsync)}()", menuGuid.ToString());

    Guid menuCommandLockGuid = typeof(ShellExtension.ContextMenuVerbIntegrated).GUID;

    if (menuGuid == menuCommandLockGuid)
    {
        return new MenuCommandLock(this, this.Logger);
    }

    Logger.LogError($"Menu not found", menuGuid.ToString());
    throw new NotImplementedException();
}
See Also