VB.NET: Can't load audio from resources - vb.net

I'm trying to add multiple sounds on an application using a Public function... When I use the absolute path for my sounds everything works perfectly, but when I'm trying to load them from Resources I don't get any sound output.. Any ideas what's wrong?
Public Class Form1
Public Declare Function mciSendString Lib "winmm.dll" Alias "mciSendStringA" (ByVal lpstrCommand As String, ByVal lpstrReturnString As String, ByVal uReturnLength As Integer, ByVal hwndCallback As Integer) As Integer
Dim musicAlias As String = "myAudio"
'Dim musicPath As String = "C:\Users\Teo\Documents\Visual Studio 2015\Projects\test\test\Resources\sound.mp3"
'Dim musicPath As String = "Resources\sound.mp3"
'Dim musicPath As String = My.Resources.ResourceManager.GetObject("sound.mp3")
Dim musicPath2 As String = "C:\Users\Teo\Desktop\sound.mp3"
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
mciSendString("Open " & musicPath & " alias " & musicAlias, CStr(0), 0, 0)
mciSendString("play " & musicAlias, CStr(0), 0, 0)
End Sub
End Class
The last one works perfectly, I tried every one of the above... The three comments above are different ways I tried to make it work, but all failed...

You can load the file from resources and cache them locally and play them.
Open Resources.resx file under My Project. Then add your file for example YourFileName.mp3 to the resources by choosing Add Existing File... then when you want to play the file, use this code:
Dim file As String = System.IO.Path.Combine(Application.StartupPath, "YourFileName.mp3")
If (Not System.IO.File.Exists(file)) Then
System.IO.File.WriteAllBytes(file, My.Resources.YourFileName)
End If
'Now the file exists locally
'Play the file here

I know this has an answer marked correct, but once you have a sound file in your Resources, it's much easier this way:
My.Computer.Audio.Play(My.Resources.MyCoolSound, AudioPlayMode.Background)
No reason to use an API call.

Related

Window explorer is freezing when open

I need to open the specific folder for a file and I am doing it with:
file = Directory.GetFiles(filepath,Filename,
SearchOption.AllDirectories).FirstOrDefault()
Process.Start("explorer.exe", "/select," & file.ToString)
This code is immediately opening the folder which is already fully loaded, but it doesnt seem enabled, endeed I cant do any action in it. The form is not freezing.
Thanks
I'll give you an answer in two parts...
Firstly, if the GetFiles() call takes to long and freezes the form (which doesn't seem to be the current problem), you should do the following:
Use EnumerateFiles() instead because in this case, FirstOrDefault() will return immediately after finding a matching file, unlike GetFiles() which will get all the files first before calling FirstOrDefault().
Wrap the call to EnumerateFiles() in a Task.Run() to execute it on a worker thread in case the search takes a little too long:
' Or:
' Private Async Sub SomeEventHandler()
Private Async Function ParentMethod() As Task
Dim filePath As String = Await Task.Run(
Function()
Return Directory.EnumerateFiles(dirPath, FileName, SearchOption.AllDirectories).
FirstOrDefault()
End Function)
' TODO: Use `filePath` to open the folder and select the file.
End Function
Secondly, do not use Process.Start("explorer.exe", "/select") because a) it starts a new Explorer.exe process rather than opening the directory in the current one, b) it seems to be causing you some issues, and c) it has some limitations.
Instead, use the approach demonstrated in the answer linked in point (c) above. The code is in C# but it can be easily converted to VB. Here's the VB version of the code (with an additional overload).
Add the following class to your project:
Imports System.IO
Imports System.Runtime.InteropServices
Public Class NativeMethods
<DllImport("shell32.dll", SetLastError:=True)>
Private Shared Function SHOpenFolderAndSelectItems(
pidlFolder As IntPtr, cidl As UInteger,
<[In], MarshalAs(UnmanagedType.LPArray)> apidl As IntPtr(),
dwFlags As UInteger) As Integer
End Function
<DllImport("shell32.dll", SetLastError:=True)>
Private Shared Sub SHParseDisplayName(
<MarshalAs(UnmanagedType.LPWStr)> name As String,
bindingContext As IntPtr, <Out> ByRef pidl As IntPtr,
sfgaoIn As UInteger, <Out> ByRef psfgaoOut As UInteger)
End Sub
Public Shared Sub OpenFolderAndSelectFile(filePath As String)
Dim dirPath As String = Path.GetDirectoryName(filePath)
Dim fileName As String = Path.GetFileName(filePath)
OpenFolderAndSelectFile(dirPath, fileName)
End Sub
Public Shared Sub OpenFolderAndSelectFile(dirPath As String, fileName As String)
Dim nativeFolder As IntPtr
Dim psfgaoOut As UInteger
SHParseDisplayName(dirPath, IntPtr.Zero, nativeFolder, 0, psfgaoOut)
If nativeFolder = IntPtr.Zero Then
' Log error, can't find folder
Return
End If
Dim nativeFile As IntPtr
SHParseDisplayName(Path.Combine(dirPath, fileName),
IntPtr.Zero, nativeFile, 0, psfgaoOut)
Dim fileArray As IntPtr()
If nativeFile = IntPtr.Zero Then
' Open the folder without the file selected if we can't find the file
fileArray = New IntPtr(-1) {}
Else
fileArray = New IntPtr() {nativeFile}
End If
SHOpenFolderAndSelectItems(nativeFolder, CUInt(fileArray.Length), fileArray, 0)
Marshal.FreeCoTaskMem(nativeFolder)
If nativeFile <> IntPtr.Zero Then
Marshal.FreeCoTaskMem(nativeFile)
End If
End Sub
End Class
Then, you can easily call it like this:
NativeMethods.OpenFolderAndSelectFile(filePath)
Some additional notes:
You should choose meaningful variable names. filePath should refer to the path of a file. If you want to refer to a folder/directory path, use something like dirPath or folderPath instead.
You don't need to call .ToString() on a variable that's already of a String type.
I would change the variable name file to something else. Maybe foundFile. After all File is the name of a class in System.IO and vb.net is not case sensitive. Your code works fine for me with the variable name change. Also got rid of the .ToString. I used .EnumerateFiles as commented by #jmcilhinney in the question you deleted. I purposely chose a path with all sorts of strange characters and it still worked.
Private Sub OPCode()
Dim filepath = "C:\Users\xxxx\Documents\TextNotes\Dogs & Cats (Pets)"
Dim Filename = "Specialty Vets.txt"
Dim foundFile = Directory.EnumerateFiles(filepath, Filename,
IO.SearchOption.AllDirectories).FirstOrDefault()
Process.Start("explorer.exe", "/select," & foundFile)
End Sub

