Click or drag to resize

EngineGetMenuCommandAsync Method

IT Hit User File System
Gets context menu command.

Namespace:  ITHit.FileSystem
Assembly:  ITHit.FileSystem (in ITHit.FileSystem.dll) Version: 6.1.20210.0
Syntax
public virtual Task<IMenuCommand> GetMenuCommandAsync(
	Guid menuGuid
)

Parameters

menuGuid
Type: SystemGuid
Context menu command GUID.

Return Value

Type: TaskIMenuCommand
Menu implemntation.

Implements

IEngineGetMenuCommandAsync(Guid)
Remarks

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

  1. Derive your class from the [!:CloudFilesContextMenuVerbBase] class. 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) 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: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)
    {
        bool? isLocked = await IsLockedAsync(filesPath);
        return isLocked.HasValue ? MenuState.Enabled : MenuState.Hidden;
    }

    public async Task InvokeAsync(IEnumerable<string> filesPath)
    {
        // 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.TryGetLockInfo(out ServerLockInfo lockInfo))
                    {
                        // Detect if locked by this user.
                        bool thisUser = engine.CurrentUserPrincipal.Equals(lockInfo.Owner, StringComparison.InvariantCultureIgnoreCase);
                        if (!thisUser)
                        {
                            // Typically we can not unlock items locked by other users. We must hide or disable the menu in tis 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)
{
    // 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