Форум программистов, компьютерный форум, киберфорум
edmonsur
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  

VB.NET Динамическая загрузка WebView2 контрола в ваш проект (часть 2)

Запись от edmonsur размещена 10.10.2025 в 04:06
Показов 4805 Комментарии 2

часть 1

В первой части мы уже создали структуру директорий и распаковали туда наши зависимости

Теперь приступаем к их динамической загрузке

Мы имеем 3 файла, два это управляемые сборки "Microsoft.Web.WebView2.Core.dll" "Microsoft.Web.WebView2.WinForms.dll "
и одна нативная "WebView2Loader.dll" неуправляемая. По этому загружать их в проект будем по разному.

Для этого добавим в наш класс DynamicWebView2Loader приватный класс "NativeMethods" с двумя нативными методами Windows API


VB.NET
1
2
3
4
5
6
7
8
9
    Private Class NativeMethods
        <DllImport("kernel32.dll", CharSet:=CharSet.Unicode, SetLastError:=True)>
        Public Shared Function AddDllDirectory(path As String) As IntPtr
        End Function
 
        <DllImport("kernel32.dll", CharSet:=CharSet.Unicode, SetLastError:=True)>
        Public Shared Function LoadLibrary(lpFileName As String) As IntPtr
        End Function
    End Class
Так же напишем метод регистрации для библиотек... "AutoReg" и вызовем его в процедуре "New" после остального кода

' Загружает нативные и управляемые библиотеки WebView2
VB.NET
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
   Private Sub AutoReg()
       ' Загрузка нативной DLL через Windows API
 
 
       Dim result As IntPtr = NativeMethods.AddDllDirectory(Path.GetDirectoryName(LibFiles(2)))
 
       If result = IntPtr.Zero Then
           Dim errorCode = Marshal.GetLastWin32Error()
           ShowCriticalError($"Ошибка AddDllDirectory: код ошибки {errorCode}")
       End If
 
       Dim libraryHandle As IntPtr = NativeMethods.LoadLibrary(LibFiles(2))
 
       If libraryHandle = IntPtr.Zero Then
           Dim errorCode = Marshal.GetLastWin32Error()
           ShowCriticalError($"Ошибка LoadLibrary: код ошибки {errorCode}")
       End If
 
       ' Загрузка управляемых сборок через Reflection
 
       CoreAssembly = Assembly.LoadFrom(LibFiles(0))
       If CoreAssembly Is Nothing Then
           ShowCriticalError("Сборка WebView2 Core не загружена")
       End If
 
       WinFormsAssembly = Assembly.LoadFrom(LibFiles(1))
       If WinFormsAssembly Is Nothing Then
           ShowCriticalError("Сборка WebView2 WinForms не загружена")
       End If
 
   End Sub
Так же нам понадобятся два новых приватных поля
VB.NET
1
2
    Public CoreAssembly As Assembly
    Public WinFormsAssembly As Assembly

на данном этапе проект будет выглядит так


VB.NET
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
Imports System.IO
Imports System.IO.Compression
Imports System.Reflection
Imports System.Runtime.InteropServices
 