Set icon from generated exe in VB.NET

I'm trying to set the icon from a generated Windows Form Application, here's my code.
Private Sub CompileSourceCode()
Dim cProvider As CodeDomProvider = New VBCodeProvider
Dim cParams As New CompilerParameters
Dim cResult As CompilerResults
Dim sourceCode As String = generate_exe.final_winform
With cParams
.GenerateInMemory = False
.GenerateExecutable = True
.OutputAssembly = "test.exe"
.CompilerOptions = "/target:winexe /win32icon:eye.ico"
.ReferencedAssemblies.AddRange({"System.dll", "System.Windows.Forms.dll", "Microsoft.VisualBasic.dll"})
.MainClass = "MyNamespace.form1"
End With
cResult = cProvider.CompileAssemblyFromSource(cParams, sourceCode)
cProvider.Dispose()
If cResult.Errors.HasErrors Then
MsgBox(cResult.Errors(0).Line.ToString & ", " & cResult.Errors(0).ErrorText)
End If
End Sub
The problem:
The first time i run it, it creates the EXE with the icon i chose.
The second time, if i just change the icon i want to use but leave it as the same OutputAssembly name (test.exe) it creates the EXE but with the old icon, doesn't update.
Edit: Found a very good solution, Although It's been a long time since my question, I think it could help someone else with the same problem using SHChangeNotify. Add that to the top of the code:
Const SHCNE_ASSOCCHANGED As Integer = &H8000000
Const SHCNF_IDLIST As Integer = 0
Private Class NativeMethods
<DllImport("shell32")>
Public Shared Sub SHChangeNotify(ByVal wEventId As Integer, ByVal flags As Integer, ByVal item1 As IntPtr, ByVal item2 As IntPtr)
End Sub
End Class
Usage: (before or after your compile command)
NativeMethods.SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, Nothing, Nothing)

Prevent file from being deleted but still be able to read it

