Page 1 of 2
GetPrivateProfileString
Posted: Thu Jan 09, 2020 12:26 pm
by lagraf
Ich lese einen String aus einer INI-Datei mit:
Code: Select all
METHOD GetString(cSection, cEntry)
LOCAL ptrBuffer AS PTR
LOCAL cValue AS STRING
ptrBuffer := MemAlloc(INI_STRING_LEN)
GetPrivateProfileString(String2Psz(cSection), String2Psz(cEntry), String2Psz(" "), PSZ( _CAST, ptrBuffer ), INI_STRING_LEN, String2Psz(SELF:fullPath))
cValue := Psz2String(PSZ(_CAST, ptrBuffer))
MemFree(ptrBuffer)
RETURN cValue
Die gesamte Section wäre demnach
Code: Select all
METHOD GetSection(cSection) CLASS IniFile
LOCAL cBuffer AS STRING
LOCAL ptrBuffer AS PTR
LOCAL nLen AS DWORD
ptrBuffer := MemAlloc(INI_STRING_LEN)
nLen := GetPrivateProfileString(String2Psz(cSection), NULL_PSZ, String2Psz(" "), PSZ(_CAST, ptrBuffer), INI_STRING_LEN, String2Psz(SELF:FullPath))
cBuffer := Psz2String(PSZ(_CAST, ptrBuffer))
MemFree(ptrBuffer)
RETURN IIF(nLen<=0, {}, String2Array(Left(cBuffer, nLen-1), _CHR(0)))
Ich erhalte aber immer nur das erste Element, hat sich da etwas seit VO geändert?
LG Franz
GetPrivateProfileString
Posted: Thu Jan 09, 2020 3:35 pm
by wriedmann
Hallo Franz,
da hat sich nichts geändert.... Das Problem ist, dass dieser Buffer Null-terminierte Strings enthält, und unter X# ist alles Unicode....
Versuchs mal damit:
Code: Select all
public virtual method GetSection( cSection as string ) as array
local aReturn as array
local pszBuffer as byte[]
local aEntries as string[]
local nPos as int
local nMaxLen as int
aReturn := {}
nMaxLen := 65767
pszBuffer := byte[]{ nMaxLen }
if IniFile.GetSection( cSection, pszBuffer, nMaxLen, _cFileName )
aEntries := Encoding.ASCII:GetString( pszBuffer ):Trim( '' ):Split( '' )
foreach cEntry as string in aEntries
AAdd( aReturn, cEntry )
next
endif
return aReturn
[DllImport("kernel32.dll",CharSet:=CharSet.Ansi,EntryPoint:="GetPrivateProfileSection")];
static method GetSection(lpAppName as string, lpszReturnBuffer as byte[], nSize as int, lpFileName as string) as logic pascal
Wolfgang
GetPrivateProfileString
Posted: Thu Jan 09, 2020 5:15 pm
by Karl-Heinz
Hallo Franz,
>> Ich erhalte aber immer nur das erste Element, hat sich da etwas seit VO geändert?
Ich kann mir nicht vorstellen, dass Deine GetSection() Methode - so wie gepostet - mit VO funktioniert. Da ptrBuffer mit chr(0) separierte Strings enthält bewirkt ein
cBuffer := Psz2String(PSZ(_CAST, ptrBuffer))
dass cBuffer immer nur den ersten string beinhaltet.
wäre der Inhalt von ptrBuffer:
"eins" + CHR (0) + "zwei" + CHR (0) + "Drei" + CHR (0) + CHR ( 0 )
wäre der Inhalt von cBuffer also immer "eins".
So sollte es mit VO und X# funktionieren. Den besseren net Weg hat ja Wolfgang gepostet.
Code: Select all
METHOD GetSection(cSection) CLASS IniFile
LOCAL ptrBuffer AS PTR
LOCAL nLen AS DWORD
local aValues := {} as array
ptrBuffer := MemAlloc(INI_STRING_LEN)
nLen := GetPrivateProfileString(String2Psz(cSection), NULL_PSZ, String2Psz(" "), PSZ(_CAST, ptrBuffer), INI_STRING_LEN, String2Psz(SELF:FullPath))
if nLen > 0
aValues := Psz2Array ( ptrBuffer )
endif
MemFree(ptrBuffer)
RETURN aValues
Code: Select all
FUNCTION Psz2Array ( ptrEnv AS PTR ) AS ARRAY PASCAL
LOCAL ptrTemp AS BYTE PTR
LOCAL cString AS STRING
LOCAL aRet := {} AS ARRAY
ptrTemp := ptrEnv
cString := Psz2String ( ptrTemp )
WHILE cString != NULL_STRING
AAdd ( aRet , cString )
ptrTemp += SLen ( cString ) + 1
cString := Psz2String ( ptrTemp )
ENDDO
RETURN aRet
Gruß
Karl-Heinz
GetPrivateProfileString
Posted: Thu Jan 09, 2020 6:20 pm
by lagraf
Hallo Karl-Heinz,
dein Code funktioniert! Mein Code in VO war noch etwas einfacher, ich hatte ihn schon so angepaßt, dass X# keine Fehler mehr gemeldet hat, das Original war:
Code: Select all
METHOD GetSection(cSection) CLASS IniFile
LOCAL cBuffer AS STRING
LOCAL nLen AS DWORD
cBuffer := Buffer(4096)
nLen := GetPrivateProfileString(PSZ(cSection), NULL_PTR, PSZ(" "), PSZ(cBuffer), 4096, PSZ(SELF:FullPath))
RETURN IIF(nLen<=0, {}, String2Array(Left(cBuffer, nLen-1), _CHR(0)))
Hallo Wolfgang,
habe ich entfernt, da jede Menge Fehler. Danach bleiben 2 Fehler übrig:
Code: Select all
error XS0120: An object reference is required for the non-static field, method, or property 'IniFile.GetSection(params XSharp.__Usual[])'
error XS0103: The name 'Encoding' does not exist in the current context
GetPrivateProfileString
Posted: Thu Jan 09, 2020 6:29 pm
by wriedmann
Hallo Franz,
auf den DLLImport kannst Du nicht verzichten, ggf. solltest Du den Namen anpassen, z.B. auf
Code: Select all
[DllImport("kernel32.dll",CharSet:=CharSet.Ansi,EntryPoint:="GetPrivateProfileSection")];
static method GetSectionX(lpAppName as string, lpszReturnBuffer as byte[], nSize as int, lpFileName as string) as logic pascal
und dann den Aufruf entsprechend anpassen.
Den Fehler mit dem Encoding kannst Du durch ein
im Kopf der Datei beheben, bzw. durch volle Qualifizierung:
Code: Select all
System.Text.Encoding.ASCII:GetString( pszBuffer )
Wolfgang
GetPrivateProfileString
Posted: Fri Jan 10, 2020 6:57 am
by lagraf
Hallo Wolfgang,
Code: Select all
PUBLIC VIRTUAL METHOD GetSection( cSection AS STRING ) AS ARRAY
...
IF IniFile.GetSectionX( cSection, pszBuffer, nMaxLen, "C:WINAPPSPDFMAILPDFMAIL.INI" )
...
[DllImport("kernel32.dll",CharSet:=CharSet.Ansi,EntryPoint:="GetPrivateProfileSection")];
STATIC METHOD GetSectionX(lpAppName AS STRING, lpszReturnBuffer AS BYTE[], nSize AS INT, lpFileName AS STRING) AS LOGIC PASCAL
bringt die Fehler
Code: Select all
error XS0246: The type or namespace name 'DllImportAttribute' could not be found (are you missing a using directive or an assembly reference?)
error XS0246: The type or namespace name 'DllImport' could not be found (are you missing a using directive or an assembly reference?)
error XS0246: The type or namespace name 'CharSet' could not be found (are you missing a using directive or an assembly reference?)
error XS0103: The name 'CharSet' does not exist in the current context
error XS0246: The type or namespace name 'EntryPoint' could not be found (are you missing a using directive or an assembly reference?)
GetPrivateProfileString
Posted: Fri Jan 10, 2020 7:19 am
by wriedmann
Hallo Franz,
bitte ergänze oben in der PRG-Datei
Code: Select all
using System.Runtime.InteropServices
.NET organisiert die Klassen und Methoden in sogenannten Namespaces. Dadurch kommt es nicht mehr zu Überschneidungen zwischen verschiedenen Klassen, die in verschiedenen Assemblies mit demselben Namen vorliegen können.
Und die Klassen und Attribute für die Einbindung sind im Namespace System.Runtime.Interop definiert.
Wolfgang
GetPrivateProfileString
Posted: Fri Jan 10, 2020 7:35 am
by lagraf
Hallo Wolfgang,
damit bleibt nun noch zwei identische Meldungen bei der Zeile System.Text.Encoding.ASCII:
Code: Select all
error XS1503: Argument 1: cannot convert from 'string' to 'char'
GetPrivateProfileString
Posted: Fri Jan 10, 2020 8:18 am
by wriedmann
Hallo Franz,
sorry, im VO-Dialekt muss man bei den einfachen Hochkommas definieren, dass die als Char zu interpretieren sind:
Code: Select all
aEntries := Encoding.ASCII:GetString( pszBuffer ):Trim( c'' ):Split( c'' )
Mein Code ist nämlich im Core-Dialekt und gibt ein Dictionary zurück:
Code: Select all
public virtual method GetSection( cSection as string ) as Dictionary<string,string>
local oReturn as Dictionary<string,string>
local pszBuffer as byte[]
local aEntries as string[]
local cKey as string
local cValue as string
local nPos as int
local nMaxLen as int
oReturn := Dictionary<string,string>{}
nMaxLen := 65767
pszBuffer := byte[]{ nMaxLen }
if IniFile.GetSection( cSection, pszBuffer, nMaxLen, _cFileName )
aEntries := Encoding.ASCII:GetString( pszBuffer ):Trim( '' ):Split( '' )
foreach cEntry as string in aEntries
nPos := cEntry:IndexOf( "=" )
if nPos > 0
cKey := cEntry:SubStr( 0, nPos )
cValue := cEntry:SubStr( nPos + 1 )
oReturn:Add( cKey, cValue )
endif
next
endif
return oReturn
Wolfgang
GetPrivateProfileString
Posted: Fri Jan 10, 2020 8:42 am
by lagraf
Hallo Wolfgang,
das sind dann die Feinheiten! Die Methode bringt im Gegensatz zum VO-Code nicht nur die Schlüsselworte, sondern auch gleich den Wert dazu. Danke, so funktionierts jetzt!
Eine Frage: Ich sehe immer wieder, dass du versuchst, soviel wie möglich mit .NET zu lösen. Beziehst du dein Wissen über .NET aus dem Netz oder aus einem Buch? Wie geht man da am Besten vor um sich zu informieren oder eine Lösung für eine Problemstellung zu finden?