Read/Write "INI" file - vb.net

Evening Everyone -
I'm looking for some thoughts on how to read / write values from a windows "ini" structured file. I have a settings file created with another application and I would like to update values of a key within a specified section. I got it working using a buffer.replace process but now realize that some keys are used over in sections and globally replacing a value will cause problems.
Here is a sample of what my ini file looks like
IMPORT-1]
SETTINGS="HELLO"
FILENAME="C:\TEST\TEST1.CSV"
[ENCODE-2]
FILENAME="C:\TEST\REPORT1.XPS"
I've got dozens of blocks so any clarity on accomplishing a read and write of a value within a specific section would be hugely appreciated!
--Cheers & Thanks
George

You can use some of the kernel32 functions.
Private Declare Auto Function GetPrivateProfileString Lib "kernel32" (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
This will let you read an ini file
Dim sb As StringBuilder
sb = New StringBuilder(500)
GetPrivateProfileString("IMPORT-1", "SETTINGS", "", sb, sb.Capacity, "test.ini")

Related

VBA: Running "Elevated" Command (Shell vs. ShellExecute)

In my VBA procedure, I need to run the app "Skitch" and use it to open a JPEG file. This is the command I've been using:
ReturnValue = Shell("C:\Program Files (x86)\Evernote\Skitch\Skitch.exe " & """" & aPic & """", 1)
...where "aPic" is the path and filename.
After some experimenting, I think I need to run the command as if it were in an Elevated Command window (in other words, run it "as Administrator"). Is it possible to run Shell elevated?
If that's not possible: If I understand correctly, using ShellExecute instead of Shell will automatically elevate the command. But I'm much less familiar with it. Can someone show me how to run my command using ShellExecute? (BTW, I know that ShellExecute is good for running commands associated with the file type, but on this user's computer *.jpg will likely not be associated with Skitch.)
Thanks.
Try this:
Private Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" ( _
ByVal hWnd As Long, _
ByVal lpOperation As String, _
ByVal lpFile As String, _
ByVal lpParameters As String, _
ByVal lpDirectory As String, _
ByVal nShowCmd As Long) As Long
Const SW_SHOWNORMAL = 1
Public Sub test()
ShellExecute 0, "runas", "C:\Program Files (x86)\Evernote\Skitch\Skitch.exe", aPic, vbNullString, SW_SHOWNORMAL
End Sub
I don't have skitch so can't try this, but it should work.
For more information about ShellExecute, click here to have a look on MSDN.

vb.net win32api pointer to integer array parameter

Because I need to extract an icon from a file, but not the first icon, I cannot use the vb.net icon extraction function. The WIN32API function that should do this expects a pointer to an integer array.
How can I provide this type as a parameter?
Declare Function ExtractIconEx Lib "shell32.dll" Alias "ExtractIconExA" _
(ByVal lpszFile As String, _
ByVal nIconIndex As Integer, _
ByRef phiconLarge As Integer, _
ByRef phiconSmall As Integer, _
ByVal nIcons As Long) As Integer
Dim icons As integer()
ExtractIconEx("%systemroot%/shell32.dll", 15, icons, 0, 5)
I've taken a gander at the System.Reflection.Pointer class?/namespace?, but the documentation is sparse and less than sensible.
IntPtr doesn't provide support for arrays afaikt
Ok tx to Hans I've managed to correct the signature to:
<Runtime.InteropServices.DllImport("shell32.dll", _
CharSet:=Runtime.InteropServicesCharSet.Auto)> _
Shared Function ExtractIconEx(ByVal szFileName As String, _
ByVal nIconIndex As Integer, _
ByRef phiconLarge() As IntPtr, _
ByRef phiconSmall() As IntPtr, _
ByVal nIcons As UInteger) As UInteger
End Function
...
Dim icons(8) As IntPtr, smicons(8) As IntPtr
MsgBox(ExtractIconEx("%systemroot%/shell32.dll", 15, icons, smicons, 1))
Try
MsgBox(icons.Count)
Catch ex As Exception
MsgBox(ex.Message & " by " & ex.Source)
End Try
...
The subsequent calls always cause an exception (Value cannot be null). I get a return value of 4294967295, which is the maximum 32 bit integer value.
Any ideas how to tame this function and make it work?
ByRef phiconLarge() As IntPtr, _
ByRef phiconSmall() As IntPtr, _
The VB.NET declaration on that webpage has a bug, these arrays need to be passed ByVal, not ByRef. Note how they got it correct in the example code on the bottom of the page.
I edited the page to correct the bug.

How to execute a file residing in memory with BoxedAPP

I've purchased a license of BoxedAPP and when I wrote for help to the support mail I got any answer.
I've downloaded the SDK examples but all the important examples are in C# (and even if I use a translator I can't understand it), and the vb.net examples are for store files not executing they.
My question is simple, How I can use BoxedAPP to store a file in memory (Virtualize a file) and then execute it from memory?
For example I want to virtualize a Video file named "test.avi" as "my.resources.test" and then execute it with "process.start", this is what I've tryed to virtualize my recurse but don't run:
BoxedAppSDK.NativeMethods.BoxedAppSDK_CreateVirtualFile(My.Resources.test, _
BoxedAppSDK.NativeMethods.EFileAccess.GenericAll, _
BoxedAppSDK.NativeMethods.EFileShare.None, IntPtr.Zero, _
BoxedAppSDK.NativeMethods.ECreationDisposition.New, _
BoxedAppSDK.NativeMethods.EFileAttributes.Normal, _
IntPtr.Zero)
The first argument should be a string, check the function declaration:
<DllImport("bxsdk32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
Public Shared Function BoxedAppSDK_CreateVirtualFile( _
ByVal lpFileName As String, _
ByVal dwDesiredAccess As EFileAccess, _
ByVal dwShareMode As EFileShare, _
ByVal lpSecurityAttributes As IntPtr, _
ByVal dwCreationDisposition As ECreationDisposition, _
ByVal dwFlagsAndAttributes As EFileAttributes, _
ByVal hTemplateFile As IntPtr) As IntPtr
End Function
Also what does BoxedAppSDK_CreateVirtualFile return?

VB.NET string path be cut off automatically

I ended up a simple program sending and receiving a RS-232 message. My parameters (baudrate, COM port) are stored in an INI file (the file will be created automatically if not existing). The progam runs without error but I don't know why it cuts off the path that point to INI file when the path length exceed a limit (there are Unicode Japanese characters in the path string)
My path string in New function (construction) is like this: "D:\通信プログラム20120709\新しいフォルダー\新しいフォルダー\新しいフォルダー\新しいフォルダー\Debug\Config.ini"
and in an event function, it will become: D:\通信プログラム20120709\新しいフォルダー\新しいフォルダー\新しいフォ・
After consulting some source on Internet, they show me that a .NET String would have a very huge capacity so I guess my problem not concerned to VB.NET String.
Any help would be appreciated.
From Comments
I found that the path is changed after the first line of code below
RS232TransPort = IniRoutine.GetString(IniSectionName, ConfigName.COMPort, "COM3")
RS232Baudrate = IniRoutine.GetInteger(IniSectionName, ConfigName.Baudrate, 9600)
This is the function to get a string:
Public Function GetString(ByVal Section As String, ByVal Key As String, ByVal [Default] As String) As String
Dim intCharCount As Integer
Dim objResult As New System.Text.StringBuilder(256)
intCharCount = GetPrivateProfileString(Section, Key, [Default], objResult, objResult.Capacity, strFilename)
GetString = String.Empty
If intCharCount > 0 Then GetString = Left(objResult.ToString, intCharCount)
End Function
where strFilename is a local variable of this class.
And this is the API declaire:
Private Declare Ansi Function GetPrivateProfileString _
Lib "kernel32.dll" Alias "GetPrivateProfileStringA" _
(ByVal lpApplicationName As String, _
ByVal lpKeyName As String, ByVal lpDefault As String, _
ByVal lpReturnedString As System.Text.StringBuilder, _
ByVal nSize As Integer, ByVal lpFileName As String) _
As Integer
You are using GetPrivateProfileStringA instead of GetPrivateProfileStringW.
Since you are using Unicode, you need to use GetPrivateProfileStringW instead.

IFDEF equivalent in VBA

I have code that needs to run on both Excel 2003 and Excel 2007, and there are a few spots where changes in the versions cause the code to halt. I tried separating these lines out with If-Else statements, but the code won't compile on either because it doesn't recognize the code used for the other. Is there any way I could tell one version to ignore a block of code, similar to a C or C++-style #ifdef, in VBA?
This is a good starting point, but it won't work with the version of Excel that its running on, since that can only be figured out at run-time, not compile time.
If you need to branch your code based on information only discoverable at run time you might consider late binding as a solution. There are two ways you can sneak around version problems.
The first way can be used if you need to Access a property or method that only exists in certain versions, you can use CallByName. The advantage of call by name is that it allows you to preserve early binding (and intellisense) for your objects as much as possible.
To give an example, Excel 2007 has a new TintAndShade property. If you wanted to change the color of a range, and for Excel 2007 also ensure TintAndShade was set to 0 you would run into trouble because your code won't compile in Excel 2003 which does not have TintAndShade as a property of the range object. If you access the property that you know is not in all versions using CallByName, you code will compile in all versions fine, but only run in the versions you specify. See below:
Sub Test()
ColorRange Selection, Excel.Application.version, 6
End Sub
Sub ColorRange(rng As Excel.Range, version As Double, ParamArray args() As Variant)
With rng.Interior
.colorIndex = 6
.Pattern = xlSolid
If version >= 12# Then
'Because the property name is stored in a string this will still compile.
'And it will only get called if the correct version is in use.
CallByName rng.Interior, "TintAndShade", VbLet, 0
End If
End With
End Sub
The second way is for classes that have to be instantiated via "New" and don't even exist in old versions. You won't run into this problem with Excel, but I will give a quickie demo so you can see what I mean:
Imagine that you wanted to do File IO, and for some bizarre reason not all of the computers had the Microsoft Scripting Runtime on them. But for some equally bizarre reason you wanted to make sure it was used whenever it was available. If set a reference to it and use early binding in your code, the code won't compile on systems that don't have the file. So you use late binding instead:
Public Sub test()
Dim strMyString As String
Dim strMyPath As String
strMyPath = "C:\Test\Junk.txt"
strMyString = "Foo"
If LenB(Dir("C:\Windows\System32\scrrun.dll")) Then
WriteString strMyPath, strMyString
Else
WriteStringNative strMyPath, strMyString
End If
End Sub
Public Sub WriteString(ByVal path As String, ByVal value As String)
Dim fso As Object '<-Use generic object
'This is late binding:
Set fso = CreateObject("Scripting.FileSystemObject")
fso.CreateTextFile(path, True, False).Write value
End Sub
Public Sub WriteStringNative(ByVal path As String, ByVal value As String)
Dim lngFileNum As Long
lngFileNum = FreeFile
If LenB(Dir(path)) Then Kill path
Open path For Binary Access Write Lock Read Write As #lngFileNum
Put #lngFileNum, , value
Close #lngFileNum
End Sub
There is a comprehensive list of all Adds and Changes to Excel Object Model since 2003:
http://msdn.microsoft.com/en-us/library/bb149069.aspx
For changes between 1997 and 2000 go here:
http://msdn.microsoft.com/en-us/library/aa140068(office.10).aspx
Yes it is possible to do conditional compilation in Excel VBA. Below is a brief resource and some example code:
Conditional Compilation
#If Win32 Then
' Profile String functions:
Private Declare Function WritePrivateProfileString Lib "KERNEL32" Alias "WritePrivateProfileStringA" (ByVal lpApplicationName As String, ByVal lpKeyName As Any, ByVal lpString As Any, ByVal lpFileName As String) As Long
Private Declare Function GetPrivateProfileString Lib "KERNEL32" Alias "GetPrivateProfileStringA" (ByVal lpApplicationName As Any, ByVal lpKeyName As Any, ByVal lpDefault As Any, ByVal lpReturnedString As String, ByVal nSize As Long, ByVal lpFileName As String) As Long
#Else
' Profile String functions:
Private Declare Function WritePrivateProfileString Lib "Kernel" (ByVal lpApplicationName As String, ByVal lpKeyName As Any, ByVal lpString As Any, ByVal lpFileName As String) As Integer
Private Declare Function GetPrivateProfileString Lib "Kernel" (ByVal lpApplicationName As String, ByVal lpKeyName As Any, ByVal lpDefault As Any, ByVal lpReturnedString As String, ByVal nSize As Integer, ByVal lpFileName As String) As Integer
#End If
Can you post the offending lines of code?
If it is a constant like vbYes or xlFileFormat or whatever, use the corresponding numeric value.
Show me what you got, I'll see if I can refactor it.
Bill