VB.NET Copying myself and then run the copy fails - vb.net

I'm trying to make it possible to run my project, copy itself to update.exe and then run that update.exe for the purpose of testing the update routine.
The problem I'm having is that the exefile is copied succesfully but when update.exe is then starts, it just always crashes.
If I abort the update.exe program from the crash, but my main exe still runs, I can then just start update.exe from explorer and all works fine. I can't for life figure out why update.exe crashes if it is started after it was copied from another exefile.
Here's the code:
Public Class Updater
Public sFullname As String
Public sExename As String
Public sArguments As String
Public Sub New()
'Constructor
Me.Initiate()
Me.FakeUpdate()
Me.DoUpdate()
'MsgBox(Me.sFullname)
End Sub
Private Sub Initiate()
Dim sCmdLine As String = Environment.CommandLine()
Dim iPos = sCmdLine.IndexOf("""", 2)
Me.sFullname = sCmdLine.Substring(1, iPos - 1).Trim()
Dim iPos2 = sFullname.LastIndexOf("\")
Me.sExename = sFullname.Substring(iPos2 + 1).Trim()
Me.sArguments = sCmdLine.Substring(iPos + 1).Trim()
End Sub
Private Sub FakeUpdate()
'If we start the app with -fakeupdate parameter, copy myself to update.exe, then run update.exe to debug the update process.
If Me.sArguments = "-fakeupdate" Then
FileCopy(Me.sFullname, "update.exe")
Shell("update.exe")
End If
End Sub
Private Sub DoUpdate()
If Me.sExename = "update.exe" Then
MsgBox("DoUpdate called from update.exe")
End If
End Sub
End Class
Public Class Form1
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim Updater As New Updater
End Sub
End Class
The project is configured that it runs with parameter -fakeupdate
The code is part of a larger project, but I have commented out all other code and still receive this error.
The error I'm getting from update.exe: Length cannot be less than null. Parametername: length
System.ArgumentOutOfRangeException: Length cannot be less than null.
Parameternaam: length
bij System.String.InternalSubStringWithChecks(Int32 startIndex, Int32 length, Boolean fAlwaysCopy)
bij Todo_List.Updater.Initiate() in S:\VB Projects\Todo List\Todo List\Form1.vb:regel 19
bij Todo_List.Updater..ctor() in S:\VB Projects\Todo List\Todo List\Form1.vb:regel 8
bij Todo_List.Form1.Form1_Load(Object sender, EventArgs e) in S:\VB Projects\Todo List\Todo List\Form1.vb:regel 594
bij System.EventHandler.Invoke(Object sender, EventArgs e)
bij System.Windows.Forms.Form.OnLoad(EventArgs e)
bij System.Windows.Forms.Control.CreateControl(Boolean fIgnoreVisible)
bij System.Windows.Forms.Control.CreateControl()
bij System.Windows.Forms.Control.WmShowWindow(Message& m)
bij System.Windows.Forms.Control.WndProc(Message& m)
bij System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
bij System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
EDIT: small update, it also goes wrong if I don't even copy the file. Just shell("update.exe") goes wrong. I even created a button on the form to launch it upon click and it fails every time. But if I run it from explorer, all is fine.

This is weird behavior, possibly even a bug, but I figured it out.
Apparently, if you use shell ("program.exe") to start a program, and from within that program, you call Environment.CommandLine() it will just be program.exe, whereas if you doubleclick the program from explorer it will be C:\MyPath\program.exe instead.
In order to solve it, I had to change my code as follows:
Private Sub FakeUpdate()
Dim sShell As String
'If we start the app with -fakeupdate parameter, copy myself to update.exe, then run update.exe to debug the update process.
If Me.sArguments = "-fakeupdate" Then
FileCopy(Me.sFullname, "update.exe")
sShell = My.Computer.FileSystem.CurrentDirectory & "\update.exe"
Shell(sShell)
End If
End Sub
Now it works correctly, both from explorer AND from launching the program from within the program.

Related

Receiving System.NotSupportedException when trying to make a string ProperCase (VB)

Private Sub btnNewStudent_Click(sender As Object, e As EventArgs) Handles btnNewStudent.Click
Dim name As String = InputBox("Enter the Student's Name", "Name", "Student Name")
name = StrConv(name, vbProperCase)
addStudent(name)
If name = "" Then
errorMessage("Please Enter a Name")
lstStudents.Items.Remove("")
End If
End Sub
Error Description:
"System.NotSupportedException: No data is available for encoding
1252. For information on defining a custom encoding, see the documentation for the Encoding.RegisterProvider method.
Error Details:
System.NotSupportedException HResult=0x80131515 Message=No data
is available for encoding 1252. For information on defining a custom
encoding, see the documentation for the Encoding.RegisterProvider
method. Source=Microsoft.VisualBasic.Core StackTrace: at
Microsoft.VisualBasic.Strings.StrConv(String str, VbStrConv
Conversion, Int32 LocaleID) at
StudentTrackerVB.frmStudentTrackers.btnNewStudent_Click(Object sender,
EventArgs e) in E:\College\Year 2\Unit 15 - Object Oriented
Programming\Assignment
3\StudentTrackerVB\StudentTrackerVB\Form1.vb:line 11 at
System.Windows.Forms.Control.OnClick(EventArgs e) at
System.Windows.Forms.Button.OnClick(EventArgs e) at
System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent) at
System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons
button, Int32 clicks) at
System.Windows.Forms.Control.WndProc(Message& m) at
System.Windows.Forms.ButtonBase.WndProc(Message& m) at
System.Windows.Forms.Button.WndProc(Message& m) at
System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, WM msg,
IntPtr wparam, IntPtr lparam)
When I try to make name into ProperCase, it comes up with an error. I've done a similar thing for items in an array making them UpperCase which works perfectly. But for some reason, this doesn't?
What am I doing wrong xD
Try using Globalization
Dim ti As Globalization.TextInfo = Globalization.CultureInfo.CurrentCulture.TextInfo
name = ti.ToTitleCase(name)
Changing Case

Catching a framework exception

I'm having some trouble catching and handling an exception.
My (simplified) application has a picturebox which shows a live video feed from a connected webcam. I'm using the Metrilius Metricam SDK (http://www.metrilus.de/blog/portfolio-items/metricam/) to connect to the webcam.
Using a backgroundworker, I am calling the camera.update function, grabbing the bitmap and setting the picturebox to it. Whenever the user hits Enter, the current frame is grabbed and stored.
As mentioned earlier, an exception is thrown at completely random points in time when the picturebox is being updated with the latest bmp from the camera. As you can see in the code below, I have wrapped the assignment in a try/catch block but it isn't catching it. What could I do to handle this gracefully? The exception draws a big red X on the picturebox and the program has to be closed and restarted.
The picturebox's sizemode property is set to Zoom.
Code below:
Private Sub BG1_DoWork(sender As Object, e As DoWorkEventArgs) Handles BG1.DoWork
While Not BG1.CancellationPending
If pauseCamUpdate = False Then 'PausecamUpdate is a flag that is set to False during calls to store the current frame
i += 1
If i Mod 2 = 0 Then Continue While 'Dropping every nth frame to make the update smoother
If i > 10000 Then
i = 0
End If
Try
activeCam.Update()
pictPhoto.Image = CType(CType(activeCam, WebCam).CalcBitmap(), Bitmap)
'pictPhoto.Invalidate()
Application.DoEvents()
Catch exp As Exception
End Try
End If
End While
End Sub
The exception text minus the loaded assemblies:
See the end of this message for details on invoking
just-in-time (JIT) debugging instead of this dialog box.
************** Exception Text **************
**System.InvalidOperationException: Object is currently in use elsewhere.**
at System.Drawing.Image.get_Height()
at System.Drawing.Image.get_Size()
at
System.Windows.Forms.PictureBox.ImageRectangleFromSizeMode(PictureBoxSizeMode mode)
at System.Windows.Forms.PictureBox.OnPaint(PaintEventArgs pe)
at System.Windows.Forms.Control.PaintWithErrorHandling(PaintEventArgs e,
Int16 layer)
at System.Windows.Forms.Control.WmPaint(Message& m)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr
wparam, IntPtr lparam)
Thank you for any assistance.

naudio not releasing file after dispose vb.net, It's really an declaration issue I think

I only post here when I'm really stuck, so here goes.
I'm creating a program where I can edit the metadata of MP3 files (with all data pulled from a mysql db), using taglib-sharp.
If I preview an audio file using naudio, I can hear the audio no problems and I can stop it, so that is all good.
For the sake of what is happening in my code, It's a matter of choosing a file from a listbox, and then I push a 'play' button to start, and another button to stop. My error is showing up with a right click context menu when I'm trying to save metadata.
The problem is when I go to edit the metadata of that same file I just played, the error appears - as per this shown in the following example of code. When I try and call the mp3.save() line, I receive the following error:
************** Exception Text **************
System.IO.IOException: The process cannot access the file
'C:\temp\test.mp3' because it is being used by another process. at
System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.IO.FileStream.Init(String path, FileMode mode, FileAccess
access, Int32 rights, Boolean useRights, FileShare share, Int32
bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String
msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess
access, FileShare share) at
TagLib.File.LocalFileAbstraction.get_WriteStream() at
TagLib.File.set_Mode(AccessMode value) at
TagLib.NonContainer.File.Save() at
LinersDB_META.Form1.menuChoice(Object sender, EventArgs e) in
C:\Users\smonro\source\repos\WindowsApp1\WindowsApp1\Form1.vb:line
2281 at System.Windows.Forms.ToolStripItem.RaiseEvent(Object key,
EventArgs e) at
System.Windows.Forms.ToolStripMenuItem.OnClick(EventArgs e) at
System.Windows.Forms.ToolStripItem.HandleClick(EventArgs e) at
System.Windows.Forms.ToolStripItem.HandleMouseUp(MouseEventArgs e)
at System.Windows.Forms.ToolStrip.OnMouseUp(MouseEventArgs mea) at
System.Windows.Forms.ToolStripDropDown.OnMouseUp(MouseEventArgs mea)
at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons
button, Int32 clicks) at
System.Windows.Forms.Control.WndProc(Message& m) at
System.Windows.Forms.ToolStrip.WndProc(Message& m) at
System.Windows.Forms.ToolStripDropDown.WndProc(Message& m) at
System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg,
IntPtr wparam, IntPtr lparam)
etc
I know why it's happening, but I'm lost as to how to solve it.
According to this page, (which is in C#) I need to release the "Mp3FileReader".
In my case, it would be "data" - this:
Dim data As New NAudio.Wave.Mp3FileReader(file)
The problem is, it's in a private sub, as a private variable.
However, I'm struggling to see how I can make this declaration public, when I need to have file also declared, but it would also need to be known too, and reinitialized every time I choose a different audio file.
Any thoughts?
Should I just try and rearrange my program to work differently? Thanks in advance.
'...
Imports System.IO 'File Operations
Imports TagLib ' Tagging
Imports NAudio
'...
'Wave out device for playing the sound
Public Shared Wave1 As New NAudio.Wave.WaveOut 'Wave out device for playing the sound
Public Sub start_audio()
Dim file As String = "C:\test\test.mp3"
If IO.File.Exists(file) Then
Dim data As New NAudio.Wave.Mp3FileReader(file)
Wave1.Init(data)
Wave1.Play()
End If
End Sub
Public Sub Button5_Click_1(sender As Object, e As EventArgs) Handles Button5.Click
Wave1.Stop()
End Sub
Public Sub menuChoice(ByVal sender As Object, ByVal e As EventArgs)
Dim item = CType(sender, ToolStripMenuItem)
Dim selection = CInt(item.Tag)
Select Case selection
Case 1
' Remove the Artwork
'Insert Album art and save to file and dispose.
If IO.File.Exists(GLOBAL_Full_Path) Then
Wave1.Stop()
Wave1.Dispose()
System.GC.Collect()
System.GC.WaitForPendingFinalizers()
Dim mp3 As TagLib.File = TagLib.File.Create(GLOBAL_Full_Path)
' Clear the artwork from the file.. (It's a big process)
Dim pics As Picture = New Picture()
Dim picsFrame As New TagLib.Id3v2.AttachedPictureFrame(pics)
picsFrame.MimeType = System.Net.Mime.MediaTypeNames.Image.Jpeg
'set the type of picture (front cover)
picsFrame.Type = TagLib.PictureType.FrontCover
picsFrame.Description = "" ' So the Actual location of the image is not stored in the file. This would otherwise reveal internal systems to the public.
'Id3v2 allows more than one type of image, just one is needed here.
Dim pictFrames() As TagLib.IPicture = {picsFrame}
'set the pictures in the tag
mp3.Tag.Pictures = pictFrames
' ******************************************
' Error occurs here after a file has been played.
mp3.Save()
' Error occurs here
' ******************************************
mp3.Dispose()
End If
Case Else
End Select
End Sub
After #TnTinMn pointed me in the right direction, I solved the issue in the end. While this is not the full example, I've now solved this by adding and changing a couple of minor things.
Imports NAudio
' NEW/required to get the Mp3FileReader, so it can be dynamically populated.
Imports NAudio.Wave
Dim WavePlayOut As New NAudio.Wave.WaveOut 'Wave out device for playing the sound
Dim WaveFile As String = "" ' *** NEW/Declared ***
Dim WaveData As Mp3FileReader ' *** Changed ***
Public Sub start_audio()
If File_ListView.SelectedItems.Count > 0 Then
WaveFile = TxtBx_Path.Text & "\" & File_ListView.FocusedItem.Text
If WavePlayOut IsNot Nothing Then
WavePlayOut = New NAudio.Wave.WaveOut
End If
If WaveData IsNot Nothing Then
WaveData.Dispose()
WaveData = New Mp3FileReader(WaveFile)
If WaveData.Length > 1 Then
If IO.File.Exists(WaveFile) Then
WavePlayOut.Init(WaveData)
WavePlayOut.Play()
End If
End If
Else
WaveData = New Mp3FileReader(WaveFile)
If WaveData.Length > 1 Then
If IO.File.Exists(WaveFile) Then
WavePlayOut.Init(WaveData)
WavePlayOut.Play()
End If
End If
End If
End If
End Sub
To unload the audio file, use the following:
If WaveData IsNot Nothing Then
WaveData.Dispose()
End If
If WavePlayOut IsNot Nothing Then
WavePlayOut.Stop()
WavePlayOut.Dispose()
End If

How to embed a Console in a Windows Form application?

I'm trying to build a Text Adventure game in VB.net, just like the days of old. The obvious choice would be a Console application, however, I have decided on a Windows Form because I am hoping to include interactive buttons and pictures. Currently, I have already got on my form a picture box and a Rich Text Box. I was hoping that with the Rich Text Box I could achieve something that worked in the same way as a console. Alas, my efforts are futile. Everything I have tried has failed, including: reading Rich_Text_Box.Text and Rich_Text_Box_KeyUp with an if statement for enter being pressed to call the procedure for an enter button.
I was wondering if there was any way to include a Console with standard Console.WriteLine and Console.ReadLine capabilities inside of my Form? This would very much shorten my task and streamline the whole process.
Any ideas?
You could use not one but two Textboxes for your purpose. tbOutput and tbInput. tbOutput would be Multiline and ReadOnly whereas tbInput would be single line, not readonly and placed beneath tbOutput. Then to process inputs you could do something like:
Private Sub Output(s As String)
If s <> "" Then
tbOutput.AppendText(vbCrLf & ">> " & s)
End If
End Sub
Private Sub tbInput_KeyDown(sender As Object, e As KeyEventArgs) Handles tbInput.KeyDown
If e.KeyCode = Keys.Enter Then
If tbInput.Text <> "" Then
Output(tbInput.Text)
' Handle input value
tbInput.Text = ""
End If
End If
End Sub
At the 'Handle input value you would check the user input and handle it according to your needs. Use Lucida Console font in bold in gray and black background for style :-)
Sure, a RichTextBox can be used to emulate a console. Some surgery is required to avoid the user from making it malfunction as a console. Add a new class to your project and paste the code shown below. Compile. Drop the new control from the top of the toolbox onto your form. Subscribe the InputChanged event to detect when the user presses the Enter key, the Input property gives you the typed text. Use the Write() or WriteLine() methods to add text.
Imports System.Windows.Forms
Public Class RichConsole
Inherits RichTextBox
Public Event InputChanged As EventHandler
Public ReadOnly Property Input() As String
Get
Return Me.Text.Substring(InputStart).Replace(vbLf, "")
End Get
End Property
Public Sub Write(txt As String)
Me.AppendText(txt)
InputStart = Me.SelectionStart
End Sub
Public Sub WriteLine(txt As String)
Write(txt & vbLf)
End Sub
Private InputStart As Integer
Protected Overrides Function ProcessCmdKey(ByRef m As Message, keyData As Keys) As Boolean
'' Defeat backspace
If (keyData = Keys.Back OrElse keyData = Keys.Left) AndAlso InputStart = Me.SelectionStart Then Return True
'' Defeat up/down cursor keys
If keyData = Keys.Up OrElse keyData = Keys.Down Then Return True
'' Detect Enter key
If keyData = Keys.[Return] Then
Me.AppendText(vbLf)
RaiseEvent InputChanged(Me, EventArgs.Empty)
InputStart = Me.SelectionStart
Return True
End If
Return MyBase.ProcessCmdKey(m, keyData)
End Function
Protected Overrides Sub WndProc(ByRef m As Message)
'' Defeat the mouse
If m.Msg >= &H200 AndAlso m.Msg <= &H209 Then Return
MyBase.WndProc(m)
End Sub
End Class

Capturing the ctrl+V in VB.NET combobox

I am trying to remove the newline and replace with whitespace before pasting to comboBox as it ignores anything beyond a line. I am trying this:
If e.Modifiers = Keys.Control AndAlso e.KeyValue = Keys.V Then Then
Clipboard.SetText(Regex.Replace(Clipboard.GetText(TextDataFormat.UnicodeText), "\n", " "))
e.Handled = True
End If
I am performing this inside KeyDown event but it is able to capture either Ctrl or V but not both. I tried Capture CTRL+V or paste in a textbox in .NET and http://social.msdn.microsoft.com/Forums/windows/en-US/096540f4-4ad4-4d24-ae12-cfb3e1b246f3/interceptingoverriding-paste-behavior-on-combobox but no results as desired. May be there is something i am missing in my code. Please help me out.
I am getting the needed value with this Clipboard.GetText().Replace(vbCrLf, " ") when i debug but i am not able to set it. I tried using a variable to set it but even then no change. I also tried clearing the clipboard and then resetting with this variable holding the modified value.
I am using Winforms and i tried this but still no change to my clipboard:
Private Const WM_PASTE As Integer = &H302
Protected Overrides Sub WndProc(ByRef m As Message)
If m.Msg = WM_PASTE Then
Dim returnText As String = Nothing
If (Clipboard.ContainsText()) Then
returnText = Clipboard.GetText().Replace(vbCrLf, " ")
Clipboard.Clear()
Clipboard.SetText(returnText)
End If
End If
MyBase.WndProc(m)
End Sub
Handling keyboard only events for intercepting pasting doesn't solve the problem, because pasting can also be done using mouse or touch interface.
Thus, if you are using WPF, then simply add the DataObject.Pasting event handler to your ComboBox, so definition of the control in XAML will look like:
<ComboBox Name="comboBox1" IsEditable="true" DataObject.Pasting="comboBox1_Pasting" ... />
And, finally, in your code handle it as (I'm adding a method here to the code-behind, which is not as nice, as using commands):
private void comboBox1_Pasting(object sender, DataObjectPastingEventArgs e)
{
// modify the clipboard content here
}
If you're using WinForms, then look here: hook on default “Paste” event of WinForms TextBox control
This piece of code worked for me:
Private Const WM_PASTE As Integer = &H302
Protected Overrides Function ProcessCmdKey(ByRef msg As Message, keyData As Keys) As Boolean
If keyData = (Keys.Control Or Keys.V) Or msg.Msg = WM_PASTE Then
If (Clipboard.ContainsText()) Then
Clipboard.SetText(Clipboard.GetText().Replace(vbCrLf, " "))
End If
End If
Return MyBase.ProcessCmdKey(msg, keyData)
End Function
Use the keydown event and alter the clipboard like this
Private Sub ComboBox1_KeyDown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles ComboBox1.KeyDown
If e.KeyCode = Keys.V AndAlso (e.Modifiers And Keys.Control) <> 0 Then
My.Computer.Clipboard.SetText(My.Computer.Clipboard.GetText().Replace(vbCrLf, " "))
End If
End Sub
But this example is going to alter the clipboard contents. Modify it to paste or insert yourself as you wish