Что передать в качестве первого параметра IActiveScriptProfilerControl.StartProfiling?

Пытаясь использовать IActiveScriptProfilerControl::StartProfiling из моего кода C# я создал это определение интерфейса:

[ComImport]
[Guid(@"784b5ff0-69b0-47d1-a7dc-2518f4230e90")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IActiveScriptProfilerControl
{
    void StartProfiling(
        ref Guid clsidProfilerObject, 
        ProfilerEventMask eventMask, 
        uint dwContext);

    // ...
}

Который, я считаю, правильно переведен на.NET.

Первоначальный первый параметр определяется как

[in] REFCLSID clsidProfilerObject

С этими определениями:

typedef GUID CLSID;
typedef CLSID *REFCLSID;

Я также могу создать экземпляр Microsoft JQueryScriptEngine объект и запрос для IActiveScriptProfilerControl,

То, что я в настоящее время терплю неудачу в том, как сказать StartProfiling функция использовать мой IActiveScriptProfilerCallback объект

Мой вопрос:

Как связать мой собственный класс обратного вызова профилировщика с активным интерфейсом управления сценарием сценария через вызов IActiveScriptProfilerControl::StartProfiling?

В идеале я хотел бы сделать это без необходимости RegAsm моего класса.

Обновление 1:

Я изменил первый параметр определения интерфейса:

[ComImport]
[Guid(@"784b5ff0-69b0-47d1-a7dc-2518f4230e90")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IActiveScriptProfilerControl
{
    void StartProfiling(
        IActiveScriptProfilerCallback clsidProfilerObject, // <-- changed.
        ProfilerEventMask eventMask, 
        uint dwContext);

    // ...
}

и попытался вызвать эту функцию, передав экземпляр моего IActiveScriptProfilerCallback класс.

Тем не менее, я получаю ошибку:

Класс не зарегистрирован (Исключение из HRESULT: 0x80040154 (REGDB_E_CLASSNOTREG))

1 ответ

Решение

(Обновление от моего будущего я, которое пришло сюда при поиске аналогичной ошибки)

Мне удалось решить эту проблему с помощью мониторинга реестра, как при выполнении вызова Regasm.exe в моей сборке, так и при отслеживании того, какие ключи запрашивает профилировщик при вызове StartProfiling,

Эти ключи были необходимы для HKEY_CLASSES_ROOT:

REGEDIT4

[HKEY_CLASSES_ROOT \ ZetaProducer.SuperSlimScriptingEngineProfiler.SlimScriptEngineProfilerCallback] @ = "ZetaProducer.SuperSlimScriptingEngineProfiler.SlimScriptEngineProfilerCallback"

[HKEY_CLASSES_ROOT \ ZetaProducer.SuperSlimScriptingEngineProfiler.SlimScriptEngineProfilerCallback \ CLSID] @ = "{1C406FBA-59EF-4FB2-938C-C1DA182D5914}"

[HKEY_CLASSES_ROOT \ CLSID {1C406FBA-59EF-4FB2-938C-C1DA182D5914}] @ = "ZetaProducer.SuperSlimScriptingEngineProfiler.SlimScriptEngineProfilerCallback"

[HKEY_CLASSES_ROOT \ CLSID {1C406FBA-59EF-4FB2-938C-C1DA182D5914} \ InprocServer32] @ = "mscoree.dll" "ThreadingModel" = "Both" "Class" = "ZetaProducer.SuperSlimScriS недействительный" SuperSlimScriptingEngineProfiler, версия =14.1.0.0, культура = нейтральная, PublicKeyToken=null" "RuntimeVersion"="v4.0.30319" "CodeBase"=" файл: /// C: / P / Zeta Producer / 13 / Zeta Producer Main / Bin /Applications/ZetaProducer.SuperSlimScriptingEngineProfiler.dll"

[HKEY_CLASSES_ROOT \ CLSID {1C406FBA-59EF-4FB2-938C-C1DA182D5914} \ InprocServer32 \ 14.1.0.0] "Class" = "ZetaProducer.SuperSlimScriptingEngineProfiler.SlimScriptEngineProfiler.0.1 нейтральный, PublicKeyToken=null" "RuntimeVersion"="v4.0.30319" "CodeBase"="file:///C:/P/Zeta Producer/13/Zeta Producer Главная / Бин / Приложения / ZetaProducer.SuperSlimScriptingEngineProfiler.dll "

[HKEY_CLASSES_ROOT \ CLSID {1C406FBA-59EF-4FB2-938C-C1DA182D5914} \ ProgId] @ = "ZetaProducer.SuperSlimScriptingEngineProfiler.SlimScriptEngineProfilerCallback"

[HKEY_CLASSES_ROOT \ CLSID {1C406FBA-59EF-4FB2-938C-C1DA182D5914} \ Реализованные категории {62C8FE65-4EBB-45E7-B440-6E39B2CDBF29}]

Еще одно предложение для JScript также добавить:

[HKEY_CURRENT_USER \ Environment]
"JS_PROFILER" = "{1C406FBA-59EF-4FB2-938C-C1DA182D5914}"

Поскольку я хотел, чтобы моя программа работала без административных привилегий, я создал класс для создания вышеуказанных ключей HKEY_CURRENT_USER, который также работает.

Ниже приводится полный файл класса для справочных целей:

namespace ZetaProducer.SuperSlimScriptingEngineProfiler.Helper
{
    using Microsoft.Win32;
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Reflection;
    using System.Security.AccessControl;
    using System.Security.Principal;
    using Zeta.VoyagerLibrary.Common.IO;

    public static class ProfilerComRegistration
    {
        public const string ClsidString = @"1C406FBA-59EF-4FB2-938C-C1DA182D5914";
        public static readonly Guid Clsid = new Guid(ClsidString);

        /*
        REGEDIT4

        [HKEY_CLASSES_ROOT\ZetaProducer.SuperSlimScriptingEngineProfiler.SlimScriptEngineProfilerCallback]
        @="ZetaProducer.SuperSlimScriptingEngineProfiler.SlimScriptEngineProfilerCallback"

        [HKEY_CLASSES_ROOT\ZetaProducer.SuperSlimScriptingEngineProfiler.SlimScriptEngineProfilerCallback\CLSID]
        @="{1C406FBA-59EF-4FB2-938C-C1DA182D5914}"

        [HKEY_CLASSES_ROOT\CLSID\{1C406FBA-59EF-4FB2-938C-C1DA182D5914}]
        @="ZetaProducer.SuperSlimScriptingEngineProfiler.SlimScriptEngineProfilerCallback"

        [HKEY_CLASSES_ROOT\CLSID\{1C406FBA-59EF-4FB2-938C-C1DA182D5914}\InprocServer32]
        @="mscoree.dll"
        "ThreadingModel"="Both"
        "Class"="ZetaProducer.SuperSlimScriptingEngineProfiler.SlimScriptEngineProfilerCallback"
        "Assembly"="ZetaProducer.SuperSlimScriptingEngineProfiler, Version=15.0.0.0, Culture=neutral, PublicKeyToken=null"
        "RuntimeVersion"="v4.0.30319"
        "CodeBase"="file:///C:/P/Zeta Producer/13/Zeta Producer Main/Bin/Applications/ZetaProducer.SuperSlimScriptingEngineProfiler.dll"

        [HKEY_CLASSES_ROOT\CLSID\{1C406FBA-59EF-4FB2-938C-C1DA182D5914}\InprocServer32\15.0.0.0]
        "Class"="ZetaProducer.SuperSlimScriptingEngineProfiler.SlimScriptEngineProfilerCallback"
        "Assembly"="ZetaProducer.SuperSlimScriptingEngineProfiler, Version=15.0.0.0, Culture=neutral, PublicKeyToken=null"
        "RuntimeVersion"="v4.0.30319"
        "CodeBase"="file:///C:/P/Zeta Producer/13/Zeta Producer Main/Bin/Applications/ZetaProducer.SuperSlimScriptingEngineProfiler.dll"

        [HKEY_CLASSES_ROOT\CLSID\{1C406FBA-59EF-4FB2-938C-C1DA182D5914}\ProgId]
        @="ZetaProducer.SuperSlimScriptingEngineProfiler.SlimScriptEngineProfilerCallback"

        [HKEY_CLASSES_ROOT\CLSID\{1C406FBA-59EF-4FB2-938C-C1DA182D5914}\Implemented Categories\{62C8FE65-4EBB-45E7-B440-6E39B2CDBF29}]
        */

        /*
        Siehe http://www.hexacorn.com/blog/2014/04/27/beyond-good-ol-run-key-part-11/:

        [HKEY_CURRENT_USER\Environment]
        "JS_PROFILER"="{1C406FBA-59EF-4FB2-938C-C1DA182D5914}"
         */

        public static void Register()
        {
            // Achtung vor dem Wow6432Node-Schlüssel.
            // https://stackru.com/questions/2039186/reading-the-registry-and-wow6432node-key
            var views = new[]
            {
                RegistryView.Registry32,
                RegistryView.Registry64
            };

            foreach (var registryView in views)
            {
                var key = checkCreateKey(
                    registryView,
                    @"Software\Classes\ZetaProducer.SuperSlimScriptingEngineProfiler.SlimScriptEngineProfilerCallback");
                if (key != null)
                {
                    key.SetValue(null,
                        @"ZetaProducer.SuperSlimScriptingEngineProfiler.SlimScriptEngineProfilerCallback",
                        RegistryValueKind.String);
                    key.Close();
                }

                key = checkCreateKey(
                    registryView,
                    @"Software\Classes\ZetaProducer.SuperSlimScriptingEngineProfiler.SlimScriptEngineProfilerCallback\CLSID");
                if (key != null)
                {
                    key.SetValue(null, $@"{{{ClsidString}}}", RegistryValueKind.String);
                    key.Close();
                }

                key = checkCreateKey(
                    registryView,
                    $@"Software\Classes\CLSID\{{{ClsidString}}}");
                if (key != null)
                {
                    key.SetValue(null,
                        @"ZetaProducer.SuperSlimScriptingEngineProfiler.SlimScriptEngineProfilerCallback",
                        RegistryValueKind.String);
                    key.Close();
                }

                key = checkCreateKey(
                    registryView,
                    $@"Software\Classes\CLSID\{{{ClsidString}}}\InprocServer32");
                if (key != null)
                {
                    key.SetValue(null, @"mscoree.dll", RegistryValueKind.String);
                    key.SetValue(@"ThreadingModel", @"Both", RegistryValueKind.String);
                    key.SetValue(@"Class",
                        @"ZetaProducer.SuperSlimScriptingEngineProfiler.SlimScriptEngineProfilerCallback",
                        RegistryValueKind.String);
                    key.SetValue(@"Assembly",
                        @"ZetaProducer.SuperSlimScriptingEngineProfiler, Version=15.0.0.0, Culture=neutral, PublicKeyToken=null",
                        RegistryValueKind.String);
                    key.SetValue(@"RuntimeVersion", @"v4.0.30319", RegistryValueKind.String);
                    key.SetValue(@"CodeBase", getFileUrl(), RegistryValueKind.String);
                    key.Close();
                }

                key = checkCreateKey(
                    registryView,
                    $@"Software\Classes\CLSID\{{{ClsidString}}}\InprocServer32\15.0.0.0");
                if (key != null)
                {
                    key.SetValue(@"Class",
                        @"ZetaProducer.SuperSlimScriptingEngineProfiler.SlimScriptEngineProfilerCallback",
                        RegistryValueKind.String);
                    key.SetValue(@"Assembly",
                        @"ZetaProducer.SuperSlimScriptingEngineProfiler, Version=15.0.0.0, Culture=neutral, PublicKeyToken=null",
                        RegistryValueKind.String);
                    key.SetValue(@"RuntimeVersion", @"v4.0.30319", RegistryValueKind.String);
                    key.SetValue(@"CodeBase", getFileUrl(), RegistryValueKind.String);
                    key.Close();
                }

                key = checkCreateKey(
                    registryView,
                    $@"Software\Classes\CLSID\{{{ClsidString}}}\ProgId");
                if (key != null)
                {
                    key.SetValue(null,
                        @"ZetaProducer.SuperSlimScriptingEngineProfiler.SlimScriptEngineProfilerCallback",
                        RegistryValueKind.String);
                    key.Close();
                }

                // Aus der Dokumentation https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/scripting-articles/cc843609(v=vs.94):
                //
                // The JavaScript language runtime checks the JS_PROFILER environment variable on creation
                // to determine whether profiling should be enabled. If this variable is set to the CLSID
                // of the profiler, the language runtime creates an instance of the profiler COM object,
                // using the value of the variable to determine which profiler to create.

                // Ein Beispiel habe ich hier gefunden:
                // http://www.hexacorn.com/blog/2014/04/27/beyond-good-ol-run-key-part-11/

                key = checkCreateKey(registryView, @"Environment");
                if (key != null)
                {
                    key.SetValue(@"JS_PROFILER", $@"{{{ClsidString}}}", RegistryValueKind.String);
                    key.Close();
                }
            }
        }

        private static string getFileUrl()
        {
            // ReSharper disable once AssignNullToNotNullAttribute
            var filePath = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location),
                @"ZetaProducer.SuperSlimScriptingEngineProfiler.dll");
            return PathHelper.ConvertFilePathToFileUrl(filePath);
        }

        public static void Unregister()
        {
            // Achtung vor dem Wow6432Node-Schlüssel.
            // https://stackru.com/questions/2039186/reading-the-registry-and-wow6432node-key
            var views = new[]
            {
                RegistryView.Registry32,
                RegistryView.Registry64
            };

            foreach (var registryView in views)
            {
                var baseKey = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, registryView);

                var key = baseKey.OpenSubKey(@"Software\Classes", true);

                if (key != null &&
                    new List<string>(key.GetSubKeyNames()).Contains(
                        @"ZetaProducer.SuperSlimScriptingEngineProfiler.SlimScriptEngineProfilerCallback"))
                {
                    try
                    {
                        key.DeleteSubKeyTree(
                            @"ZetaProducer.SuperSlimScriptingEngineProfiler.SlimScriptEngineProfilerCallback", false);
                    }
                    catch (AccessViolationException)
                    {
                    }

                    key.Close();
                }

                key = baseKey.OpenSubKey(@"Software\Classes\CLSID", true);

                if (key != null &&
                    new List<string>(key.GetSubKeyNames()).Contains($@"{{{ClsidString}}}"))
                {
                    try
                    {
                        key.DeleteSubKeyTree($@"{{{ClsidString}}}", false);
                    }
                    catch (AccessViolationException)
                    {
                    }

                    key.Close();
                }

                key = baseKey.OpenSubKey(@"Environment", true);
                if (key != null)
                {
                    key.DeleteValue(@"JS_PROFILER", false);
                    key.Close();
                }
            }
        }

        private static RegistryKey checkCreateKey(RegistryView registryView, string keyPath)
        {
            // Achtung vor dem Wow6432Node-Schlüssel.
            // https://stackru.com/questions/2039186/reading-the-registry-and-wow6432node-key

            var rs = new RegistrySecurity();

            // Jeder.
            var user = new SecurityIdentifier(WellKnownSidType.WorldSid, null);

            rs.AddAccessRule(
                new RegistryAccessRule(
                    user,
                    RegistryRights.FullControl,
                    InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit,
                    PropagationFlags.None,
                    AccessControlType.Allow));

            var key = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, registryView)
                .CreateSubKey(
                    keyPath,
                    RegistryKeyPermissionCheck.ReadWriteSubTree,
                    rs);

            return key;
        }
    }
}

Обновление июль 2018

Я снова получил первоначальную ошибку на моей машине для разработки при запуске непосредственно из Visual Studio 2017:

Класс не зарегистрирован (Исключение из HRESULT: 0x80040154 (REGDB_E_CLASSNOTREG))

После некоторых попыток и ошибок я понял, что это связано с тем, что я настроил Visual Studio на постоянную работу от имени администратора.

Когда вы начинаете из этого контекста, кажется, что-то что-то идет не так. Я до сих пор не знаю, что именно.

Решением для этого было просто запустить мой исполняемый файл прямо из проводника Windows, а не из Visual Studio.

Другое возможное решение (которое я не пробовал) должно состоять в том, чтобы не запускать Visual Studio от имени администратора.

Другие вопросы по тегам