I have searched this a lot but still I couldn't find something useful basically I tried changing file permissions to deny the delete option and keep modification and so many other combinations.I want something to prevent file from being deleted but still allow me to read it I did this both manually and using vb.net this is the code I used(it is not mine btw)
lets say I have a text file already created I want that file to be read but not deleted by the user
Imports System.IO
Imports System.Security.AccessControl
Public Class Form1
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
Dim filename As String = "C:\users\mbpc\desktop\test.txt"
AddFileSecurity(filename, "Everyone", FileSystemRights.Delete, AccessControlType.Deny)
End Sub
Sub AddFileSecurity(ByVal fileName As String, ByVal account As String, _
ByVal rights As FileSystemRights, ByVal controlType As AccessControlType)
Dim fSecurity As FileSecurity = File.GetAccessControl(fileName)
Dim accessRule As FileSystemAccessRule = _
New FileSystemAccessRule(account, rights, controlType)
fSecurity.AddAccessRule(accessRule)
File.SetAccessControl(fileName, fSecurity)
End Sub
Sub RemoveFileSecurity(ByVal fileName As String, ByVal account As String, _
ByVal rights As FileSystemRights, ByVal controlType As AccessControlType)
Dim fSecurity As FileSecurity = File.GetAccessControl(fileName)
fSecurity.RemoveAccessRule(New FileSystemAccessRule(account, _
rights, controlType))
File.SetAccessControl(fileName, fSecurity)
End Sub
End Class

VB.NET How to write text to a .ini file?

