Модератор
Эксперт .NET
 Аватар для Yury Komar
4356 / 3426 / 512
Регистрация: 27.01.2014
Сообщений: 6,257

Готовые решения и полезные коды на Visual Basic .NET (Часть-2)

26.08.2021, 13:11. Показов 25267. Ответов 42

Студворк — интернет-сервис помощи студентам
Данная тема является продолжение одноимённой темы
Готовые решения и полезные коды на Visual Basic .NET (Часть-1)

Предлагаю в этой теме размещать ответы на часто задаваемые вопросы и просто делиться полезными кодами.

Для исходников есть отдельная тема и они будут либо удаляться из этой темы, либо переноситься в соответствующую тему)

Обращаю внимание на некоторые моменты, которые являются дополнением к основным правилам
  1. Запрещается копировать материалы с других сайтов или форумов
  2. Решения должны быть написаны с использованием языка Visual Basic .NET
  3. Запрещено создавать посты с уточнениями и замечаниями. Такие вопросы задавайте на форуме
  4. Код, в котором присутствуют комментарии, читается и понимается намного легче и быстрее
  5. Длинные коды и объемные вопросы одного содержания заключайте в теги [SPОILER]Большой код[/SPОILER]
  6. При создании поста убедитесь, что этот вопрос не был освещен ранее, так же он отсутствует в первой части данной темы
  7. Код должен быть написан грамотно, большие и неэффективные коды будут удаляться
  8. Список вопросов по конкретной теме нельзя "разрывать" на 2 и более поста

Просьба не спешите постить решения "сгоряча", тщательно обдумайте список вопросов, их тематику и порядок.

Перед загрузкой архива на форума настоятельно рекомендуется выполнить шаги по уменьшению его размера:
  1. Удалить из архива служебные папки IDE такие как: .vs, .vscode, .idea;
  2. Удалить из архива папку .git, если вы пользуетесь системой контроля версий;
  3. Удалить из архива папку obj.

Если вы найдете информацию, которой можно было бы дополнить ваши предыдущие сообщения, что-то изменить или перегруппировать, пишите модераторам в л/с.

 Комментарий модератора 
Данные правила обязательны к исполнению в рамках темы
Примечание: Некоторые коды приведены без учета строгой типизации (Параметр Strict), поэтому для их использования необходимо выполнить приведение типов.
2
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
26.08.2021, 13:11
Ответы с готовыми решениями:

Готовые решения и полезные коды на Visual Basic .NET (Часть-1)
Предлагаю в этой теме размещать ответы на часто задаваемые вопросы и просто делиться полезными...

Обсуждение кода из темы "Готовые решения и полезные коды": Функция MeTka
Всем привет. Цель данной темы обсудить код функции MeTka. В первую очередь скажу что моей целью...

Обсуждение "Суммы чисел" из темы "Готовые рещения и полезные коды"
Тема создана для обсуждения кода "Сумма чисел". У меня есть ряд вопросов по коду от Zhivoder....

42
Модератор
Эксперт .NET
 Аватар для Yury Komar
4356 / 3426 / 512
Регистрация: 27.01.2014
Сообщений: 6,257
27.08.2021, 18:44  [ТС]
RSS Feed на Visual Basic .NET

На вход получает URL Feed'a, на выходе DataTable, который можно отобразить в таблице.


Код
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
Function GetRSSFeedTable(URL As String) As DataTable
        Dim rssFeed As HttpWebRequest = DirectCast(WebRequest.Create(URL), HttpWebRequest)
        Dim response = rssFeed.GetResponse()
        Dim rssStream = response.GetResponseStream()
 
        Dim rssDoc As New XmlDocument()
        rssDoc.Load(rssStream)
        Dim rssItems As XmlNodeList = rssDoc.SelectNodes("rss/channel/item")
        Dim i As Integer = 0
        Dim dt As DataTable = New DataTable("table")
        dt.Columns.Add("title", Type.GetType("System.String"))
        dt.Columns.Add("link", Type.GetType("System.String"))
 
        While i < rssItems.Count
            Dim node As XmlNode = rssItems.Item(i).SelectSingleNode("title")
            Dim title As String
            Dim link As String
            If node IsNot Nothing Then
                title = node.InnerText
            Else
                title = ""
            End If
 
            node = rssItems.Item(i).SelectSingleNode("link")
            If node IsNot Nothing Then
                link = node.InnerText
            Else
                link = ""
            End If
            Dim dr As DataRow = dt.NewRow()
            dr("title") = title
            dr("link") = link
 
            dt.Rows.Add(dr)
 
            i += 1
        End While
 
        Return dt
    End Function
Миниатюры
Готовые решения и полезные коды на Visual Basic .NET (Часть-2)  
0
Нарушитель
 Аватар для HACKER KAY
21 / 47 / 5
Регистрация: 03.06.2019
Сообщений: 368
Записей в блоге: 10
28.08.2021, 09:56
Определяем, на какой ОС юзер запустил приложение

Совсем недавно, при разработке кроссплатформенного приложения на Mono мне понадобился код, умеющий отличать Windows/Unix систему. (можно вместо Console использовать MsgBox, при этом добавив ссылку и библиотеку Microsoft.VisualBasic.dll в сборку)

Код был проверен на Windows 7, Windows 10 || WSL Kali, Ubuntu и исправно работает
VB.NET
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    Private Sub WhatTheOS()
        Dim Windows_STR As String = "Приложение запущено на Windows"
        Dim Unix_STR As String = "Это операционная система Unix"
        Dim Err_STR As String = "Не удалось определить ОС"
        Dim GetOSInfo As OperatingSystem = Environment.OSVersion
        Dim pid As PlatformID = GetOSInfo.Platform
 
        Select Case pid
            Case PlatformID.Win32NT, PlatformID.Win32S, PlatformID.Win32Windows, PlatformID.WinCE
                Console.WriteLine(Windows_STR)
            Case PlatformID.Unix
                Console.WriteLine(Unix_STR)
            Case Else
                Console.WriteLine(Err_STR)
        End Select
    End Sub
1
 Аватар для vova2112
147 / 135 / 34
Регистрация: 28.02.2014
Сообщений: 165
25.09.2021, 01:50
ColorEditor для редактирования свойств цвета с поддержкой альфаканала

Код

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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
Imports System.ComponentModel
Imports System.Drawing.Design
Imports System.Reflection
Imports System.Runtime.InteropServices
Imports System.Windows.Forms.Design
 
Public Class ColorEditorEx
    Inherits ColorEditor
 
    Public Overrides Function EditValue(ByVal context As ITypeDescriptorContext, ByVal provider As IServiceProvider, ByVal value As Object) As Object
        If (provider IsNot Nothing) Then
            Dim edSvc As IWindowsFormsEditorService = DirectCast(provider.GetService(GetType(IWindowsFormsEditorService)), IWindowsFormsEditorService)
            If (edSvc IsNot Nothing) Then
                _colorUI = If(_colorUI, New ColorUIWrapper(Me))
                _colorUI.Start(edSvc, value)
                edSvc.DropDownControl(_colorUI.Control)
                _colorUI.SetColor()
                If ((_colorUI.Value <> Nothing) AndAlso (_colorUI.Value <> Color.Empty)) Then
                    value = _colorUI.Value
                End If
                _colorUI.End()
            End If
        End If
        Return value
    End Function
 
    Public Overrides Sub PaintValue(ByVal e As PaintValueEventArgs)
        If TypeOf e.Value Is Color Then
            Dim _color As Color = DirectCast(e.Value, Color)
            If (_color.A < 255) Then
                Dim _Width As Integer = (e.Bounds.Right - e.Bounds.Left) - 2
                Dim _Top As Integer = e.Bounds.Top + 1
                Dim _Bottom As Integer = e.Bounds.Bottom - 1
                Dim _mid As Integer = (_Width \ 3)
                If (_mid * 3) <> _Width Then
                    _mid += 1
                End If
                If _color.IsEmpty Then
                    Using _pen As New Pen(Color.FromArgb(-14145496), 1.0!)
                        e.Graphics.FillRectangle(_pen.Brush, e.Bounds)
                        _pen.Color = Color.Red
                        e.Graphics.DrawLine(_pen, (_mid - 2), _Top, ((_mid * 3) - 1), (_Bottom - 1))
                        e.Graphics.DrawLine(_pen, ((_mid * 3) - 1), _Top, (_mid - 2), (_Bottom - 1))
                    End Using
                Else
                    Using _pen As New Pen(Color.WhiteSmoke, CSng(_mid))
                        e.Graphics.DrawLine(_pen, (_mid - 1), _Top, (_mid - 1), _Bottom)
                        _pen.Color = Color.FromArgb(-14145496) ' Color.FromArgb(255, 40, 40, 40)
                        e.Graphics.DrawLine(_pen, ((_mid * 3) - 1), _Top, ((_mid * 3) - 1), _Bottom)
                        _pen.Color = Color.DarkGray
                        e.Graphics.DrawLine(_pen, ((_mid * 2) - 1), _Top, ((_mid * 2) - 1), _Bottom)
                    End Using
                End If
            End If
            Using _pen As New Pen(_color)
                e.Graphics.FillRectangle(_pen.Brush, e.Bounds)
            End Using
        End If
    End Sub
 
    Private _colorUI As ColorUIWrapper
 
    Private Class ColorUIWrapper
        Inherits Control
 
        Public Sub New(ByVal colorEditor As ColorEditorEx)
            Dim constructor As ConstructorInfo = GetType(ColorEditor).GetNestedType("ColorUI", BindingFlags.NonPublic).GetConstructor({GetType(ColorEditor)})
            _param = New Object() {colorEditor}
            _control = DirectCast(constructor.Invoke(_param), Control)
            Dim _panel As New Panel With {
                .BackColor = SystemColors.Control,
                .Dock = DockStyle.Left,
                .Width = 28
            }
            _control.Controls.Add(_panel)
            _tbAlpha = New TrackBar With {
                .Orientation = Orientation.Vertical,
                .TickStyle = TickStyle.None,
                .Dock = DockStyle.Fill,
                .Maximum = 255,
                .Minimum = 0
            }
            _panel.Controls.Add(_tbAlpha)
            _lblAlpha = New Label With {
                .Text = "0",
                .TextAlign = ContentAlignment.MiddleCenter,
                .Height = 15,
                .Dock = DockStyle.Bottom
            }
            _panel.Controls.Add(_lblAlpha)
 
            _tabCtrl = DirectCast(_control.Controls.Item(0), TabControl)
            _pallet = _tabCtrl.TabPages.Item(0).Controls.Item(0)
            _lbCom = DirectCast(_tabCtrl.TabPages.Item(1).Controls.Item(0), ListBox)
            _lbSys = DirectCast(_tabCtrl.TabPages.Item(2).Controls.Item(0), ListBox)
 
            _pallet.Width += (_panel.Width + 4)
            BHeight = (_pallet.Height - 1)
            'Метод который задаёт или снимает флаг выделения у элемента в ListBox
            _setSelMethodInfo = GetType(ListBox.SelectedObjectCollection).GetMethod("SetSelected", (BindingFlags.NonPublic Or BindingFlags.Instance))
 
            'Методы, поля и свойства от "ColorUI" в System.Drawing.Design.ColorEditor
            _edSvcFieldInfo = _control.GetType.GetField("edSvc", (BindingFlags.NonPublic Or BindingFlags.Instance))
            _SysColorPropertyInfo = _control.GetType.GetProperty("SystemColorValues", (BindingFlags.NonPublic Or BindingFlags.Instance))
            _ComColorPropertyInfo = _control.GetType.GetProperty("ColorValues", (BindingFlags.NonPublic Or BindingFlags.Instance))
 
            'Методы, поля и свойства от "ColorPalette" в System.Drawing.Design.ColorEditor
            _selColorFieldInfo = _pallet.GetType.GetField("selectedColor", (BindingFlags.NonPublic Or BindingFlags.Instance))
            _focusFieldInfo = _pallet.GetType.GetField("focus", (BindingFlags.NonPublic Or BindingFlags.Instance))
            _statColFieldInfo = _pallet.GetType.GetField("staticColors", (BindingFlags.NonPublic Or BindingFlags.Instance))
            _custumColPropertyInfo = _pallet.GetType.GetProperty("CustomColors")
            _selColPropertyInfo = _pallet.GetType.GetProperty("SelectedColor")
 
            AddHandler _pallet.LostFocus, New EventHandler(AddressOf OnPalletLostFocus)
            AddHandler _tbAlpha.ValueChanged, New EventHandler(AddressOf OnTrackBarAlphaValueChanged)
 
            _bufColor = New Color
            _value = _bufColor
            _PreAlpha = -1
        End Sub
 
        Private Sub OnPalletLostFocus(ByVal sender As Object, ByVal e As EventArgs)
            If _tbAlpha.Focused Then
                Dim _focus As Point = DirectCast(_focusFieldInfo.GetValue(_pallet), Point)
                Dim index As Integer = -1
                If (_focus.X <> -1) AndAlso (_focus.Y <> -1) Then
                    index = _focus.X + (8 * _focus.Y)
                End If
                If (index < 48) Then '48 - кол-во элементов в "_statColFieldInfo"
                    _bufColor = DirectCast(_statColFieldInfo.GetValue(_pallet), Color())(index)
                Else
                    _bufColor = DirectCast(_custumColPropertyInfo.GetValue(_pallet, BindingFlags.Default, Nothing, Nothing, Nothing), Color())(((index - 64) + 16))
                End If
                _selColPropertyInfo.SetValue(_pallet, _bufColor, BindingFlags.Default, Nothing, Nothing, Nothing)
            End If
        End Sub
 
        Private Sub OnTrackBarAlphaValueChanged(ByVal sender As Object, ByVal e As EventArgs)
            _lblAlpha.Text = _tbAlpha.Value.ToString
        End Sub
 
        Private Sub FindColor(_Arraycolor As Object(), _list As ListBox, ByRef _end As Boolean, _GRB As Integer)
            Dim int As Integer = 0
            If _value.IsNamedColor Then
                Do While (int < _Arraycolor.Length)
                    If _value = DirectCast(_Arraycolor(int), Color) Then
                        _end = True
                        Exit Do
                    End If
                    int += 1
                Loop
            Else
                Do While (int < _Arraycolor.Length)
                    If _GRB = DirectCast(_Arraycolor(int), Color).ToArgb Then
                        _end = True
                        Exit Do
                    End If
                    int += 1
                Loop
            End If
            If _end Then
                _bufColor = DirectCast(_Arraycolor(int), Color)
                _param = New Object() {int, True}
                'Задаём флаг выделения в ListBox
                _setSelMethodInfo.Invoke(_list.SelectedItems, _param)
                'Выделяем обьект в ListBox
                SendMessage(_list.Handle, LB_SETCURSEL, int, 0)
                'Делаем выбранный элемент видимым в поле списка ListBox
                'SendMessage(_list.Handle, LB_SETTOPINDEX, int, 0)
            End If
        End Sub
 
        Public Sub Start(ByVal service As IWindowsFormsEditorService, ByVal value As Object)
            _edSvcFieldInfo.SetValue(_control, service, BindingFlags.Default, Type.DefaultBinder, Nothing)
            _value = DirectCast(value, Color)
            AdjustColorUIHeight()
            If (value IsNot Nothing) Then
                _PreAlpha = _value.A
                _tbAlpha.Value = _PreAlpha
                _bufColor = Color.FromArgb(255, _value)
 
                Dim SelTabPage As Integer = 0
                Dim colGRB As Integer = _bufColor.ToArgb
                Dim flag As Boolean = False
                Dim index As Integer = 0
 
                'Найти и выделить цвет в ListBox и _pallet
                If (_PreAlpha = 0) Then
                    If colGRB = (-16777216) Then '-16777216 = Color.Black.ToArgb
                        _bufColor = Color.Empty
                    Else
                        _bufColor = Color.Transparent
                        _param = New Object() {0, True}
                        _setSelMethodInfo.Invoke(_lbCom.SelectedItems, _param)
                        SendMessage(_lbCom.Handle, LB_SETCURSEL, 0, 0)
                        SelTabPage = 1
                    End If
                Else
                    _param = DirectCast(_ComColorPropertyInfo.GetValue(_control, BindingFlags.Default, Nothing, Nothing, Nothing), Object())
                    FindColor(_param, _lbCom, flag, colGRB)
                    If flag Then
                        SelTabPage = 1
                    Else
                        _param = DirectCast(_SysColorPropertyInfo.GetValue(_control, BindingFlags.Default, Nothing, Nothing, Nothing), Object())
                        FindColor(_param, _lbSys, flag, colGRB)
                        If flag Then
                            SelTabPage = 2
                        End If
                    End If
                    flag = False
                    Dim _color As Color() = DirectCast(_statColFieldInfo.GetValue(_pallet), Color())
                    Do While (index < 48) '48 - кол-во элементов в "_statColFieldInfo"
                        If _color(index) = _bufColor Then
                            _focusFieldInfo.SetValue(_pallet, New Point((index Mod 8), (index \ 8)), BindingFlags.Default, Type.DefaultBinder, Nothing)
                            flag = True
                            Exit Do
                        End If
                        index += 1
                    Loop
                End If
 
                DirectCast(_custumColPropertyInfo.GetValue(_pallet, BindingFlags.Default, Nothing, Nothing, Nothing), Color())(0) = _bufColor
                _selColorFieldInfo.SetValue(_pallet, _bufColor, BindingFlags.Default, Type.DefaultBinder, Nothing)
                If Not flag Then
                    _focusFieldInfo.SetValue(_pallet, New Point(0, 6), BindingFlags.Default, Type.DefaultBinder, Nothing)
                End If
                'Выбрать вкладку
                If CInt(SendMessage(_tabCtrl.Handle, TCM_GETCURSEL, 0, 0)) <> SelTabPage Then
                    SendMessage(_tabCtrl.Handle, TCM_SETCURSEL, SelTabPage, 0)
                End If
            End If
        End Sub
 
        Private Sub AdjustColorUIHeight()
            If (_pallet.Height <> (BHeight + 3)) Then
                If _pallet.Height > BHeight Then
                    _pallet.Height = BHeight
                Else
                    _pallet.Height = (BHeight + 3)
                End If
            End If
        End Sub
 
        Public Sub [End]()
            _param = Nothing
            _bufColor = New Color
            _value = _bufColor
            _edSvcFieldInfo.SetValue(_control, Nothing, BindingFlags.Default, Type.DefaultBinder, Nothing)
        End Sub
 
        Friend Sub SetColor()
            Dim _Alpha As Integer = _tbAlpha.Value
            Dim selectedItem As Object = Nothing
            Select Case _tabCtrl.SelectedIndex
                Case 0
                    selectedItem = _selColPropertyInfo.GetValue(_pallet, BindingFlags.Default, Nothing, Nothing, Nothing)
                Case 1
                    selectedItem = _lbCom.SelectedItem
                Case 2
                    selectedItem = _lbSys.SelectedItem
            End Select
            Dim TempColor As Color = If(selectedItem Is Nothing, _bufColor, DirectCast(selectedItem, Color))
            'Проверка: изменился ли цвет, или значение альфаканала
            If (_Alpha <> _PreAlpha) OrElse (TempColor <> _bufColor) Then
                If (TempColor = Color.Transparent) AndAlso (TempColor <> _bufColor) Then
                    _Alpha = 0
                End If
                If _Alpha = 0 Then
                    _value = If(_bufColor.IsEmpty OrElse (_bufColor = Color.Transparent), TempColor, Color.Transparent)
                Else
                    _value = If(_Alpha = 255, TempColor, Color.FromArgb(_Alpha, TempColor))
                End If
            End If
            'Снять выделение в ListBox
            If _lbCom.SelectedIndices.Count > 0 Then
                _param = New Object() {_lbCom.SelectedIndices(0), False}
                _setSelMethodInfo.Invoke(_lbCom.SelectedItems, _param)
                SendMessage(_lbCom.Handle, LB_SETCURSEL, -1, 0)
            End If
            If _lbSys.SelectedIndices.Count > 0 Then
                _param = New Object() {_lbSys.SelectedIndices(0), False}
                _setSelMethodInfo.Invoke(_lbSys.SelectedItems, _param)
                SendMessage(_lbSys.Handle, LB_SETCURSEL, -1, 0)
            End If
        End Sub
 
        Public ReadOnly Property Control As Control
            Get
                Return _control
            End Get
        End Property
 
        Public ReadOnly Property Value As Color
            Get
                Return _value
            End Get
        End Property
 
        <DllImport("user32.dll", CharSet:=CharSet.Auto)>
        Private Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal Msg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As IntPtr
        End Function
 
        ' Fields
        Private Const LB_GETTOPINDEX As Integer = &H18E
        Private Const LB_SETTOPINDEX As Integer = &H197
        Private Const TCM_GETCURSEL As Integer = &H130B
        Private Const TCM_SETCURSEL As Integer = &H130C
        Private Const LB_SETCURSEL As Integer = &H186
        Private ReadOnly BHeight As Integer
        Private _pallet As Control
        Private _lbCom As ListBox
        Private _lbSys As ListBox
        Private _control As Control
        Private _tabCtrl As TabControl
        Private _tbAlpha As TrackBar
        Private _lblAlpha As Label
        Private _setSelMethodInfo As MethodInfo
        Private _selColorFieldInfo As FieldInfo
        Private _edSvcFieldInfo As FieldInfo
        Private _focusFieldInfo As FieldInfo
        Private _statColFieldInfo As FieldInfo
        Private _SysColorPropertyInfo As PropertyInfo
        Private _ComColorPropertyInfo As PropertyInfo
        Private _selColPropertyInfo As PropertyInfo
        Private _custumColPropertyInfo As PropertyInfo
        Private _PreAlpha As Integer
        Private _param As Object()
        Private _bufColor As Color
        Private _value As Color
    End Class
