Почему значение моего столбца настраиваемых свойств не отображается в проводнике?C#

Место общения программистов C#
Ответить Пред. темаСлед. тема
Anonymous
 Почему значение моего столбца настраиваемых свойств не отображается в проводнике?

Сообщение Anonymous »

Я сейчас чувствую себя очень глупо. Я потратил на это слишком много времени и, должно быть, просто упустил что-то фундаментальное. Чего мне не хватает?
Я пытаюсь создать новый столбец для проводника в Windows 11. Насколько я понял, для этого требуется регистрация файла описания свойства и обработчика свойства. (COM-сервер). У меня почти нет опыта работы с COM. Я использую C# .NET 8, поэтому пошел по этому пути, а не C/C++ (я использую библиотеку CsWin32 для генерации типов окон и методов pinvoke). Я просто пытаюсь реализовать что-то типа «Hello World», поэтому я запрограммировал его так, чтобы заполнить мой новый столбец значением «Кайл» для каждого файла. Я могу добавить столбец в проводнике, но ни для одного файла в этом столбце никогда не отображается значение. Я добавил журналирование, и ничего не регистрируется. В средстве просмотра событий ошибок тоже нет.
Вот файл описания моего свойства (собранный на основе наилучшего предположения из различных источников):





Always displays the name Kyle.








Я написал простое консольное приложение для регистрации описания свойства.



Exe
net8.0
enable
enable
true














all
runtime; build; native; contentfiles; analyzers; buildtransitive





using System.Runtime.InteropServices;
using Windows.Win32;

public class Program
{
private static void Main(string[] args)
{
if (args.Length < 2)
{
Console.WriteLine("Usage: RegisterPropertySchema.exe ");
return;
}

var action = args[0];
var schemaPath = args[1];

if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows) || !OperatingSystem.IsWindowsVersionAtLeast(5, 1, 2600))
{
throw new PlatformNotSupportedException("PSRegisterPropertySchema and PSUnregisterPropertySchema are only supported on Windows.");
}

switch (action.ToLower())
{
case "register":
RegisterPropertySchema(schemaPath);
break;
case "unregister":
UnregisterPropertySchema(schemaPath);
break;
default:
Console.WriteLine("Invalid action. Use 'register' or 'unregister'.");
break;
}
}

private static void RegisterPropertySchema(string schemaPath)
{
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows) || !OperatingSystem.IsWindowsVersionAtLeast(5, 1, 2600))
{
throw new PlatformNotSupportedException("PSRegisterPropertySchema and PSUnregisterPropertySchema are only supported on Windows.");
}

var result = PInvoke.PSRegisterPropertySchema(schemaPath);

if (result == 0)
{
Console.WriteLine("Property schema registered successfully.");
}
else if (result == 0x000401A0) // INPLACE_S_TRUNCATED
{
Console.WriteLine("Property schema PARTIALLY registered. INPLACE_S_TRUNCATED");
}
else
{
Console.WriteLine($"Failed to register property schema. HRESULT: {result:X}");
}
}

private static void UnregisterPropertySchema(string schemaPath)
{
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows) || !OperatingSystem.IsWindowsVersionAtLeast(5, 1, 2600))
{
throw new PlatformNotSupportedException("PSRegisterPropertySchema and PSUnregisterPropertySchema are only supported on Windows.");
}

var result = PInvoke.PSUnregisterPropertySchema(schemaPath);

if (result == 0)
{
Console.WriteLine("Property schema unregistered successfully.");
}
else
{
Console.WriteLine($"Failed to unregister property schema. HRESULT: {result:X}");
}
}
}

И зарегистрируйте его так:
.\RegisterPropertySchema.exe register "C:\Program Files\Kyle\CustomProperty\CustomPropertyKyle.propdesc"
При этом в реестр добавляется следующее:
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\PropertySystem\PropertySchema\0003]
@="C:\\Program Files\\Kyle\\CustomProperty\\CustomPropertyKyle.propdesc"
"SchemaId"="{D84D0B56-EAB4-4E60-A125-DD699A684B3C}"
"URI"="custompropertykyle.propdesc"
"CompactURI"="66a088697b1669173504a8c3d90b3614e147d922d8f298de8116bbcd74e5c6b4"