I'm creating a program that will help users create a certain config file for another program that usually has to be done by hand.
The programs config file reads it like; 'This_Setting = 0/1 (Off/On)'
So I want to make it so that if the user ticks say a checkbox on my program, it will write in the text file '1' and if it is unticked, it will write '0'.
Another way I thought about doing it was having a text box, the user ticks the boxes they want, and then click a button and then it would paste the config code in the text box so they could copy/paste it. I personally think this would be a better option, but I still have not the slightest clue how to do it.
Any help is appreciated!
If you just need to create a file, then File.WriteAllText is probably what you need. If it is a large file, you can use the StringBuilder class to build up the contents of the file, or if it is a small file, you can use simple string concatenation. After you have your string, you can use File.WriteAllText to write it to disk.
The traditional way is to use GetPrivateProfileString (or GetPrivateProfileSection) to retrieve INI settings, and WritePrivateProfileString (or WritePrivateProfileSection) to change them.
You can find the syntax at PInvoke
Here is the VB.NET code to write to INI file,
Imports System.IO
Imports System.Text
Imports System.Runtime.InteropServices
Public Class Form1
<DllImport("kernel32")>
Private Shared Function WritePrivateProfileString(ByVal lpSectionName As String, ByVal lpKeyName As String, ByVal lpString As String, ByVal lpFileName As String) As Long
End Function
Private Function SetIniValue(section As String, key As String, filename As String, Optional defaultValue As String = "") As String
Dim sb As New StringBuilder(500)
If WritePrivateProfileString(section, key, defaultValue, filename) > 0 Then
Return sb.ToString
Else
Return defaultValue
End If
End Function
Private Sub WriteToINI()
SetIniValue("default", "This_Setting", "C:\myconfigfile.ini", "1")
End Sub
End Class
Reference: http://vbnet.mvps.org/index.html?code/file/pprofilebasic.htm
This should be very easy. What you would want to do is use the following code.
FileOpen(1, "WHATEVER-THE-FILE-PATH-IS.ini", OpenMode.Output)
PrintLine(1, "WHATEVER-TEXT-YOU-WANT-TO-WRITE")
FileClose(1)
All you have to do is just change some things to make it suit your needs. First of all, on FileOpen() you want to change where it says "WHATEVER-THE-FILE-PATH-IS.ini" to your file path (make sure you have .ini on the end.)
The next thing you have to do to make this work is change where it says OpenMode.Output. You use OpenMode.Output to write to a text file, you use OpenMode.Input when you want to read from a text file (you would use that when you load the application) and you use OpenMode.Append to just add text on.
Now there are some things you need to look out for:
When you use OpenMode.Output it actually clears all the text from the text file first and then writes the text you want to write.
When you use OpenMode.Input you can't use PrintLine(1, "WHATEVER") as that is for writing to the text file not reading - so it will just crash. When using OpenMode.Input to read from the text file you have to use LineInput(1)
For Example:
Dim bool As Boolean
FileOpen(1, "WHATEVER", OpenMode.Input)
If LineInput(1) = "1" Then bool = True Else bool = False
FileClose(1)
This code will read the .ini file and if it says 1 in it then it will set the value to True and if it has 0 in it then it will set the value to False!
So here is the code after all going through all that!
To load the values:
Dim bool As Boolean
FileOpen(1, "WHATEVER.ini", OpenMode.Input)
If LineInput(1) = "1" Then bool = True Else bool = False
FileClose(1)
To save the values:
Dim bool As Boolean
FileOpen(1, "WHATEVER.ini", OpenMode.Input)
If bool = True Then PrintLine(1, "1") Else PrintLine(1, "0")
FileClose(1)
(don't forget you can add as many PrintLine(1, "") and LineInput(1) as you want)
A Class for reading and writing .INI files easily.
I didn't make these.
Instructions
Put this code into your project.
VB Code:
Class INIReadWrite
<DllImport("kernel32.dll", SetLastError:=True)> _
Private Shared Function GetPrivateProfileString(ByVal lpAppName As >String, ByVal lpKeyName As String, ByVal lpDefault As String, ByVal >lpReturnedString As StringBuilder, ByVal nSize As Integer, ByVal lpFileName >As String) As Integer
End Function
<DllImport("kernel32.dll", SetLastError:=True)> _
Private Shared Function WritePrivateProfileString(ByVal lpAppName As >String, ByVal lpKeyName As String, ByVal lpString As String, ByVal >lpFileName As String) As Boolean
End Function
Public Shared Function ReadINI(ByVal File As String, ByVal Section As >String, ByVal Key As String) As String
Dim sb As New StringBuilder(500)
GetPrivateProfileString(Section, Key, "", sb, sb.Capacity, File)
Return sb.ToString
End Function
Public Shared Sub WriteINI(ByVal File As String, ByVal Section As >String, ByVal Key As String, ByVal Value As String)
WritePrivateProfileString(Section, Key, Value, File)
End Sub
End Class
To read an .INI file
Code:
ReadINI(File, Section, Key)
To write to an .INI file
Code:
WriteINI(File, Section, Key, Value)

Open INI file and place content in different textboxes

I am creating a program in VB.net that opens a .INI file and reads the content. I wrote the following code:
Private Sub OpenINIButton_Click(sender As Object, e As EventArgs) Handles OpenINIButton.Click
Dim OpenDLG As New OpenFileDialog
Dim FileLocation = OpenDLG.FileName.ToString()
OpenDLG.Filter = "INI File (*.ini)|*.ini"
OpenDLG.Title = "Open INI File"
OpenDLG.InitialDirectory = "C:\"
OpenDLG.RestoreDirectory = True
DialogResult = OpenDLG.ShowDialog
If DialogResult = Windows.Forms.DialogResult.OK Then
TextBox1.Text = ReadIni(FileLocation, INIkey, INIvalue, "")
ElseIf DialogResult = Windows.Forms.DialogResult.Cancel Then
End If
End Sub
The open file dialog opens and I can open a INI file but the value of INIkey is not placed in TextBox1.
Any idea how I can fix this?
You initialize the path beore the user has selected it:
Dim FileLocation = OpenDLG.FileName.ToString()
Do that after ShowDialog, so here is the correct place:
If DialogResult = Windows.Forms.DialogResult.OK Then
Dim FileLocation = OpenDLG.FileName.ToString()
TextBox1.Text = ReadIni(FileLocation, INIkey, INIvalue, "")
ElseIf DialogResult = Windows.Forms.DialogResult.Cancel Then
End If
But why don't you notice an exception? I assume that you have an empty catch block where you try to open the file in ReadIni. That's a bad habit to kick anyway.
Note that the FileLocation variable in your code references the String OpenDLG.FileName at the time you assign it, there is no permanent connection between both. So if it changes later the variable references still the old string.
The best way to do this would be to make an iniParse module like below and just use the function as shown:
Module iniParse
Public readwrtie As Integer
Public settingValueReturn As New System.Text.StringBuilder(255)
Private Declare Auto Function WritePrivateProfileString Lib "Kernel32" _
(ByVal IpApplication As String, ByVal Ipkeyname As String, _
ByVal IpString As String, ByVal IpFileName As String) As Integer
Private Declare Auto Function GetPrivateProfileString Lib "Kernel32" _
(ByVal IpApplicationName As String, ByVal IpKeyName As String, _
ByVal IpDefault As String, ByVal IPReturnedString As System.Text.StringBuilder, _
ByVal nsize As Integer, ByVal IpFileName As String) As Integer
Public Sub WriteINIFile(heading As String, setting As String, settingvalue As String, path As String)
WritePrivateProfileString(heading, setting, settingvalue, path)
End Sub
Public Sub ReadIniFile(heading As String, setting As String, path As String)
GetPrivateProfileString(heading, setting, "", settingValueReturn, 100, path)
End Sub
End Module
Example:
Button1_click blah blah blah handles button1.click...
ReadIniFile("MAIN", "test", "C:\config.ini")
'this would read the following ini file:
'[MAIN]
'test=hi
'to get that 'hi' value you would use this code:
textbox1.text = settingReturnValue.tostring '(settingValueReturn Will always be the value of the setting entered in the function args)
'to write ini file:
Button1_click blah blah blah handles button1.click...
WriteIniFile("MAIN", "test2", "hi2", "C:\config.ini")
'this would write the following to the ini # C:\config.ini file:
'[MAIN]
'test2=hi2
I hope this helps your needs!