GetPrivateProfileString Oddity - winapi

I was just tinkering around with calling GetPrivateProfileString and GetPrivateProfileSection in kernel32 from .NET and came across something odd I don't understand.
Let's start with this encantation:
Private Declare Unicode Function GetPrivateProfileString Lib "kernel32" Alias "GetPrivateProfileStringW" ( _
ByVal lpApplicationName As String, _
ByVal lpKeyName As String, _
ByVal lpDefault As String, _
ByVal lpReturnedString() As Char, _
ByVal nSize As Int32, _
ByVal lpFileName As String) As Int32
If I pass an lpApplicationName (section), no lpKeyName and no lpDefault, I should get all of the keys for that section, and indeed I do: 50% of the time.
If the ini file has the lpApplicationName starting on the first line, the buffer returns nothing. If lpApplicationName stats on the second line in the file, it returns the expected values.
At first I though it was a matter of using the W version and Unicode in the Declare, but changing those seems to have no effect.
What am I missing?

Check to see if the file you are opening has a byte order mark (a few bytes marking the type of text encoding).
These Windows API calls don't seem to grok byte order marks and is causes them to miss the first section (hence everything works fine if there is a blank line).

Good call. Editing the ini file in VS.NET is of course (Duh) adding a utf-8 BOM. Grrr.
Opening it in notepad and doing a SaveAs ASCII yields the expected results.
So obvious. So obtuse. Another hour down the crapper. :-)
Thanks!
-=Chris

Related

What is happening in this code

I was looking for some vb6 that would allow me to populate a listbox with a directory of files when I found the following elegant piece of code.
List1.hwnd, &H18D, &H20, "directory*.*"
Most of the other examples I found were 4 or more lines of code. Can someone help me understand what is happening here? What is the
List1.hwnd, &H18D, &H20
Part doing?
There was a general declaration I left out.
Private Declare Function SendMessageStr Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As String) As Long
Your edit still makes not enough sense - unless the code was
SendMessageStr List1.hwnd, &H18D, &H20, "directory*.*"
and you thought the space means it's a stand-alone bit (it isn't).
That code is
SendMessage (List1.hwnd, LB_DIR, DDL_ARCHIVE, "directory*.*") - it sends a documented Windows message to a ListBox control named List1 to fill it with files that match the mask "directory*.*", including the archived ones.

SAPI5 Event returns 42 instead of 0

I am using SAPI5 COM, and there is one event called
Word(ByVal StreamNumber As Long, ByVal StreamPosition As Variant, ByVal CharacterPosition As Long, ByVal Length As Long)
It works fine, but CharacterPosition starts off with 42, and I have no idea why it doesn't start off with 0 or 1.
The docu say:
CharacterPosition
The character position in the input stream one character before the start of the word. In the case of the first word in a stream, this parameter is zero.
But for me, it always starts with 42, no matter which voice I use.
Does anybody know what might cause this?
Thank you very much!
I found the reason:
The stupid SAPI5 engine takes the tags into account.

Detect copy event on windows

can someone give me a piece of code or API on how I can monitor any copy event on window base OS using vb classic (vb 6.0).
I want to trap the copy event let say a user is copying a file on a computer, how can I get the name of the file that is being copied and write a log that file was copied on this date. I want to create a free program about file tracking. I have googled and I can't find code to detect copy event on windows. Please help.
Create a Timer control (or have it in a loop with DoEvents()) and use GetClipboardData() like so:
Private Declare Function OpenClipboard Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function GetClipboardData Lib "user32" (ByVal wFormat As Long) As Long
Private Declare Function CloseClipboard Lib "user32" () As Long
Private Declare Function lstrlen Lib "kernel32" Alias "lstrlenA" (ByVal lpString As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDst As Any, pSrc As Long, ByVal ByteLen As Long)
Private Sub Timer1_Timer()
Dim ptr As Long
OpenClipboard hwnd
ptr = GetClipboardData(49158)
If ptr Then
Dim size As Long
size = lstrlen(ptr)
If size > 0 Then
Dim data As String
data = Space$(size)
CopyMemory ByVal data, ByVal ptr, size
MsgBox data
End If
End If
CloseClipboard
End Sub
FYI: 49158 is a private clipboard format called "FileName" and unfortunately cannot be used with Clipboard.GetData() as the number is too high for an Integer.
When you copy something, the data variable will contain the file name copied.
You can monitor the clipboard: ClipBoard Monitor C#
This will cover more than files and only tells you that a file name or file contents have been copied, not when it actually is. You'll need to do more to catch the actual write.
I believe the term you are missing is "hook", in which case this question/answer should get you what you need: Windows XP/7 copy FILE hook
1) You can hook the WinAPi functions like CopyFile and CopyFileEx
creating a system wide hook, writing the hook yourself or using a API
hook library like madCodeHook or Deviare API hook (I've used both
libraries with great results.)
2) Writing a File System Filter Driver.

Is there an API to get the advanced printer device settings?