Это обработчик моего свойства:



net8.0
enable
enable
true
true












all
runtime; build; native; contentfiles; analyzers; buildtransitive





using System.Runtime.InteropServices;
using Windows.Win32.System.Com.StructuredStorage;
using Windows.Win32.System.Variant;
using Windows.Win32.UI.Shell.PropertiesSystem;

[ComVisible(true)]
[Guid("12345678-1234-1234-1234-1234567890AB")]
public unsafe class CustomPropertyHandler : IPropertyStore
{
private static string LogFilePath { get; } = """C:\abc\CustomPropertyHandler.txt""";

private static PROPERTYKEY PropertyKeyTitle { get; } = new()
{
fmtid = new ("4F4F4F4F-FFFF-FFFF-FFFF-FFFFFFFFFFFF")
, pid = 100
};

public void GetCount(out uint propertyCount)
{
try
{
Log(nameof(GetCount), "START");
propertyCount = 1;
}
catch (Exception ex)
{
Log(nameof(GetCount), $" EXCEPTION: {ex.Message}");
propertyCount = 1;
}
finally
{
Log(nameof(GetCount), " END");
}
}

public void GetAt(uint propertyIndex, PROPERTYKEY* key)
{
try
{
Log(nameof(GetAt), $"START propertyIndex: {propertyIndex}");

ArgumentOutOfRangeException.ThrowIfNotEqual(propertyIndex, 0);

*key = PropertyKeyTitle;
}
catch (Exception ex)
{
Log(nameof(GetAt), $" EXCEPTION: {ex.Message}");
}
finally
{
Log(nameof(GetAt), " END");
}
}

public void GetValue(PROPERTYKEY* key, out PROPVARIANT pv)
{
try
{
Log(nameof(GetValue), $"START key: fmtid={key->fmtid} pid={key->pid}");

pv = new ();

if (key->fmtid == PropertyKeyTitle.fmtid && key->pid == PropertyKeyTitle.pid)
{
Log(nameof(GetValue), " MATCH");

pv.Anonymous.Anonymous.vt = VARENUM.VT_LPWSTR;
pv.Anonymous.Anonymous.Anonymous.pwszVal = (char*)Marshal.StringToCoTaskMemUni("Kyle");
}
else
{
Log(nameof(GetValue), " NO MATCH");

pv.Anonymous.Anonymous.vt = VARENUM.VT_EMPTY;
}
}
catch (Exception ex)
{
Log(nameof(GetValue), $" EXCEPTION: {ex.Message}");
pv = new();
}

Log(nameof(GetValue), " END");
}

public void SetValue(PROPERTYKEY* key, in PROPVARIANT propvar) => Log(nameof(SetValue), $"START key: {key->fmtid} {key->pid} propvar: vt={propvar.Anonymous.Anonymous.vt} pwszVal={propvar.Anonymous.Anonymous.Anonymous.pwszVal}");

public void Commit() => Log(nameof(Commit), "START");

private static void Log(string method, string message)
{
using var writer = new StreamWriter(LogFilePath, append: true);

writer.WriteLine($"{DateTime.Now:HH:mm:ss.sss} {method} {message}");
}
}

Я регистрирую обработчик из приглашения администратора PowerShell 7 следующим образом:
regsvr32 "C:\Program Files\Kyle\CustomProperty\CustomPropertyKyle.comhost.dll"
При этом в реестр добавляется следующее:
[HKEY_CLASSES_ROOT\CLSID\{12345678-1234-1234-1234-1234567890AB}]
@=".CustomPropertyHandler"

[HKEY_CLASSES_ROOT\CLSID\{12345678-1234-1234-1234-1234567890AB}\InProcServer32]
@="C:\\Program Files\\Kyle\\CustomProperty\\CustomPropertyKyle.comhost.dll"
"ThreadingModel"="Both"

[HKEY_CLASSES_ROOT\CLSID\{12345678-1234-1234-1234-1234567890AB}\ProgID]
@=".CustomPropertyHandler"


Подробнее здесь: https://stackoverflow.com/questions/785 ... e-explorer
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «C#»