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)
Related
I am making an app in VB.Net that copies many files and folders to the same directory and I wish to use windows explorer for that (so the user has GUI and I do not have to worry about showing any errors or compare files).
So, if I do this for each file/folder:
My.Computer.FileSystem.CopyDirectory(source_path, target_path, FileIO.UIOption.AllDialogs)
My.Computer.FileSystem.CopyFile(source_path, target_path, FileIO.UIOption.AllDialogs)
It works correctly and shows this window:
Which is fine, however, if I have many files and/or folders and I loop through them and call commands above, they launch a new copy window for each file/folder, instead of launching a single GUI that combines them all, like so:
Is it possible to combine multiple files/folders copy process into a single windows explorer copy window GUI?
Thanks to #Jimi, I got pointed in the direction of SHFileOperations, so i figured out how to do this. I made a small class to do this:
Imports System.Runtime.InteropServices
Public Class NativeCopy
Private Enum FO_Func As Short
FO_COPY = &H2
FO_DELETE = &H3
FO_MOVE = &H1
FO_RENAME = &H4
End Enum
Private Structure SHFILEOPSTRUCT
Public hwnd As IntPtr
Public wFunc As FO_Func
<MarshalAs(UnmanagedType.LPWStr)>
Public pFrom As String
<MarshalAs(UnmanagedType.LPWStr)>
Public pTo As String
Public fFlags As UShort
Public fAnyOperationsAborted As Boolean
Public hNameMappings As IntPtr
<MarshalAs(UnmanagedType.LPWStr)>
Public lpszProgressTitle As String
End Structure
<DllImport("shell32.dll", CharSet:=CharSet.Unicode)>
Private Shared Function SHFileOperation(
<[In]> ByRef lpFileOp As SHFILEOPSTRUCT) As Integer
End Function
Private Shared _ShFile As SHFILEOPSTRUCT
Public Shared Sub Copy(ByVal sSource As List(Of String), ByVal sTarget As String)
_ShFile.wFunc = FO_Func.FO_COPY
_ShFile.pFrom = String.Join(vbNullChar, sSource) + vbNullChar
_ShFile.pTo = sTarget
SHFileOperation(_ShFile)
End Sub
End Class
To copy files and/or folders is as simple as this:
Dim copy_items_paths As List(Of String)
Dim target_path As String
NativeCopy.Copy(copy_items_paths, target_path)
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
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.
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!
Is this possible? It gives me an error, and I had previously thought it could work for folders and drives and stuff like that as well.
Icon.ExtractAssociatedIcon("C:\") did not work when I tried it, and threw an error.
How can I get the associated icon from EVERYTHING? This is vb.net
The SHGetFileInfo() shell function can provide you with the icon you are looking for. This code worked well, it generated appropriate icons for drives, folders and files:
Imports System.Drawing
Imports System.Reflection
Imports System.Runtime.InteropServices
Public Module NativeMethods
Public Function GetShellIcon(ByVal path As String) As Icon
Dim info As SHFILEINFO = New SHFILEINFO()
Dim retval as IntPtr = SHGetFileInfo(path, 0, info, Marshal.SizeOf(info), &H100)
If retval = IntPtr.Zero Then Throw New ApplicationException("Could not retrieve icon")
'' Invoke private Icon constructor so we do not have to copy the icon
Dim cargt() As Type = { GetType(IntPtr) }
Dim ci As ConstructorInfo = GetType(Icon).GetConstructor(BindingFlags.NonPublic Or BindingFlags.Instance, Nothing, cargt, Nothing)
Dim cargs() As Object = { info.IconHandle }
Dim icon As Icon = CType(ci.Invoke(cargs), Icon)
Return icon
End Function
'' P/Invoke declaration
Private Structure SHFILEINFO
Public IconHandle As IntPtr
Public IconIndex As Integer
Public Attributes As Integer
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=260)> _
Public DisplayString As String
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=80)> _
Public TypeName As String
End Structure
Private Declare Auto Function SHGetFileInfo lib "Shell32.dll" (path As String, _
attributes As Integer, byref info As SHFILEINFO, infoSize As Integer, flags As Integer) As IntPtr
End Module
It is not possible to use Icon.ExtractAssociatedIcon on anything other than files. This API is a thin wrapper on top of the Win32 call ExtractAssociatedIcon. While the documentation for the managed code is a bit ambiguous, the native documentation is much clearer that the target must be a file. It goes further to say that it must be an executable file.
Unfortunately I'm not sure if there is an equivalent function for Directories or not.