Verify that an object has a certain property - vb.net

I found C# code for it here
So I tried
Public Function checkProperty(ByVal objectt As Object, ByVal propertyy As String) As Boolean
Dim type As Type = objectt.GetType
Return type.GetMethod(propertyy)
End Function
But it throws an error at type.GetMethod(propertyy) saying "Value of type 'System.Reflection.MethodInfo' cannot be converted to 'Boolean'."
What to do?

First, C# code checks for presence of a method, not a property. Second, C# code compares return to null:
Public Function checkProperty(ByVal objectt As Object, ByVal propertyy As String) As Boolean
Dim type As Type = objectt.GetType
Return type.GetProperty(propertyy) IsNot Nothing
End Function
EDIT To check for fields, change the method as follows:
Public Function checkField(ByVal objectt As Object, ByVal fieldName As String) As Boolean
Dim type As Type = objectt.GetType
Return type.GetField(fieldName) IsNot Nothing
End Function

it is returning the MethodInfo instead and you can just change it as follow:
Public Function checkProperty(ByVal objectt As Object, ByVal propertyy As String) As Boolean
Dim type As Type = objectt.GetType
Return type.GetMethod(propertyy) IsNot Nothing
End Function

You're trying to return type.GetMethod(propertyy), where your example code is returning the result of evaluating if that method is null or not.
try Return type.GetMethod(propertyy) isnot nothing

By splitting the line:
Return type.GetMethod(propertyy) IsNot Nothing
of dasblinkenlight into the three lines;
Dim info As System.Reflection.PropertyInfo = type.GetProperty(propertyy)
Dim reallyExists As Boolean = info IsNot Nothing
Return reallyExists
the function checkProperty will return true on existing properties.
I cannot comment to the answer of dasblinkenlight,
since my reputation is still less than 50,
so send my above improvement on his answer as a new answer.
I am not happy with this, since it makes the pages on stackoverflow less readable.
In order to make this a true answer I include a module I created,
in which the lines
Public Function propertyExists( _
through
End Function
are improvements to the code of function checkProperty of natli and dasblinkenlight.
See Verify that an object has a certain property
for the question of natli, that I am answering to.
See https://stackoverflow.com/posts/9399928/revisions and the question of natli
for the answer of dasblinkenlight, that I am commenting to.
By the way: "As you will see below I prefer not to use system namespaces,
so that I can directly see what system functions are referenced."
The module with the name net2Module I created to use this follows;
''' <summary>
''' This module with the name net2Module contains
''' tools that need at least .NET Framework 2.0.
''' This module needs System.Reflection.
''' </summary>
Public Module net2Module
''' <summary>
''' If one of the tools fails, the property exceptionMessage will
''' not be nothing, but contain an exception.
''' Each tool will set exceptionMessage to nothing or an exception.
''' </summary>
Public exceptionMessage As System.Exception = Nothing
''' <summary>
''' Checks if a property with some name exist in an object.
''' This function needs System.Reflection.
''' </summary>
''' <param name="objectt">The object.</param>
''' <param name="propertyy">The name of the property.</param>
''' <returns>True if the property exists.</returns>
Public Function propertyExists( _
objectt As Object, _
ByVal propertyy As String _
) As Boolean
Try
exceptionMessage = Nothing
Dim type As System.Type = objectt.GetType
Dim info As System.Reflection.PropertyInfo = _
type.GetProperty(propertyy)
Dim reallyExists As Boolean = info IsNot Nothing
Return reallyExists
Catch ex As System.Exception
exceptionMessage = ex
Return False
End Try
End Function ' propertyExists
End Module ' net2Module
In the following code I succesfully use my function propertyExists in order
to close or hide child forms recursively;
Friend Module sharedEnums
Friend Enum objectNamesEnum
formHandlingClass
calledForms
ownedForms
End Enum ' objectNamesEnum
Friend Enum recursiveFormTypesEnum
calledForms
ownedForms
End Enum ' recursiveFormTypesEnum
Friend Enum recursiveActionsEnum
hideForms
closeForms
End Enum ' recursiveActionsEnum
End Module ' sharedEnums
Friend Class recursiveClass
Friend recursiveFormTypes As New recursiveFormTypesEnum
Friend recursiveActions As New recursiveActionsEnum
Friend Sub hideOrCloseFormsRecursively( _
formsToHandle As System.Windows.Forms.Form())
If Not formsToHandle Is Nothing Then
Dim formToHandle As System.Windows.Forms.Form = Nothing
Dim propertyToExist As String = String.Empty
If Me.recursiveFormTypes = recursiveFormTypesEnum.calledForms Then
propertyToExist = objectNamesEnum.calledForms.ToString
Else ' Me.recursiveFormTypes = recursiveFormTypesEnum.ownedForms
propertyToExist = objectNamesEnum.ownedForms.ToString
End If
For Each formToHandle In formsToHandle
Try ' Recurse through the forms to handle
Dim formObject As Object = formToHandle
If net2Module.propertyExists(formObject, _
objectNamesEnum.formHandlingClass.ToString) Then
If net2Module.propertyExists( _
formObject.formHandlingClass, propertyToExist) Then
If Me.recursiveFormTypes = _
recursiveFormTypesEnum.calledForms Then
Call Me.hideOrCloseFormsRecursively( _
formObject.formHandlingClass.calledForms.ToArray)
Else ' Me.recursiveFormTypes = recursiveFormTypesEnum.ownedForms
Call Me.hideOrCloseFormsRecursively( _
formObject.formHandlingClass.ownedForms)
End If
End If
End If
If net2Module.propertyExists(formObject, propertyToExist) Then
If Me.recursiveFormTypes = _
recursiveFormTypesEnum.calledForms Then
Call Me.hideOrCloseFormsRecursively( _
formObject.calledForms.ToArray)
Else ' Me.recursiveFormTypes = recursiveFormTypesEnum.ownedForms
Call Me.hideOrCloseFormsRecursively( _
formObject.ownedForms)
End If
End If
Catch
End Try
Try ' Take the action to take on each found form
If Me.recursiveActions = _
recursiveActionsEnum.hideForms Then
Call formToHandle.Hide()
Else ' Me.recursiveActions = recursiveActionsEnum.closeForms
Call formToHandle.Close()
End If
Catch
End Try
Next
End If
End Sub ' hideOrCloseFormsRecursively
End Class ' recursiveClass
I would be delighted to read from you if you have been helped by me or not.
I am Dutch, so would also like comments on my Engish, so that I can improve it.

Related

How to use GetType and GetFields?

I'm updating a program and there is about 40 classes. I need to create a function that takes two lists of type object as parameters. Both lists only have one item in them (A version of the item BEFORE any changes were made, and AFTER the changes happened). I'm using these objects to create a single object to implement an UNDO button. With these parameters I need to get the type of each and make sure they match, if not then something went wrong. Next I'll need to read in the fields/properties/members (Not sure what to choose) and then compare them to each other and find what changed so I can set that as the item description. I don't want to trace the whole code and add specific functions for each and I know there has got to be a way to do this generically. I have created this small mock-up program that semi works for what I am trying to do. I can get the class type out of the object in list, but i have no idea how to get fields or whatever.
I'm using a large database with entity framework.
Also Using VB.NET!
Thanks for the help!
Here's code for generic program:
Imports System.Reflection
Module Module1
Sub Main()
Dim Myself As New Human("Matthew", "Cucco", Now, "Blonde", 19, False)
Dim NotMe As New Human("Jake", "Cucco", Now, "Blonde", 19, False)
Dim Him As New Employee("Matt", "Cucco", Now, "Blonde", 19, False, 215, "LuK", True)
Dim Her As New Customer("Jessie", "Keller", Now, "Blonde", 19, True, 25, "Cereal", "me#gmail.com")
Dim ListofPeople As IList(Of Object) = {Myself, NotMe, Him, Her}
Dim ListofPeople2 As IList(Of Object) = {Myself, NotMe, Him, Her}
ObjectsAreSameClass(ListofPeople, ListofPeople2)
Console.ReadKey()
End Sub
Private Function ObjectsAreSameClass(object1 As IList(Of Object), object2 As IList(Of Object)) As Boolean
Dim ObjectType As Type = object1.First.GetType()
Dim AreSameClass As Boolean = Nothing
Console.WriteLine(ObjectType.ToString)
If (object1.First.GetType() = object2.First.GetType()) Then
AreSameClass = True
Console.WriteLine("Object1 is of type: " + object1.First.GetType().Name)
Console.WriteLine("Object2 is of type: " + object2.First.GetType().Name)
If (object1.First.GetType().Name = "Human") Then
Console.WriteLine("Yep this works")
End If
Else
AreSameClass = False
Console.WriteLine("Object1 is of type: " + object1.First.GetType().Name)
Console.WriteLine("Object2 is of type: " + object2.First.GetType().Name)
If (object1.First.GetType().Name = "Human") Then
Console.WriteLine("Yep this works")
Console.WriteLine(object1.First.GetType().GetFields().ToString)
End If
End If
Dim MyField As PropertyInfo() = ObjectType.GetProperties()
Dim i As Integer
For i = 0 To MyField.Length - 1
Console.WriteLine(MyField(i).ToString)
Next i
Console.WriteLine("Objects are equal? t/f : " + AreSameClass.ToString)
Return AreSameClass
End Function
Public Class Human
Public FirstName As String
Public LastName As String
Public Birthdate As Date
Public HairColor As String
Public Age As Integer
Public Gender As Boolean 'False for male, true for female
Public Sub New()
FirstName = ""
LastName = ""
Birthdate = Now
HairColor = ""
Age = 0
Gender = False
End Sub
Public Sub New(f As String, l As String, b As Date, h As String, a As Integer, g As Boolean)
FirstName = f
LastName = l
Birthdate = b
HairColor = h
Age = a
Gender = g
End Sub
End Class
Public Class Employee
Inherits Human
Dim EmployeeId As Integer
Dim PlaceOfEmployment As String
Dim IsManager As Boolean
Public Sub New()
MyBase.New()
EmployeeId = 0
PlaceOfEmployment = ""
IsManager = False
End Sub
Public Sub New(f As String, l As String, b As Date, h As String, a As Integer, g As Boolean, i As Integer, p As String, m As Boolean)
MyBase.New(f, l, b, h, a, g)
EmployeeId = i
PlaceOfEmployment = p
IsManager = m
End Sub
End Class
Public Class Customer
Inherits Human
'used for testing
Dim IdNumber As Integer
Dim FavoriteItem As String
Dim email As String
Public Sub New()
MyBase.New()
IdNumber = 0
FavoriteItem = ""
email = ""
End Sub
Public Sub New(f As String, l As String, b As Date, h As String, a As Integer, g As Boolean, i As Integer, fav As String, e As String)
MyBase.New(f, l, b, h, a, g)
IdNumber = i
FavoriteItem = fav
email = e
End Sub
End Class
End Module
This Currently displays this:
TestProject.Module1+Human
Object1 is of type: Human
Object2 is of type: Human
Yep this works
Objects are equal? t/f : True
Also for reference, here is my main program that I will be implementing this into:
Function NewItem(Before As IEnumerable(Of Object), After As IEnumerable(Of Object), ObjectType As String)
ObjectsAreSameClass(Before, After, ObjectType) 'Check if objects are same class
Dim BeforeFields() As FieldInfo = GetFieldData(Before) 'gets all field info, saves to an array
Dim AfterFields() As FieldInfo = GetFieldData(After)
'Now check and make sure the objects are not the same
Dim ThisChanged As FieldInfo
If (ObjectValuesAreEqual(BeforeFields, AfterFields) = True) Then
'These objects did not not change
ThisChanged = Nothing
Else
'Change occured, find out where
ThisChanged = FindWhatChanged(BeforeFields, AfterFields)
End If
'Create a new UndoRedo item and give it these values
Dim UndoRedoNow As New ClsUndoRedo
UndoRedoNow.BeforeObject = Before.Single
UndoRedoNow.AfterObject = After.Single
UndoRedoNow.ObjectCounter += 1
UndoRedoNow.WhatChanged = ThisChanged
If WhatGroupChanged.isDeleted Then
UndoRedoNow.WhatAction = Before.Single.GetType().ToString + " item was Deleted"
ElseIf WhatGroupChanged.isNew Then
UndoRedoNow.WhatAction = After.Single.GetType().ToString + " item was created"
ElseIf WhatGroupChanged.isChanged Then
UndoRedoNow.WhatAction = After.Single.GetType().ToString + " item was changed"
End If
UndoRedoNow.WhatGroupChanged.isRedo = False 'Make sure it is not a redo object
'Now add object to list
ChangeLog.Add(UndoRedoNow)
Return Nothing
End Function
Private Function ObjectsAreSameClass(before As IEnumerable(Of Object), after As IEnumerable(Of Object), WhatType As String) As Boolean
Dim AreSameClass As Boolean = False
Try
If (before.Single.GetType() = after.Single.GetType() Or (before Is Nothing) Or (after Is Nothing)) Then
'Objects are of the same class or nothing
If before Is Nothing Then
WhatGroupChanged.isNew = True 'New item
ElseIf after Is Nothing Then
WhatGroupChanged.isDeleted = True 'Deleted item
Else
WhatGroupChanged.isChanged = True 'item was changed
End If
AreSameClass = True
End If
Catch
'Need to raise error
End Try
Return AreSameClass
End Function
''' <summary>
''' This function will return all of the fields for a certain class as well as the data stored in them
''' </summary>
''' <param name="list"></param>
''' <returns></returns>
Public Shared Function GetFieldData(ByVal list As IList(Of Object)) As FieldInfo()
Dim fields() As FieldInfo = list.Single.GetType().GetFields()
Return fields
End Function
''' <summary>
''' This function will check that the values in the datafields are not equal
''' </summary>
''' <param name="Before"></param>
''' <param name="After"></param>
''' <returns></returns>
Private Function ObjectValuesAreEqual(Before() As FieldInfo, After() As FieldInfo) As Boolean
Dim isEqual As Boolean = New Boolean 'This will keep track of if the elements are equal or not
For index As Integer = 0 To (Before.Count - 1)
If Before.ElementAt(index).GetValue(Before.ElementAt(index)).Equals(After.ElementAt(index).GetValue(After.ElementAt(index))) Then
'They are equal so set to true
isEqual = True
Else
'They are not equal so set to false and return
isEqual = False
Return isEqual
End If
Next
Return isEqual
End Function
Private Function FindWhatChanged(Before() As FieldInfo, After() As FieldInfo) As FieldInfo
Dim ThisIsChange As FieldInfo
For index As Integer = 0 To (Before.Count - 1)
If Before.ElementAt(index).GetValue(Before.ElementAt(index)).Equals(After.ElementAt(index).GetValue(After.ElementAt(index))) Then
ThisIsChange = After.ElementAt(index)
Return ThisIsChange
Else
'Raise error
End If
Next
End Function
The proper way to preserve type information when working with unknown types is to write a generic function (and if necessary generic classes, structures, etc.).
Using GetType, in a perfect world, should never be needed.
Generic functions look like this:
Public Function MyGenericFunction(Of T)(myArg as T) as Integer
' do something with myArg1, myArg2 ... without knowing their exact type
Return 0
End Function
' or with multiple types
Public Function MyGenericFunction2(Of T1, T2, ... )(myArg1 as T1, myArg2 as T2, ...) as T1()
' do something with myArg1, myArg2 ... without knowing their exact type
Return { myArg1 }
End Function
When you call these functions, the generic types are usually automatically deduced from the arguments you passed. If they can't be guessed, you will need to explicitly annotate the types, like this:
Dim x = MyGenericFunction(Of SomeClass1)(foo)
Dim x = MyGenericFunction(Of SomeClass2)(foo)
A full guide here: https://msdn.microsoft.com/en-us/library/w256ka79.aspx
However, if you need to handle specific types with the same function, then what you want to do use is a more narrow tool: overloading, or more technically parametric polymorphism.
What that means is, you will need to provide two (or more) different definitions of the same function ( = having the same name), that accept parameters of different types.
A simple example:
Public Class MyClass1
Public Foo1 As String = "foo1"
End Class
Public Class MyClass2
Public Foo2 As String = "foo2"
End Class
Public Sub MyFunction(arg as MyClass1)
Console.WriteLine(arg.Foo1)
End Sub
Public Sub MyFunction(arg as MyClass2)
Console.WriteLine(arg.Foo2)
End Sub
Dim x as Object
' let's give x a random value of either MyClass1 or MyClass2,
' and we don't know in advance which one
If DateTime.Today.DayOfWeek = DayOfWeek.Tuesday Then
x = new MyClass1
Else
x = new MyClass2
End If
' the program will automatically invoke the correct function based on x's value, and print either "foo1" or "foo2"
MyFunction(x)

VB: Problems with using variable from another class + what to do with not used interface`s functions

I have a problem with getting variable from another class and cannot understand what to do with interface`s functions which have already existed in another class.
What I have:
Form where clicking on a button I should see reversed string:
(I want to call pooraja.StringReverse which is below)
Private Sub btnPoora1_Click(sender As System.Object, e As System.EventArgs) _
Handles btnPoora1.Click
'Dim text As PrjTekstiPooraja.ITeisendused = New PrjTekstiPooraja.CtekstiPooraja
Dim text As PrjTekstiPooraja.ITeisendused = New PrjTekstiPooraja.CtekstiPooraja
Dim pooraja As PrjTekstiPooraja.ITeisendused = New PrjTekstiPooraja.CAlgrotimilinePooraja
text.strText = txtSisendTekst.Text
txtValjundTekst1.Text = pooraja.stringReverse
text.intStart = 1
text.intEnd = Len(txtSisendTekst.Text)
ascFSymbol.Text = text.ascFirstSymbol
ascLSymbol.Text = text.ascLastSymbol()
End Sub
CtekstiPooraja:
(Thiss class will be used to store data.Under data I mean strPooratavText. Data will be used in CAlgoritmilinePooraja)
Public Class CtekstiPooraja
Implements ITeisendused
Public intStartSymbol As Integer
Public intEndSymbol As Integer
Public strPooratavText As String
Private Property intEnd As Integer Implements ITeisendused.intEnd
Get
Return intEndSymbol
End Get
Set(ByVal value As Integer)
intEndSymbol = value
End Set
End Property
Private Property intStart As Integer Implements ITeisendused.intStart
Get
Return intStartSymbol
End Get
Set(ByVal value As Integer)
intStartSymbol = value
End Set
End Property
Public Function pooraText() As String Implements ITeisendused.pooraText
Return StrReverse(strPooratavText)
End Function
Public Property strText As String Implements ITeisendused.strText
Get
Return strPooratavText
End Get
Set(ByVal value As String)
strPooratavText = value
MsgBox(strPooratavText)
End Set
End Property
Public Sub teisendaText(ByRef strSisendText As String) Implements ITeisendused.teisendaText
strPooratavText = StrReverse(strSisendText)
End Sub
Public Function ascFirstSymbol() As String Implements ITeisendused.ascFirstSymbol
Return Asc(GetChar(strPooratavText, intStartSymbol))
End Function
Public Function ascLastSymbol() As String Implements ITeisendused.ascLastSymbol
Return Asc(GetChar(strPooratavText, intEndSymbol))
End Function
Public Function stringReverse() As String Implements ITeisendused.stringReverse
Return Nothing
End Function
End Class
CAlgrotimilinePooraja:
(This class will be called by form button. There I need to use stringReverse function with data from CtekstiPooraja. The problem is that everywhere is used the same interface and there is some functions and procedures from this interface which isnt necessary. I dont know what value should return these unused functions/procedures. Just using "return Nothing or return 0/ "" is bad idea, may be there is possible somehow referenceto to CTekstiPooraja functions/procedures variables")
Public Class CAlgrotimilinePooraja
Implements ITeisendused
Private x As New PrjTekstiPooraja.CtekstiPooraja
Public Function stringReverse() As String Implements ITeisendused.stringReverse
MsgBox(x.strPooratavText)
Dim i As Integer = 0
Dim j As Integer
Dim characters(j) As Char
Dim newString(j) As Char
characters = x.strPooratavText.ToCharArray()
newString = x.strPooratavText.ToCharArray()
Do While i <= j - 1
newString(i) = characters(j - 1)
newString(j - 1) = characters(i)
i += 1
j -= 1
Loop
Return newString
End Function
Public Function ascFirstSymbol() As String Implements ITeisendused.ascFirstSymbol
Return x.ascFirstSymbol()
End Function
Public Function ascLastSymbol() As String Implements ITeisendused.ascLastSymbol
Return Nothing
End Function
Public Property intEnd As Integer Implements ITeisendused.intEnd
Get
Return x.intEndSymbol
End Get
Set(ByVal value As Integer)
End Set
End Property
Public Property intStart As Integer Implements ITeisendused.intStart
Get
Return x.intStartSymbol
End Get
Set(ByVal value As Integer)
End Set
End Property
Public Function pooraText() As String Implements ITeisendused.pooraText
Return x.pooraText()
End Function
Public Property strText As String Implements ITeisendused.strText
Get
Return x.strPooratavText
End Get
Set(ByVal value As String)
End Set
End Property
Public Sub teisendaText(ByRef strSisendText As String) Implements ITeisendused.teisendaText
x.strPooratavText = StrReverse(strSisendText)
End Sub
End Class
MyInterface:
Public Interface ITeisendused
Property intStart As Integer
Property intEnd As Integer
Property strText As String
Function pooraText() As String
Function ascFirstSymbol() As String
Function ascLastSymbol() As String
Function stringReverse() As String
Sub teisendaText(ByRef strSisendText As String)
End Interface
I cannot understand how to get variable strPooratavText from CTekstiPooraja to CAlgrotimilinePooraja. Usually that instancewhich I create worked but not now. And I cannot understand what to do with already existed function and procedures in CAlgoritmilinePooraja when the same function and procedures has in another class. Maybe, it is possible to reference them somehow to existed functions/procedures in CTekstiPooraja? Could you explain me how to id, already tired to surf Internet to find a solution for it, have already try a lot.
Well, I think you have a fundamental problem with understanding interfaces. They describe data and behavior, it should be extremely rare to want to implement part of an interface.
That said, if you do want to implement part of an interface, instead of returning bogus data, throw an exception for behavior you don't implement.
Your specific problem is that CAlgoritmilinePooraja works on an instance of CtekstiPooraja, but it creates a new instance instead of using an existing one. Add
Sub New(incomingX as CtekstiPooraja)
x = incomingX
End Sub
to CAlgoritmilinePooraja. And then in your event, use....
Dim text As PrjTekstiPooraja.CtekstiPooraja = New PrjTekstiPooraja.CtekstiPooraja
text.strText = txtSisendTekst.Text
Dim pooraja As PrjTekstiPooraja.ITeisendused = New PrjTekstiPooraja.CAlgrotimilinePooraja(text)
That is the minimum change to your design that gets what you want to happen to happen but it's problably not what you should do. Other than implementing strReverse, CtekstiPooraja seems to be what you want, CAlgrotimilinePooraja looks to do just one thing, the actual string reversal.
I would move the implementation of strReverse into CtekstiPooraja, and then eliminate CAlgrotimilinePooraja.
PS I would try to stick to English for class names as well as functions and variables.

Visual basic "Unhandled exception"

Hello I'm getting this error, while trying to save serial number to XML File.
If the file doesn't exist, it saves the file fine, but if i change Registered tag to False in Xml file, and try again, it says "The Process Cannot acces the file ... because it is being used by another process".
In my main form i read the information from XML, and in my regform (which i open if registered tag in xml is false) i write to the file. is it because of that?! I don't think so.
Here is my Registration class:
Imports System.IO
Imports System.Xml
Public Class RegistrationClass
Public Property SerialNumber As String
Public Property Registered As Boolean = False
Public Sub Write_Reg(ByVal FileString As String, ByVal RegisterName As String, ByVal RegisterCompany As String, ByVal RegisterSerialNumber As String)
Dim Registered As Boolean = False
Dim Comment As String = "StroySoft 2012 Register Database"
Dim SerialNumber As String = "dev-xxx-123"
Dim ClientOS As String = Trim(My.Computer.Info.OSFullName)
If RegisterSerialNumber = SerialNumber Then
Dim settings As New XmlWriterSettings()
settings.Indent = True
' Initialize the XmlWriter.
Dim XmlWrt As XmlWriter = XmlWriter.Create(FileString, settings)
With XmlWrt
' Write the Xml declaration.
.WriteStartDocument()
' Write a comment.
.WriteComment(Comment)
' Write the root element.
.WriteStartElement("Data")
' Start our first person.
.WriteStartElement("Register")
' The person nodes.
.WriteStartElement("Name")
.WriteString(RegisterName.ToString())
.WriteEndElement()
.WriteStartElement("Company")
.WriteString(RegisterCompany.ToString())
.WriteEndElement()
.WriteStartElement("SerialNumber")
.WriteString(RegisterSerialNumber.ToString())
.WriteEndElement()
Registered = True
.WriteStartElement("Registered")
.WriteString(Registered)
.WriteEndElement()
.WriteStartElement("ClientOS")
.WriteString(ClientOS)
.WriteEndElement()
' The end of this person.
.WriteEndElement()
' Close the XmlTextWriter.
.WriteEndDocument()
.Close()
End With
MsgBox("Успешна регистрация! Благодарим Ви!")
MainForm.РегистрацияToolStripMenuItem.Visible = False
Else
MsgBox("Невалиден сериен номер!")
End If
End Sub
Public Sub Check_Reg(ByVal FileString As String)
If (System.IO.File.Exists(FileString)) Then
Dim document As XmlReader = New XmlTextReader(RegForm.RegFile)
While (document.Read())
Dim type = document.NodeType
If (type = XmlNodeType.Element) Then
If (document.Name = "Registered") Then
If document.ReadInnerXml.ToString() = "True" Then
Registered = True
Else
Registered = False
End If
End If
If (document.Name = "SerialNumber") Then
SerialNumber = document.ReadInnerXml.ToString()
End If
End If
End While
Else
MessageBox.Show("The filename you selected was not found.")
End If
End Sub
End Class
is it because of that?! I don't think so.
It's exactly because of that.
You should always make sure to properly dispose IDisposable resources such as Streams and Writers/Readers by wrapping them in a Using block. In your case I don't see you closing your reader. But if you wrap it in a Using block you shouldn't worry about it. Even if an exception is thrown the resource will be properly released.
Example:
Using XmlWrt As XmlWriter = XmlWriter.Create(FileString, settings)
...
End Using
You should do the same with your XmlReader:
Using document As XmlReader = XmlReader.Create(RegForm.RegFile)
...
End Using

How do you return an object as the return value through a RealProxy transparent proxy?

I'm working up a system where I plan on using RealProxy objects to enable intercepting method calls against a set of objects, handling the call, and then returning appropriate results.
This works just find for simple return types like strings or ints, but I can't seem to return objects from the RealProxy.Invoke method.
Everything works. I get no errors, but the returned value is always NOTHING, instead of an object.
I've worked up the smallest sample code I could, and have included it below.
Essentially, just call RPtest and single step through.
The code creates a simple object, RPTestA, with a string field and an object valued field
It then retrieves the string
Dim x = c.Name
Which works fine
and then attempts to retrieve the object
Dim r = c.SubObj
Which always returns nothing.
However, in the FieldGetter routine, this code:
'---- the field is an OBJECT type field
Dim mc = New MethodCallMessageWrapper(Msg)
'---- create the object
Dim o = Activator.CreateInstance(t)
'---- and construct the return message with that object
Dim r = New ReturnMessage(o, mc.Args, mc.Args.Length, mc.LogicalCallContext, mc)
Return r
appears to work just fine, setting the ReturnValue field of the ReturnMessage to the object that was created by the Activator.CreateInstance(t) call just above.
I suspect it's a serialization thing of some sort, but I'm at a loss.
You should be able to run this code straight away, but just pasting it into a new VB.net project.
'----------------------------------------------------------------------------
Imports System.Security.Permissions
Imports System.Diagnostics
Imports System.Reflection
Imports System.Runtime.CompilerServices
Imports System.Runtime.Serialization
Imports System.Runtime.Remoting
Imports System.Runtime.Remoting.Activation
Imports System.Runtime.Remoting.Messaging
Imports System.Runtime.Remoting.Proxies
Public Module RPTest
Public Sub RPTest()
'---- create a new object that is automatically proxied
' See the RPProxyAttribute for details
Dim c = New RPTestA
Dim x = c.Name
'x is returned as a string value just fine
Dim r = c.SubObj
'********* PROBLEM IS HERE, r ends up nothing
End Sub
End Module
'ROOT test object
Public Class RPTestA
Inherits RPBase
Public Name As String = "Test Name"
Public SubObj As RPTestB
End Class
'SUB OBJECT which should be returned as a field value from the root object above
Public Class RPTestB
Inherits RPBase
Public SubProperty As String = "SubObj Test Property"
End Class
''' <summary>
''' Base proxyable object class
''' </summary>
''' <remarks></remarks>
<RPProxy()> _
Public MustInherit Class RPBase
Inherits ContextBoundObject
End Class
<PermissionSet(SecurityAction.Demand, Name:="FullTrust")> _
Public Class RPProxy
Inherits RealProxy
Private m_target As MarshalByRefObject
Public Sub New()
m_target = DirectCast(Activator.CreateInstance(GetType(ConfigRP)), MarshalByRefObject)
Dim myObjRef = RemotingServices.Marshal(m_target)
End Sub
Public Sub New(ByVal classToProxy As Type)
MyBase.New(classToProxy)
End Sub
Public Sub New(ByVal ClassToProxy As Type, ByVal targetObject As MarshalByRefObject)
m_target = targetObject
Dim myObjRef = RemotingServices.Marshal(m_target)
End Sub
Public Overrides Function Invoke(ByVal msg As IMessage) As IMessage
Dim returnMsg As IMethodReturnMessage = Nothing
If TypeOf msg Is IConstructionCallMessage Then
'---- handle constructor calls
Dim ConstructionCallMessage = DirectCast(msg, IConstructionCallMessage)
returnMsg = InitializeServerObject(ConstructionCallMessage)
Me.m_target = Me.GetUnwrappedServer()
SetStubData(Me, Me.m_target)
Return returnMsg
ElseIf TypeOf msg Is IMethodCallMessage Then
'---- handle all other method calls
Dim methodCallMessage = DirectCast(msg, IMethodCallMessage)
'---- before message processing
preprocess(methodCallMessage)
'---- execute the method call
Dim rawReturnMessage = RemotingServices.ExecuteMessage(Me.m_target, methodCallMessage)
'---- and postprocess
returnMsg = postprocess(methodCallMessage, rawReturnMessage)
Else
Throw New NotSupportedException()
End If
Return returnMsg
End Function
'Called BEFORE the actual method is invoked
Private Sub PreProcess(ByVal msg As IMessage)
Console.WriteLine("before method call...")
End Sub
'Called AFTER the actual method is invoked
Private Function PostProcess(ByVal Msg As IMethodCallMessage, ByVal msgReturn As ReturnMessage) As ReturnMessage
Dim r As ReturnMessage
If Msg.MethodName = "FieldGetter" Then
r = FieldGetter(Msg, msgReturn)
ElseIf Msg.MethodName = "FieldSetter" Then
'na
r = msgReturn
ElseIf Msg.MethodName.StartsWith("get_") Then
'na
r = msgReturn
ElseIf Msg.MethodName.StartsWith("set_") Then
'na
r = msgReturn
Else
r = msgReturn
End If
Return r
End Function
Private Function FieldGetter(ByVal Msg As IMethodCallMessage, ByVal msgReturn As IMethodReturnMessage) As IMethodReturnMessage
Dim t = Me.Target.GetType
'---- This retrieves the type of the field that the getter should retrieve
t = t.GetField(Msg.InArgs(1), BindingFlags.Instance Or BindingFlags.Public).FieldType
If t.Name = "String" Then
'---- just return what the object returned as a result of ExecuteMessage
Return msgReturn
ElseIf t.BaseType.Equals(GetType(RPBase)) Then
'---- the field is an OBJECT type field
Dim mc = New MethodCallMessageWrapper(Msg)
'---- create the object
Dim o = Activator.CreateInstance(t)
'---- and construct the return message with that object
Dim r = New ReturnMessage(o, mc.Args, mc.Args.Length, mc.LogicalCallContext, mc)
Return r
Else
Return msgReturn
End If
End Function
Public Property Target() As Object
Get
Return Me.m_target
End Get
Set(ByVal value As Object)
Me.m_target = value
End Set
End Property
End Class
<AttributeUsage(AttributeTargets.Class)> _
<SecurityPermissionAttribute(SecurityAction.Demand, Flags:=SecurityPermissionFlag.Infrastructure)> _
Public Class RPProxyAttribute
Inherits ProxyAttribute
Public Overrides Function CreateInstance(ByVal Type As Type) As MarshalByRefObject
Dim proxy = New RPProxy(Type)
Dim transparentProxy = DirectCast(proxy.GetTransparentProxy(), MarshalByRefObject)
Return transparentProxy
End Function
End Class
Well, it turns out to be a pretty simple fix, once you work past the god awful ReturnMessage constructor that's quite misleading!
Many thanks to an old colleague of mine, Rich Quackenbush, for taking a few minutes and checking this out. Sometimes, you can't see the forest for the trees!
Anyway, in FieldGetter, I was doing this
ElseIf t.BaseType.Equals(GetType(RPBase)) Then
'---- the field is an OBJECT type field
Dim mc = New MethodCallMessageWrapper(Msg)
'---- create the object
Dim o = Activator.CreateInstance(t)
'---- and construct the return message with that object
Dim r = New ReturnMessage(o, mc.Args, mc.Args.Length, mc.LogicalCallContext, mc)
Return r
Seems completely reasonable, that newly created object being passed into the ReturnMessage constructor argument called ReturnValue.
But no. You actually have to create an object array and pass it is as the 3 element in that array, like this:
ElseIf t.BaseType.Equals(GetType(RPBase)) Then
'---- the field is an OBJECT type field
Dim mc = New MethodCallMessageWrapper(Msg) '---- create the object
Dim o = Activator.CreateInstance(t)
'---- and construct the return message with that object
Dim r = New ReturnMessage(Nothing, New Object() {Nothing, Nothing, o}, 3, mc.LogicalCallContext, mc)
Return r
It turns out, this is because the FieldGetter function is what in being "called" and intercepted by the proxy, and it's signature is
FieldGetter(StringtypeName,StringfieldName,Object&val)
Which, for purposes of constructing a ReturnMessage for that call means that it doesn't have a Returnvalue at all, but rather that the return value is returned as the 3'rd argument in that list.
Since I'm not actually calling the real FieldGetter function, the first two argument (the typename and fieldname) are immaterial, but that 3'rd argument is the proper place to put the return value.
It's always obvious in hindsight!
Many thanks to Rich.

How to declare a fixed-length string in VB.NET?

How do i Declare a string like this:
Dim strBuff As String * 256
in VB.NET?
Use the VBFixedString attribute. See the MSDN info here
<VBFixedString(256)>Dim strBuff As String
It depends on what you intend to use the string for. If you are using it for file input and output, you might want to use a byte array to avoid encoding problems. In vb.net, A 256-character string may be more than 256 bytes.
Dim strBuff(256) as byte
You can use encoding to transfer from bytes to a string
Dim s As String
Dim b(256) As Byte
Dim enc As New System.Text.UTF8Encoding
...
s = enc.GetString(b)
You can assign 256 single-byte characters to a string if you need to use it to receive data, but the parameter passing may be different in vb.net than vb6.
s = New String(" ", 256)
Also, you can use vbFixedString. I'm not sure exactly what this does, however, because when you assign a string of different length to a variable declared this way, it becomes the new length.
<VBFixedString(6)> Public s As String
s = "1234567890" ' len(s) is now 10
To write this VB 6 code:
Dim strBuff As String * 256
In VB.Net you can use something like:
Dim strBuff(256) As Char
Use stringbuilder
'Declaration
Dim S As New System.Text.StringBuilder(256, 256)
'Adding text
S.append("abc")
'Reading text
S.tostring
Try this:
Dim strbuf As New String("A", 80)
Creates a 80 character string filled with "AAA...."'s
Here I read a 80 character string from a binary file:
FileGet(1,strbuf)
reads 80 characters into strbuf...
You can use Microsoft.VisualBasic.Compatibility:
Imports Microsoft.VisualBasic.Compatibility
Dim strBuff As New VB6.FixedLengthString(256)
But it's marked as obsolete and specifically not supported for 64-bit processes, so write your own that replicates the functionality, which is to truncate on setting long values and padding right with spaces for short values. It also sets an "uninitialised" value, like above, to nulls.
Sample code from LinqPad (which I can't get to allow Imports Microsoft.VisualBasic.Compatibility I think because it is marked obsolete, but I have no proof of that):
Imports Microsoft.VisualBasic.Compatibility
Dim U As New VB6.FixedLengthString(5)
Dim S As New VB6.FixedLengthString(5, "Test")
Dim L As New VB6.FixedLengthString(5, "Testing")
Dim p0 As Func(Of String, String) = Function(st) """" & st.Replace(ChrW(0), "\0") & """"
p0(U.Value).Dump()
p0(S.Value).Dump()
p0(L.Value).Dump()
U.Value = "Test"
p0(U.Value).Dump()
U.Value = "Testing"
p0(U.Value).Dump()
which has this output:
"\0\0\0\0\0"
"Test "
"Testi"
"Test "
"Testi"
This object can be defined as a structure with one constructor and two properties.
Public Structure FixedLengthString
Dim mValue As String
Dim mSize As Short
Public Sub New(Size As Integer)
mSize = Size
mValue = New String(" ", mSize)
End Sub
Public Property Value As String
Get
Value = mValue
End Get
Set(value As String)
If value.Length < mSize Then
mValue = value & New String(" ", mSize - value.Length)
Else
mValue = value.Substring(0, mSize)
End If
End Set
End Property
End Structure
https://jdiazo.wordpress.com/2012/01/12/getting-rid-of-vb6-compatibility-references/
Have you tried
Dim strBuff as String
Also see Working with Strings in .NET using VB.NET
This tutorial explains how to
represent strings in .NET using VB.NET
and how to work with them with the
help of .NET class library classes.
Dim a as string
a = ...
If a.length > theLength then
a = Mid(a, 1, theLength)
End If
This hasn't been fully tested, but here's a class to solve this problem:
''' <summary>
''' Represents a <see cref="String" /> with a minimum
''' and maximum length.
''' </summary>
Public Class BoundedString
Private mstrValue As String
''' <summary>
''' The contents of this <see cref="BoundedString" />
''' </summary>
Public Property Value() As String
Get
Return mstrValue
End Get
Set(value As String)
If value.Length < MinLength Then
Throw New ArgumentException(String.Format("Provided string {0} of length {1} contains less " &
"characters than the minimum allowed length {2}.",
value, value.Length, MinLength))
End If
If value.Length > MaxLength Then
Throw New ArgumentException(String.Format("Provided string {0} of length {1} contains more " &
"characters than the maximum allowed length {2}.",
value, value.Length, MaxLength))
End If
If Not AllowNull AndAlso value Is Nothing Then
Throw New ArgumentNullException(String.Format("Provided string {0} is null, and null values " &
"are not allowed.", value))
End If
mstrValue = value
End Set
End Property
Private mintMinLength As Integer
''' <summary>
''' The minimum number of characters in this <see cref="BoundedString" />.
''' </summary>
Public Property MinLength() As Integer
Get
Return mintMinLength
End Get
Private Set(value As Integer)
mintMinLength = value
End Set
End Property
Private mintMaxLength As Integer
''' <summary>
''' The maximum number of characters in this <see cref="BoundedString" />.
''' </summary>
Public Property MaxLength As Integer
Get
Return mintMaxLength
End Get
Private Set(value As Integer)
mintMaxLength = value
End Set
End Property
Private mblnAllowNull As Boolean
''' <summary>
''' Whether or not this <see cref="BoundedString" /> can represent a null value.
''' </summary>
Public Property AllowNull As Boolean
Get
Return mblnAllowNull
End Get
Private Set(value As Boolean)
mblnAllowNull = value
End Set
End Property
Public Sub New(ByVal strValue As String,
ByVal intMaxLength As Integer)
MinLength = 0
MaxLength = intMaxLength
AllowNull = False
Value = strValue
End Sub
Public Sub New(ByVal strValue As String,
ByVal intMinLength As Integer,
ByVal intMaxLength As Integer)
MinLength = intMinLength
MaxLength = intMaxLength
AllowNull = False
Value = strValue
End Sub
Public Sub New(ByVal strValue As String,
ByVal intMinLength As Integer,
ByVal intMaxLength As Integer,
ByVal blnAllowNull As Boolean)
MinLength = intMinLength
MaxLength = intMaxLength
AllowNull = blnAllowNull
Value = strValue
End Sub
End Class