Итак, есть класс. Сериализуемый.
Поначалу он был включен в состав exe, но потом выяснилось следующее: в файле данных, куда записывается сериализованный класс, имеется заголовок, содержащий имя корневого пространства имен и класса в нем.
Так вот тогда получается, что десеализовать класс можно только той же программой, что и сериализовали. Нашел решение в сети - класс, подлежащий сериализации, собрать в отдельной DLL, которую потом прицепляем к нужной программе. Проблем нет: разные exe без проблем десерализуют файл созданный не ими, но одной и той же DLL.
Проблема вот в чем: понадобилось мне эту dll с сериализуемым классом прикрутить к надстройке для Excel (надстройка выполнена в виде dll). С сериализацией проблем нет - все записывается в файи и нормально десериализуется затем другой программой (заголовок с атрибутами сборки и класса тот что надо). А вот с десериализацией из этой же надстройки ничего не пашет - вываливается сообщение, что искомая сборка (та, в которой описан сериализуемый класс) не найдена среди загруженный. Проверял, веть у нас есть возможность через
My.Application.Info.LoadedAssemblies в надстройке excel получить коллекцию загруженных сборок и увидеть их имена. Нужная сборка именно та, что вроде как не найдена, там есть.
Вопрос: кто сталкивался с таким, как решал?
Вот код сериализуемого класса:
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
| Imports System.Runtime.Serialization
<Serializable()> Public Class AccessInfo
Implements ISerializable
Dim ClientCount As Integer
Dim User As String
Dim Password As String
Dim ConnString As String
Public Property ConnectionCount() As Integer
Get
Return ClientCount
End Get
Set(ByVal value As Integer)
ClientCount = value
End Set
End Property
Public Property ConnectedUser() As String
Get
Return User
End Get
Set(ByVal value As String)
User = value
End Set
End Property
Public Property ConnectedPassword() As String
Get
Return Password
End Get
Set(ByVal value As String)
Password = value
End Set
End Property
Public Property ConnectionString() As String
Get
Return ConnString
End Get
Set(ByVal value As String)
ConnString = value
End Set
End Property
Public Sub GetObjectData(ByVal info As SerializationInfo, ByVal context As StreamingContext) Implements ISerializable.GetObjectData
info.AddValue("ClientCount", ClientCount)
info.AddValue("User", User)
info.AddValue("Password", Password)
info.AddValue("ConnString", ConnString)
End Sub
Public Overrides Function ToString() As String
Return "Connections Count = " & ClientCount & vbCrLf & "ConnectionString: " & ConnString
End Function
Public Sub New()
' метод по-умолчанию
End Sub
Public Sub New(ByVal info As SerializationInfo, ByVal context As StreamingContext)
ClientCount = info.GetInt32("ClientCount")
User = info.GetString("User")
Password = info.GetString("Password")
ConnString = info.GetString("ConnString")
End Sub
End Class |
|
Вот его вызовы для сериализации и обратно (уже в одной из форм надстройки, и аналогично из других exe):
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
110
111
112
113
| Imports System.Runtime.Serialization
Public Class frmMain
Private inFileName As String = My.Computer.FileSystem.SpecialDirectories.Temp & "\SvetichAccess.bin"
Private AccessInfoString As String
Dim oldInfo As AccessCLS.AccessInfo
Private Sub GetFromFile()
On Error Resume Next
Dim inFile As IO.FileStream
Dim formatter As Formatters.Binary.BinaryFormatter
If Not IO.File.Exists(inFileName) Then
AccessInfoString = "Нет активных компонентов!"
Else
inFile = New IO.FileStream(inFileName, IO.FileMode.Open)
formatter = New Formatters.Binary.BinaryFormatter
formatter.AssemblyFormat = Formatters.FormatterAssemblyStyle.Simple
oldInfo = CType(formatter.Deserialize(inFile), AccessCLS.AccessInfo)
inFile.Close()
AccessInfoString = "Подключено компонентов: " & oldInfo.ConnectionCount & vbCrLf & "Пользователь: " & oldInfo.ConnectedUser
End If
Me.Drawinfo()
My.Application.inFileNameApp = Me.inFileName
Me.NotifyIcon1.Text = AccessInfoString
End Sub
Private Sub Drawinfo()
Dim tbmp As Bitmap = New Bitmap(Me.ClientRectangle.Width, Me.ClientRectangle.Height, Imaging.PixelFormat.Format32bppArgb)
Dim gr As Graphics = Graphics.FromImage(tbmp)
Dim sf As StringFormat = New StringFormat
sf.Alignment = StringAlignment.Center
sf.LineAlignment = StringAlignment.Center
gr.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
gr.TextRenderingHint = Drawing.Text.TextRenderingHint.AntiAliasGridFit
gr.DrawString(Me.AccessInfoString, New Font(Me.Font, FontStyle.Underline), Brushes.Blue, Me.ClientRectangle.Width / 2, Me.ClientRectangle.Height / 2, sf)
Me.BackgroundImage = tbmp
End Sub
Private Sub frmMain_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Click
Me.GetFromFile()
End Sub
Private Sub frmMain_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Me.GetFromFile()
With Me.fswWatch
.Path = IO.Path.GetDirectoryName(inFileName)
.IncludeSubdirectories = False
.Filter = "SvetichAccess.bin"
.EnableRaisingEvents = True
End With
End Sub
Private Sub frmMain_FormClosing(ByVal sender As System.Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles MyBase.FormClosing
If e.CloseReason = CloseReason.UserClosing Then
e.Cancel = True
Dim p As Point = New Point(-Me.Bounds.Width - 100, -Me.Bounds.Height - 100)
Me.WindowState = FormWindowState.Minimized
Me.Location = p
Me.WindowState = FormWindowState.Normal
End If
End Sub
Private Sub tsmiShow_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tsmiShow.Click
Dim p As Point = New Point(Screen.PrimaryScreen.WorkingArea.Width - Me.Bounds.Width, Screen.PrimaryScreen.WorkingArea.Height - Me.Bounds.Height)
Me.Location = p
End Sub
Private Sub tsmiQuit_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles tsmiQuit.Click
Global.System.Windows.Forms.Application.Exit()
End Sub
Private Sub NotifyIcon1_DoubleClick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles NotifyIcon1.DoubleClick
Dim p As Point = New Point(Screen.PrimaryScreen.WorkingArea.Width - Me.Bounds.Width, Screen.PrimaryScreen.WorkingArea.Height - Me.Bounds.Height)
Me.Location = p
End Sub
Private Sub fswWatch_Changed(ByVal sender As System.Object, ByVal e As System.IO.FileSystemEventArgs) Handles fswWatch.Changed, fswWatch.Created, fswWatch.Deleted
Me.GetFromFile()
Me.CheckEmpty()
Me.GetFromFile()
End Sub
Private Sub CheckEmpty()
On Error Resume Next
If oldInfo.ConnectionCount < 1 Then
IO.File.Delete(inFileName)
End If
End Sub
Private Sub SaveToFile()
If oldInfo Is Nothing Then
oldInfo = New AccessCLS.AccessInfo
oldInfo.ConnectionCount = 0
oldInfo.ConnectedUser = "User1"
oldInfo.ConnectedPassword = "Password1"
oldInfo.ConnectionString = "ConnectionString1"
End If
' ----- Serialize an employee object to a file.
Dim formatter As Formatters.Binary.BinaryFormatter
Dim outFile As IO.FileStream
' ----- Open the data file for storage.
outFile = New IO.FileStream(inFileName, IO.FileMode.Create)
' ----- Send the employee to the stream through
' a binary serialization formatter.
formatter = New Formatters.Binary.BinaryFormatter
formatter.Serialize(outFile, oldInfo)
' ----- Finished.
outFile.Close()
End Sub
End Class |
|