Public Class DynamicWebView2Loader
    Private ReadOnly isDevelopment As Boolean = True
 
    Private LibFiles As String() ' это сгенерированный массив в котором хранятся   прямые ссылки на файлы зависимостей
 
    Public CoreAssembly As Assembly
 
    Public WinFormsAssembly As Assembly
    Private Sub ShowCriticalError(message As String, Optional ex As Exception = Nothing)
        Dim errorMessage As String
        If isDevelopment Then
            errorMessage = $"{message}{vbCrLf}{If(ex IsNot Nothing, "Детали: " & ex.ToString(), "Детали отсутствуют")}"
        Else
            errorMessage = $"Дальнейшее выполнение программы невозможно.{vbCrLf}Обратитесь в службу поддержки."
        End If
 
        MessageBox.Show(errorMessage, "Критическая ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error)
        Application.Exit()
    End Sub
 
    Public Sub New()
        ' приступаем к формированию ссылок 
 
        Dim resName As String = NameOf(My.Resources._2_1_0_3537_50).TrimStart("_"c).Replace("_"c, "."c) ' так только ленивые делают, вроде меня;) 
        Dim libDir As String = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), Me.GetType().Name)
        Dim verDir As String = libDir & Path.DirectorySeparatorChar & resName
        Dim ldrDir As String = Path.Combine(verDir, "runtimes", "win-x86", "native")
        '  ссылки на папки сформированы... пора их создать, если они конечно ещё не существуют
        Directory.CreateDirectory(libDir)
        Directory.CreateDirectory(verDir)
 
        LibFiles = {
                Path.Combine(verDir, "Microsoft.Web.WebView2.Core.dll"),
                Path.Combine(verDir, "Microsoft.Web.WebView2.WinForms.dll"),
                Path.Combine(ldrDir, "WebView2Loader.dll")}
        ' проверим и если файлы не сушествуют... распаковываем их из ресурсов 
        If Not FilesExist(LibFiles) Then
            Extract(verDir, My.Resources._2_1_0_3537_50)
        End If
        AutoReg()
    End Sub
 
 
 
    Private Function FilesExist(stringmassive As String()) As Boolean
        Try
            Return stringmassive.All(Function(f) File.Exists(f))
        Catch ex As Exception
            Return False
        End Try
    End Function
 
 
    Private Sub Extract(destinationDirectoryName As String, buffer As Byte())
        Try
            Using archive = New ZipArchive(New MemoryStream(buffer), ZipArchiveMode.Read)
                archive.ExtractToDirectory(destinationDirectoryName)
            End Using
        Catch ex As Exception
            ShowCriticalError("Ошибка распаковки", ex)
        End Try
    End Sub
    Private Class NativeMethods
        <DllImport("kernel32.dll", CharSet:=CharSet.Unicode, SetLastError:=True)>
        Public Shared Function AddDllDirectory(path As String) As IntPtr
        End Function
 
        <DllImport("kernel32.dll", CharSet:=CharSet.Unicode, SetLastError:=True)>
        Public Shared Function LoadLibrary(lpFileName As String) As IntPtr
        End Function
    End Class
 
    Private Sub AutoReg()
        ' Загрузка нативной DLL через Windows API
 
 
        Dim result As IntPtr = NativeMethods.AddDllDirectory(Path.GetDirectoryName(LibFiles(2)))
 
        If result = IntPtr.Zero Then
            Dim errorCode = Marshal.GetLastWin32Error()
            ShowCriticalError($"Ошибка AddDllDirectory: код ошибки {errorCode}")
        End If
 
        Dim libraryHandle As IntPtr = NativeMethods.LoadLibrary(LibFiles(2))
 
        If libraryHandle = IntPtr.Zero Then
            Dim errorCode = Marshal.GetLastWin32Error()
            ShowCriticalError($"Ошибка LoadLibrary: код ошибки {errorCode}")
        End If
 
        ' Загрузка управляемых сборок через Reflection
 
        CoreAssembly = Assembly.LoadFrom(LibFiles(0))
        If CoreAssembly Is Nothing Then
            ShowCriticalError("Сборка WebView2 Core не загружена")
        End If
 
        WinFormsAssembly = Assembly.LoadFrom(LibFiles(1))
        If WinFormsAssembly Is Nothing Then
            ShowCriticalError("Сборка WebView2 WinForms не загружена")
        End If
 
    End Sub
End Class
запустим наш проект и посмотри... возникнут ошибки или нет... если нет.. приступаем к созданию WebView2 контрола

Для этого создадим два новых приватных поля

VB.NET
1
2
Public webView2Type As Type
Public WebView2Control
и напишем процедуру для создания WebView2 контрола "CreateWebView2Control" и вызовем её в процедуре "New"