I need to get the available supported printer document features for a particular printer through the win32 api.
The options I'm referring to are displayed for a sample printer in the image below. You can get this dialog by right clicking the printer icon and the click preferences, and the clicking the advanced tab in the dialog.
Can anyone tell me the need api i need to call, and in what other?
I am targeting Windows Windows XP+ and using vb6.
The DeviceCapabilities function is read only. What you're looking for is the DocumentProperties function. DeviceCapabilities is actually rather dated and should have been obsoleted long ago since it assumes only a single user and single application is using the printer. You don't want to set printer properties for every print job; you want to set document properties for your current print job. The DocumentProperties function will do that for you, but pay close attention to the instructions in the link above on how to make changes. It's a needlessly complex function.
What I think you are looking for is DeviceCapabilities from winspool.drv. Sample code from Microsoft. Most of the documentation online now days is for .Net, So I typed in the VB6 definition from Dan Appleman's Visual Basic Programmer's Guide to the Win32 API
The declaration for VB6 is:
Declare Function DeviceCapabilities& Lib "winspool.drv" Alias "DeviceCapabilitiesA" (ByVal lpDeviceName as String, ByVal lpPort as String, ByVal iIndex as Long, ByVal lpOutput as String, ByVal lpDeviceMode as Long)
Based on your Comment you would need to use DocumentProperties it can be used to retreive or modify a DevMode Structure. It may or may not have what you are looking for. Your best bet would be to get the above book, Chapter 12 has wealth of information. Also looking at your picture it looks like you are using somesort of a POS print, you should consult the manufacturers documentation about specific api's that the printer might support.
Declare Function DocumentProperties& Lib "winspool.drv" Alias "DocumentPropertiesA" (ByVal hwnd as Long, ByVal hPrinter as Long, ByVal pDeviceName as String, ByVal pDeviceModeOutput as Long, ByVal pDeviceModelInput as Long, ByVal fMode as Long)
DevMode Structure
Public Const CCHDEVICENAME = 32
Public Const CCHFORMNAME = 32
Type DEVMODE
dmDeviceName as String * CCHDEVICENAME
dmSpecVersion as Integer
dmDriverVersion as Integer
dmSize as Integer
dmDriverExtra as Integer
dmFields as Long
dmOrientation as Integer
dmPaperSize as Integer
dmPaperLength as Integer
dmPaperWidth as Integer
dmScale as Integer
dmCopies as Integer
dmDefaultSource as Integer
dmPrintQuality as Integer
dmColor as Integer
dmDuplex as Integer
dmYResolution as Integer
dmTTOption as Integer
dmCollate as Integer
dmFormName as String * CCHFORMNAME
dpBitsPerPixel as Integer
dmBitsPerPel as Long
dmPelWidth as Long
dmPelHeight as Long
dmDisplayFlags as Long
dmDisplayFrequency as Long
dmICMMethod as Long
dmICMIntent as Long
dmMediaType as Long
dmDitherType as Long
dmReserved1 as Long
dmReserved2 as Long
End Type

Is there a way to read an .ini file into memory and then read particular values from it?

I've got a situation where an ini file is in memory (in a string variable) and I'd like to read values out of it without writing the ini file data to disk.
UPDATE:This is data that I do not want to write to the HD. I'm downloading it from a web server into memory and then getting some data.
Is there any way to do that in VB6? Maybe with a Win API call?
Clay,
Check out this article at DevX.com
Read/Write INI without using API
This should get you pointed in a good direction. The modules are a bit dirty and do, at this point, require a path for the INI to be stored. Instead simply modify the modules to use your string directly and you should receive the desired result. Let me know how this works out for you.
The ini file is to be stored on hard disk. If you want to save in registry instead (this should be added to the registry file too), you can use these functions:
SaveSetting
GetSetting
If you don't want to save it on disk I think it might be difficult to use any specific API calls. But if it's an ini file it should be in a structured format, why not just loop through it until the section you want and then read the values you want from it.
It's been a long time but it should be something like this I think:
Just Split it on newlines to get an array of lines, then each section should start in a certain format and for each line in there you check if it contains an = I think, and if so everything to the left of the first = is the name of the value and everything to the right of it is the value.
Declare the two Windows API function imports
Public Declare Function GetPrivateProfileStringA Lib "kernel32.dll" (ByVal lpApplicationName As String, ByVal lpKeyName As Any, ByVal lpDefault As String, ByVal lpReturnedString As String, ByVal nSize As Long, ByVal lpFileName As String) As Long
Public Declare Function WritePrivateProfileStringA Lib "kernel32.dll" (ByVal lpApplicationName As String, ByVal lpKeyName As Any, ByVal lpString As Any, ByVal lpFileName As String) As Long
For reading
sReturn = Space(255)
sReturn = Left(sReturn, GetPrivateProfileStringA(header, key, defaultReturn, sReturn, 255, filePath))
For writting
WritePrivateProfileStringA header, key, Datum, filePath
Remember the structure of an INI file is
[header]
key=data

Resources