End Class

Использование:
VB.NET
1
2
    <Editor(GetType(ColorEditorEx), GetType(UITypeEditor))>
    Public Property Disable_SC As Color
Изображения
 
3
 Аватар для ViterAlex
8951 / 4863 / 1886
Регистрация: 11.02.2013
Сообщений: 10,246
31.01.2022, 16:17
Текстовое поле, которое умеет вычислять введённое выражение после нажатия знака "=".

Навеяно темой. Синтаксис выражения похож на SQL, но работает как с точкой, так и с запятой.

Название: 2022-01-31_172727.png
Просмотров: 2123

Размер: 15.6 Кб

Кликните здесь для просмотра всего текста
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.ComponentModel
Imports System.Globalization
''' <summary>
''' <see cref="TextBox"/>, который умеет вычислять арифметические выражения при вводе знака "="
''' </summary>
Public Class ComputableTextbox
    Inherits TextBox
 
#Region " Поля и свойства "
    ''' <summary>
    ''' Таблица <see cref="DataTable"/>, которая делает всю магию вычислений.
    ''' </summary>
    Private Shared ReadOnly dt As New DataTable()
    Private _LastEquation As String
    Private _LastResult As Double
    Private _format As String
    ''' <summary>
    ''' Формат вывода ответа. Как для обычных чисел
    ''' </summary>
    Public Property Format() As String
        Get
            Return _format
        End Get
        Set(ByVal value As String)
            _format = value
            If Not String.IsNullOrEmpty(LastEquation) Then
                SetResult()
            End If
        End Set
    End Property
    ''' <summary>
    ''' Последнее вычисленное выражение
    ''' </summary>
    <Browsable(False)>
    Public ReadOnly Property LastEquation() As String
        Get
            Return _LastEquation
        End Get
    End Property
 
    ''' <summary>
    ''' Последний вычисленный результат
    ''' </summary>
    <Browsable(False)>
    Public ReadOnly Property LastResult As Double
        Get
            Return _LastResult
        End Get
    End Property
    ''' <summary>
    ''' Полное выражение с ответом
    ''' </summary>
    <Browsable(False)>
    Public ReadOnly Property FullEquation As String
        Get
            Dim sep = IIf(_LastEquation.Contains(","), ",", ".")
            Dim ci = New CultureInfo(CultureInfo.CurrentUICulture.LCID)
            ci.NumberFormat.NumberDecimalSeparator = sep
            ci.NumberFormat.CurrencyDecimalSeparator = sep
            If Not String.IsNullOrEmpty(Format) Then
                Return LastEquation & "=" & LastResult.ToString(Format, ci)
            End If
            Return LastEquation & "=" & LastResult.ToString(ci)
        End Get
    End Property
#End Region
 
    Public Sub New()
        MyBase.New()
        Multiline = False
    End Sub
 
#Region " Переопределённые методы и свойства "
 
    Public Overrides Property Multiline As Boolean
        Get
            Return False
        End Get
        Set(value As Boolean)
            MyBase.Multiline = False
        End Set
    End Property
 
Protected Overrides Sub OnKeyUp(e As KeyEventArgs)
    MyBase.OnKeyUp(e)
    If e.KeyCode = Keys.Oemplus AndAlso Not e.Shift Then
        ComputeExpression()
    End If
