fbpx
Welcome, Guest
Username: Password: Remember me
Hier wird Deutsch gesprochen
  • Page:
  • 1

TOPIC: GetPrivateProfileString

GetPrivateProfileString 1 week 2 days ago #12515

  lagraf's Avatar Topic Author lagraf Offline Posts: 62
Ich lese einen String aus einer INI-Datei mit:
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
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

Please Log in or Create an account to join the conversation.

GetPrivateProfileString 1 week 2 days ago #12519

  wriedmann's Avatar wriedmann Offline Posts: 1995
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:
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( '\0' ):Split( '\0' )
		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

www.riedmann.it - docs.xsharp.it

Please Log in or Create an account to join the conversation.

GetPrivateProfileString 1 week 2 days ago #12522

  Karl-Heinz's Avatar Karl-Heinz Offline Posts: 456
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.
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 
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

Please Log in or Create an account to join the conversation.

GetPrivateProfileString 1 week 2 days ago #12524

  lagraf's Avatar Topic Author lagraf Offline Posts: 62
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:
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,
[DllImport("kernel32.dll" ...
habe ich entfernt, da jede Menge Fehler. Danach bleiben 2 Fehler übrig:
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

Please Log in or Create an account to join the conversation.

GetPrivateProfileString 1 week 2 days ago #12525

  wriedmann's Avatar wriedmann Offline Posts: 1995
Hallo Franz,
auf den DLLImport kannst Du nicht verzichten, ggf. solltest Du den Namen anpassen, z.B. auf
[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
using System.Text
im Kopf der Datei beheben, bzw. durch volle Qualifizierung:
System.Text.Encoding.ASCII:GetString( pszBuffer )
Wolfgang
Wolfgang Riedmann
Meran, South Tyrol, Italy

www.riedmann.it - docs.xsharp.it

Please Log in or Create an account to join the conversation.

GetPrivateProfileString 1 week 1 day ago #12530

  lagraf's Avatar Topic Author lagraf Offline Posts: 62
Hallo Wolfgang,
PUBLIC VIRTUAL METHOD GetSection( cSection AS STRING ) AS ARRAY
...
IF IniFile.GetSectionX( cSection, pszBuffer, nMaxLen, "C:\WINAPPS\PDFMAIL\PDFMAIL.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
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?)

Please Log in or Create an account to join the conversation.

GetPrivateProfileString 1 week 1 day ago #12531

  wriedmann's Avatar wriedmann Offline Posts: 1995
Hallo Franz,

bitte ergänze oben in der PRG-Datei
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

www.riedmann.it - docs.xsharp.it

Please Log in or Create an account to join the conversation.

GetPrivateProfileString 1 week 1 day ago #12532

  lagraf's Avatar Topic Author lagraf Offline Posts: 62
Hallo Wolfgang,
damit bleibt nun noch zwei identische Meldungen bei der Zeile System.Text.Encoding.ASCII:
error XS1503: Argument 1: cannot convert from 'string' to 'char'

Please Log in or Create an account to join the conversation.

GetPrivateProfileString 1 week 1 day ago #12533

  wriedmann's Avatar wriedmann Offline Posts: 1995
Hallo Franz,

sorry, im VO-Dialekt muss man bei den einfachen Hochkommas definieren, dass die als Char zu interpretieren sind:
aEntries := Encoding.ASCII:GetString( pszBuffer ):Trim( c'\0' ):Split( c'\0' )
Mein Code ist nämlich im Core-Dialekt und gibt ein Dictionary zurück:
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( '\0' ):Split( '\0' )
		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

www.riedmann.it - docs.xsharp.it

Please Log in or Create an account to join the conversation.

GetPrivateProfileString 1 week 1 day ago #12534

  lagraf's Avatar Topic Author lagraf Offline Posts: 62
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?

Please Log in or Create an account to join the conversation.

GetPrivateProfileString 1 week 1 day ago #12536

  wriedmann's Avatar wriedmann Offline Posts: 1995
Hallo Franz,
auch meine VO-Version liefert Schlüsselworte und Werte zurück, in einem zweidimensionalen Array.

Was die Lösung über .NET betrifft: ich probiere das meistens über .NET zu lösen, weil die Lösung da fast immer wesentlich einfacher und leistungsfähiger ist. Für manche Dinge braucht es in VO viel eigenen Code, und in .NET ist es eine Zeile.
Ein gutes Beispiel ist z.B. die Methode Split() der String-Klasse. Die zerlegt einen String in Teile:
docs.microsoft.com/en-us/dotnet/api/syst...iew=netframework-4.8
Sowas habe ich zwar in VO, aber wesentlich weniger leistungsfähig und fehleranfälliger, und zudem nicht Unicode-fähig.
Was die Suche betrifft: Google ist der beste Freund, vielleicht kombiniert mit dem Zusatzwort C#. StackOverflow bietet sehr oft gute Lösungen, aber auch die Microsoft-Seiten selber.
Und der Rest ist viel Probieren....
Wolfgang
Wolfgang Riedmann
Meran, South Tyrol, Italy

www.riedmann.it - docs.xsharp.it

Please Log in or Create an account to join the conversation.

GetPrivateProfileString 1 week 1 day ago #12538

  lumberjack's Avatar lumberjack Offline Posts: 631
Hi Franz,

lagraf wrote: Ich lese einen String aus einer INI-Datei mit:

I wrote a .INI file reader in the Vulcan days that does not require the Win32 API calls. Not sure if you have it, otherwise please let me know and I can submit it.
______________________
Johan Nel
George, South Africa

Please Log in or Create an account to join the conversation.

GetPrivateProfileString 1 week 1 day ago #12540

  wriedmann's Avatar wriedmann Offline Posts: 1995
Hi Johan,
yes, I know your code (and I have similar code from my Clipper times <g>).
But I do prefer using the Windows API to be 100% compatible with VO and other applications that access Ini files.
Wolfgang
Wolfgang Riedmann
Meran, South Tyrol, Italy

www.riedmann.it - docs.xsharp.it

Please Log in or Create an account to join the conversation.

GetPrivateProfileString 1 week 1 day ago #12544

  lagraf's Avatar Topic Author lagraf Offline Posts: 62
Hi Johan,
thank you for your offer, but I use GetPrivateProfileString in my INI reader in all my apps for years and with the code of Karl-Heinz it also does well in X#! If M$ deletes this call in the future I would come back to you!
Franz

Please Log in or Create an account to join the conversation.

  • Page:
  • 1
Moderators: wriedmann