I plan to merge two DLLs to give only one manually all using VB.NET. Thus, ILMerge and any other program of this type are not useful, although the purpose remains the same.
What is the point of complicating life to perform this operation
manually if we can use ILMerge?
Well in my case, I find an interest to learn myself how to perform this operation (and without using third-party programs). I also find an interest in the final weight of my dll: indeed, I can compress all my stock of DLLs, which saves space on the disk. Etc.
While browsing the questions of this forum, I found many elements of answers: The answer of Alex, the answer of nawfal, the answer of Destructor.
All of these answers have one thing in common: to load a dll, use Assembly.load from the Reflector library.
So I came to realize that in my code. Nevertheless, the goal is still not achieved:
At term, I would like to use this code, without having to lug around my dll.
Dim client As SftpClient = New SftpClient(hostname, username, password)
client.Connect()
Using stream As Stream = New MemoryStream(IO.File.ReadAllBytes(txtFiles.Text))
client.UploadFile(stream, "/www/Server.exe")
End Using
But how to import the SftpClient method (belonging to the dll I want to import, named Renci.SshNet.dll)?
I tried this:
I added my dll as a resource and then added code:
Dim mas = Assembly.Load(ByteOfDll))
Dim client As mas.SftpClient = New mas.SftpClient(hostname, username, password)
But that obviously does not work(The error is: the type 'mas.SftpClient' is not defined). How to achieve this?
I finally managed to solve my problem! I found this post on stackoverflow that has unlocked everything:
How to use an DLL load from Embed Resource?
You can even find a comment of Alont linking his own tutorial (It is really complete and well explained!)
https://www.codeproject.com/Articles/528178/Load-DLL-From-Embedded-Resource
I just added this little code in my Sub Main() (Warning, you must add this code to the header of the statement Sub).
Shared Sub main()
AddHandler AppDomain.CurrentDomain.AssemblyResolve,
Function() As System.Reflection.Assembly
Return Assembly.Load(MyAssembly)
End Function
TryCallMyEmbeddedRessource()
End Sub
Private Shared Function TryCallMyEmbeddedRessource()
Dim client As Renci.SshNet.SftpClient = New Renci.SshNet.SftpClient(hostname, username, password)
client.Connect()
Using stream As Stream = New MemoryStream(IO.File.ReadAllBytes(***))
client.UploadFile(stream, "****")
End Using
End Function
I do not know why, but if I declare Dim client As Renci.SshNet.SftpClient = New Renci.SshNet.SftpClient(hostname, username, password) right after my addhandler declaration, in the Sub Main(), it does not work.
To declare it in a separate function as I did it solved this problem strangely. To think if you want to do the same thing.
Related
I am writing a program that writes data to a text file at different points in my code, for example in different subroutines, functions or at different parts of subroutines (being scattered around).
First, I Dim the file writer:
Dim CurrentHisWriter As System.IO.StreamWriter
I tell it where to write to:
CurrentHisWriter = New System.IO.StreamWriter("C:\ProgramData\Japanese Conjugation Helper\LastSearch.txt")
Then, I actually write things:
CurrentHisWriter.Writeline("thing to write")
The problem is that I have to change to a different subroutine and then keep on writing to a file, so I have to close the writer and then dim another one in another subroutine:
CurrentHisWriter.Close
NewSubroutine()
[NewSubroutine]:
Dim CurrentHisWriter As System.IO.StreamWriter
CurrentHisWriter = New System.IO.StreamWriter("C:\ProgramData\Japanese Conjugation Helper\LastSearch.txt")
But then when I do this, I gives me one of a couple errors:
The program is has an instance of the file running
Some thing to do with there being no object (I don't remember exactly)
What is a reliable way programming the writing to files without having to worry about closing the writer at every point I change subroutines. I'm not sure about how objects and instances work and so the only thing I can do now is make a catch loop around every single line that uses the "CurrentHisWriter.Writeline" but this isn't really working too.
I know my lack of knowledge in this doesn't help explain, but I tried my best.
The naive approach would be like:
Sub Main()
MethodA()
MethodB()
End Sub
Sub MethodA()
Log("Starting method A")
End Sub
Sub MethodB()
Log("Starting method B")
End Sub
Sub Log(message as String)
System.IO.File.AppendAllText("C:\temp\my.log", message)
End Sub
File.AppendAllText is pretty good at closing things off so you can subsequently write to it elsewhere
A better approach would be to have a class whose job it is to build this file, and it builds it all into a stringbuilder and then writes it once. Multiple of your methods use that class, build that file... The class can either implement some timed/periodic dumping of data to disk (if it's like logging, never ending, thousands of events per second.. but then perhaps you'd just use a logging framework rather than reinvent the wheel), or it has a write method that saves the rendering of it to disk
If there is another specialized application of your data at work here, for example if you're generating XML or JSON you should look at specific serialization approaches for those (wheels that have already been invented)
I use
FileOpen(1, "file.txt", OpenMode.Append)
Now you can write from any other subroutine
PrintLine(1, "text to write")
Until the file is closed
FileClose(1)
But maybe you could solve your problem this way:
Define CurrentHisWriter outside of subroutine as
Private CurrentHisWriter As System.IO.StreamWriter = ....
Then you won't have to close and reopen the writer, all your Subs and functions will have access to it.
I want to check my (bar)code or get missing checksum number before creating a barcode picture in VB.NET. This is critical parts of minimized example on how this look like:
Imports ZXing
Imports ZXing.Common
Imports ZXing.OneD
...
Dim writer As EAN8Writer = New EAN8Writer
Dim data As String = "1234567" '(0)
Dim check As Integer = UPCEANReader.getStandardUPCEANChecksum(data)
I find that part of code in a various examples on the net. But on my system I get error 'getStandardUPCEANChecksum is not a member of UPCEANReader'. Why this don't work as expected?
Is here any other way to get checksum for such case except to calculate it manually?
The method UPCEANReader.getStandardUPCEANChecksum() is declared as "internal" and can't be accessed from outside the library (without using reflection or similar stuff).
You can copy the source code into your own application if you want to use it.
I use the IBM Host Access Class Library for COM Automation as a way to communicate with an IBM AS400 (aka iSeries, IBM i, green screen, 5250) through a terminal emulator. I notice that when you issue a "SendKeys" instruction, control returns to your application before the IBM emulator finishes with the command. This can lead to timing problems because you might then send another "SendKeys" instruction before the system is ready to accept it.
For example:
Imports AutPSTypeLibrary
Imports AutConnListTypeLibrary
Imports AutSessTypeLibrary
Sub Example
Dim connections As New AutConnList
connections.Refresh()
If connections.Count < 1 Then Throw New InvalidOperationException("No AS400 screen can currently be found.")
Dim connection As IAutConnInfo = DirectCast(connections(1), IAutConnInfo)
_Session = New AutSess2
_Session.SetConnectionByHandle(connection.Handle)
Dim _Presentation As AutPS = DirectCast(_Session.autECLPS, AutPS)
_Presentation.SendKeys("PM70[enter]", 22, 8)
_Presentation.SendKeys("ND71221AD[enter]", 22, 20)
End Sub
would work correctly when stepping through code in a debugger, but would fail when running normally because the second instruction was sent too soon.
One way to work with this is to put a timer or loop after each command to slow the calling program down. I consider this less than ideal because the length of time is not always predictable, you will often be waiting longer than necessary to accommodate an occasional hiccup. This slows down the run time of the entire process.
Another way to work around this is to wait until there is a testable condition on the screen as a result of your sent command. This will work sometimes, but some commands do not cause a screen change to test and if you are looking to abstract your command calling into a class or subroutine, you would have to pass in what screen condition to be watching for.
What I would like to find is one of the "Wait" methods that will work in the general case. Options like the autECLScreenDesc class seem like they have to be tailored to very specific conditions.
The autECLPS (aka AutPS) class has a number of Wait methods (Wait, WaitForCursor, WaitWhileCursor, WaitForString, WaitWhileString, WaitForStringInRect, WaitWhileStringInRect, WaitForAttrib, WaitWhileAttrib, WaitForScreen, WaitWhileScreen) but they also seem to be waiting for specific conditions and do not work for the general case. The general case it important to me because I am actually trying to write a general purpose field update subroutine that can be called from many places inside and outside of my .dll.
This example is written in VB.NET, but I would expect the same behavior from C#, C++, VB6, Java; really anything that uses IBM's Personal Communications for Windows, Version 6.0
Host Access Class Library.
The "Operator Information Area" class seems to provide a solution for this problem.
My general case seems to be working correctly with this implementation:
Friend Sub PutTextWithEnter(ByVal field As FieldDefinition, ByVal value As String)
If IsNothing(field) Then Throw New ArgumentNullException("field")
If IsNothing(value) Then Throw New ArgumentNullException("value")
_Presentation.SendKeys(Mid(value.Trim, 1, field.Length).PadRight(field.Length) & "[enter]", field.Row, field.Column)
WaitForEmulator(_Session.Handle)
End Sub
Private Sub WaitForEmulator(ByVal EmulatorHandle As Integer)
Dim Oia As New AutOIATypeLibrary.AutOIA
Oia.SetConnectionByHandle(EmulatorHandle)
Oia.WaitForInputReady()
Oia.WaitForAppAvailable()
End Sub
I give thanks to a user named "khieyzer" on this message board for pointing our this clean and general-purpose solution.
Edit:
After a few weeks debugging and working through timing and resource release issues, this method now reads like:
Private Sub WaitForEmulator(ByRef NeededReset As Boolean)
Dim Oia As New AutOIA
Oia.SetConnectionByHandle(_Presentation.Handle)
Dim inhibit As InhibitReason = Oia.InputInhibited
If inhibit = InhibitReason.pcOtherInhibit Then
_Presentation.SendKeys("[reset]")
NeededReset = True
WaitForEmulator(NeededReset)
Marshal.ReleaseComObject(Oia)
Exit Sub
End If
If Not Oia.WaitForInputReady(6000) Then
If Oia.InputInhibited = InhibitReason.pcOtherInhibit Then
_Presentation.SendKeys("[reset]")
NeededReset = True
WaitForEmulator(NeededReset)
Marshal.ReleaseComObject(Oia)
Exit Sub
Else
Marshal.ReleaseComObject(Oia)
Throw New InvalidOperationException("The system has stopped responding.")
End If
End If
Oia.WaitForInputReady()
Oia.WaitForAppAvailable()
Marshal.ReleaseComObject(Oia)
End Sub
I'm coding a pokedex type deal as practice for my class.
Basically, I have a class titled "pokemon". One of the properties of the class is "ImgName" Which I want to use to display an image from the resources with the same name.
VB doesn't allow me to call the ImgName as a string and then use 'My.Resources.ImgName'
How can i do this, or what are some alternative options to it? I want it to be determined by a property in the pokemon object, and i don't want to have to hard code in an if-elseif statement for every single pokemon.
One way is you can have a resource file added to your project. Then drop the resource into it. You will be able to address it like this:
My.Resources.Resource1.ImgName
Resource1 is your resource file name, and ImgName is the resource name here. But you need to do hard code for every call. However, you get full intellisense support with type checking.
If you don't want hard code, here is a stripped down version of my production code:
Imports System.Reflection
Imports System.Xml.Linq
Public Class EmbeddedResourceManager
Private Class EmbeddedResourceManagerCore
Private Shared _executingAssembly As Assembly
Private Shared _resourcePrefix As String
Shared Sub New()
_executingAssembly = Assembly.GetExecutingAssembly
_resourcePrefix = _executingAssembly.GetName.Name & "."
End Sub
Public Shared Function GetStream(resourceRelName As String) As IO.Stream
Return _executingAssembly.GetManifestResourceStream(_resourcePrefix & resourceRelName)
End Function
End Class
Public Shared Function GetImage(ByVal resourceName As String) As Bitmap
Return New Bitmap(EmbeddedResourceManagerCore.GetStream(resourceName))
End Function
End Class
So whenever you need, just call EmbeddedResourceManager.GetImage and pass the resource name, as it appears in your project (your image file needs to be attached to a project). You need to have Build Action for an image in question to be set to Embedded Resource.
This piles up all your resource into an executable, which has both benefits and drawbacks, depending on the situation. Still, it should work for your needs, since I am assuming number of different pokemons is limited and does not change throughout the game (i.e. downloaded from a 3rd party server in real time etc.).
BackgroundImage = My.Resources.ResourceManager.GetObject(aString)
10 time easier than previous answer imho
I have been creating multiple background threads to parse xml files and recreate new xml files. Now the problem I am having is that even though I use synclock on global variables, I will still at times get errors and I am sure that this is just the crude way of coding I am doing, but I was wondering if someone had a better option.
program flow =
access local folder and upload all files into list
strip each file into xml entries and put these entries into an arraylist
parse for specific values and enter these values into a database table
now create a thread and take the arraylist of entries and the thread will reparse
thread parses and creates a new xml file
main thread continues with another function and then goes and get a file from list
I will add some code to show problem areas but if I have declared global variable in use does the different threads overwrite that value in the variable causing contamination.
For Each g In resultsList
gXmlList.Add(g)
Next
Dim bgw As New BackgroundWorker
bgw.WorkerSupportsCancellation = True
AddHandler bgw.DoWork, New DoWorkEventHandler(AddressOf createXML)
AddHandler bgw.RunWorkerCompleted, AddressOf WorkComplete
threadlist.Add(bgw)
bgw.RunWorkerAsync()
Private Sub createXML()
num += 1
Dim file As String = Module1.infile
xmlfile = directoryPath & "\New" & dateTime.Now.ToUniversalTime.ToString("yyyyMMddhhmmss") & endExtension
Thread.Sleep(2000)
Dim doc As XmlDocument = New XmlDocument
**xwriter = New XmlTextWriter(xmlfile, Encoding.UTF8)** this is where ioexception error
xwriter.Formatting = Formatting.Indented
xwriter.Indentation = 2
xwriter.WriteStartDocument(True)
xwriter.WriteStartElement("Posts")
I have global variables through out the app and should I be locking each one and does this not make using threads then useless.
Dim j As Integer = 0
I believe your biggest problem is not knowing what features in .Net are thread safe. A list for example is not (a dictionary is). While you may get away with it you will eventually run into problems with locking, etc.
Your using classes and variables that are not thread safe. Any time you are working with threads you have to be Extremely careful with locking. To answer your question, yes, you have to lock and unlock everything you are working with unless the type / method specifically handles it for you.
There are a lot of multi threading (PLINQ for example) in .Net 4.0 which handle a lot of the "grunt work" for you. While you should learn and understand how to do thread safe code yourself it will give you a head start.
Try passing the data into the createXML() method. That may help isolate the code from other data being accessed. I would suggest reading up on threading and learning how to do it without a background worker.
Global variables are generally a bad idea. Given your VB code I'm guessing this is a carry over from the VB6 world for you. That's not in any way intended to be insulting, just trying to help advance your skills forward. Variable scope should be as confined as possible.
Another thought looking at your code is to learn how to use String.Format() when building strings / paths.
Simple manual thread in VB to get you started:
Dim bThread As New Threading.Thread(AddressOf createXML)
bThread.IsBackground = True
bThread.Start()
Well if you are having issues with thread locking then you can simply wrap your action in the following manor.
'This will need to be out of scope so that all threads have access to it
Dim readerWriterLock As New Threading.ReaderWriterLockSlim
readerWriterLock.EnterWriteLock()
xwriter = New XmlTextWriter(xmlfile, Encoding.UTF8)
'other logic
readerWriterLock.ExitWriteLock()
'anything reading from this would need to have the following
readerWriterLock.EnterReadLock()
'logic
readerWriterLock.ExitReadLock()
Try this and then if not successful post the exception message and any other information that you can.