End Sub
#End Region
    ''' <summary>
    ''' Метод, выполнящий вычисления и обновляющий значения свойств
    ''' </summary>
    Private Sub ComputeExpression()
        Dim exp = Text.Substring(0, Text.Length - 1)
        Dim val As Object
        Dim dotExpr As String
        Try
            dotExpr = exp.Replace(","c, ".")
            val = dt.Compute(dotExpr, String.Empty)
        Catch ex As Exception
            Throw ex
        End Try
        _LastEquation = IIf(exp = dotExpr, dotExpr, exp)
        _LastResult = Convert.ToDouble(val)
        SetResult()
        SelectionStart = Text.Length
    End Sub
 
    Private Sub SetResult()
        Text = FullEquation
    End Sub
End Class
8
Нарушитель
 Аватар для HACKER KAY
21 / 47 / 5
Регистрация: 03.06.2019
Сообщений: 368
Записей в блоге: 10
21.05.2022, 18:40
Определяем: Используется настоящая или система в виртуальной машине?

Только для познавательных целей. Создавал модуль интеграции основной системы с виртуальной, вот тут и пригодилось подобное решение.

Если приложение запущено в VirtualBox или другой подобной песочнице, то функция VM_Detected() вернёт True

vmdetector.vb:
VB.NET
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
' Creator: HACKER KAY
Imports System.Management
Class vmdetector
    Public Function VM_Detected() As Boolean
        Using mgr = New ManagementObjectSearcher("Select * from Win32_ComputerSystem")
            Using items = mgr.[Get]()
                For Each check In items
                    Dim manufacturer As String = check("Manufacturer").ToString().ToLower()
                    If (manufacturer = "microsoft corporation" AndAlso
                        check("Model").ToString().ToUpperInvariant().Contains("VIRTUAL")) OrElse
                        manufacturer.Contains("vmware") OrElse
                        check("Model").ToString() = "VirtualBox" Then
                        Return True
                    End If
                Next
            End Using
        End Using
        Return False
    End Function
End Class
Использование:
VB.NET
1
2
3
4
5
6
Dim chck = New vmdetector
If chck.VM_Detected Then
    MsgBox("Приложение запущено в виртуальной машине!")
Else
    MsgBox("Приложение запущено на основной ОС компьютера")
End If
0
Нарушитель
 Аватар для HACKER KAY
21 / 47 / 5
Регистрация: 03.06.2019
Сообщений: 368
Записей в блоге: 10
28.08.2022, 14:18
Определяем тип файла: NET-гибрид или натив?

На днях писал свой криптор-обфускатор для бинарей, на ум пришло гениальное и простое решение для определения типа EXE-файла через его открытие в виде бинарника, перевод в строку и поиск нужных данных. (открывать как текст сразу нельзя - файл может сохраниться не полностью!)

VB.NET
1
2
3
4
Dim IsNative = Not Encoding.ASCII.GetString(
                       File.ReadAllBytes("файл.exe")
                       ).Contains(".NETFramework,Version=")
MsgBox($"Файл является NET-приложением? {IsNative}!")
0
Модератор
Эксперт .NET
 Аватар для Yury Komar
4356 / 3426 / 512
Регистрация: 27.01.2014
Сообщений: 6,257
15.09.2022, 15:20  [ТС]
Функции конвертации String->Bytes, String->Binary, String->Hex, Bytes->String, Binary->String, Hex->Bytes, Hex->String
(помощник при работе с бинарными или Hex данными)

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
#Region "Hex,Byte,Binary,String Conversion Helper"
    Function StrToByteArray(Str As String) As Byte()
        Return System.Text.Encoding.Default.GetBytes(Str)
    End Function
 
    Function BytesArrayToString(BytesArray As Byte()) As String
        Return System.Text.Encoding.Default.GetString(BytesArray)
    End Function
 
    Function HexToString(HEX_String As String) As String
        If HEX_String.Length <> 0 Then
            Try
                HEX_String = HEX_String.Replace(Space(1), Nothing).Replace(",", Nothing).Replace("-", Nothing)
                Dim ResultSTRING As New System.Text.StringBuilder(HEX_String.Length \ 2)
                For i As Integer = 0 To HEX_String.Length - 2 Step 2
                    ResultSTRING.Append(Chr(Convert.ToByte(HEX_String.Substring(i, 2), 16)))
                Next
                Return ResultSTRING.ToString
            Catch ex As Exception
                MsgBox("Incorrect HEX data", MsgBoxStyle.Exclamation)
                Return HEX_String
            End Try
        End If
        Return HEX_String
    End Function
 
    Function StringToHex(TEXT As String) As String
        If TEXT.Length <> 0 Then
            Dim ResultHEX As String = Nothing
            For i As Integer = 0 To TEXT.Length - 1
                ResultHEX &= Asc(TEXT.Substring(i, 1)).ToString("x").ToUpper
            Next
            Return ResultHEX.ToString
        End If
        Return TEXT
    End Function
 
    Function HexStringToBytesArray(HexString As String) As Byte()
        Return System.Runtime.Remoting.Metadata.W3cXsd2001.SoapHexBinary.Parse(HexString.Replace(" ", "").Replace("-", "")).Value
    End Function
 
    Function TextToBinaryString(Txt As String) As String
        'ONLY 7bit TEXT and DIGITS / NO SPACES and ANY OTHER SYMBOLS
        Return String.Concat(System.Text.Encoding.UTF8.GetBytes(Txt).Select(Function(b) Convert.ToString(b, 2)))
    End Function
 
    Function BinaryStringToText(BinaryString As String) As String
        'ONLY 7bit TEXT and DIGITS / NO SPACES and ANY OTHER SYMBOLS
        Dim DivideUp As String = String.Concat(Enumerable.Range(0, CInt(BinaryString.Length / 7)).Select(Function(i) BinaryString.Substring(i * 7, 7) & " ").ToArray).Trim()
        Return String.Concat(DivideUp.Split.Select(Function(s) Convert.ToChar(Convert.ToInt32(s, 2))))
    End Function
#End Region
5
Модератор
Эксперт .NET
 Аватар для Yury Komar
4356 / 3426 / 512
Регистрация: 27.01.2014
Сообщений: 6,257
16.09.2022, 20:11  [ТС]
Установить разделитель дробных чисел в RUNTIME на ТОЧКУ
Очень полезно, когда нужно работать с числами у которых должна быть точка как разделитель.
Ну и такая конструкция (замена) .ToString().Replace(",", ".") сама собой отпадет, да и памяти она кушает, когда очень много данных приходится обрабатывать\парсить.

VB.NET
1
2
3
4
'Установить разделитель дробных чисел в RUNTIME на ТОЧКУ,
'Независимо от того, какой разделитель установлен в системе
'Программа будет использовать ТОЧКУ
Application.CurrentCulture = New CultureInfo(Application.CurrentCulture.Name) With {.NumberFormat = New NumberFormatInfo With {.NumberDecimalSeparator = "."}}
5
7 / 7 / 0
Регистрация: 11.12.2022
Сообщений: 12
17.12.2022, 10:24
Расширенный класс RichTextBox:
- вместо библиотеки riched20.dll (не поддерживает таблицы с ячейками в несколько строк) загружается msftedit.dll (поддерживает таблицы с ячейками в несколько строк)
- добавлен метод печати содержимого RichTextBox с возможностью пропуска непечатаемых страниц

Код для класса RichTextBoxE:
Кликните здесь для просмотра всего текста
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
Imports System
Imports System.Drawing
Imports System.Runtime.InteropServices
Imports System.Drawing.Printing
 
'класс RichTextBoxE (использование msftedit.dll + печать выборочных страниц)
Public Class RichTextBoxE
    
    'наследование класса RichTextBox
    Inherits RichTextBox
 
    'использование msftedit.dll вместо riched20.dll
    Private Declare Function LoadLibrary Lib "kernel32.dll" Alias "LoadLibraryA" ( dllName As String) As IntPtr
    Protected Overrides ReadOnly Property CreateParams() As CreateParams
        Get
            Dim baseParams As CreateParams = MyBase.CreateParams
            'загрузить библиотеку из системной папки
            If LoadLibrary(System.IO.Path.Combine(Environment.SystemDirectory, "msftedit.dll")) <> System.IntPtr.Zero Then baseParams.ClassName = "RICHEDIT50W"
            Return baseParams
        End Get
    End Property
 
    'печать через RichTextBox
    ' Convert the unit that is used by the .NET framework (1/100 inch) 
    ' and the unit that is used by Win32 API calls (twips 1/1440 inch)
    Private Const AnInch As Single = 14.4
    <StructLayout(LayoutKind.Sequential)>
    Private Structure RECT
        Public Left As Integer
        Public Top As Integer
        Public Right As Integer
        Public Bottom As Integer
    End Structure
   
    <StructLayout(LayoutKind.Sequential)>
    Private Structure CHARRANGE
        Public cpMin As Integer          ' First character of range (0 for start of doc)
        Public cpMax As Integer          ' Last character of range (-1 for end of doc)
    End Structure
 
    <StructLayout(LayoutKind.Sequential)>
    Private Structure FORMATRANGE
        Public hdc As IntPtr             ' Actual DC to draw on
        Public hdcTarget As IntPtr       ' Target DC for determining text formatting
        Public rc As RECT                ' Region of the DC to draw to (in twips)
        Public rcPage As RECT            ' Region of the whole DC (page size) (in twips)
        Public chrg As CHARRANGE         ' Range of text to draw (see above declaration)
    End Structure
 
    Private Const WM_USER As Integer = &H400
    Private Const EM_FORMATRANGE As Integer = WM_USER + 57
    Private Declare Function SendMessageIntPtr Lib "USER32" Alias "SendMessageA" ( hWnd As IntPtr,  Msg As Integer,  wParam As IntPtr,  lParam As IntPtr) As IntPtr
    Public Function Print( charFrom As Integer,  charTo As Integer,  e As PrintPageEventArgs, Optional  PageToPrintMode As Integer = 1) As Integer
 
        ' Mark starting and ending character 
        Dim cRange As CHARRANGE
        cRange.cpMin = charFrom
        cRange.cpMax = charTo
 
        ' Calculate the area to render and print
        Dim rectToPrint As RECT
        rectToPrint.Top = CInt(e.MarginBounds.Top * AnInch)
        rectToPrint.Bottom = CInt(e.MarginBounds.Bottom * AnInch)
        rectToPrint.Left = CInt(e.MarginBounds.Left * AnInch)
        rectToPrint.Right = CInt(e.MarginBounds.Right * AnInch)
 
        ' Calculate the size of the page
        Dim rectPage As RECT
        rectPage.Top = CInt(e.PageBounds.Top * AnInch)
        rectPage.Bottom = CInt(e.PageBounds.Bottom * AnInch)
        rectPage.Left = CInt(e.PageBounds.Left * AnInch)
        rectPage.Right = CInt(e.PageBounds.Right * AnInch)
 
        Dim hdc As IntPtr = e.Graphics.GetHdc()
        Dim fmtRange As FORMATRANGE
        fmtRange.chrg = cRange                 ' Indicate character from to character to 
        fmtRange.hdc = hdc                     ' Use the same DC for measuring and rendering
        fmtRange.hdcTarget = hdc              ' Point at printer hDC
        fmtRange.rc = rectToPrint              ' Indicate the area on page to print
        fmtRange.rcPage = rectPage             ' Indicate whole size of page
 
        'Dim res As IntPtr = IntPtr.Zero
 
        'PageToPrintMode 'Режим печати текущей страницы: 0 - измерить и не печатать; 1 - измерить и печатать;
        Dim wParam As New IntPtr(PageToPrintMode)
 
        ' Move the pointer to the FORMATRANGE structure in memory
        Dim lParam As IntPtr = Marshal.AllocCoTaskMem(Marshal.SizeOf(fmtRange))
        Marshal.StructureToPtr(fmtRange, lParam, False)
 
        ' Send the rendered data for printing
        Dim res As IntPtr = SendMessageIntPtr(Handle, EM_FORMATRANGE, wParam, lParam)
 
        ' Free the block of memory allocated
        Marshal.FreeCoTaskMem(lParam)
 
        ' Release the device context handle obtained by a previous call
        e.Graphics.ReleaseHdc(hdc)
 
        ' Return last + 1 character printer
        Return res.ToInt32()
 
    End Function
 
End Class

Ниже приведена реализация печати содержимого RichTextBox (код объемный, поэтому привожу только основную идею):
- расчет массива начальных позиций печатаемого текста каждой страницы
- печать всех страниц
- печать выбранных страниц

На основной форме FormMain должны быть контролы: меню MenuStripFilePrint и PrintDocumentMain

Код для основной формы:
Кликните здесь для просмотра всего текста
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
114
115
116
117
118
119
120
121
122
123
124
Friend TempRichTextBoxResult As New RichTextBoxE 'создаем новый экземпляр RichTextBoxE
 
    'рассчитать массив начальных позиций печатаемого текста каждой страницы
    Public PageMarginBoundsCInch As Rectangle 'область печати страницы с учетом полей в 0.01 дюйма
    Public CharToPrintCurPosPages() As Integer 'массив начальных позиций печатаемого текста каждой страницы
    Friend Sub CalcCharToPrintCurPosPages() 'рассчитать массив начальных позиций печатаемого текста каждой страницы
 
        'обработка исключения - если ошибка обращения к принтеру - пропустить печать
        Try
            'по умолчанию всегда есть одна страница
            ReDim CharToPrintCurPosPages(0 To 1) 'массив начальных позиций печатаемого текста каждой страницы
            CharToPrintCurPosPages(0) = 1 'номер текущей страницы (на которой расположен курсор)
            CharToPrintCurPosPages(1) = 0 'начальная позиция печатаемого текста первой страницы
 
            If TempRichTextBoxResult.TextLength = 0 Then Exit Sub 'если текста нет - выходим
 
            'получить поверхность устройства печати
            Dim g As Graphics 'поверхность устройства печати
            'если есть установленные принтеры и текущий принтер действительный
            If InstalledPrintersCount > 0 Then
                g = PrintDocumentMain.DefaultPageSettings.PrinterSettings.CreateMeasurementGraphics(PrintDocumentMain.DefaultPageSettings)
            Else 'если нет установленных принтеров или текущий принтер недействительный
                g = Me.CreateGraphics()
            End If
 
            'данные для события печати страницы
            Dim e As New PrintPageEventArgs(g, PageMarginBoundsCInch, PrintDocumentMain.DefaultPageSettings.Bounds, PrintDocumentMain.DefaultPageSettings)
 
            Dim PageToPrintCurNumber As Integer = 0 'номер печатаемой страницы
            Dim CharToPrintCurPos As Integer = 0 'начальная позиция печатаемого текста
 
            CharToPrintCurPosPages(0) = -1 'номер текущей страницы (на которой расположен курсор)
 
            'рассчитать массив начальных позиций печатаемого текста каждой страницы
            Do
                PageToPrintCurNumber += 1 'номер печатаемой страницы - первая
                ReDim Preserve CharToPrintCurPosPages(0 To PageToPrintCurNumber) 'массив начальных позиций печатаемого текста каждой страницы
                CharToPrintCurPosPages(PageToPrintCurNumber) = CharToPrintCurPos 'начальная позиция печатаемого текста текущей страницы
                CharToPrintCurPos = TempRichTextBoxResult.Print(CharToPrintCurPos, TempRichTextBoxResult.TextLength, e, 0) 'первый символ следующей страницы
                'определить номер текущей страницы (на которой расположен курсор)
                If CharToPrintCurPosPages(0) = -1 Then If TempRichTextBoxResult.SelectionStart < CharToPrintCurPos Then CharToPrintCurPosPages(0) = PageToPrintCurNumber 'номер текущей страницы
                'System.Windows.Forms.Application.DoEvents() 'пауза для обработки других задач
            Loop While CharToPrintCurPos < TempRichTextBoxResult.TextLength 'пока не превышена длина текста
 
            'особые случаи для номера текущей страницы (на которой расположен курсор)
            If TempRichTextBoxResult.SelectionStart = 0 Then CharToPrintCurPosPages(0) = 1 'номер текущей страницы 
            If TempRichTextBoxResult.SelectionStart = TempRichTextBoxResult.TextLength Then CharToPrintCurPosPages(0) = CharToPrintCurPosPages.Length - 1 'номер текущей страницы 
            If CharToPrintCurPosPages(0) = -1 Then CharToPrintCurPosPages(0) = 1 'все другие случаи для номера текущей страницы (на которой расположен курсор)
 
            g.Dispose() 'освободить ресурсы
 
        Catch ex As Exception
        End Try
 
    End Sub
 
    'печатать результаты расчета на принтер по умолчанию
    'AddHandler() PrintDocumentMain.PrintPage - 'печатать результаты расчета на принтер по умолчанию
    Private Sub PrintDocumentMain_PrintPage_Default(sender As Object, e As Printing.PrintPageEventArgs) 'Handles PrintDocumentMain.PrintPage
 
       TempRichTextBoxResult.Print(CharToPrintCurPosPages(PageToPrintCurNumber), TempRichTextBoxResult.TextLength, e, 1) 'печать содержимого одной страницы
        PageToPrintCurNumber += 1
        e.HasMorePages = (PageToPrintCurNumber <> CharToPrintCurPosPages.Length)
    End Sub
 
    'печатать диапазон страниц
    'AddHandler() PrintDocumentMain.PrintPage - 'печатать диапазон страниц
    Private Sub PrintDocumentMain_PrintPage_SomePages(sender As Object, e As Printing.PrintPageEventArgs) 'Handles PrintDocumentMain.PrintPage
 
        If PrintDocumentMain.PrinterSettings.PrintRange <> PrintRange.Selection Then HeaderFooterPrint(e) 'печать колонтитулов
 
        TempRichTextBoxResult.Print(CharToPrintCurPosPages(PageToPrintCurNumber), TempRichTextBoxResult.TextLength, e, 1) 'печать содержимого одной страницы
        e.HasMorePages = (PageToPrintCurNumber <> FormPrint.ToPages(SamePagesToPrintCurIndex))
        PageToPrintCurNumber += FormPrint.StepPages(SamePagesToPrintCurIndex) 'перейти на следующую страницу
 
        'если выбрано условие - разбирать по копиям
        If FormPrint.CheckBoxPrintCopiesCollate.Checked = True Then
 
            'если текущая страница - последняя
            If e.HasMorePages = False Then
                'если индекс печатаемого диапазона страниц не равен индексу последнего диапазона
                If SamePagesToPrintCurIndex <> FormPrint.ToPages.Length - 1 Then
                    'если распечатана последняя выбранная страница
                    SamePagesToPrintCurIndex += 1 'индекс печатаемого диапазона страниц
                    PageToPrintCurNumber = FormPrint.FromPages(SamePagesToPrintCurIndex) 'вернуться на первую страницу диапазона
                    e.HasMorePages = True 'есть нераспечатанные страницы новой копии документа
                End If
            End If
 
            'если текущая страница - последняя
            If e.HasMorePages = False Then
                'если необходимое количество копий документа - не распечатано 
                If DocumentToPrintCopiesNumber < FormPrint.PrintCopies Then
                    SamePagesToPrintCurIndex = 0 'индекс печатаемого диапазона страниц
                    PageToPrintCurNumber = FormPrint.FromPages(SamePagesToPrintCurIndex) 'вернуться на первую страницу диапазона
                    DocumentToPrintCopiesNumber += 1 'распечатана еще 1 копия документа
                    e.HasMorePages = True
                End If
            End If
 
        Else 'если выбрано условие - не разбирать по копиям
 
            'если необходимое количество копий документа - не распечатано 
            If DocumentToPrintCopiesNumber < FormPrint.PrintCopies Then
 
                PageToPrintCurNumber -= FormPrint.StepPages(SamePagesToPrintCurIndex) 'вернуться на предыдущую страницу
                DocumentToPrintCopiesNumber += 1 'распечатана еще 1 копия документа
                e.HasMorePages = True 'есть нераспечатанные страницы новой копии документа
 
            Else 'если необходимое количество копий документа - распечатано 
 
               DocumentToPrintCopiesNumber = 1 'номер печатаемой копии документа
                'если текущая страница - последняя
                If e.HasMorePages = False Then
                    'если индекс печатаемого диапазона страниц не равен индексу последнего диапазона
                    If SamePagesToPrintCurIndex <> FormPrint.ToPages.Length - 1 Then
                        SamePagesToPrintCurIndex += 1 'индекс печатаемого диапазона страниц
                        PageToPrintCurNumber = FormPrint.FromPages(SamePagesToPrintCurIndex) 'вернуться на первую страницу диапазона
                        e.HasMorePages = True 'есть нераспечатанные страницы новой копии документа
                    End If
                End If
            End If
        End If
    End Sub

Также можно реализовать собственную форму FormPrint для предварительного просмотра перед печатью
на форме должна быть PanelPage, на которой отображаются страницы предварительного просмотра
идея в использовании класса PreviewPrintController:
Кликните здесь для просмотра всего текста
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
'просмотр выбранной страницы для печати
    Private Sub PrintPreviewPage( PageNumber As Integer) 'просмотр выбранной страницы для печати
        '---------------------------------------------------------------------
        FlagUserClick = False 'флаг нажатия пользователем кнопки
        '---------------------------------------------------------------------
        'проверить и установить номер выбранной страницы для просмотра
        If PageNumber < 1 Then PageNumber = 1 'нижний предел
        If PageNumber > FormMain.CharToPrintCurPosPages.Length - 1 Then PageNumber = FormMain.CharToPrintCurPosPages.Length - 1 'верхний предел
        FormMain.PageToPrintCurNumber = PageNumber 'номер страницы для просмотра
        '---------------------------------------------------------------------
        'установить контролер печати - для просмотра
        Dim OldPrintController As PrintController = FormMain.PrintDocumentMain.PrintController 'запомнить старый контроллер печати
        Dim NewPreviewPrintController As New PreviewPrintController() 'новый контроллер печати - для просмотра
        FormMain.PrintDocumentMain.PrintController = NewPreviewPrintController 'присвоить новый контроллер печати - для просмотра
        '---------------------------------------------------------------------
        'получить изображение выбранной страницы
        '---------------------------------------------------------------------
        Try
            FormMain.PrintDocumentMain.Print() 'печать выбранной страницы
            Dim PagesPreviewPageInfo As PreviewPageInfo() = NewPreviewPrintController.GetPreviewPageInfo() 'получить коллекцию изображений страниц для печати
            PanelPage.BackgroundImage = PagesPreviewPageInfo(0).Image 'вывести изображение страницы для печати
        Catch ex As Exception
            'показываем окно сообщения об ошибке
            FormMessage.ShowMessage("Не удается получить параметры принтера " & Chr(34) & FormMain.PrintDocumentMain.PrinterSettings.PrinterName & Chr(34) & "." & vbCrLf & "Описание ошибки: " & ex.Message, My.Application.Info.Title, MessageBoxButtons.OK, MessageBoxIcon.Error,,,,, Me)
        End Try
        '---------------------------------------------------------------------
        'If PagesPreviewPageInfo.Length > 0 Then
        ComboBoxPageNumber.Text = PageNumber.ToString 'номер страницы, выбранной для просмотра - этот вариант быстрее других
        'ComboBoxPageNumber.SelectedItem = PageNumber.ToString 'номер страницы, выбранной для просмотра
        'ComboBoxPageNumber.SelectedIndex = PageNumber - 1 'номер страницы, выбранной для просмотра
        GroupBoxPrintPreview.Text = "Страница " & PageNumber & " из " & FormMain.CharToPrintCurPosPages.Length - 1
        'End If
        '---------------------------------------------------------------------
        'вернуть старый контроллер печати
        FormMain.PrintDocumentMain.PrintController = OldPrintController 'вернуть старый контроллер печати
        '---------------------------------------------------------------------
        FlagUserClick = True 'флаг нажатия пользователем кнопки
        '---------------------------------------------------------------------
    End Sub
3
7 / 7 / 0
Регистрация: 11.12.2022
Сообщений: 12
18.12.2022, 07:00
Текстовый редактор в стиле WordPad
Весь код объемный, поэтому ограничусь общим описанием трех моментов:
1) работа в трех режимах переноса текста: в пределах страницы; в пределах окна; без переноса;
2) выделение текста с помощью мыши в зонах слева и справа от текстового окна;
3) поддержка масштабирования содержимого текстового окна, в том числе при изменении размеров окна приложения.

1) создаем макет редактора (названия контролов специфические - можно переименовать как вам удобно):
PanelResult - общий контейнер для всех элементов, фон редактора слева и справа от страницы;
RichTextBoxResult - непосредственно текстовое окно как часть страницы (выключаем встроенные скролбары ScrollBars = RichTextBoxScrollBars.None);
LabelPageLeft - примыкает слева к текстовом окну, имитирует левое поле страницы шириной ResultPageMarginLeftPixel (правое поле страницы задается свойством RichTextBoxResult.RightMargin=ResultPage MarginRightPixel);
LabelLeft - фон редактора слева от страницы;
VSResult - вертикальный скролбар (в правой части контейнера PanelResult, может не примыкать к тестовому окну);
HSResult - горизонтальный скролбар (внизу контейнера PanelResult, может не примыкать к тестовому окну).

Слева от текстового окна курсор мыши будет меняться на LeftHand (чтобы не ссылаться на файл курсора на диске, помещаем картинку будущего курсора в PictureBoxCursorLeftHand - горячая точка курсора должна быть по центру картинки, и превращаем ее в курсор):
Кликните здесь для просмотра всего текста
VB.NET
1
2
3
4
5
6
7
8
9
'создание курсора - стрелка направо
        Dim TempBitmap As Bitmap = CType(FormSettings.PictureBoxCursorLeftHand.Image, Bitmap)
        LabelPageLeft.Cursor = New Cursor(TempBitmap.GetHicon)
        LabelLeft.Cursor = LabelPageLeft.Cursor
                'установка системных размеров для полос прокрутки
        VSResult.Width = SystemInformation.VerticalScrollBarWidth
        HSResult.Height = SystemInformation.HorizontalScrollBarHeight
        'количество строк, прокручиваемых при вращении колесика мыши
        MouseWheelSLines = SystemInformation.MouseWheelScrollLines

связь между текстовым окном и скролбарами обеспечиваем через Win API:
Кликните здесь для просмотра всего текста
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
'получить и установить позицию VScrollBar и HScrollBar 
    Private Const WM_USER As Integer = &H400
    Private Const EM_GETSCROLLPOS As Integer = WM_USER + 221 'получить позицию VScrollBar и HScrollBar 
    Private Const EM_SETSCROLLPOS As Integer = WM_USER + 222 'установить позицию VScrollBar и HScrollBar
    Private Declare Function SendMessagePointB Lib "user32.dll" Alias "SendMessageA" (hWnd As IntPtr, msg As Integer, wParam As Integer, ByRef lParam As Point) As Boolean
 
    'AddHandler RichTextBoxResult.VScroll
    Private Sub RichTextBoxResult_VScroll(sender As Object, e As EventArgs)
        SetVSPosition() 'установить позицию полосы прокрутки
    End Sub
 
    Private Sub SetVSPosition() 'установить позицию полосы прокрутки
        If VSResult.Enabled = False Then Exit Sub 'если полоса прокрутки не доступна - выходим
        Dim VSValue As Integer = VSResult.Value 'текущая позиция прокрутки
        'определить текущую позицию полосы прокрутки
        Dim SPos As Point
        If SendMessagePointB(RichTextBoxResult.Handle, EM_GETSCROLLPOS, 0, SPos) = True Then VSValue = SPos.Y
        FitValueToIntervalInteger(VSValue, 0, VSResult.Maximum - VSResult.LargeChange) 'подогнать число Integer в заданный интервал значений
        VSResult.Value = VSValue 'текущая позиция прокрутки
    End Sub
 
    'текстовое окно РР - вертикальная прокрутка колесиком мыши
    'AddHandler RichTextBoxResult.MouseWheel
    Private Sub RichTextBoxResult_MouseWheel(sender As Object, e As MouseEventArgs)
        'для всех режимов представления текстового окна
        If My.Computer.Keyboard.CtrlKeyDown = True Then Exit Sub 'если нажата клавиша Ctrl - выходим
        If My.Computer.Keyboard.ShiftKeyDown = True Then Exit Sub 'если нажата клавиша Shift - выходим
        If VSResult.Enabled = False Then Exit Sub 'если полоса прокрутки не доступна - выходим
        Dim NewValue As Integer = VSResult.Value - Math.Sign(e.Delta) * MouseWheelSLines * VSResult.SmallChange
        FitValueToIntervalInteger(NewValue, 0, VSResult.Maximum - VSResult.LargeChange) 'подогнать число Integer в заданный интервал значений
        RTBVScroll(NewValue) 'прокрутить текстовое окно
    End Sub
 
    'текстовое окно РР - горизонтальная прокрутка
    'получить позицию курсора
    Private Declare Function GetCaretPos Lib "user32.dll" Alias "GetCaretPos" (ByRef lpPoint As Point) As Boolean
    Private Function GetCursorPos() As Point 'получить позицию курсора
        'получить позицию курсора
        Dim CPos As Point
        If GetCaretPos(CPos) = True Then GetCursorPos = CPos Else GetCursorPos = Point.Empty
    End Function
 
    'горизонтальный скроллинг панели результатов
    'AddHandler RichTextBoxResult.SelectionChanged
    Private Sub RichTextBoxResult_SelectionChanged(sender As Object, e As EventArgs)
        SetEnabledEditOperation() 'определить доступ к операциям правки 
        PanelResult_HScroll() 'горизонтальный скроллинг панели результатов
    End Sub
 
    Private Sub PanelResult_HScroll() 'горизонтальный скроллинг панели результатов
        If My.Settings.ResultMode <> 0 Then Exit Sub 'если режим переноса текста окна РР - не 0 в пределах страницы - выходим
        If My.Settings.ResultTextScaleMode = 1 Then Exit Sub 'если режим масштаба окна РР - 1 по ширине страницы - выходим 
        If HSResult.Enabled = False Then Exit Sub 'если полоса прокрутки не доступна - выходим
        'определить позицию курсора по которой выполнять горизонтальную прокрутку
        Dim CurPosX As Integer = GetCursorPos().X
        'установить положение левой границы панели страницы
        Dim PanelPageResultLeft As Integer = PanelPageResult.Left
        Select Case CurPosX
                'выравнивание по правой границе текста
            Case Is > PanelResult.Width - VSResult.Width - PanelPageResultLeft - RichTextBoxResult.Left - RichTextBoxResult.Top * 2
                PanelPageResultLeft = PanelResult.Width - VSResult.Width - RichTextBoxResult.Left - CurPosX - MouseWheelSLines * HSResult.SmallChange
                If CurPosX >= PanelPageResult.Width + PanelPageResultGap - HSResult.LargeChange Then PanelPageResultLeft = PanelResult.Width - VSResult.Width - PanelPageResult.Width - PanelPageResultGap
                'выравнивание по левой границе текста
            Case Is < -PanelPageResultLeft - RichTextBoxResult.Left
                PanelPageResultLeft = -RichTextBoxResult.Left - CurPosX + MouseWheelSLines * HSResult.SmallChange
                If CurPosX <= HSResult.LargeChange Then PanelPageResultLeft = RichTextBoxResult.Top * 2 - CInt(My.Settings.ResultTextScale / 100 * ResultPageMarginLeftPixel)
        End Select
        PanelPageResult.Left = PanelPageResultLeft
        LabelLeft.Width = PanelPageResultLeft
        SetHSPosition() 'установить позицию полосы прокрутки
    End Sub
 
    'текстовое окно РР - горизонтальная прокрутка
    'AddHandler RichTextBoxResult.HScroll
    Private Sub RichTextBoxResult_HScroll(sender As Object, e As EventArgs)
        SetHSPosition() 'установить позицию полосы прокрутки
    End Sub
 
    Private Sub SetHSPosition() 'установить позицию полосы прокрутки
        If HSResult.Enabled = False Then Exit Sub 'если полоса прокрутки не доступна - выходим
        Dim HSValue As Integer = HSResult.Value 'текущая позиция прокрутки
        'режим представления текстового окна
        Select Case My.Settings.ResultMode
            Case 0 'перенос слов в пределах страницы
                HSValue = PanelPageResultGap - PanelPageResult.Left
            'Case 1 'перенос слов в пределах окна
            Case 2 'без переноса слов
                'определить текущую позицию полосы прокрутки
                Dim SPos As Point
                If SendMessagePointB(RichTextBoxResult.Handle, EM_GETSCROLLPOS, 0, SPos) = True Then HSValue = SPos.X
        End Select
        FitValueToIntervalInteger(HSValue, 0, HSResult.Maximum - HSResult.LargeChange) 'подогнать число Integer в заданный интервал значений
        HSResult.Value = HSValue 'текущая позиция прокрутки
    End Sub
 
    'текстовое окно РР - изменение размеров содержащегося текста
    Dim VSMax As Integer 'максимальное значение вертикальной полосы прокрутки
    Dim HSMax As Integer 'максимальное значение горизонтальной полосы прокрутки
    'Изменение масштаба текстового окна РР
    'AddHandler RichTextBoxResult.ContentsResized
    Private Sub RichTextBoxResult_ContentsResized(sender As Object, e As ContentsResizedEventArgs)
        'если нажата клавиша Ctrl
        If My.Computer.Keyboard.CtrlKeyDown = True Then
            'если масштаб текстового окна изменился
            Dim TextScale As Integer = CInt(Me.RichTextBoxResult.ZoomFactor * 100)
            Select Case TextScale
                Case Is > My.Settings.ResultTextScale
                    SetScaleResultUp() 'увеличить на +10%
                Case Is < My.Settings.ResultTextScale
                    SetScaleResultDown() 'уменьшить на -10%
            End Select
        End If
        'вертикальная полоса прокрутки
        'обновить максимальное значение полосы прокрутки
        VSMax = e.NewRectangle.Height
        If VSMax < 0 Then VSMax = 0
 
        'горизонтальная полоса прокрутки
        'если режим переноса текста в окне РР - без переноса
        If My.Settings.ResultMode = 2 Then
            'обновить максимальное значение полосы прокрутки
            HSMax = e.NewRectangle.Width
            If HSMax < 0 Then HSMax = 0
        End If
        UpdateRTBResult() 'обновить параметры текстового окна
    End Sub
 
    'вертикальная полоса прокрутки - прокрутка
    Private Sub VSResult_Scroll(sender As Object, e As ScrollEventArgs) Handles VSResult.Scroll
        RTBVScroll(e.NewValue) 'прокрутить текстовое окно
    End Sub
 
    Private Sub RTBVScroll(NewValue As Long) 'прокрутить текстовое окно
        'определить текущую позицию полосы прокрутки
        Dim SPos As Point = Point.Empty
        SendMessagePointB(RichTextBoxResult.Handle, EM_GETSCROLLPOS, 0, SPos)
        'установить новую позицию полосы прокрутки
        SPos.Y = CInt(NewValue)
        SendMessagePointB(RichTextBoxResult.Handle, EM_SETSCROLLPOS, 0, SPos)
    End Sub
 
    'горизонтальная полоса прокрутки - прокрутка
    Private Sub HSResult_Scroll(sender As Object, e As ScrollEventArgs) Handles HSResult.Scroll
        RTBHScroll(e.NewValue) 'прокрутить текстовое окно
    End Sub
    Private Sub RTBHScroll(NewValue As Long) 'прокрутить текстовое окно
        'режим представления текстового окна
        Select Case My.Settings.ResultMode
            Case 0 'перенос слов в пределах страницы
                'проверить крайнее горизонтальное положение панели страницы
                Dim PanelPageResultLeft As Integer = CInt(PanelPageResultGap - NewValue)
                Dim PanelPageResultLeftMax As Integer = PanelResult.Width - VSResult.Width - PanelPageResult.Width - PanelPageResultGap
                If PanelPageResultLeft < PanelPageResultLeftMax Then PanelPageResultLeft = PanelPageResultLeftMax
                PanelPageResult.Left = PanelPageResultLeft
                LabelLeft.Width = PanelPageResult.Left
                SetHSPosition() 'установить позицию полосы прокрутки - кажется лишним - требует проверки
            'Case 1 'перенос слов в пределах окна
            Case 2 'без переноса слов
                'определить текущую позицию полосы прокрутки
                Dim SPos As Point = Point.Empty
                SendMessagePointB(RichTextBoxResult.Handle, EM_GETSCROLLPOS, 0, SPos)
                'установить новую позицию полосы прокрутки
                SPos.X = CInt(NewValue)
                SendMessagePointB(RichTextBoxResult.Handle, EM_SETSCROLLPOS, 0, SPos)
        End Select
    End Sub

2) обеспечим выделение текста с помощью мыши в зонах слева и справа от текстового окна (управляем свойством RichTextBoxResult.Capture = False/True):
Кликните здесь для просмотра всего текста
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
 'координаты границ окна для захвата мыши
    Dim CaptureX1 As Integer
    Dim CaptureY1 As Integer
    Dim CaptureX2 As Integer
    Dim CaptureY2 As Integer
 
    'Мышь над элементом - панель РР
    'PanelResult.MouseEnter
    'LabelLeft.MouseEnter
    'LabelPageLeft.MouseEnter
    'LabelPageTop.MouseEnter
    Private Sub PanelRresult_MouseEnter(sender As Object, e As EventArgs) Handles PanelResult.MouseEnter, LabelLeft.MouseEnter, LabelPageLeft.MouseEnter, LabelPageTop.MouseEnter
        StatusStripInfo.Text = "Редактирование результатов расчета"
        RichTextBoxResult.Capture = True 'захват мыши текстовым окном РР за пределами окна
 
        Select Case True
            Case sender Is PanelResult
                'координаты области захвата мыши
                CaptureX1 = RichTextBoxResult.Width
                CaptureY1 = -RichTextBoxResult.Top
                CaptureX2 = CaptureX1 + PanelResult.Width - PanelPageResult.Right - VSResult.Width
                CaptureY2 = RichTextBoxResult.Height
            Case sender Is LabelLeft, sender Is LabelPageLeft
                'координаты области захвата мыши
                CaptureX1 = -PanelPageResult.Left - RichTextBoxResult.Left
                CaptureY1 = -RichTextBoxResult.Top
                CaptureX2 = 0
                CaptureY2 = RichTextBoxResult.Height
            Case sender Is LabelPageTop
                'координаты области захвата мыши
                CaptureX1 = 0
                CaptureY1 = -RichTextBoxResult.Top
                CaptureX2 = RichTextBoxResult.Width
                CaptureY2 = 0
        End Select
    End Sub
 
    'Мышь над элементом - текстовое окно РР
    'AddHandler RichTextBoxResult.MouseMove
    Private Sub RichTextBoxResult_MouseMove(sender As Object, e As MouseEventArgs)
        StatusStripInfo.Text = "Редактирование результатов расчета"
        'снятие захвата мыши текстовым окном РР за пределами окна
        If RichTextBoxResult.Capture = False Then Exit Sub
        If e.X < CaptureX1 Or e.X > CaptureX2 Or e.Y < CaptureY1 Or e.Y > CaptureY2 Then RichTextBoxResult.Capture = False 'захват мыши текстовым окном РР за пределами окна
    End Sub

3) Еще требуется обеспечить изменение режимов представления и масштаба текстового окна:
Кликните здесь для просмотра всего текста
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
 'изменить режим представления текстового окна РР
    Private Sub SetRTBResultMode(Optional FlagVisible As Boolean = False) 'изменить режим представления текстового окна РР
        'скрыть элементы перед изменением режима
        If FlagVisible = True Then
            LabelLeft.Visible = False
            PanelPageResult.Visible = False
        End If
        Dim TextScale As Integer = My.Settings.ResultTextScale
        Select Case My.Settings.ResultMode
            Case 0 'перенос слов в пределах страницы
                PanelResult.BackColor = FormSettings.PictureBox0_01.BackColor 'фон текстового окна результатов расчета
                RichTextBoxResult.RightMargin = ResultPageWidthPixel - ResultPageMarginLeftPixel - ResultPageMarginRightPixel 'ширина страницы без полей
                If RichTextBoxResult.WordWrap = False Then RichTextBoxResult.WordWrap = True
                PanelPageResult.Dock = DockStyle.None
                FormSettings.RadioButtonResultModeWordwrapPage.Checked = True
                MenuStripViewWordwrapPage.Checked = True
                MenuStripViewWordwrapWindow.Checked = False
                MenuStripViewWordwrapNone.Checked = False
            Case 1 'перенос слов в пределах окна
                PanelResult.BackColor = SystemColors.Window 'фон текстового окна результатов расчета
                LabelLeft.Width = 0
                HSResult.Enabled = False 'полоса прокрутки не доступна
                RichTextBoxResult.Left = RichTextBoxResult.Top * 2
                LabelPageLeft.Width = RichTextBoxResult.Left
                RichTextBoxResult.RightMargin = 0
                If RichTextBoxResult.WordWrap = False Then RichTextBoxResult.WordWrap = True
                PanelPageResult.Dock = DockStyle.Fill
                FormSettings.RadioButtonResultModeWordwrapWindow.Checked = True
                MenuStripViewWordwrapPage.Checked = False
                MenuStripViewWordwrapWindow.Checked = True
                MenuStripViewWordwrapNone.Checked = False
            Case 2 'без переноса слов
                PanelResult.BackColor = SystemColors.Window 'фон текстового окна результатов расчета
                LabelLeft.Width = 0
                RichTextBoxResult.Left = RichTextBoxResult.Top * 2
                LabelPageLeft.Width = RichTextBoxResult.Left
                RichTextBoxResult.RightMargin = 0
                If RichTextBoxResult.WordWrap = True Then RichTextBoxResult.WordWrap = False
                PanelPageResult.Dock = DockStyle.Fill
                FormSettings.RadioButtonResultModeWordwrapNone.Checked = True
                MenuStripViewWordwrapPage.Checked = False
                MenuStripViewWordwrapWindow.Checked = False
                MenuStripViewWordwrapNone.Checked = True
        End Select
        SetResultTextScale(TextScale) 'установить масштаб текстового окна РР
        UpdateRTBResult() 'обновить параметры текстового окна
        PanelResult_HScroll() 'горизонтальный скроллинг панели результатов
        'SetRTBResultLeftPosition() 'выровнять левую границу текстового окна
        'показать элементы после изменения режима
        If FlagVisible = True Then
            LabelLeft.Visible = True
            PanelPageResult.Visible = True
        End If
    End Sub
 
    'определить количество физических строк - учитывает WordWrap=True
    Private Function GetRTBLinesCount() As Integer 'определить количество физических строк - учитывает WordWrap=True
        GetRTBLinesCount = RichTextBoxResult.GetLineFromCharIndex(RichTextBoxResult.TextLength) + 1
    End Function
 
    'определить ширину шрифта с учетом масштаба 
    Private Function GetRTBFontSizeZoom() As Integer 'определить ширину шрифта с учетом масштаба 
        GetRTBFontSizeZoom = CInt(RichTextBoxResult.Font.Size * RichTextBoxResult.ZoomFactor)
    End Function
 
 'изменить масштаб текстового окна РР - при нажатии "Ctrl+" и "Ctrl-"
    'AddHandler RichTextBoxResult.KeyDown
    Private Sub RichTextBoxResult_KeyDown(sender As Object, e As KeyEventArgs)
        If e.Control = True And e.Shift = False Then 'нажата клавиша Ctrl
            Select Case e.KeyCode
                Case Keys.Add ', Keys.Oemplus 'нажата клавиша "+"
                    SetScaleResultUp() 'увеличить на +10%
                Case Keys.Subtract ', Keys.OemMinus 'нажата клавиша "-"
                    SetScaleResultDown() 'уменьшить на -10%
            End Select
        End If
    End Sub
 
    'масштаб - увеличить на +10%
    Private Sub SetScaleResultUp() 'увеличить на +10%
        My.Settings.ResultTextScaleMode = 0 'режим масштаба текстового окна - 0 произвольный масштаб
        Dim TextScale As Integer = CInt(Math.Floor((My.Settings.ResultTextScale + 10) / 10) * 10)
        FitValueToIntervalInteger(TextScale, 10, 500) 'подогнать число Integer в заданный интервал значений
        SetResultTextScale(TextScale)
        UpdateRTBResult() 'обновить параметры текстового окна
    End Sub
 
    'масштаб - уменьшить на -10%
    Private Sub SetScaleResultDown() 'уменьшить на -10%
        My.Settings.ResultTextScaleMode = 0 'режим масштаба текстового окна - 0 произвольный масштаб
        Dim TextScale As Integer = CInt(Math.Ceiling((My.Settings.ResultTextScale - 10) / 10) * 10)
        FitValueToIntervalInteger(TextScale, 10, 500) 'подогнать число Integer в заданный интервал значений
        SetResultTextScale(TextScale)
        UpdateRTBResult() 'обновить параметры текстового окна
    End Sub
 
    'панель результатов - вращение колесика мыши - изменение масштаба текстового окна РР
    Private Sub PanelResult_MouseWheel(sender As Object, e As MouseEventArgs) Handles PanelResult.MouseWheel
        If My.Computer.Keyboard.CtrlKeyDown = False Then
            RichTextBoxResult_MouseWheel(sender, e) 'текстовое окно РР - вертикальная прокрутка колесиком мыши
            Exit Sub 'если не нажата клавиша Ctrl - выходим
        End If
        Select Case Math.Sign(e.Delta)
            Case Is > 0
                SetScaleResultUp() 'увеличить на +10%
            Case Is < 0
                SetScaleResultDown() 'уменьшить на -10%
        End Select
    End Sub

Весь код привести не получилось. Понимаю, что в чужом коде копаться - дело неблагодарное, постарался показать основную идею.
0
7 / 7 / 0
Регистрация: 11.12.2022
Сообщений: 12
18.12.2022, 09:09
Работа с текстовыми окнами

ввод только чисел (в рассмотрение включен случай, когда в тексте был выделен фрагмент):
Кликните здесь для просмотра всего текста
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
Private Sub TextBox1_KeyPress(sender As Object, e As KeyPressEventArgs) Handles TextBox1.KeyPress
        KeyPressOnlyDoubleValue(sender, e)
End Sub
 
Private Sub KeyPressOnlyDoubleValue(sender As Object, e As KeyPressEventArgs)
 
'системный десятичный разделитель 
Dim CurrentDecimalSeparator As Char = System.Globalization.CultureInfo.CurrentCulture.NumberFormat.CurrencyDecimalSeparator(0)
 
'элемент, в котором происходит событие
Dim TempTextBox As TextBox = CType(sender, TextBox)
 
'если в тексте был выделен фрагмент - запоминаем текст, в котором удален выделенный фрагмент, чтобы проверить его
Dim TempString As String = TempTextBox.Text.Remove(TempTextBox.SelectionStart, TempTextBox.SelectionLength)
 
        'проверяем вводимый символ
        Select Case Asc(e.KeyChar)
 
            Case 8 'Backspace - ввод разрешен
 
            'Для целых числе запрет ввода 0 с первой позиции
            'Case 48 'цифра "0" - ввод разрешен
            '    'если знак вводится начиная с первой позиции - блокировка ввода
            '    If TempTextBox.SelectionStart = 0 Then e.Handled = True
 
            Case 48 To 57 'все цифры "0123456789" - ввод разрешен
 
            'Разрешить ввод символа Плюс "+"
            'Case 43 'Плюс "+"
            '    'если знак вводится начиная со второй позиции - блокировка ввода
            '    If TempTextBox.SelectionStart <> 0 Then e.Handled = True
            '    'если знак уже вводился - блокировка ввода
            '    If Strings.InStr(TempString, "+") <> 0 Then e.Handled = True
 
            Case 44 'Запятая ","
                'заменяем "," на текущий десятичный разделитель
                e.KeyChar = CurrentDecimalSeparator
                'если знак уже вводился - блокировка ввода
                If Strings.InStr(TempString, CurrentDecimalSeparator) <> 0 Then e.Handled = True
 
            Case 45 'Минус "-"
                'если знак вводится начиная со второй позиции - блокировка ввода
                If TempTextBox.SelectionStart <> 0 Then e.Handled = True
                'если знак уже вводился - блокировка ввода
                If Strings.InStr(TempString, "-") <> 0 Then e.Handled = True
 
            Case 46 'Точка "."
                'заменяем "." на текущий десятичный разделитель
                e.KeyChar = CurrentDecimalSeparator
                'если знак уже вводился - блокировка ввода
                If Strings.InStr(TempString, CurrentDecimalSeparator) <> 0 Then e.Handled = True
 
            Case Else 'в остальных случаях - блокировка ввода
                e.Handled = True
 
        End Select
    End Sub

Однако при вставке текста из буфера обмена пользователь сможет обойти эти ограничения.
Поэтому перед использованием числа из текстового окна выполняем проверку:
Кликните здесь для просмотра всего текста
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
Private Function CheckTextBoxMinMaxDoubleValue(ByRef TempTextBox As TextBox, MinValue As Double, MaxValue As Double, OldValue As Double, NewIndexLabelMenuChecked As Integer, MessageString As String, Optional TabControlCalcSelectedIndex As Integer = -1, Optional FlagOver As Boolean = False) As Boolean
        '----------------------------------------------------
        Dim TempValue As Double
        'если строку можно преобразовать в Double
        If Double.TryParse(TempTextBox.Text, TempValue) = True Then
 
            Select Case FlagOver 'вариант условия (включать границы интервала или нет)
 
                Case True 'без учета границ
                    'если число задано в пределах допустимого диапазона
                    If TempValue > MinValue And TempValue < MaxValue Then
                        CheckTextBoxMinMaxDoubleValue = True
                        'принять новое значение
                        TempTextBox.Text = TempValue.ToString
                        Exit Function 'выходим
                    End If
 
                Case False 'с учетом границ
 
                    'если число задано в пределах допустимого диапазона
                    If TempValue >= MinValue And TempValue <= MaxValue Then
                        CheckTextBoxMinMaxDoubleValue = True
                        'принять новое значение
                        TempTextBox.Text = TempValue.ToString
                        Exit Function 'выходим
                    End If
 
            End Select
 
        End If
 
        'во всех других случаях - отказ
        CheckTextBoxMinMaxDoubleValue = False
 
        'показываем окно предупреждения
        MessageBox.Show(MessageString, My.Application.Info.Title, MessageBoxButtons.OK, MessageBoxIcon.Warning)
 
        'установить текущее (старое) значение
        TempTextBox.Text = OldValue.ToString
        TempTextBox.Select() 'установить курсор на элемент
 
End Function
Указанный код можно адаптировать для целых чисел, положительных и отрицательных.

Часто бывает удобно, чтобы при попадании фокуса на текстовое поле, курсор размещался за крайним правым символом:
Кликните здесь для просмотра всего текста
VB.NET
1
2
3
4
5
6
Private Sub TextBoxGotFocus(sender As Object, e As EventArgs) 
       'элемент, в котором происходит событие
        Dim TempTextBox As TextBox = CType(sender, TextBox)
        'установить курсор в крайнее правое положение
        TempTextBox.SelectionStart = TempTextBox.TextLength
End Sub
0
7 / 7 / 0
Регистрация: 11.12.2022
Сообщений: 12
24.12.2022, 07:42
Полезный код для ComboBox

1) Всплывающая подсказка для элементов списка
На форме должны быть расположены:
ComboBox1 - имя контрола ComboBox (необходимо задать режим "ручной" прорисовки элементов списка ComboBox1.DrawMode = DrawMode.OwnerDrawFixed)
ToolTip1 - контрол всплывающей подсказки
Кликните здесь для просмотра всего текста
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
Imports System
Imports System.Drawing
Imports System.ComponentModel
'прорисовка элементов списка и отслеживание расположения мыши над конкретным элементом
Private Sub ComboBox1_DrawItem(sender As Object, e As DrawItemEventArgs) Handles ComboBox1.SelectedIndexChanged
        'если выводится какой-либо элемент списка
        If e.Index <> -1 Then
 
            'текст элемента списка
            Dim TempString As String = ComboBox1.GetItemText(ComboBox1.Items(e.Index))
 
            'если указатель мыши над элементом списка
            If (e.State And DrawItemState.Selected) = DrawItemState.Selected Then
                'если список открыт
                If ComboBox1.DroppedDown = True Then
                        'показываем подсказку в заданных координатах относительно списка
                        ToolTip1.Show(TempString, ComboBox1, 0, -ComboBox1.Height)
                End If
            End If
 
            e.DrawBackground() 'прорисовка фона элемента
            'прорисовка текста
            e.Graphics.DrawString(TempString, e.Font, New SolidBrush(e.ForeColor), e.Bounds)
            e.DrawFocusRectangle() 'если элемент находится в фокусе - прорисовка пунктирной рамки
        End If
End Sub
'мышь над элементом - установить всплывающую подсказку для списка
Private Sub ComboBox1_MouseHover(sender As Object, e As EventArgs) Handles ComboBox1.MouseHover
         'если выбран какой-либо элемент списка            
        If ComboBox1.SelectedIndex <> -1 Then
            ToolTip1.SetToolTip(ComboBox1, ComboBox1.GetItemText(ComboBox1.SelectedItem))
        Else 
            ToolTip1.SetToolTip(ComboBox1, "Выбрать элемент списка")
        End If
End Sub 
'скрыть всплывающую подсказку
Private Sub ComboBox1_MouseLeave_DropDownClosed(sender As Object, e As EventArgs) Handles ComboBox1.MouseLeave, ComboBox1.DropDownClosed
        ToolTip1.Hide(ComboBox1) 'скрыть подсказку
End Sub

2) Цветные элементы списка
На форме должны быть расположены:
ComboBoxColorScheme - контрол ComboBox с элементами списка, обозначающими цветовую схему:
Black; DarkStateGray; Brown; SaddleBrown; OrangeRed; ForestGreen; SeaGreen; RoyalBlue
Необходимо задать режим "ручной" прорисовки элементов списка ComboBoxColorScheme.DrawMode = DrawMode.OwnerDrawFixed
LabelSampleColorScheme - метка, цвет которой соответствует элементу списка (образец выбранного цвета)
Кликните здесь для просмотра всего текста
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
Imports System
Imports System.Drawing
Imports System.ComponentModel
 
'изменение индекса элемента списка цветовой схемы
    Private Sub ComboBoxColorScheme_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ComboBoxColorScheme.SelectedIndexChanged
        'установить цвет на образце цветовой схемы
        LabelSampleColorScheme.BackColor = GetColor(ComboBoxColorScheme.SelectedIndex)
    End Sub
 
 'текущий цвет
    Private Function GetColor(ColorIndex As Integer) As System.Drawing.Color 'установить цвет
        Dim TempColor As System.Drawing.Color = Color.RoyalBlue 'по умолчанию
        Select Case ColorIndex
            Case 0
                TempColor = Color.Black
            Case 1
                TempColor = Color.DarkSlateGray
            Case 2
                TempColor = Color.Brown
            Case 3
                TempColor = Color.SaddleBrown
            Case 4
                TempColor = Color.OrangeRed
            Case 5
                TempColor = Color.ForestGreen
            Case 6
                TempColor = Color.SeaGreen
            Case 7
                TempColor = Color.RoyalBlue
        End Select
        GetColor = TempColor
    End Function
 
'прорисовка элементов списка и отслеживание расположения мыши над конкретным элементом
    Private Sub ComboBoxColorScheme_DrawItem(sender As Object, e As DrawItemEventArgs) Handles ComboBoxColorScheme.DrawItem
        'если выводится какой-либо элемент списка
        If e.Index <> -1 Then
            'цвет элемента списка по-умолчанию
            Dim TempColor As Color '= e.ForeColor
 
            'если указатель мыши над элементом списка
            If (e.State And DrawItemState.Selected) = DrawItemState.Selected Then
                'цвет выделенного элемента списка
                TempColor = SystemColors.HighlightText
            Else 'если указатель не над элементом списка
                'задаем цвет элемента списка соответственно его названию
                TempColor = FormMain.GetColor(e.Index)
            End If
 
            e.DrawBackground() 'прорисовка текста на заднем фоне Background элемента
            'текст списка
            e.Graphics.DrawString(ComboBoxColorScheme.GetItemText(ComboBoxColorScheme.Items(e.Index)), e.Font, New SolidBrush(TempColor), e.Bounds)
            e.DrawFocusRectangle() 'если элемент находится в фокусе - прорисовка пунктирной рамки
 
            'изменение цветовой схемы в зависимости от расположения указателя мыши над элементом списка
            LabelSampleColorScheme.BackColor = FormMain.GetColor(e.Index)
 
        End If
    End Sub

3) Раскрыть/закрыть список нажатием клавиши пробела
Кликните здесь для просмотра всего текста
VB.NET
1
2
3
4
Private Sub ComboBoxColorScheme_KeyUp(sender As Object, e As KeyEventArgs) Handles ComboBox1.KeyUp, ComboBoxColorScheme.KeyUp
        Dim TempComboBox As ComboBox = CType(sender, ComboBox) 'элемент, в котором происходит событие
        If e.KeyCode = Keys.Space Then TempComboBox.DroppedDown = Not TempComboBox.DroppedDown 'при отпускании клавиши Space
    End Sub
0
7 / 7 / 0
Регистрация: 11.12.2022
Сообщений: 12
24.12.2022, 16:13
Имитация плоской кнопки (Button) с помощью метки (Label),
которая реагирует только на события мыши и не может получить фокус,
код подходит для группы из нескольких элементов.

Заранее подготовьте три цвета, например, такие:
Кликните здесь для просмотра всего текста
VB.NET
1
2
3
Dim Color1 As System.Drawing.Color = Color.RoyalBlue 'исходный цвет метки
Dim Color2 As System.Drawing.Color = ColorTranslator.FromHtml("#6787E7") 'цвет метки при наведении указателя мыши
Dim Color3 As System.Drawing.Color = ColorTranslator.FromHtml("#D0DAF7") 'цвет метки при нажатии кнопки мыши

На форме разместите две метки Label1, Label2 или другое количество - по необходимости.
настройте внешний вид и исходный цвет меток:
Кликните здесь для просмотра всего текста
VB.NET
1
2
3
4
5
6
7
8
Label1.FlatStyle = FlatStyle.Standard
Label1.BorderStyle = BorderStyle.None
Label1.BackColor = Color1
Label1.ForeColor = SystemColors.Window
Label2.FlatStyle = FlatStyle.Standard
Label2.BorderStyle = BorderStyle.None
Label2.BackColor = Color1
Label2.ForeColor = SystemColors.Window

Код для событий меток
Кликните здесь для просмотра всего текста
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
Imports System
Imports System.Drawing
Imports System.ComponentModel
 
'мышь над элементом
Private Sub Label1_MouseMove(sender As Object, e As MouseEventArgs) Handles Label1.MouseMove, Label2.MouseMove
        SetControlBackColorAnyMouseMove(sender, e) 'установить цвет фона метки при событии MouseMove
End Sub
 
'установить цвет фона метки при событии MouseMove
Private Sub SetControlBackColorAnyMouseMove(sender As Object, e As MouseEventArgs)
        Dim TempControl As Control = CType(sender, Control) 'элемент
        TempControl.BackColor = Color2 'цвет метки при наведении указателя мыши
        If e.Button = MouseButtons.Left Then 'если нажата левая кнопка мыши
            If CheckCursorPositionInSideBoundsControl(sender, e) = True Then 'если указатель мыши в пределах элемента
                TempControl.BackColor = Color3 'цвет метки при нажатии кнопки мыши
            End If
        End If
End Sub
 
'определить - находится ли указатель мыши в пределах элемента
Private Function CheckCursorPositionInSideBoundsControl(sender As Object, e As MouseEventArgs) As Boolean
        CheckCursorPositionInSideBoundsControl = False 'указатель мыши за пределами метки
        Dim TempControl As Control = CType(sender, Control)
        If e.X >= 0 Then
            If e.X <= TempControl.Width Then
                If e.Y >= 0 Then
                    If e.Y <= TempControl.Height Then
                        CheckCursorPositionInSideBoundsControl = True 'указатель мыши в пределах метки
                    End If
                End If
            End If
        End If
End Function
 
'нажать кнопку мыши
Private Sub Label1_MouseDown(sender As Object, e As MouseEventArgs) Handles Label1.MouseDown, Label2.MouseDown
        SetControlBackColorAnyMouseDown(sender, e) 'установить цвет фона метки при событии MouseDown
End Sub
 
'установить цвет фона метки при событии MouseDown
Private Sub SetControlBackColorAnyMouseDown(sender As Object, e As MouseEventArgs)
        If e.Button = MouseButtons.Left Then 'если нажата левая кнопка мыши
            Dim TempControl As Control = CType(sender, Control) 'элемент
            TempControl.BackColor = Color3 'цвет метки при нажатии кнопки мыши
        End If
End Sub
 
'отжать кнопку мыши - выполнение команд для каждой метки
Private Sub Label1_MouseUp(sender As Object, e As MouseEventArgs) Handles Label1.MouseUp, Label2.MouseUp
        If e.Button <> MouseButtons.Left Then Exit Sub 'если не нажата левая кнопка мыши - выходим
        SetControlBackColorAnyMouseUp(sender, e) 'установить цвет фона метки при событии MouseUp
        If CheckCursorPositionInSideBoundsControl(sender, e) = False Then Exit Sub 'если координаты мыши за пределами элемента - выходим
 
'код команд для каждой метки
        Select Case True
            Case sender Is Label1
            'вставьте код команды для метки 1
              
            Case sender Is Label2
            'вставьте код команды для метки 2
 
        End Select
End Sub
 
'установить цвет фона метки при событии MouseUp
Private Sub SetControlBackColorAnyMouseUp(sender As Object, e As MouseEventArgs)
        If e.Button = MouseButtons.Left Then 'если нажата левая кнопка мыши
            Dim TempControl As Control = CType(sender, Control) 'элемент
            TempControl.BackColor = Color1 'исходный цвет метки
        End If
End Sub
 
'покидание указателя мыши зоны метки
Private Sub Label1_MouseLeave(sender As Object, e As EventArgs) Handles Label1.MouseLeave, Label2.MouseLeave
        SetControlBackColorAnyMouseLeave(sender) 'установить цвет фона метки при событии MouseLeave
End Sub
 
'установить цвет фона метки при событии MouseLeave
Private Sub SetControlBackColorAnyMouseLeave(sender As Object)
        Dim TempControl As Control = CType(sender, Control) 'элемент
        TempControl.BackColor = Color1 'исходный цвет метки
End Sub
0
69 / 65 / 5
Регистрация: 11.04.2021
Сообщений: 288
Записей в блоге: 7
25.12.2022, 06:39
Думаю понадобиться тем кто занимается графикой и игростроением
В архиве рабочий пример по применению

VB.NET
1
2
3
4
5
6
7
8
9
    ''' <summary>
    ''' Эта функция поможет развернуть картинку в направлении движения ...к примеру курсора
    ''' </summary>
    ''' <param name="penultimate">предпоследняя координата курсора</param>
    ''' <param name="last">последняя</param>
    ''' <returns>на выхлопе имеем градусы на которые нужно повернуть картинку</returns>
    Private Function DirectionOfTravel(penultimate As Point, last As Point) As Single
        Return Atan2(last.X - penultimate.X, -(last.Y - penultimate.Y)) * (180 / PI)
    End Function
Вложения
Тип файла: zip DirectionOfTravel.zip (9.2 Кб, 36 просмотров)
1
7 / 7 / 0
Регистрация: 11.12.2022
Сообщений: 12
25.12.2022, 08:53
Некоторые приемы для разработки текста в формате RTF на базе контрола RichTextBox

1) Если текст должен иметь сложную структуру, например, таблицы с ячейками в несколько строк, то "родная" библиотека Visual Studio riched20.dll не позволяет это реализовать. В этом случае рекомендую использовать библиотеку msftedit.dll, поставляемую с программой WordPad, вариант реализации описан здесь: Готовые решения и полезные коды на Visual Basic .NET (Часть-2). Там же приводится метод печати содержимого RichTextBox.

в проекте использую два экземпляра RichTextBox
Кликните здесь для просмотра всего текста
VB.NET
1
2
Dim RichTextBoxResult As New RichTextBoxE 'основное окно редактора - видимое
Dim TempRichTextBoxResult As New RichTextBoxE 'временное вспомогательное окно - невидимое

2) Для отработки форматирования текста удобно использовать две процедуры по конвертации текста с кодом RTF и без кода RTF:
Кликните здесь для просмотра всего текста
VB.NET
1
2
3
4
5
6
7
8
9
10
11
12
13
 'представить текст без кода в формате RTF
    Private Sub TXTtoRTF()
        TempRichTextBoxResult.Rtf = RichTextBoxResult.Rtf 'запомнить исходный текст
        Try
            RichTextBoxResult.Rtf = RichTextBoxResult.Text
        Catch ex As Exception 
            RichTextBoxResult.Rtf = TempRichTextBoxResult.Rtf 'в случае неудачи - вернуть исходный текст
        End Try
    End Sub
    'представить текст с кодом в формате RTF
    Private Sub RTFtoTXT() 
        RichTextBoxResult.Text = RichTextBoxResult.Rtf
    End Sub

Эти процедуры удобно вызывать во время выполнения приложения кнопками/элементами/командами, что позволяет в онлайн режиме редактировать RTF код и изучать его влияние на представление текста, например, если в окне RichTextBoxResult с текущим шрифтом Times New Roman написать строку: 0123456789, то текст с RTF кодом будет иметь вид:
Кликните здесь для просмотра всего текста
{\rtf1\ansi\ansicpg1251\deff0\nouicompat \deflang1049{\fonttbl{\f0\fnil\fcharset2 04 Times New Roman;}}
{\*\generator Riched20 10.0.14393}\viewkind4\uc1
\pard\f0\fs24 0123456789\par
}

То есть RTF код автоматически генерируется окном RichTextBoxResult - остается только списать . Дальше вооружаетесь последней спецификацией формата RTF (на сегодня версия 1.9.1) и путем супермощного метода проб и ошибок формируете текст с необходимой структурой. Очень удобно разработать макет будущего текста в каком-либо продвинутом редакторе, например, MS Word, затем скопировать его в окно RichTextBoxResult и увидеть RTF код. В следующем примере выводится таблица из двух строк и четырех столбцов, в которой в столбце 2 две строки объединены в одну ячейку:
Кликните здесь для просмотра всего текста
{\rtf1\ansi\ansicpg1251\deff0\nouicompat \deflang1049{\fonttbl{\f0\froman\fprq2\f charset204 Times New Roman;}{\f1\fnil\fcharset204 Times New Roman;}}
{\*\generator Riched20 10.0.14393}\viewkind4\uc1
\pard\widctlpar\f0\fs28\'d2\'e0\'e1\'eb\ 'e8\'f6\'e0 \'f1 \'ff\'f7\'e5\'e9\'ea\'e0\'ec\'e8 \'e2 \'ed\'e5\'f1\'ea\'ee\'eb\'fc\'ea\'ee \'f1\'f2\'f0\'ee\'ea\par
\trowd\trgaph108\trleft5\trbrdrl\brdrs\b rdrw10 \trbrdrt\brdrs\brdrw10 \trbrdrr\brdrs\brdrw10 \trbrdrb\brdrs\brdrw10 \trpaddl108\trpaddr108\trpaddfl3\trpaddf r3
\clvertalc\clbrdrl\brdrw10\brdrs\clbrdrt \brdrw10\brdrs\clbrdrr\brdrw10\brdrs\clb rdrb\brdrw10\brdrs \cellx2341\clvmgf\clvertalc\clbrdrl\brdr w10\brdrs\clbrdrt\brdrw10\brdrs\clbrdrr\ brdrw10\brdrs\clbrdrb\brdrw10\brdrs \cellx4677\clvertalc\clbrdrl\brdrw10\brd rs\clbrdrt\brdrw10\brdrs\clbrdrr\brdrw10 \brdrs\clbrdrb\brdrw10\brdrs \cellx7013\clvertalc\clbrdrl\brdrw10\brd rs\clbrdrt\brdrw10\brdrs\clbrdrr\brdrw10 \brdrs\clbrdrb\brdrw10\brdrs \cellx9349
\pard\intbl\widctlpar\qc 1.1\cell 1.2\cell 1.3\cell 1.4\cell\row\trowd\trgaph108\trleft5\trb rdrl\brdrs\brdrw10 \trbrdrt\brdrs\brdrw10 \trbrdrr\brdrs\brdrw10 \trbrdrb\brdrs\brdrw10 \trpaddl108\trpaddr108\trpaddfl3\trpaddf r3
\clvertalc\clbrdrl\brdrw10\brdrs\clbrdrt \brdrw10\brdrs\clbrdrr\brdrw10\brdrs\clb rdrb\brdrw10\brdrs \cellx2341\clvmrg\clvertalc\clbrdrl\brdr w10\brdrs\clbrdrt\brdrw10\brdrs\clbrdrr\ brdrw10\brdrs\clbrdrb\brdrw10\brdrs \cellx4677\clvertalc\clbrdrl\brdrw10\brd rs\clbrdrt\brdrw10\brdrs\clbrdrr\brdrw10 \brdrs\clbrdrb\brdrw10\brdrs \cellx7013\clvertalc\clbrdrl\brdrw10\brd rs\clbrdrt\brdrw10\brdrs\clbrdrr\brdrw10 \brdrs\clbrdrb\brdrw10\brdrs \cellx9349
\pard\intbl\widctlpar\qc 2.1\cell\cell 2.3\cell 2.4\cell\row
\pard\f1\fs24\par
}

Из полученного RTF кода удаляю всякий "хлам", который никак не влияет на структуру текста.

3) При программном создании RTF кода очень эффективно использовать класс StringBuilder. При больших объемах текста после использования StringBuilder следует применить метод Clear для освобождения памяти. В качестве примера ниже привожу фрагмент кода из своего инженерного приложения:
Кликните здесь для просмотра всего текста
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
'Результаты расчета - создание Раздела исходных данных в формате RTF
Private Function GetRTFResultInputData() As String 'Результаты расчета - создание Раздела исходных данных в формате RTF
        Dim TempRTFStringBuilder As New System.Text.StringBuilder 'Строка РР в формате RTF
        'Результаты расчета - Заголовок
        TempRTFStringBuilder.Append("Приложение " & Chr(34) & My.Application.Info.Title & Chr(34) & " версия " & My.Application.Info.Version.ToString & "\par" & vbCrLf)
        TempRTFStringBuilder.Append(Strings.Format(System.DateTime.Now, "dd.MM.yy HH:mm:ss") & " Начало расчета\par\par" & vbCrLf)
        'Результаты расчета - исходные данные
        TempRTFStringBuilder.Append("1 Исходные данные\par\par" & vbCrLf)
        'Параметры расчета
        TempRTFStringBuilder.Append("Таблица 1.1 – Параметры расчета\par" & vbCrLf)
        TempRTFStringBuilder.Append("\trowd\trgaph108\trleft5\trbrdrl\brdrs\brdrw10 \trbrdrt\brdrs\brdrw10 \trbrdrr\brdrs\brdrw10 \trbrdrb\brdrs\brdrw10 \trpaddl108\trpaddr108\trpaddfl3\trpaddfr3\clvertalc\clbrdrl\brdrw10\brdrs\clbrdrt\brdrw10\brdrs\clbrdrr\brdrw10\brdrs\clbrdrb\brdrw10\brdrs \cellx2750\clvertalc\clbrdrl\brdrw10\brdrs\clbrdrt\brdrw10\brdrs\clbrdrr\brdrw10\brdrs\clbrdrb\brdrw10\brdrs \cellx9350\pard\intbl\qc Параметр\cell Значение\cell\row" & vbCrLf)
        'формирование строки описания
        Dim TempString As String = "Текст описания"
        TempRTFStringBuilder.Append("\trowd\trgaph108\trleft5\trbrdrl\brdrs\brdrw10 \trbrdrt\brdrs\brdrw10 \trbrdrr\brdrs\brdrw10 \trbrdrb\brdrs\brdrw10 \trpaddl108\trpaddr108\trpaddfl3\trpaddfr3\clvertalc\clbrdrl\brdrw10\brdrs\clbrdrt\brdrw10\brdrs\clbrdrr\brdrw10\brdrs\clbrdrb\brdrw10\brdrs \cellx2750\clvertalc\clbrdrl\brdrw10\brdrs\clbrdrt\brdrw10\brdrs\clbrdrr\brdrw10\brdrs\clbrdrb\brdrw10\brdrs \cellx9350\pard\intbl Описание\cell " & TempString & "\cell\row" & vbCrLf)
        TempRTFStringBuilder.Append("\pard\par" & vbCrLf)
 
        'заголовок Таблицы 1.2 – Структура ПКМ
        TempRTFStringBuilder.Append("Таблица 1.2 – Структура ПКМ\par" & vbCrLf)
        'заголовок таблицы
        'заголовок таблицы - первый уровень
        TempRTFStringBuilder.Append("\trowd\trgaph108\trleft5\trbrdrl\brdrs\brdrw10 \trbrdrt\brdrs\brdrw10 \trbrdrr\brdrs\brdrw10 \trbrdrb\brdrs\brdrw10 \trpaddl108\trpaddr108\trpaddfl3\trpaddfr3" & vbCrLf)
        TempRTFStringBuilder.Append("\clvmgf\clvertalc\clbrdrl\brdrw10\brdrs\clbrdrt\brdrw10\brdrs\clbrdrr\brdrw10\brdrs \cellx800" & vbCrLf)
        TempRTFStringBuilder.Append("\clvmgf\clvertalc\clbrdrl\brdrw10\brdrs\clbrdrt\brdrw10\brdrs\clbrdrr\brdrw10\brdrs \cellx3900" & vbCrLf)
        TempRTFStringBuilder.Append("\clvertalc\clbrdrl\brdrw10\brdrs\clbrdrt\brdrw10\brdrs\clbrdrr\brdrw10\brdrs\clbrdrb\brdrw10\brdrs \cellx5900" & vbCrLf)
        TempRTFStringBuilder.Append("\clvmgf\clvertalc\clbrdrl\brdrw10\brdrs\clbrdrt\brdrw10\brdrs\clbrdrr\brdrw10\brdrs \cellx6850" & vbCrLf)
        TempRTFStringBuilder.Append("\clvmgf\clvertalc\clbrdrl\brdrw10\brdrs\clbrdrt\brdrw10\brdrs\clbrdrr\brdrw10\brdrs \cellx8300" & vbCrLf)
        TempRTFStringBuilder.Append("\clvmgf\clvertalc\clbrdrl\brdrw10\brdrs\clbrdrt\brdrw10\brdrs\clbrdrr\brdrw10\brdrs \cellx9350" & vbCrLf)
        TempRTFStringBuilder.Append("\pard\intbl\qc №\par слоя\cell Материал\cell Угол армир., °\cell Кол. мон.\cell Толщина, мм\cell Доля, %\cell\row" & vbCrLf)
        'заголовок таблицы - второй уровень
        TempRTFStringBuilder.Append("\trowd\trgaph108\trleft5\trbrdrl\brdrs\brdrw10 \trbrdrt\brdrs\brdrw10 \trbrdrr\brdrs\brdrw10 \trbrdrb\brdrs\brdrw10 \trpaddl108\trpaddr108\trpaddfl3\trpaddfr3" & vbCrLf)
        TempRTFStringBuilder.Append("\clvmrg\clvertalc\clbrdrl\brdrw10\brdrs\clbrdrr\brdrw10\brdrs\clbrdrb\brdrw10\brdrs \cellx800" & vbCrLf)
        TempRTFStringBuilder.Append("\clvmrg\clvertalc\clbrdrl\brdrw10\brdrs\clbrdrr\brdrw10\brdrs\clbrdrb\brdrw10\brdrs \cellx3900" & vbCrLf)
        TempRTFStringBuilder.Append("\clvertalc\clbrdrl\brdrw10\brdrs\clbrdrt\brdrw10\brdrs\clbrdrr\brdrw10\brdrs\clbrdrb\brdrw10\brdrs \cellx4900" & vbCrLf)
        TempRTFStringBuilder.Append("\clvertalc\clbrdrl\brdrw10\brdrs\clbrdrt\brdrw10\brdrs\clbrdrr\brdrw10\brdrs\clbrdrb\brdrw10\brdrs \cellx5900" & vbCrLf)
        TempRTFStringBuilder.Append("\clvmrg\clvertalc\clbrdrl\brdrw10\brdrs\clbrdrr\brdrw10\brdrs\clbrdrb\brdrw10\brdrs \cellx6850" & vbCrLf)
        TempRTFStringBuilder.Append("\clvmrg\clvertalc\clbrdrl\brdrw10\brdrs\clbrdrr\brdrw10\brdrs\clbrdrb\brdrw10\brdrs \cellx8300" & vbCrLf)
        TempRTFStringBuilder.Append("\clvmrg\clvertalc\clbrdrl\brdrw10\brdrs\clbrdrr\brdrw10\brdrs\clbrdrb\brdrw10\brdrs \cellx9350" & vbCrLf)
        TempRTFStringBuilder.Append("\pard\intbl\qc\cell\cell по 0°\cell по X\cell\cell\cell\cell\cell\row" & vbCrLf)
 
        'вывод строк таблицы - в данном примере пропущено
        'Окончание таблицы - в данном примере пропущено
        'Примечание - в данном примере пропущено
 
        TempRTFStringBuilder.Append("\pard\par" & vbCrLf)
 
        'создать раздел исходных данных в формате RTF
        GetRTFResultInputData = TempRTFStringBuilder.ToString 'возврат функции созданной строки в формате RTF
        TempRTFStringBuilder.Clear() 'очистить строку
 
End Function
1
7 / 7 / 0
Регистрация: 11.12.2022
Сообщений: 12
28.12.2022, 17:09
Получение позиции вертикального скроллинга RichTextBox с помощью Win API

Сначала уточнение по библиотекам riched20.dll и msftedit.dll, которые обеспечивают работу Rich Text Edit Control (по нашему RichTextBox).
Буквально недавно выяснил, что при Net Framework версии 4.7.2 и выше - riched20.dll прекрасно работает, в том числе поддерживает таблицы с многострочными ячейками и надобность в подключении библиотеки msftedit.dll отпадает.

Кроме того, раньше была проблема скроллинга текста с позицией свыше 16 bit (свыше числа 65535). При получении (Get) позиции скроллбара через API функцию - она не могла превысить число 65535. При этом установка (Set) позиции свыше 65535 происходила нормально. Долго не мог въехать в этот глюк . При Net Framework версии 4.7.2 и выше Get и Set работают корректно.

Что касается msftedit.dll, то проблема 16 bit имеется в Rich Text Edit Control версии ниже 7.5 (версия файла 6.3), это было еще при Windows 7. Для msftedit.dll версия Net Framework не играет роли.

Теперь про скроллинг. Изучил три API функции получения/установки вертикальной позиции текста:

Функция 1 (GetScrollPos) - не работает (выдает 0), если в текстовом окне вертикальный ScrollBar выключен
Кликните здесь для просмотра всего текста
VB.NET
1
2
3
4
5
6
7
8
9
10
   'получить/установить позицию ScrollBar
    Const SB_HORZ As Integer = 0
    Const SB_VERT As Integer = 1
    Const SB_CTL As Integer = 2
    Const SB_BOTH As Integer = 3
    Declare Function GetScrollPos Lib "user32.dll" (hWnd As IntPtr, nBar As Integer) As Long
    Declare Function SetScrollPos Lib "user32.dll" (hWnd As IntPtr, nBar As Integer, nPos As Integer, bRedraw As Boolean) As Long
    Private Function GetVSPos1(rtb As RichTextBox) As Long
        GetVSPos1 = GetScrollPos(rtb.Handle, SB_VERT)
    End Function

Функция 2 (SendMessage) - работает независимо от того, выключен или выключен вертикальный ScrollBar
Кликните здесь для просмотра всего текста
VB.NET
1
2
3
4
5
6
7
8
9
10
11
    'получить/установить позицию ScrollBar
    Const WM_USER As Integer = &H400
    Const EM_GETSCROLLPOS As Integer = WM_USER + 221
    Const EM_SETSCROLLPOS As Integer = WM_USER + 222
    Declare Function SendMessagePoint Lib "user32.dll" Alias "SendMessageA" (ByVal hWnd As IntPtr, ByVal msg As Integer, ByVal wParam As Integer, ByRef lParam As Point) As Boolean
    'вариант 2
    Private Function GetVSPos2(rtb As RichTextBox) As Point
        Dim TempPoint As Point = Point.Empty
        SendMessagePoint(rtb.Handle, EM_GETSCROLLPOS, 0, TempPoint)
        GetVSPos2 = TempPoint
    End Function

Функция 3 (GetScrollInfo) - не работает (выдает 0), если в текстовом окне вертикальный ScrollBar выключен
Кликните здесь для просмотра всего текста
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
    'получить/установить параметры ScrollBar
    Structure SCROLLINFO
        Dim cbSize As Integer
        Dim fMask As Integer
        Dim nMin As Integer
        Dim nMax As Integer
        Dim nPage As Integer
        Dim nPos As Integer
        Dim nTrackPos As Integer
    End Structure
    Private Enum ScrollInfoMask
        SIF_RANGE = 1
        SIF_PAGE = 2
        SIF_POS = 4
        SIF_DISABLENOSCROLL = 8
        SIF_TRACKPOS = 10
        SIF_ALL = (SIF_RANGE Or SIF_PAGE Or SIF_POS Or SIF_DISABLENOSCROLL Or SIF_TRACKPOS)
    End Enum
    Declare Function GetScrollInfo Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal nBar As Integer, ByRef lpScrollInfo As SCROLLINFO) As Boolean
    Declare Function SetScrollInfo Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal nBar As Integer, ByVal lpScrollInfo As SCROLLINFO, ByVal fRedraw As Boolean) As Integer
    Private Function GetVSPos3(rtb As RichTextBox) As Integer
        Dim S As New SCROLLINFO
        S.cbSize = Runtime.InteropServices.Marshal.SizeOf(S)
        S.fMask = ScrollInfoMask.SIF_ALL
        Dim Result As Boolean = GetScrollInfo(rtb.Handle, SB_VERT, S)
        GetVSPos3 = S.nPos
    End Function

Все функции показывают одинаковые значения скроллинга текста с учетом вышеописанной проблемы 16 bit. Для себя использую функцию 2, поскольку мне необходимо собственные ScrollBars текстового окна выключать.

Максимальную позицию скроллинга текста (высоту текста) в текстовом окне можно отслеживать через событие ContentsResized:
Кликните здесь для просмотра всего текста
VB.NET
1
2
3
4
5
Dim VSMax As Integer 'максимальная позиция скроллбара
Private Sub RichTextBox1_ContentsResized(sender As Object, e As ContentsResizedEventArgs) Handles RichTextBox1.ContentsResized 
                VSMax = e.NewRectangle.Height
                VScrollBar1.Maximum = VSMax
End Sub

По поводу проблемы 16 бит придумал такое решение: при загрузке приложения создавал текст высотой гарантировано больше числа 65535. Получал его позицию PosValue - если она была меньше 65535, значит контролл с глюком. Тогда при получении позиции пересчитывал число по формуле:
Кликните здесь для просмотра всего текста
VB.NET
1
PosValue = CInt(VSMax / 65535 * PosValue)

Повторюсь - установка (Set) позиции скроллинга работает нормально при любых версиях контролла и Net Framework.
2
Покинул форум
3700 / 1483 / 355
Регистрация: 07.05.2015
Сообщений: 2,903
02.03.2023, 01:03
Количество неудачных попыток запуска системы
Кликните здесь для просмотра всего текста
Краткое объяснение сего "феномена".

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
Imports Microsoft.Win32
Imports System.Runtime.InteropServices
 
Friend NotInheritable Class Program
  Private Shared Function CorrectBoot(ByRef counter As UInt32) As Boolean
    Dim key As String = "SYSTEM\CurrentControlSet\Control\" & _
      "Session Manager\Memory Management\PrefetchParameters"
    Using rk As RegistryKey = Registry.LocalMachine.OpenSubKey(key)
      If Nothing Is rk Then
        Return False
      End If
      counter = CUInt(CInt(rk.GetValue("BootId")))
    End Using
    Return True
  End Function
 
  Friend Shared Sub Main()
    If 10 > Marshal.ReadInt32(CType(&H7FFE026C, IntPtr)) Then
      Console.WriteLine("Требуется Win10.")
      Return
    End If
 
    Dim count As UInt32 = 0
    If Not CorrectBoot(count) Then
      Console.WriteLine("Невозможно получить количество удачных загрузок.")
      Return
    End If
 
    Dim tries As UInt32 = Marshal.ReadInt32(CType(&H7FFE02C4, IntPtr))
    Console.WriteLine("Всего неудачных загрузок системы: {0}", tries - count)
  End Sub
End Class
1
Покинул форум
3700 / 1483 / 355
Регистрация: 07.05.2015
Сообщений: 2,903
19.03.2023, 20:39
Диапазоны физической памяти, а также размер последней

Данные о физической памяти Windows хранит среди прочего в реестре. Код ниже эти данные разбирает (без объявления вспомогательных структур).
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
Imports System.IO
Imports Microsoft.Win32
Imports System.ComponentModel
Imports Microsoft.Win32.SafeHandles
Imports System.Runtime.InteropServices
 
Namespace MmPhysicalPages
  Friend NotInheritable Class NativeMethods
    Private Sub New
    End Sub
 
    'на pinvoke.net т.н. "корректные" функции таковыми не являются
    <DllImport("advapi32.dll", CharSet := CharSet.Unicode, SetLastError := True)> _
    Friend Shared Function RegQueryValueEx( _
      ByVal hKey As SafeRegistryHandle, _
      ByVal lpValueName As String, _
      ByVal lpReserved As UInt32, _
      ByVal lpType As Byte(), _
      ByVal lpData As Byte(), _
      ByRef lpcbData As UInt32 _
    ) As Int32
    End Function
  End Class
 
  Friend NotInheritable Class Program
    Friend Shared Sub Main
      Dim [size] As UInt32 = 0
      Dim data As Byte() = New Byte(9) {}
 
      'отсюда и забираем данные
      Using rk As RegistryKey = Registry.LocalMachine.OpenSubKey( _
        "HARDWARE\RESOURCEMAP\System Resources\Physical Memory" _
      )
        If Nothing Is rk Then
          Return
        End If
 
        Dim status As Int32 = NativeMethods.RegQueryValueEx( _
          rk.Handle, ".Translated", 0, Nothing, Nothing, [size] _
        )
        If 0 <> status Then
          Console.WriteLine((New Win32Exception(status)).Message)
          rk.Dispose()
          Return
        End If
 
        Array.Resize(data, CType([size], Int32))
        status = NativeMethods.RegQueryValueEx( _
          rk.Handle, ".Translated", 0, Nothing, data, [size] _
        )
        If 0 <> status Then
          Console.WriteLine((New Win32Exception(status)).Message)
          rk.Dispose()
          Return
        End If
      End Using
 
      Console.WriteLine("Start              End                Size")
      Console.WriteLine("------             -----              ------")
      Using ms as MemoryStream = New MemoryStream(data)
        Using br As BinaryReader = New BinaryReader(ms)
          'количество блоков данных
          Dim lst As UInt32 = br.ReadUInt32()
          While 0 <> lst
            ms.Seek(&H0C, SeekOrigin.Current)
           'количество дескрипторов
            Dim des As UInt32 = br.ReadUInt32()
            While 0 <> des
              'пропускаем флаги и прочие данные о диапазоне
              ms.Seek(&H04, SeekOrigin.Current)
              Dim start as Int64 = br.ReadInt64()
              [size] = br.ReadUInt32()
              Console.WriteLine("0x{0:X16} 0x{1:X16} {2,10} K", start, start + [size], [size] / 1024)
              'отбросили "младшие" байты
              ms.Seek(&H04, SeekOrigin.Current)
              des -= 1
            End While
            lst -= 1
          End While
        End Using
      End Using
    End Sub
  End Class
End Namespace
Вариант хоть и "на коленке", но позволит понять как именно разбираются REG_RESOURCE_LIST данные.
P.S. Если сложить все значения в колонке Size, получим истинный размер физической памяти системы.
1
7 / 7 / 0
Регистрация: 11.12.2022
Сообщений: 12
15.04.2023, 07:40
Изменение настроек печати с помощью диалогового окна функции DocumentProperties WinApi (winspool.drv)

В приложении должен быть экземпляр класса PrintDocument и кнопка ButtonPrinterSettings

Этап 1 - подготовка текущих настроек печати приложения, которые будут переданы в окно DocumentProperties
Используем метод PrintDocument.PrinterSettings.GetHdevmod e( PrintDocument.DefaultPageSettings), который создает дескриптор структуры DEVMODE, относящейся к настройкам печати PageSettings. Затем через WinApi функцию GlobalLock получаем указатель на блок неуправляемой памяти для структуры DEVMODE.

Этап 2 - выделение блока неуправляемой памяти для настроек печати, которые будут получены из окна DocumentProperties
Для этого обращаемся к функции DocumentProperties с параметром fMode=0 и получаем необходимый размер блока памяти. Далее с помощью метода Marshal.AllocHGlobal выделяем блок неуправляемой памяти заданного размера и получаем указатель на первый байт блока памяти.

Этап 3 - вызов окна DocumentProperties с параметром fMode=14 (DM_IN_BUFFER or DM_OUT_BUFFER or DM_IN_PROMPT)
передаем в окно данные по указателю pDevModeInput, получаем из окна данные по указателю pDevModeOutput.

Этап 4 - сохранение измененных настроек печати в приложении с помощью метода PrintDocument.DefaultPageSettings.SetHde vmode. Далее разблокировка и освобождение неуправляемой памяти с помощью WinApi GlobalUnlock, GlobalFree, а также метода Marshal.FreeHGlobal.
Cохранить измененных настроек печати можно двумя способами:
PrintDocument.DefaultPageSettings.SetHde vmode - изменяются параметры страницы
PrintDocument.PrinterSettings.SetHdevmod e - изменяются параметры принтера

Особенности:
- при объявлении DocumentProperties требуется маршалинг текстовой строки имени принтера <MarshalAs(UnmanagedType.LPTStr)> pDeviceName As String
- DocumentProperties работает (Windows 7/10 64bit) без передачи дескриптора принтера hPrinter (если все же получить дескриптор необходимо - используйте WinApi OpenPrinter и ClosePrinter)

Пример кода:
Кликните здесь для просмотра всего текста
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
 <DllImport("winspool.drv", CharSet:=CharSet.Auto, SetLastError:=True)>
    Private Shared Function DocumentProperties(hWnd As IntPtr, hPrinter As IntPtr, <MarshalAs(UnmanagedType.LPTStr)> pDeviceName As String, pDevModeOutput As IntPtr, pDevModeInput As IntPtr, fMode As Integer) As Integer
    End Function
    <DllImport("kernel32.dll", CharSet:=CharSet.Auto, SetLastError:=True)>
    Private Shared Function GlobalLock(hMem As IntPtr) As IntPtr
    End Function
    <DllImport("kernel32.dll", CharSet:=CharSet.Auto, SetLastError:=True)>
    Private Shared Function GlobalUnlock(hMem As IntPtr) As IntPtr
    End Function
    <DllImport("kernel32.dll", CharSet:=CharSet.Auto, SetLastError:=True)>
    Private Shared Function GlobalFree(hMem As IntPtr) As IntPtr
    End Function
 
    Dim InstalledPrintersCount As Integer 'количество установленных принтеров
 'открыть диалоговое окно "настройка печати принтера"
    Private Sub ButtonPrinterSettings_Click(sender As Object, e As EventArgs) Handles ButtonPrinterSettings.Click
        'определить количество установленных принтеров
        Try
            InstalledPrintersCount = Printing.PrinterSettings.InstalledPrinters.Count
        Catch ex As Exception
            InstalledPrintersCount = 0
        End Try
        If InstalledPrintersCount = 0 Then Exit Sub
        Try
            'создать дескриптор структуры DEVMODE с текущими настройками печати для передачи в окно DocumentProperties 
            Dim hDevModeInput As IntPtr = PrintDocument.PrinterSettings.GetHdevmode(PrintDocument.DefaultPageSettings)
            'заблокировать структуру DEVMODE в неуправляемой памяти и получить указатель на первый байт блока памяти
            Dim pDevModeInput As IntPtr = GlobalLock(hDevModeInput) 'указатель на структуру DEVMODE с текущими настройками печати, которые будут переданы в окно DocumentProperties 
            '---------------------------------------------------------------------
            'определить необходимый размер неуправляемой памяти для настроек печати fMode=0
            Dim DevModeSize As Integer = DocumentProperties(Me.Handle, IntPtr.Zero, PrintDocument.PrinterSettings.PrinterName, IntPtr.Zero, IntPtr.Zero, 0)
            'выделить блок неуправляемой памяти заданного размера и получить указатель на первый байт блока памяти
            Dim pDevModeOutput As IntPtr = Marshal.AllocHGlobal(DevModeSize) 'указатель на структуру DEVMODE с новыми настройками печати, которые будут получены из окна DocumentProperties 
            '---------------------------------------------------------------------
            'вывести окно настроек печати DocumentProperties fMode=14 (DM_IN_BUFFER + DM_OUT_BUFFER + DM_IN_PROMPT = 8 + 2 + 4)
            Dim Result As Integer = DocumentProperties(Me.Handle, IntPtr.Zero, PrintDocument.PrinterSettings.PrinterName, pDevModeOutput, pDevModeInput, 14)
            Select Case Result
                Case DialogResult.OK 'при нажатии кнопки OK
                    'сохранить новые настройки печати, полученные из окна DocumentProperties
                    PrintDocument.DefaultPageSettings.SetHdevmode(pDevModeOutput)
                Case DialogResult.Cancel 'при нажатии кнопки Cancel
                Case Else 'в остальных случаях
                   MessageBox.Show("Не удается открыть свойства принтера " & Chr(34) & PrintDocument.PrinterSettings.PrinterName & Chr(34) & "." & vbCrLf & "Код ошибки: " & Marshal.GetLastWin32Error.ToString, My.Application.Info.Title, MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
            End Select
            GlobalUnlock(hDevModeInput) 'разблокировать неуправляемую память
            GlobalFree(hDevModeInput) 'освободить неуправляемую память и сделать недействительным дескриптор
            Marshal.FreeHGlobal(pDevModeOutput) 'освободить неуправляемую память
        Catch ex As Exception
            'показываем окно сообщения об ошибке
             MessageBox.Show("Не удается открыть свойства принтера " & Chr(34) & PrintDocument.PrinterSettings.PrinterName & Chr(34) & "." & vbCrLf & "Описание ошибки: " & ex.Message, My.Application.Info.Title, MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
            Exit Sub
        End Try
    End Sub
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
15.04.2023, 07:40
Помогаю со студенческими работами здесь

Visual Basic .Net и Visual Basic 6.0 - В чём разница
В общем возник вопрос: Visual Bisic.Net и Visual Basic - это два разных языка, или же .NET версия...

Готовые коды для решения лабораторных работ
Доброго времени суток всем! Очень срочно нужны готовые коды для решения лабораторных работ в С# по...

Изменение элемента коллекции классов (основано на "готовых решениях, полезных кодах")
Основа тут (спасибо Памирычу): Visual Basic .NET FAQ. Готовые решения, полезные коды Вопрос...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

Новые блоги и статьи
Access
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
Фото: Daniel Greenwood
kumehtar 13.11.2025
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru