.NET 8 подвергается воздействию VB6 с использованием COM

.NET 8 подвергается воздействию VB6 с использованием COM

Проблема

У нас есть большое приложение с большим количеством кода графического интерфейса на VB6 и логикой, в основном, в библиотеках .NET Framework 4.7.2. Теперь мы хотим перейти на .NET 8 и испытываем трудности с доступом к библиотекам VB6 с помощью COM:

  1. Set oObject = Новый COMObject не работает (класс пуст в браузере объектов VB6)
  2. События не раскрываются

Обе проблемы, похоже, связаны с предоставлением классов с атрибутом [ClassInterface(ClassInterfaceType.AutoDual)].

Мы используем dscom32 (tlbexport/tlbregister) и знаем CA1408.

Как нам преодолеть наши проблемы (1 и 2), не переписывая много кода VB6 небезопасным с точки зрения типов способом и не создавая дополнительный уровень .NET Framework 4.7.2?

Файл проекта .NET 8

<Project Sdk = "Microsoft.NET.Sdk">

    <PropertyGroup>
        <TargetFramework>net8.0</TargetFramework>
        <EnableComHosting>True</EnableComHosting>
        <PlatformTarget>x86</PlatformTarget>
    </PropertyGroup>

    <Target Name = "ServerUsage" AfterTargets = "Build">
        <Message Importance = "High" Text = "Register:%0a    regsvr32.exe &quot;$(ProjectDir)$(OutputPath)$(ComHostFileName)&quot;" />
        <Message Importance = "High" Text = "Unregister:%0a    regsvr32.exe /u &quot;$(ProjectDir)$(OutputPath)$(ComHostFileName)&quot;" />
    </Target>

</Project>

Код .NET 8

using System.Runtime.InteropServices;

namespace TestCOM
{
    [ComVisible(true)]
    [Guid("A5447236-9520-4596-B4C6-D40175EBDA10")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface ITestCOM
    {
        string GetString();
    }

    [ComVisible(true)]
    [Guid("3FCD4A46-F73D-495F-9DE3-85D50924ED06")]
    //[ClassInterface(ClassInterfaceType.AutoDual)]
    public class TestCOM : ITestCOM
    {
        string ITestCOM.GetString() => "Test";
    }
}

Код VB6

Sub Main()

    ' This is not working:
    ' Dim oTest As TestCOM
    ' Set oTest = New TestCOM
    '
    ' Requires ClassInterfaceType.AutoDual
    '
    ' dscom32 tlbexport "%cd%\Test.dll"
    ' -> Failed to export type library. Dual class interfaces not supported!
    
    ' This is working:
    Dim oTest As ITestCOM
    Set oTest = CreateObject("TestCOM.TestCOM")
    Debug.Print oTest.GetString()

End Sub

Новый кодекс по мотивам Севы Алексеева

Обе проблемы теперь решены для меня.

Код .NET 8

using System;
using System.Runtime.InteropServices;

namespace TestCOM
{
    internal delegate void OnGetStringCOM(EventArgsCOM args);

    [ComVisible(true)]
    [Guid("E6BCA6A0-70F3-4218-B344-3632F638D51A")]
    [InterfaceType(ComInterfaceType.InterfaceIsDual)]
    public interface IEventArgsCOM
    {
        string Message { get; set; }
    }

    [ComVisible(true)]
    [Guid("77414A17-1CA5-4E45-940E-F26C8F50BE3E")]
    [ClassInterface(ClassInterfaceType.None)]
    public class EventArgsCOM(string message) : EventArgs, IEventArgsCOM
    {
        public string Message { get; set; } = message;
    }

    [ComVisible(true)]
    [Guid("891E4AFB-8CD3-4611-80F6-F3AC755EF3B4")]
    [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
    public interface ITestCOMEvents
    {
        [DispId(1)]
        void OnGetStringCOM(EventArgsCOM args);
    }

    [ComVisible(true)]
    [Guid("A5447236-9520-4596-B4C6-D40175EBDA10")]
    [InterfaceType(ComInterfaceType.InterfaceIsDual)]
    public interface ITestCOM
    {
        string GetString();
    }

    [ComVisible(true)]
    [Guid("3FCD4A46-F73D-495F-9DE3-85D50924ED06")]
    [ClassInterface(ClassInterfaceType.None)]
    [ComSourceInterfaces(typeof(ITestCOMEvents))]
    public class TestCOM : ITestCOM
    {
        private event OnGetStringCOM OnGetStringCOM;

        public string GetString()
        {
            OnGetStringCOM?.Invoke(new EventArgsCOM("test raised"));
            return "test returned";
        }
    }
}

Код VB6

Private WithEvents moTest As Test.TestCOM

Private Sub Class_Initialize()

    Set moTest = New TestCOM
    
End Sub

Public Function PrintString()

    Debug.Print moTest.GetString()
    ' test returned

End Function

Private Sub moTest_OnGetStringCOM(ByVal args As Test.IEventArgsCOM)

    Debug.Print args.Message
    ' test raised
    
End Sub

Вам определенно не понадобится .NET Framework, чтобы заставить VB6 взаимодействовать с .NET 8. Есть ли у вас где-нибудь полностью воспроизводимый компилируемый проект, чтобы мы не теряли время на детали?

Simon Mourier 03.04.2024 14:46

VB6 — это Visual Basic 2006 до того, как Net Library объединила Visual Basic и C# в одну библиотеку Net 3.0. Microsoft попыталась сделать Active X устаревшим. Поэтому любой объект Active X вам приходилось регистрировать вручную с помощью Regsrv32.

jdweng 03.04.2024 14:51

Microsoft пыталась устаревшие компоненты ActiveX, начиная с VB5 (~ 2005 г.). Microsoft заменяла Win95 на XP, а также готовилась к выпуску Net 3.0 (быстро замененной на Net 3.5 из-за большого количества ошибок). На работе мы попытались обновить Win95 до XP и обнаружили, что ActiveX не работает. У нас был элемент управления счетчиком ActiveX, а в Net не было эквивалентного объекта. Мы нашли решение — вручную установить библиотеки ActiveX с помощью Regsrv32.

jdweng 03.04.2024 15:52

@jdweng Я думаю, у тебя там какие-то даты перепутаны. VB5 был выпущен в 1997 году и в значительной степени поддерживал ActiveX. VB6 был выпущен в 1998 году. .NET 3.0 был выпущен в 2006 году, через много лет после XP, который был в 2001 году. ActiveX все еще работает в Windows 11, если вы действительно этого хотите. В 2006 году не было версии VB.NET, была версия 2005 года, которая также называлась VB8.

Charlieface 04.04.2024 01:05

По моему опыту, нет ничего плохого в использовании AutoDual, если вы сами используете библиотеки. Если вы всегда перестраиваете клиент и сервер вместе, используйте AutoDual и облегчите себе жизнь. Я говорю из .NET framework.experience, я не пробовал dscom.

StayOnTarget 04.04.2024 13:19

Является ли проблема использованием regsvr32? В .NET framework вы никогда не сможете этого сделать — вместо этого это сделали VS или msbuild. Если dscom создает файлы .TLB, вам следует ссылаться на файлы из VB6 (а не на библиотеки DLL). Однако я не уверен, что делает dscom для регистрации классов, указанных в TLB?

StayOnTarget 04.04.2024 13:23

Кажется, dscom не поддерживает AutoDual - github.com/dspace-group/dscom?tab=readme-ov-file#limitations

StayOnTarget 04.04.2024 13:29

И вместо regsvr32, похоже, вам следует использовать команду dscom tlbregister. github.com/dspace-group/dscom?tab=readme-ov-file#usage

StayOnTarget 04.04.2024 13:31
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
5
8
287
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Попробуйте аннотировать класс (не интерфейс!) с помощью [ClassInterface(ClassInterfaceType.None)]. Вы не хотите, чтобы .NET также автоматически генерировал COM-интерфейс для класса — это будет мешать.

Для интерфейса попробуйте [InterfaceType(ComInterfaceType.InterfaceIsDual)] или InterfaceIsIDispatch. Я не помню, может ли VB6 использовать пользовательские (т. е. не производные от IDispatch) интерфейсы, но автоматизация на основе IDispatch всегда была родным режимом работы Visual Basic.

Затем перестройте, а затем восстановите ссылку из проекта VB. Я не думаю, что VB6 улавливает изменения библиотеки типов при сборке.

существует два типа объектов: 1) Раннее связывание 2) Позднее связывание. Объект раннего связывания разрешается во время компиляции. Объект позднего связывания разрешается во время выполнения. Решение выглядит так, будто оно использует позднее связывание. Использование Regsrv32 будет использовать раннее связывание и создание объектов Com библиотек, которые можно будет скомпилировать в проект.

jdweng 04.04.2024 21:17

Кстати, VB6 может использовать пользовательские производные интерфейсы IUnknown.

wqw 10.04.2024 14:04

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