GetPrivateProfileString

Deutschsprachiges X#-Forum – German language forum

Moderator: wriedmann

lagraf
Posts: 450
Joined: Thu Jan 18, 2018 9:03 am
Location: A

GetPrivateProfileString

Post 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
User avatar
wriedmann
Posts: 3759
Joined: Mon Nov 02, 2015 5:07 pm
Location: Italy

GetPrivateProfileString

Post 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
Wolfgang Riedmann
Meran, South Tyrol, Italy
wolfgang@riedmann.it
https://www.riedmann.it - https://docs.xsharp.it
Karl-Heinz
Posts: 774
Joined: Wed May 17, 2017 8:50 am
Location: Germany

GetPrivateProfileString

Post 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
lagraf
Posts: 450
Joined: Thu Jan 18, 2018 9:03 am
Location: A

GetPrivateProfileString

Post 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,

Code: Select all

[DllImport("kernel32.dll" ...
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
User avatar
wriedmann
Posts: 3759
Joined: Mon Nov 02, 2015 5:07 pm
Location: Italy

GetPrivateProfileString

Post 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

Code: Select all

using System.Text
im Kopf der Datei beheben, bzw. durch volle Qualifizierung:

Code: Select all

System.Text.Encoding.ASCII:GetString( pszBuffer )
Wolfgang
Wolfgang Riedmann
Meran, South Tyrol, Italy
wolfgang@riedmann.it
https://www.riedmann.it - https://docs.xsharp.it
lagraf
Posts: 450
Joined: Thu Jan 18, 2018 9:03 am
Location: A

GetPrivateProfileString

Post 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?)
User avatar
wriedmann
Posts: 3759
Joined: Mon Nov 02, 2015 5:07 pm
Location: Italy

GetPrivateProfileString

Post 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
Wolfgang Riedmann
Meran, South Tyrol, Italy
wolfgang@riedmann.it
https://www.riedmann.it - https://docs.xsharp.it
lagraf
Posts: 450
Joined: Thu Jan 18, 2018 9:03 am
Location: A

GetPrivateProfileString

Post 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'
User avatar
wriedmann
Posts: 3759
Joined: Mon Nov 02, 2015 5:07 pm
Location: Italy

GetPrivateProfileString

Post 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
Wolfgang Riedmann
Meran, South Tyrol, Italy
wolfgang@riedmann.it
https://www.riedmann.it - https://docs.xsharp.it
lagraf
Posts: 450
Joined: Thu Jan 18, 2018 9:03 am
Location: A

GetPrivateProfileString

Post 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?
Post Reply