I'm creating a program that has a "rehost workflowdesigner" (like Autodesk SubAssembly Composer did) and it fails to create the toolbox controls.
The error that occurs:
System.IO.FileNotFoundException: Could not load file or assembly....
So far I understand that, because the DLL is not in the GAC, windows cannot find it.
So I tested the following hypotheses:
NETLOAD for the first time, without setting DLL folder in "support file search path"
when calling the command, result: ERROR
Add the DLL folder to the "support file search path" and then NETLOAD
when calling the command, result: WORKS
Enable autoload by the "LOADCTRLS" key (defined in IExtensionApplication.Initialize), without adding the DLL in the "support file search path"
when calling the command, result: ERROR
Now that the dll is loaded by the registry ("LOADCTRLS" ), still without the "support file search path"
when calling the command, result: ERROR
In the same cad session as in step 4, add the DLL to the ""support file search path", editing the field without clicking the "Browse" button
when calling the command, result: ERROR
In the same cad session as in step 5, add the DLL to the ""support file search path", editing the field by clicking the "Browse" button
when calling the command, result: ERROR
In the same cad session as in step 6, I call the NETLOAD command (filedia=1), navigate to the DLL folder, DO NOT SELECT ANYTHING AND CLICK CANCEL
when calling the command, result: WORKS
I close cad, open it again, set FILEDIA=0
when calling the command, result: ERROR
In the same cad session of step 8, NETLOAD, I inform the full path of the DLL
when calling the command, result: ERROR
In the same cad session as in step 9, FILEDIA=1, NETLOAD, I navigate to the folder, but I don't select anything, as in step 7,
when calling the command, result: WORKS
So it concludes that the NETLOAD command doesn't just do an "Assembly.LoadFrom".
And the fact that it works with FILEDIA=1, makes me believe that it is the part of the code that shows the NETLOAD window that somehow makes the DLL, or its types
visible and the System.IO.FileNotFoundException error does not occur
I added the code so you can look.
If you can help me, thank you
"MyCustomActivity.vb"
Imports System.Activities
Imports System.Activities.Presentation
Imports System.ComponentModel
Imports System.Drawing
Imports System.Windows
Imports System.Windows.Media
Imports System.Windows.Media.Imaging
<ToolboxBitmap(GetType(MyCustomActivity), "arc.png"), Designer(GetType(MyCustomDesigner))>
Public Class MyCustomActivity
Inherits CodeActivity
Protected Overrides Sub Execute(context As CodeActivityContext)
'faz alguma coisa
End Sub
End Class
Public NotInheritable Class MyCustomDesigner
Inherits MyActivityDesigner
Public Sub New()
MyBase.New(GetType(MyCustomActivity))
End Sub
End Class
Public MustInherit Class MyActivityDesigner
Inherits ActivityDesigner
Public Sub New(customActivityType As Type)
Dim toolAttrib As ToolboxBitmapAttribute = customActivityType.GetCustomAttributes(GetType(ToolboxBitmapAttribute), True)(0)
Using bitmap As New Bitmap(toolAttrib.GetImage(customActivityType))
Dim ImageDrawing As New ImageDrawing(System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(bitmap.GetHbitmap,
IntPtr.Zero,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions),
New Rect(0, 0, 16, 16))
Me.Icon = New DrawingBrush(ImageDrawing)
End Using
End Sub
End Class
"TestClass.VB"
Imports System.Reflection
Imports Microsoft.Win32
Imports Autodesk.AutoCAD.Runtime
Imports Autodesk.AutoCAD.DatabaseServices
Imports System.IO
Public NotInheritable Class TesteClass
'precisa ser public, senao IExtensionApplication nao funciona
Implements IExtensionApplication
Public Shared ReadOnly PRODUCTKEY As String = HostApplicationServices.Current.UserRegistryProductRootKey
Public Shared ReadOnly LOADER As String = Reflection.Assembly.GetExecutingAssembly.Location
Public Shared ReadOnly PASTA As String = New FileInfo(LOADER).DirectoryName
Public Sub Initialize() Implements IExtensionApplication.Initialize
Try
Dim cUserApp = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(PRODUCTKEY & "\Applications", True)
With cUserApp.CreateSubKey(My.Application.Info.Title)
.SetValue("DESCRIPTION", My.Application.Info.Description)
.SetValue("MANAGED", 1, RegistryValueKind.DWord)
.SetValue("LOADCTRLS", 2, RegistryValueKind.DWord)
.SetValue("LOADER", System.Reflection.Assembly.GetExecutingAssembly.Location)
Try
.DeleteSubKey("Commands")
Catch
End Try
With .CreateSubKey("Commands")
For Each tp As Type In Assembly.GetExecutingAssembly.GetExportedTypes()
For Each meth As MethodInfo In tp.GetMethods()
For Each obj As CommandMethodAttribute In meth.GetCustomAttributes(GetType(CommandMethodAttribute), True)
.SetValue(obj.GlobalName, obj.GlobalName)
Next
Next
Next
End With
End With
Catch
End Try
End Sub
Public Sub Terminate() Implements IExtensionApplication.Terminate
End Sub
<CommandMethod("teste")>
Public Sub teste()
Dim f As New Form1
f.ShowDialog()
End Sub
End Class
"Form1.vb"
Imports System.Activities
Imports System.Activities.Core.Presentation
Imports System.Activities.Presentation
Imports System.Activities.Presentation.Toolbox
Imports System.Activities.Statements
Imports System.Windows
Imports System.Windows.Forms
Public Class Form1
Private Shared _firsload As Boolean = True
Public Sub New()
Dim dd As New DesignerMetadata()
dd.Register()
' Esta chamada é requerida pelo designer.
InitializeComponent()
' Adicione qualquer inicialização após a chamada InitializeComponent().
Dim WorkflowDesigner As New WorkflowDesigner
Dim ActivityBuilder As New ActivityBuilder With {.Implementation = New Flowchart}
WorkflowDesigner.Load(ActivityBuilder)
Dim ctrl As New ToolboxControl()
'Dim item As New ToolboxItemWrapper("TesteCAD.MyCustomActivity", TesteClass.LOADER, "", "teste")
Dim item As New ToolboxItemWrapper(GetType(MyCustomActivity), "teste")
ctrl.Categories.Add(New ToolboxCategory("teste") From {item})
ElementHost1.Child = ctrl
ElementHost2.Child = WorkflowDesigner.View
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
Dim wd As New WorkflowDesigner
Using lixo As New Form With {.Size = New System.Drawing.Size(1, 1), .ShowInTaskbar = False, .FormBorderStyle = FormBorderStyle.None}
Dim elementHost As New Integration.ElementHost
lixo.Controls.Add(elementHost)
elementHost.Child = wd.View
AddHandler lixo.Activated, Sub()
Forms.Application.DoEvents()
lixo.Close()
End Sub
lixo.ShowDialog()
End Using
End Sub
End Class
"Form1.Designer.vb"
Imports System.Windows.Forms
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()>
Partial Class Form1
Inherits System.Windows.Forms.Form
'Descartar substituições de formulário para limpar a lista de componentes.
<System.Diagnostics.DebuggerNonUserCode()> _
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
Try
If disposing AndAlso components IsNot Nothing Then
components.Dispose()
End If
Finally
MyBase.Dispose(disposing)
End Try
End Sub
'Exigido pelo Windows Form Designer
Private components As System.ComponentModel.IContainer
'OBSERVAÇÃO: o procedimento a seguir é exigido pelo Windows Form Designer
'Pode ser modificado usando o Windows Form Designer.
'Não o modifique usando o editor de códigos.
<System.Diagnostics.DebuggerStepThrough()> _
Private Sub InitializeComponent()
Me.SplitContainer1 = New System.Windows.Forms.SplitContainer()
Me.ElementHost1 = New System.Windows.Forms.Integration.ElementHost()
Me.ElementHost2 = New System.Windows.Forms.Integration.ElementHost()
CType(Me.SplitContainer1, System.ComponentModel.ISupportInitialize).BeginInit()
Me.SplitContainer1.Panel1.SuspendLayout()
Me.SplitContainer1.Panel2.SuspendLayout()
Me.SplitContainer1.SuspendLayout()
Me.SuspendLayout()
'
'SplitContainer1
'
Me.SplitContainer1.Dock = System.Windows.Forms.DockStyle.Fill
Me.SplitContainer1.Location = New System.Drawing.Point(0, 0)
Me.SplitContainer1.Name = "SplitContainer1"
'
'SplitContainer1.Panel1
'
Me.SplitContainer1.Panel1.Controls.Add(Me.ElementHost1)
'
'SplitContainer1.Panel2
'
Me.SplitContainer1.Panel2.Controls.Add(Me.ElementHost2)
Me.SplitContainer1.Size = New System.Drawing.Size(800, 450)
Me.SplitContainer1.SplitterDistance = 266
Me.SplitContainer1.TabIndex = 0
'
'ElementHost1
'
Me.ElementHost1.Dock = System.Windows.Forms.DockStyle.Fill
Me.ElementHost1.Location = New System.Drawing.Point(0, 0)
Me.ElementHost1.Name = "ElementHost1"
Me.ElementHost1.Size = New System.Drawing.Size(266, 450)
Me.ElementHost1.TabIndex = 0
Me.ElementHost1.Text = "ElementHost1"
Me.ElementHost1.Child = Nothing
'
'ElementHost2
'
Me.ElementHost2.Dock = System.Windows.Forms.DockStyle.Fill
Me.ElementHost2.Location = New System.Drawing.Point(0, 0)
Me.ElementHost2.Name = "ElementHost2"
Me.ElementHost2.Size = New System.Drawing.Size(530, 450)
Me.ElementHost2.TabIndex = 0
Me.ElementHost2.Text = "ElementHost2"
Me.ElementHost2.Child = Nothing
'
'Form1
'
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
Me.ClientSize = New System.Drawing.Size(800, 450)
Me.Controls.Add(Me.SplitContainer1)
Me.Name = "Form1"
Me.Text = "Form1"
Me.SplitContainer1.Panel1.ResumeLayout(False)
Me.SplitContainer1.Panel2.ResumeLayout(False)
CType(Me.SplitContainer1, System.ComponentModel.ISupportInitialize).EndInit()
Me.SplitContainer1.ResumeLayout(False)
Me.ResumeLayout(False)
End Sub
Friend WithEvents SplitContainer1 As SplitContainer
Friend WithEvents ElementHost1 As Integration.ElementHost
Friend WithEvents ElementHost2 As Integration.ElementHost
End Class
I found a solution by adding an AssemblyResolve event to the current AppDomain:
Private Shared Function MyHandler(ByVal source As Object, ByVal e As ResolveEventArgs) As Assembly
Return If(e.Name = GetType(TesteClass).Assembly.FullName, Assembly.LoadFile(LOADER), Nothing)
End Function
And I added the following line in 'Initialize':
AddHandler AppDomain.CurrentDomain.AssemblyResolve, AddressOf MyHandler
Worked perfectly!!!
Related
Using the code below I can create a box with a combo box that shows the current com ports
What I need to do is show what is attached to the com Port, for example I want it to list
COM PORT1 FTDI USB serial adapter, the reason is to let you the user know which port to enter in a batch file that runs when another button is clicked ( i have removed that part of the code as its not important)
I have done some google work and found this link http://social.msdn.microsoft.com/Forums/en-US/vbgeneral/thread/331a26c1-0f42-4cf1-8adb-32fb09a18953/ But that just errors out
Imports System
Imports System.Threading
Imports System.IO.Ports
Imports System.ComponentModel
Public Class Form1
'------------------------------------------------
Dim myPort As Array
Delegate Sub SetTextCallback(ByVal [text] As String) 'Added to prevent threading
errors during receiveing of data
'------------------------------------------------
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
myPort = IO.Ports.SerialPort.GetPortNames()
ComboBox1.Items.AddRange(myPort)
End Sub
End Class
The following shows how to get a list of COM devices in VB.NET for both .NET 6 and .NET Framework 4.8 in VS 2022. If a USB COM (serial port) device is added/removed, the ComboBox will be updated.
Option 1 - Windows Forms App: (.NET 6)
Create a new project: Windows Forms App (name: SerialPortGetComDevices)
Download/install the following NuGet packages:
System.IO.Ports
System.Management
Option 2 - Windows Forms App (.NET Framework) - v4.8:
Create a new project: Windows Forms App (.NET Framework) (name: SerialPortGetComDevices)
Add Reference:
In VS menu, click Project
Select Add Reference...
Select Assemblies
Check System.Management
Click OK
The instructions below are the same for both Windows Forms App and Windows Forms App (.NET Framework) (ie: the instructions below are the same regardless of which option you've chosen above).
Create a class (name: ComPortInfo.vb)
In VS menu, select Project
Select Add Class... (name: ComPortInfo.vb)
Click Add
ComPortInfo.vb:
Public Class ComPortInfo
Public Property Caption As String
Public Property PortName As String
End Class
Open Solution Explorer:
In VS menu, click View
Select Solution Explorer
Open Properties Window:
In VS menu, click View
Select Properties Window
Add Load Event Handler
In Solution Explorer, right-click Form1.vb and select View Designer.
In Properties Window, click
Double-click Load
Add FormClosing Event Handler
In Solution Explorer, right-click Form1.vb and select View Designer.
In Properties Window, click
Double-click FormClosing
Add a ComboBox to the Form (name: ComboBoxComPorts)
In VS menu, click View
Select Toolbox
In Toolbox, select ComboBox, and drag it to the Form.
In the Properties Window, change (Name) to ComboBoxComPorts
In the Properties Window, change DropDownStyle to DropDownList
Select one of the options below. The 1st option uses ManagementEventWatcher to detect USB device insertion and removal. The 2nd option overrides WndProc.
Note: The WndProc version (Option 2) seems to have slightly better performance.
Option 1 (ManagementEventWatcher)
Note: The code for detecting the insertion and removal of a USB device, is adapted from here.
Add the code below in your Form (ex: Form1.vb)
Form1.vb
Imports System.ComponentModel
Imports System.Management
Imports System.IO.Ports
Public Class Form1
'create new instance
Private _comPorts As BindingList(Of ComPortInfo) = New BindingList(Of ComPortInfo)
Private _managementEventWatcher1 As ManagementEventWatcher = New ManagementEventWatcher()
Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
InitializeManagementEventWatcher()
UpdateCOM()
'set properties
ComboBoxComPorts.DataSource = _comPorts
ComboBoxComPorts.DisplayMember = "Caption"
ComboBoxComPorts.ValueMember = "PortName"
End Sub
Private Sub GetComPorts()
'this method Is only called from 'UpdateCOM'
'_comPorts' is only modified in this method
Dim portDict As Dictionary(Of String, String) = New Dictionary(Of String, String)
'clear existing data
_comPorts.Clear()
'get port names
For Each pName As String In SerialPort.GetPortNames()
If Not portDict.ContainsKey(pName) Then
portDict.Add(pName, pName) 'add to Dictionary
End If
Next
'get USB COM ports - this may result in a more descriptive name than 'COM1'
Using searcherPnPEntity As ManagementObjectSearcher = New ManagementObjectSearcher("SELECT Name FROM Win32_PnPEntity WHERE PNPClass = 'Ports'")
For Each objPnPEntity As ManagementObject In searcherPnPEntity.Get()
If objPnPEntity Is Nothing Then
Continue For
End If
'get name
Dim name As String = objPnPEntity("Name")?.ToString()
If Not String.IsNullOrEmpty(name) AndAlso name.ToUpper().Contains("COM") Then
Dim portName As String = name.Substring(name.IndexOf("(") + 1, name.IndexOf(")") - name.IndexOf("(") - 1)
If Not portDict.ContainsKey(portName) Then
portDict.Add(portName, name) 'add to Dictionary
Else
portDict(portName) = name 'update value
End If
End If
Next
End Using
'add items from Dictionary to BindingList
For Each kvp As KeyValuePair(Of String, String) In portDict
_comPorts.Add(New ComPortInfo() With {.Caption = kvp.Value, .PortName = kvp.Key}) 'add
Next
End Sub
Private Sub InitializeManagementEventWatcher()
'see https:'learn.microsoft.com/en-us/windows/win32/wmisdk/within-clause
'WITHIN sets the polling interval in seconds
'polling too frequently may reduce performance
Dim query As WqlEventQuery = New WqlEventQuery("SELECT * FROM __InstanceOperationEvent WITHIN 2 WHERE TargetInstance ISA 'Win32_PnPEntity'")
'Dim query As WqlEventQuery = New WqlEventQuery("SELECT * FROM __InstanceOperationEvent WITHIN 1 WHERE TargetInstance ISA 'Win32_PnPEntity'")
'set property
_managementEventWatcher1.Query = query
'subscribe to event
AddHandler _managementEventWatcher1.EventArrived, AddressOf ManagementEventWatcher_EventArrived
'start
_managementEventWatcher1.Start()
End Sub
Private Sub LogMsg(msg As String, Optional includeTimestamp As Boolean = True)
If includeTimestamp Then
msg = $"{DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.fff")} - {msg}"
End If
Debug.WriteLine(msg)
End Sub
Public Sub UpdateCOM()
If ComboBoxComPorts.InvokeRequired Then
'LogMsg("ComboBoxComPorts.InvokeRequired")
ComboBoxComPorts.Invoke(New MethodInvoker(Sub()
GetComPorts()
End Sub))
Else
GetComPorts()
End If
End Sub
Public Sub ManagementEventWatcher_EventArrived(sender As Object, e As EventArrivedEventArgs)
Dim obj As ManagementBaseObject = DirectCast(e.NewEvent, ManagementBaseObject)
Dim target As ManagementBaseObject = If(obj("TargetInstance") IsNot Nothing, DirectCast(obj("TargetInstance"), ManagementBaseObject), Nothing)
Dim usbEventType As String = String.Empty
Select Case target.ClassPath.ClassName
Case "__InstanceCreationEvent"
usbEventType = "added"
Case "__InstanceDeletionEvent"
usbEventType = "removed"
Case Else
usbEventType = target.ClassPath.ClassName
End Select
If target("PNPClass") IsNot Nothing AndAlso target("PNPClass").ToString() = "Ports" Then
'update COM ports
UpdateCOM()
End If
End Sub
Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles MyBase.FormClosing
'stop
_managementEventWatcher1.Stop()
'unsubscribe from event
RemoveHandler _managementEventWatcher1.EventArrived, AddressOf ManagementEventWatcher_EventArrived
End Sub
End Class
Option 2 (override WndProc)
Note: The code for detecting the insertion and removal of a USB device, is adapted from here.
Add a Module (name: UsbDeviceNotification.vb)
In VS menu, select Project
Select Add Module... (name: UsbDeviceNotification.vb)
Click Add
UsbDeviceNotification.vb
Imports System.Runtime.InteropServices
Module UsbDeviceNotification
Public Const DbtDeviceArrival As Integer = &H8000 'device added
Public Const DbtDeviceRemoveComplete As Integer = &H8004 'device removed
Public Const WM_DEVICECHANGE As Integer = &H219 'device change event
Public Const DBT_DEVTYP_DEVICEINTERFACE As Integer = 5
Private ReadOnly _guidDevInterfaceUSBDevice As Guid = New Guid("A5DCBF10-6530-11D2-901F-00C04FB951ED") 'USB devices
Private _notificationHandle As IntPtr
Declare Auto Function RegisterDeviceNotification Lib "user32" (recipient As IntPtr, notificationFilter As IntPtr, flags As Integer) As IntPtr
Declare Auto Function UnregisterDeviceNotification Lib "user32" (hwnd As IntPtr) As Boolean
<StructLayout(LayoutKind.Sequential)>
Private Structure DEV_BROADCAST_DEVICEINTERFACE
Dim Size As Integer
Dim DeviceType As Integer
Dim Reserved As Integer
Dim ClassGuid As Guid
Dim Name As Short
End Structure
Public Sub RegisterUsbDeviceNotification(hwnd As IntPtr)
'Registers a window to receive notifications when USB devices are plugged or unplugged.
Dim dbi As DEV_BROADCAST_DEVICEINTERFACE = New DEV_BROADCAST_DEVICEINTERFACE() With
{
.DeviceType = DBT_DEVTYP_DEVICEINTERFACE,
.ClassGuid = _guidDevInterfaceUSBDevice
}
dbi.Size = Marshal.SizeOf(dbi)
Dim buffer As IntPtr = Marshal.AllocHGlobal(dbi.Size)
Marshal.StructureToPtr(dbi, buffer, True)
_notificationHandle = RegisterDeviceNotification(hwnd, buffer, 0)
End Sub
Public Sub UnregisterUsbDeviceNotification()
UnregisterDeviceNotification(_notificationHandle)
End Sub
End Module
Add the code below in your Form (ex: Form1.vb)
Form1.vb
Imports System.ComponentModel
Imports System.Management
Imports System.IO.Ports
Imports System.Threading
Public Class Form1
'create new instance
Private _comPorts As BindingList(Of ComPortInfo) = New BindingList(Of ComPortInfo)
Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
UpdateCOM()
'set properties
ComboBoxComPorts.DataSource = _comPorts
ComboBoxComPorts.DisplayMember = "Caption"
ComboBoxComPorts.ValueMember = "PortName"
End Sub
Private Sub GetComPorts()
'this method Is only called from 'UpdateCOM'
'_comPorts' is only modified in this method
Dim portDict As Dictionary(Of String, String) = New Dictionary(Of String, String)
'clear existing data
_comPorts.Clear()
'get port names
For Each pName As String In SerialPort.GetPortNames()
If Not portDict.ContainsKey(pName) Then
portDict.Add(pName, pName) 'add to Dictionary
End If
Next
'get USB COM ports - this may result in a more descriptive name than 'COM1'
Using searcherPnPEntity As ManagementObjectSearcher = New ManagementObjectSearcher("SELECT Name FROM Win32_PnPEntity WHERE PNPClass = 'Ports'")
If searcherPnPEntity IsNot Nothing Then
For Each objPnPEntity As ManagementBaseObject In searcherPnPEntity.Get()
If objPnPEntity Is Nothing Then
Continue For
End If
'get name
Dim name As String = objPnPEntity("Name")?.ToString()
If Not String.IsNullOrEmpty(name) AndAlso name.ToUpper().Contains("COM") Then
Dim portName As String = name.Substring(name.IndexOf("(") + 1, name.IndexOf(")") - name.IndexOf("(") - 1)
If Not portDict.ContainsKey(portName) Then
portDict.Add(portName, name) 'add to Dictionary
Else
portDict(portName) = name 'update value
End If
End If
Next
End If
End Using
'add items from Dictionary to BindingList
For Each kvp As KeyValuePair(Of String, String) In portDict
_comPorts.Add(New ComPortInfo() With {.Caption = kvp.Value, .PortName = kvp.Key}) 'add
Next
End Sub
Private Sub LogMsg(msg As String, Optional includeTimestamp As Boolean = True)
If includeTimestamp Then
msg = $"{DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.fff")} - {msg}"
End If
Debug.WriteLine(msg)
End Sub
Public Sub UpdateCOM()
'since this method/Sub is called from WndProc,
'it needs to run on a new thread
Dim threadProc As System.Threading.Thread = New System.Threading.Thread(Sub()
If ComboBoxComPorts.InvokeRequired Then
'LogMsg("ComboBoxComPorts.InvokeRequired")
ComboBoxComPorts.Invoke(New MethodInvoker(Sub()
GetComPorts()
End Sub))
Else
GetComPorts()
End If
End Sub)
threadProc.SetApartmentState(System.Threading.ApartmentState.STA)
threadProc.Start()
End Sub
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
If m.Msg = UsbDeviceNotification.WM_DEVICECHANGE Then
Select Case CInt(m.WParam)
Case UsbDeviceNotification.DbtDeviceRemoveComplete
UpdateCOM()
Case UsbDeviceNotification.DbtDeviceArrival
UpdateCOM()
End Select
End If
MyBase.WndProc(m)
End Sub
Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles MyBase.FormClosing
End Sub
End Class
The following PowerShell commands may also provide useful information.
PowerShell:
Get-CimInstance -Namespace Root\Cimv2 -Query "Select * From Win32_SerialPort Where Name like '%COM%'"
Get-CimInstance -Namespace Root\Cimv2 -Query "Select * From Win32_SerialPortConfiguration"
Get-CimInstance -Namespace Root\Cimv2 -Query "Select * From Win32_PnPEntity where PnPClass = 'Ports' and Name like '%COM%'"
mode
Resources:
System.IO.Ports Namespace
SerialPort Class
BindingList Class
ManagementEventWatcher Class
WITHIN Clause
Detecting USB drive insertion and removal using windows service and c#
Check for device change (add/remove) events
ComboBox Class
Dictionary<TKey,TValue> Class
ManagementObjectSearcher Class
ManagementObject Class
Win32_PnPEntity class
For...Next Statement (Visual Basic)
If Operator (Visual Basic)
So I've read around this and will provide relevant properties at the end.
I'm looking to store a custom ToolStrip button image size in my.settings and load them at startup, changing them to a user set size.. The code I run at startup is:
Dim tss As New List(Of ToolStrip)
tss = GetAllControls(Me).OfType(Of ToolStrip)().ToList
For Each ts In tss
ts.BackColor = My.Settings.ToolStripBGColor
ts.ImageScalingSize = New Size(My.Settings.ToolStripImgScalingSize, My.Settings.ToolStripImgScalingSize)
ts.ResumeLayout()
ts.Invalidate()
ts.Refresh()
Next
ToolStripContainer.Invalidate()
ToolStripContainer.Refresh()
This does change the properties of all of the ToolStips. However, the images initially display at the default 16x16 UNTIL I drag them into another area of the ToolStripContainer. It then resizes correctly. This tends to imply to me that it's something to so with the draw of these containers/controls (hence the blanket bombing of .invalidate, .resumelayout and .refresh!)
Regarding proprieties, the relevant ones within designer view:
ToolStripButton
.autosize = true
.imagescaling = SizeToFit
ToolStrip
.autosize = true
.imagesclaing = 16,16 (later modified by code)
ToolStripContainer
couldn't see any that would effect this!??
This is one of those where you go round in circles for half a day over what essentially could be due to a janky aspect of .net! Could be me though...
Getting this to work with AutoSize=True is always a bit confusing. I've found that if you set it to False with layout suspended and then set it to True with layout enabled, that you can get the desired effect.
That description is probably clear as mud, so here is the code pattern.
With ToolStrip1
.SuspendLayout()
.AutoSize = False
.ImageScalingSize = New Size(40, 40)
.ResumeLayout()
.AutoSize = True
End With
Imports System.Drawing : Imports Microsoft.VisualBasic
Imports Microsoft.Win32 : Imports System
Imports System.IO : Imports System.Windows.Forms
Public Class Form1
Inherits Form
Private toolStripItem1 As ToolStripButton
Private toolStrip1 As ToolStrip
Public Sub New()
toolStrip1 = New System.Windows.Forms.ToolStrip()
toolStrip1.Size = New System.Drawing.Size(580,40)
toolStrip1.BackColor = System.Drawing.Color.MistyRose
toolStrip1.AutoSize = True
toolStripItem1 = New System.Windows.Forms.ToolStripButton()
toolStrip1.SuspendLayout()
Me.SuspendLayout()
toolStrip1.Items.AddRange(New System.Windows.Forms.ToolStripButton() _
{toolStripItem1})
toolStrip1.Location = New System.Drawing.Point(0, 0)
toolStrip1.Name = "toolStrip1"
toolStripItem1.AutoSize = False
toolStripItem1.Size = New System.Drawing.Size(110,95)
toolStripItem1.BackgroundImage = Image.FromFile("D:\Book4\Resources\icos\CUT.png")
toolStripItem1.Name = "toolStripItem1"
toolStripItem1.Text = "Cut"
toolStripItem1.Font = New System.Drawing.Font("Segoe UI", 16.0!, _
System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, _
CType(0, Byte))
toolStripItem1.TextAlign = System.Drawing.ContentAlignment.TopCenter
AddHandler Me.toolStripItem1.Click, New System.EventHandler _
(AddressOf Me.toolStripItem1_Click)
Me.AutoScaleDimensions = New System.Drawing.SizeF(6F, 13F)
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
Me.ClientSize = New System.Drawing.Size(1500,900)
Me.BackColor = ColorTranslator.FromHtml("#808080")
Me.Controls.Add(Me.toolStrip1)
Me.Name = "Form1"
toolStrip1.ResumeLayout(False)
Me.ResumeLayout(False)
Me.PerformLayout()
End Sub
Public Sub Form1_Loaded(sender As Object, e As EventArgs) _
Handles MyBase.Load
Try
Dim ico As New System.Drawing.Icon("D:\Resources\icos\kvr.ico")
Me.Icon = ico
Catch ex As Exception
End Try
End Sub
Public Shared Sub Main()
Dim form1 As Form1 = New Form1()
form1.ShowDialog()
End Sub
Private Sub toolStripItem1_Click(ByVal sender As Object,ByVal e As EventArgs)
System.Windows.Forms.MessageBox.Show("Successfully enlarged ToolStripButtonImage size")
End Sub
End Class
I have looked at previous answers on this blog which dont seem to help me.
I have a datagrid and add columns that are datagridtextboxcolumn . When I click on a cell on datagrid - if the line is too big for the width of cell , it will display on the following line, but when I am not clicked on the cell, the end of the line of text will not be displayed on the next line - and is therefore not displayed.
I derived a new class from datagridtextboxcolumn and attempted to override the paint and painttext methods and this appeared to have no effect - the text is still displayed in the column and only 1 line is displayed.
My code is
Here is the derived class: -
( below I have overridden the paint and painttext class in order to see which method has some effect on the display in the datagrid - but there is no effect occuring through this process of overriding.
enter code here
Imports Microsoft.VisualBasic
Imports System.ComponentModel
Imports System.Data
Imports System.Data.Common
Imports System.Data.OleDb
Imports System.Drawing
Imports System.Windows.Forms
Namespace DataGridRichTextBox
Public Class DataGridRichTextBoxColumn
Inherits DataGridTextBoxColumn
Private _source As CurrencyManager
Private _rowNum As Integer
Private _isEditing As Boolean
Public Sub New()
_source = Nothing
_isEditing = False
End Sub 'New
Protected Overloads Sub PaintText(ByRef g As Graphics, ByVal bounds As System.Drawing.Rectangle, ByRef Text As String, ByVal alligntoright As Boolean)
End Sub
Protected Overloads Sub PaintText(ByRef g As Graphics, ByVal bounds As System.Drawing.Rectangle, ByRef Text As String, ByRef s1 As System.Drawing.Brush, ByRef s2 As System.Drawing.Brush, ByVal alligntoright As Boolean)
End Sub
Protected Overloads Overrides Sub Paint(ByVal g As Graphics, ByVal bounds As System.Drawing.Rectangle, ByVal _source As CurrencyManager, ByVal num As Integer)
End Sub
Protected Overloads Overrides Sub SetColumnValueatrow(ByVal _source As CurrencyManager, ByVal num As Integer, ByVal obj As Object)
End Sub
End Class 'DataGridComboBoxColumn
End Namespace
'Here is where I add the derived class as an object to the datagrid : -
Imports System.Windows.Forms
Imports System.Data.SqlClient
Imports System.Drawing
Public Class DataGridMine
Inherits DataGrid
Public r_counter, column_num, x1 As Integer
Public x13 As Integer
#Region " Windows Form Designer generated code "
Public Sub New()
MyBase.New()
'This call is required by the Windows Form Designer.
InitializeComponent()
End Sub
'Form overrides dispose to clean up the component list.
Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing Then
If Not (components Is Nothing) Then
components.Dispose()
End If
End If
MyBase.Dispose(disposing)
End Sub
'Required by the Windows Form Designer
Private components As System.ComponentModel.IContainer
Friend WithEvents SqlSelectCommand2 As New SqlCommand
Friend WithEvents DataSet51 As New tasks_trial2.DataSet5
Public WithEvents DataGridTableStyle1 As New DataGridTableStyle
Public WithEvents task_name_col, parent_col As New DataGridTextBoxColumn
Public WithEvents description_col As New DataGridRichTextBox.DataGridRichTextBoxColumn
Friend WithEvents SqlDataAdapter3 As New SqlDataAdapter
Friend WithEvents SqlDataAdapter2 As New SqlDataAdapter
Friend WithEvents SqlSelectCommand3 As New SqlCommand
<System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
Dim resources As System.Resources.ResourceManager = New System.Resources.ResourceManager(GetType(Form1))
CType(Priority_code_table1, System.ComponentModel.ISupportInitialize).BeginInit()
SuspendLayout()
Me.DataMember = "tasks"
Me.DataSource = DataSet51
Me.Location = New Point(8, 230)
Me.Size = New Size(1117, 384)
Me.TabIndex = 0
Me.TableStyles.AddRange(New DataGridTableStyle() {DataGridTableStyle1})
SqlDataAdapter2.SelectCommand = SqlSelectCommand2
SqlDataAdapter2.TableMappings.AddRange(New System.Data.Common.DataTableMapping() {New System.Data.Common.DataTableMapping("Table", "tasks")})
SqlSelectCommand2.CommandText = ""
SqlSelectCommand2.Connection = SqlConnection10
DataGridTableStyle1.DataGrid = Me
DataGridTableStyle1.AllowSorting = False
column_num = 3
DataGridTableStyle1.HeaderForeColor = SystemColors.ControlText
DataGridTableStyle1.MappingName = "tasks"
DataGridTableStyle1.SelectionBackColor = Color.Aquamarine
DataGridTableStyle1.SelectionForeColor = Color.Black
DataGridTableStyle1.PreferredRowHeight = 10
DataGridTableStyle1.PreferredColumnWidth = 75
description_col.HeaderText = "Description"
description_col.MappingName = "description"
description_col.Width = 260
'.....................
' where column is description_col.
Public Sub add_columns(ByRef dgrid1 As DataGridMine, ByVal column As Object)
dgrid1.DataGridTableStyle1.GridColumnStyles.AddRange(New DataGridColumnStyle() {column})
End Sub
you don't have to do all that if you use a DataGridViewTextBoxColumn
just have to set some option via code or properties menu
go to your Columns listing and select the Column you want the text to be wrapped up and not cutt off.
go to DefaulCellStyle and set
WrapMode = True
additionally you could set this on the DGV Property Menu
AutoSizeColumnsMode to Fill
and
AutoSizeRowsMode to AllCells
that should do the Trick
this is all set in Properties Menu but you can do this in Code too so your choice
My form only works when I use
Imports WindowsApplication1.FrameGrabber
but not when I use
Imports FrameGrabber
I will be using the FrameGrabber in several different projects, so I would really prefer having only to say "Imports FrameGrabber".
My "FrameGrabber / CameraWindow" is defined like this:
Imports System.Collections
Imports System.ComponentModel
Imports System.Drawing
Imports System.Data
Imports System.Windows.Forms
Imports System.Threading
Namespace FrameGrabber
''' <summary>
''' Summary description for CameraWindow.
''' </summary>
Public Class CameraWindow
Inherits System.Windows.Forms.Control
Private m_camera As Camera = Nothing
Private m_autosize As Boolean = False
Private needSizeUpdate As Boolean = False
Private firstFrame As Boolean = True
' AutoSize property
<DefaultValue(False)> _
Public Overrides Property AutoSize() As Boolean
Get
Return m_autosize
End Get
Set(value As Boolean)
m_autosize = value
UpdatePosition()
End Set
End Property
' Camera property
<Browsable(False)> _
Public Property Camera() As Camera
Get
Return m_camera
End Get
Set(value As Camera)
' lock
Monitor.Enter(Me)
' detach event
If m_camera IsNot Nothing Then
RemoveHandler m_camera.NewFrame, AddressOf Me.pCameraWindow_NewFrame
End If
m_camera = value
needSizeUpdate = True
firstFrame = True
' atach event
If m_camera IsNot Nothing Then
AddHandler m_camera.NewFrame, AddressOf Me.pCameraWindow_NewFrame
End If
' unlock
Monitor.[Exit](Me)
End Set
End Property
' Constructor
Public Sub New()
InitializeComponent()
SetStyle(ControlStyles.AllPaintingInWmPaint Or ControlStyles.DoubleBuffer Or ControlStyles.ResizeRedraw Or ControlStyles.UserPaint, True)
End Sub
#Region "Windows Form Designer generated code"
Private Sub InitializeComponent()
Me.SuspendLayout()
Me.ResumeLayout(False)
End Sub
#End Region
' Paint control
Protected Overrides Sub OnPaint(pe As PaintEventArgs)
If (needSizeUpdate) OrElse (firstFrame) Then
UpdatePosition()
needSizeUpdate = False
End If
' lock
Monitor.Enter(Me)
Dim g As Graphics = pe.Graphics
Dim rc As Rectangle = Me.ClientRectangle
If m_camera IsNot Nothing Then
Try
m_camera.Lock()
' draw frame
If m_camera.LastFrame IsNot Nothing Then
g.DrawImage(m_camera.LastFrame, rc.X + 1, rc.Y + 1, rc.Width - 2, rc.Height - 2)
firstFrame = False
Else
' Create font and brush
Dim drawFont As New Font("Arial", 12)
Dim drawBrush As New SolidBrush(Color.White)
g.DrawString("Connecting ...", drawFont, drawBrush, New System.Drawing.PointF(5, 5))
drawBrush.Dispose()
drawFont.Dispose()
End If
Catch generatedExceptionName As Exception
Finally
m_camera.Unlock()
End Try
End If
' unlock
Monitor.[Exit](Me)
MyBase.OnPaint(pe)
End Sub
Public Function getImage() As Image
If Not m_camera Is Nothing Then
If Not m_camera.LastFrame Is Nothing Then
Return m_camera.LastFrame
End If
End If
Return Nothing
End Function
' Update position and size of the control
Public Sub UpdatePosition()
' lock
Monitor.Enter(Me)
If (m_autosize) AndAlso (Me.Parent IsNot Nothing) Then
Dim rc As Rectangle = Me.Parent.ClientRectangle
Dim width As Integer = 320
Dim height As Integer = 240
If m_camera IsNot Nothing Then
m_camera.Lock()
' get frame dimension
If m_camera.LastFrame IsNot Nothing Then
width = m_camera.LastFrame.Width
height = m_camera.LastFrame.Height
End If
m_camera.Unlock()
End If
'
Me.SuspendLayout()
Me.Location = New Point((rc.Width - width - 2) \ 2, (rc.Height - height - 2) \ 2)
Me.Size = New Size(width + 2, height + 2)
Me.ResumeLayout()
End If
' unlock
Monitor.[Exit](Me)
End Sub
' On new frame ready
Private Sub pCameraWindow_NewFrame(sender As Object, e As System.EventArgs)
Invalidate()
End Sub
End Class
End Namespace
Thank you for the help!
You need to change the Root Namespace for your project or override it. When you wrap your class in a Namespace block (e.g. Namespace FrameGrabber), the given namespace is relative to the root namespace for your project. In other words, if your root namespace is WindowsApplication1, then when you say Namespace FrameGrabber, all the enclosed types will actually be in the WindowsApplication1.FrameGrabber namespace.
If you want to override the root name space for one section of code, you can use the Global keyword so that the namespace declaration is not relative, like this:
Namespace Global.FrameGrabber
' ...
End Namespace
Using the Global keyword in your namespace declaration, like that, to override the root namespace seems to be a recent addition to VB.NET, though. From what I can tell, based on the inclusion of the information about it in the MSDN article, support for that was added in Visual Studio 2012. You can also find information on it in this MSDN article:
The Global keyword can also be used in a Namespace statement. This lets you define a namespace out of the root namespace of your project. For more information, see the "Global Keyword in Namespace Statements" section in Namespaces in Visual Basic.
Another option is to remove the root namespace from your project properties and then declare the full namespace on each and every code file in your project. The setting can be found in the project settings designer screen: My Project > Application > Root namespace.
Either that or come up with a naming convention that is more conducive to VB.NET's eccentricity. For instance, if you made the root namespace for your project your company name, then MyCompany.FrameGrabber would certainly make more sense than WindowsApplication1.FrameGrabber.
Quick question about a windows service, I've added a setup project for my Windows service, and ive added a custom dialog to it, with 4 text fields, but my question is how to i get these informations/variables?
Ive also added an installer for the windows service also, and afterwards the setup project, with the custom dialog.
The informations is something like database connection strings, and so on - so just string values.
This is my code for the "project installer" . the installer item ive added for the windows serive if you wanted to see it.
Imports System
Imports System.ComponentModel
Imports System.Configuration.Install
Imports System.ServiceProcess
Imports System.Runtime.InteropServices
Public Class ProjectInstaller
Public Sub New()
MyBase.New()
'This call is required by the Component Designer.
InitializeComponent()
My.Settings.TestSetting = Context.Parameters.Item("PathValue")
#If DEBUG Then
Dim ServicesToRun As ServiceBase()
ServicesToRun = New ServiceBase() {New tdsCheckService()}
ServiceBase.Run(ServicesToRun)
#Else
Dim listener As New tdsCheckService()
listener.Start()
#End If
End Sub
Public Overrides Sub Install(ByVal stateSaver As System.Collections.IDictionary)
MyBase.Install(stateSaver)
Dim regsrv As New RegistrationServices
regsrv.RegisterAssembly(MyBase.GetType().Assembly, AssemblyRegistrationFlags.SetCodeBase)
End Sub
Public Overrides Sub Uninstall(ByVal savedState As System.Collections.IDictionary)
MyBase.Uninstall(savedState)
Dim regsrv As New RegistrationServices
regsrv.UnregisterAssembly(MyBase.GetType().Assembly)
End Sub
Private Sub ServiceProcessInstaller1_AfterInstall(sender As Object, e As InstallEventArgs) Handles ServiceProcessInstaller1.AfterInstall
End Sub
Private Sub ServiceInstaller1_AfterInstall(sender As Object, e As InstallEventArgs) Handles ServiceInstaller1.AfterInstall
End Sub
End Class
You should eb able to access them using the Context object.
'Get Protected Configuration Provider name from custom action parameter
Dim variableName As String = Context.Parameters.Item("dialogSettingName")
Public Overrides Sub Install(ByVal stateSaver As System.Collections.IDictionary)
MyBase.Install(stateSaver)