VB.NET
1
2
3
4
5
6
7
8
9
10
11
12
13
14
    Private Sub CreateWebView2Control()
 
        ' Получаем тип WebView2 контрола из сборки WinForms
        webView2Type = WinFormsAssembly.GetType("Microsoft.Web.WebView2.WinForms.WebView2", True)
        If webView2Type Is Nothing Then
            ShowCriticalError("Не удалось получить тип WebView2 контрола из сборки")
        End If
 
        ' Создаем экземпляр контрола через рефлексию
        WebView2Control = CType(Activator.CreateInstance(webView2Type), Control)
        If WebView2Control Is Nothing Then
            ShowCriticalError("Не удалось создать экземпляр WebView2 контрола")
        End If
    End Sub
Запускаем проект и если нет ошибок продолжаем...
Напишем публичную асинхронную функцию "InitializeWebView2Async" для инициализации среды WebView2
Напишем публичную процедуру "Navigate"

VB.NET
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
   Public Async Function InitializeWebView2Async() As Task
        Try
            ' Создаем среду выполнения WebView2
            Dim environmentType = CoreAssembly.GetType("Microsoft.Web.WebView2.Core.CoreWebView2Environment")
            If environmentType Is Nothing Then
                ShowCriticalError("Не удалось найти тип CoreWebView2Environment")
            End If
 
            ' Ищем метод CreateAsync для асинхронного создания среды
            Dim createAsyncMethod = (From m In environmentType.GetMethods(BindingFlags.Public Or BindingFlags.Static)
                                     Where m.Name = "CreateAsync" AndAlso m.GetParameters().Length = 3
                                     Select m).FirstOrDefault()
 
            If createAsyncMethod Is Nothing Then
                ShowCriticalError("Метод CreateAsync не найден в CoreWebView2Environment")
            End If
 
            ' Создаем временную директорию для кэша WebView2
 
            Dim _appCachePath = Path.Combine(Path.GetTempPath(), "WebView2App")
 
 
 
            Directory.CreateDirectory(_appCachePath)
 
            ' Асинхронно создаем среду выполнения
            Dim createTask = CType(createAsyncMethod.Invoke(Nothing, New Object() {Nothing, _appCachePath, Nothing}), Task)
 
            ' Проверка создания задачи
            If createTask Is Nothing Then
                ShowCriticalError("CreateAsync не вернул задачу")
            End If
 
            Await createTask
 
            Dim environment = createTask.GetType().GetProperty("Result").GetValue(createTask)
 
            ' Проверка результата
            If environment Is Nothing Then
                ShowCriticalError("Среда выполнения WebView2 не была создана")
            End If
 
            ' Теперь инициализируем CoreWebView2 контрола с созданной средой
            Dim ensureMethod = webView2Type.GetMethod("EnsureCoreWebView2Async",
            BindingFlags.Public Or BindingFlags.Instance,
            Nothing,
            New Type() {environmentType},
            Nothing)
 
            If ensureMethod Is Nothing Then
                ShowCriticalError("Метод EnsureCoreWebView2Async не найден")
            End If
 
            Dim ensureTask = CType(ensureMethod.Invoke(WebView2Control, New Object() {environment}), Task)
            Await ensureTask
 
 
 
 
        Catch ex As Exception
            ShowCriticalError("Ошибка инициализации WebView2:", ex)
 
        End Try
 
    End Function
 
    ' Выполняет навигацию к указанному URL
    Public Sub Navigate(url As String)
        Try
            Dim sourceProp = webView2Type.GetProperty("Source")
            If sourceProp Is Nothing Then
                ShowCriticalError("Свойство Source не найдено в WebView2 контроле")
            End If
 
            sourceProp.SetValue(WebView2Control, New Uri(url))
 
        Catch ex As Exception
            ShowCriticalError($"Ошибка навигации в WebView2", ex)
        End Try
    End Sub
Затем подправим код Form1

VB.NET
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Public Class Form1
    Private Browser As DynamicWebView2Loader
 
    Public Sub New()
 
        ' Dieser Aufruf ist für den Designer erforderlich.
        InitializeComponent()
 
        ' Fügen Sie Initialisierungen nach dem InitializeComponent()-Aufruf hinzu.
 
        Browser = New DynamicWebView2Loader
        Me.Controls.Add(Browser.WebView2Control)
        Browser.WebView2Control.Dock = DockStyle.Fill
    End Sub
 
    Private Async Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
 
        Await Browser.InitializeWebView2Async
        Browser.Navigate("https://www.cyberforum.ru/blogs/1794766/10620.html")
    End Sub
End Class

запускаем наш проект... всё получилось и работает. Конечно класс DynamicWebView2Loader нужно ещё доработать, но фундамент уже есть. Полный код лежит в вложениях... дерзайте
Вложения
Тип файла: zip Resources.zip (733.5 Кб, 182 просмотров)
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Всего комментариев 2
Комментарии
  1. Старый комментарий
    Аватар для Yury Komar
    А зачем распаковывать dll-ки, если можно вытянуть прямо в памяти нужную сборку в массив байт и передать этот массив в Assembly.Load? И никакие WinAPI нам тут не потребуются.
    Запись от Yury Komar размещена 20.10.2025 в 09:18 Yury Komar вне форума
  2. Старый комментарий
    Yury Komar
    Я пробовал это... такая задумка промелькнула в моей голове ... проблема заключается в неуправляемой сборке WebView2Loader.dll ...она тупо не хочет находиться, что приводит к ошибке. Для нативных библиотек этот метод не подходит. Хотя не исключаю что мой подход мог оказаться не правильным. Скажу, что я не остановился на достигнутом и уже разработал другой вариант, более удобный и надёжный не нуждающийся в таком количестве кода. Всё работает и довольно хорошо..всё нужные сборки с собой и при необходимости будут распакованы. Найдено идеальное решение для автоматического подключение их к проекту. Довёл всё до полного автоматизма.
    Запись от edmonsur размещена 04.11.2025 в 16:00 edmonsur вне форума
 
Новые блоги и статьи
Был там один разговор по поводу свободы в материальном мире.
kumehtar 19.08.2026
Суть: рассматривается живое существо, оказавшееся внутри довольно странной системы (этого мира) и пытающееся обустроить в ней свой кусок пространства. Жизнь действительно предъявляет каждому. . .
Когда логика программы не спасает от человеческих ошибок
Maks 18.08.2026
В последнее время всё чаще и чаще сталкиваюсь с таким явлением, как абсолютная невнимательность (или глупость) пользователей. Проявляется это чаще всего на работе в коллективе. Допустим, человек с. . .
Лето уходит
kumehtar 17.08.2026
Мысли в слух
kumehtar 17.08.2026
Забавно, насколько сейчас стала доступна информация. Например о магии, духовном развитии, медитациях, и других подобных направлениях, ранее зачастую тайных, передаваемых от учителя к ученику. Хотя. . .
Перемещение строк из ТЧ в другой документ с учетом текущего пробега
Maks 17.08.2026
Реализация из решения ниже выполнена на примере нетипового документа "Автозапчасти", с ТЧ "Шины". За основу взят алгоритм отсюда: https:/ / www. cyberforum. ru/ blogs/ 359708/ 10838. html Задача: . . .
Саморегулирующийся социальный контракт для сервера cross-section.
Hrethgir 14.08.2026
С кодом конечно таких глубоких размышлений пока не было, впрочем я уже привык к алгоритмизации. Суть предмета записи: снова в диалоге с нейросетью (я взял пока себе ник для учётки админа - Rector). . . .
Часы электронные
Uhbif79 12.08.2026
Выкладываю программу часов. Программа позволяет: 1. Использовать системное время и дату, 2. Есть возможность вводить время и дату вручную. 3. Реализованы 2 будильника: начало и конец рабочего дня. . . .
Часы с будильником на основе класса QLCDNumber
Uhbif79 12.08.2026
Всем добрый день, выкладываю программу часов с будильником на основе класса QLCDNumber. Здесь я пробовал самостоятельно создавал классы, впервые столкнулся с видимостью переменной одного класса из. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru