Seite 2 von 3

Verfasst: 15.03.2007 14:08
von PureBasic4.0
habe noch ein Problem. Wenn ich 2 #REG_MULTI_SZs in die Registry reingeschrieben habe und einen 3. reinschreibe, wird trotzdem noch ein Leerzeichen und eine 0 dahinter geschrieben. Ich bin mir sicher, dass ich der 3. Eintrag weder ein Leerzeichen noch eine 0 am Anfang bzw. am Ende hat. Warum wird das noch reingeschrieben? Ich benutze den gleichen Befehl.

Code: Alles auswählen

          string$ = "SYSTEM\ControlSet001\Services\Tcpip\Parameters\Interfaces\"+Handle$
          Reg_WriteMultiLineString(#HKEY_LOCAL_MACHINE,string$,"IPAddress",ip$)
          Reg_WriteMultiLineString(#HKEY_LOCAL_MACHINE,string$,"SubnetMask",subnetmask$)
          Reg_WriteMultiLineString(#HKEY_LOCAL_MACHINE,string$,"DefaultGateway",defaultgateway$)

Verfasst: 15.03.2007 14:40
von Shardik
Ich habe endlich und nachweisbar den Fehler lokalisiert:

Dieser Link brachte mich auf die richtige Spur:
http://www.winehq.org/pipermail/wine-de ... 00530.html

In einem Posting bezogen auf WineMine schreibt davep:
davep hat geschrieben: The problem here is that the 'count' parameter passed to RegSetValueEx is not the string length but the size of the entire buffer.
Und wenn man sich ts-softs Prozedur Reg_WriteMultiLineString() anschaut, sieht man, daß er beim Aufruf von

Code: Alles auswählen

Error = RegSetValueEx_(hKey, ValueName, 0, #REG_MULTI_SZ, Mem, MemorySize(Mem) + SizeOf(Character))
als Puffergröße mit MemorySize(Mem) + SizeOf(Character) zu der Puffergröße auch noch 1 Byte bei ASCII bzw. 2 Byte bei Unicode dazu addiert, was natürlich falsch ist. Nur bei der Angabe der String-Länge müßte noch das/die Null-Abschlußbyte(s) mit angegeben werden... :wink:

Korrigiert werden müßten daher in der PBOSL_Registry-Bibliothek folgende beiden Zeilen:
Wie in meinem ersten Posting beschrieben ist die Puffergröße zu klein:

Code: Alles auswählen

Mem = AllocateMemory((MemoryStringLength(@Value) + 1) * SizeOf(Character))
muß abgeändert werden in

Code: Alles auswählen

Mem = AllocateMemory((MemoryStringLength(@Value) + 2) * SizeOf(Character)) 
Und der Puffergrößenwert muß korrigiert werden. Statt

Code: Alles auswählen

Error = RegSetValueEx_(hKey, ValueName, 0, #REG_MULTI_SZ, Mem, MemorySize(Mem) + SizeOf(Character))
muß diese Zeile verwendet werden:

Code: Alles auswählen

Error = RegSetValueEx_(hKey, ValueName, 0, #REG_MULTI_SZ, Mem, MemorySize(Mem))
Auch das von PureBasic4.0 beschriebene Problem bei dem nacheinander erfolgenden Schreiben von 3 Schlüsseln ist damit beseitigt! :allright:

Tut mir leid, daß die ganze Sache so lange gedauert hat, aber alle bisherigen Postings von mir hatte ich wirklich getestet, und sie liefen danach auch wirklich wiederholt stabil. Sogar die Fehler ließen sich immer wieder reproduzieren (außer nach ts-softs letztem Posting :twisted: ). Wahrscheinlich liegt dies an der Registry, sodaß nach mehrfachem Schreiben und Löschen eines Schlüssels der Eintrag zufällig genau paßte und deshalb kein Fehler mehr auftrat. Ich habe so etwas in meiner ganzen 26-jährigen Programmierpraxis noch nicht erlebt... /:->

Verfasst: 15.03.2007 15:48
von ts-soft

Code: Alles auswählen

Mem = AllocateMemory((MemoryStringLength(@Value) + 2) * SizeOf(Character)) 
Wenn Du mir jetzt noch die 2 in der Zeile erklären würdest, die ist unlogisch,
sollte eine 1 für das Nullbyte Sein, wird ja Multipliziert mit 2 im
Unicodemodus, so das 2 Nullbytes entstehen.

Verfasst: 15.03.2007 17:00
von Shardik
ts-soft hat geschrieben:

Code: Alles auswählen

Mem = AllocateMemory((MemoryStringLength(@Value) + 2) * SizeOf(Character))  
Wenn Du mir jetzt noch die 2 in der Zeile erklären würdest, die ist unlogisch,
sollte eine 1 für das Nullbyte Sein, wird ja Multipliziert mit 2 im
Unicodemodus, so das 2 Nullbytes entstehen.
Schau Dir einmal die von PureBasic4.0 erstellten Snapshots von REG_MULTI_SZ-Einträgen an, die mit Windows "per Hand" erstellt wurden (Rechtsklick auf Schlüssel, Auswahl von "Neu/Wert der mehrteiligen Zeichenfolge" und anschließende Eingabe einer Zeichenkette, z.B. einer IP-Adresse):

Diese Einträge sind nach der Eingabe und erneuten Ansicht mit "Binärwert bearbeiten" alle mit 2 Null-Bytes (ASCII) bzw. 4 Null-Bytes (Unicode) abgeschlossen. Wenn Du einen REG_MULTI_SZ-Eintrag mit mehreren Zeichenketten (z.B. IP-Adressen) suchst, dann sind die Einzeleinträge voneinander durch ein Null-Byte (ASCII) bzw. zwei Null-Bytes (Unicode) abgetrennt. Das bedeutet, daß zwei Null-Bytes (ASCII) bzw. vier Null-Bytes (Unicode) das Ende eines REG_MULTI_SZ-Eintrags anzeigen. Ein neu angelegter Key (nach Anlegen des Key-Namens und vor Eintragung eines Wertes) wird übrigens durch ein Null-Byte (ASCII) bzw. zwei Null-Bytes (Unicode) gekennzeichnet. Sobald ich dann einen beliebigen Wert "per Hand" eintrage, stehen hinter dem eingetragenen Wert dann 2 Null-Bytes (ASCII) bzw. 4 Null-Bytes (Unicode).

Wenn Du - wie in Deinem ursprünglichen Code - für den Puffer nur ein Byte (ASCII) bzw. zwei Bytes (Unicode) als Abschluß vorsiehst, dann werden irgendwelche Zufalls-Bytes (wie von PureBasic4.0 und mir beschrieben) mit eingetragen und es werden in RegEdit oft irgendwelche seltsamen Folgezeichen angezeigt, die im Schlüssel überhaupt nicht vorhanden sind. Deshalb hatte ich auch gewarnt vor etwaigen Folgen für die Registry-Struktur, die sich Anwender durch den Fehler in der Prozedur im schlimmsten Fall einhandeln könnten :evil:

Verfasst: 15.03.2007 17:16
von ts-soft
Nagut, lasse das mal so stehen, könnte was dran sein.

PS: In der Registry sind alle Einträge grundsätzlich in Unicode! Wird nur
durch die API automatisch gewandelt, nativ sind die Einträge Unicode

Verfasst: 15.03.2007 17:28
von PureBasic4.0
@all

ES HAT FUNKTIONIERT. DANKE!!!!

Verfasst: 15.03.2007 17:58
von Shardik
ts-soft hat geschrieben: Nagut, lasse das mal so stehen, könnte was dran sein.
Beweismaterial für den "ungläubigen Thomas" 8):

http://technet2.microsoft.com/WindowsSe ... x?mfr=true
Microsoft TechNet hat geschrieben: REG_MULTI_SZ - A multiple string. Values that contain lists or multiple values in a form that people can read are usually this type. Entries are separated by spaces, commas, or other marks.
http://www.microsoft.com/technet/archiv ... x?mfr=true
Microsoft TechNet hat geschrieben: REG_MULTI_SZ - A multiple string. Values that contain lists or multiple values in human readable text are usually this type. Entries are separated by NULL characters.
http://www.pctools.com/guides/article/id/1/page/2/
pctools.com hat geschrieben: REG_MULTI_SZ - This type is a multiple string used to represent values that contain lists or multiple values, each entry is separated by a NULL character. (This type is only available using an advanced registry editor such as REGEDT32)
http://www.stonebroom.com/rxdocs.htm
RegEx Component documentation hat geschrieben: REG_MULTI_SZ - 7 - Multiple unicode strings separated by ASCII zero characters and ending with two ASCII zero characters
http://msdn2.microsoft.com/en-us/library/ms724923.aspx
MSDN hat geschrieben: lpData - [in] The data to be stored.
For string-based types, such as REG_SZ, the string must be null-terminated. With the REG_MULTI_SZ data type, the string must be terminated with two null characters.
Interessant finde ich, daß das Microsoft TechNet unter verschiedenen Links unterschiedliche Beschreibungen veröffentlicht :wink:

Verfasst: 16.03.2007 09:06
von jpd
Hallo @All,

vermuten wir das ein Netzwerkkarte zwei IP adressen hat,


und ich nur eine davon ändern möchte, wie macht man das?

jpd

Verfasst: 16.03.2007 13:12
von Shardik
jpd hat geschrieben: Hallo @All,

vermuten wir das ein Netzwerkkarte zwei IP adressen hat,


und ich nur eine davon ändern möchte, wie macht man das?
Das macht man unter Zuhilfenahme von ts-softs PBOSL_Registry-Bibliothek, indem man die IP-Adressen über die Prozedur Reg_ReadMultiLineString() ausliest, verändert und dann über Reg_WriteMultiLineString() wieder zurückschreibt.

Die PBOSL_Registry Bibliothek hat ts-soft unter diesem Link im englischen Forum vorgestellt:
http://www.purebasic.fr/english/viewtopic.php?t=24614

Und hier kann man sie herunterladen:
http://www.ts-soft.eu/dl/pbosl_registry.zip

Allerdings sieht ts-softs Prozedur Reg_WriteMultiLineString() nicht die Umsetzung von Trennzeichen in Null-Bytes vor. Ich habe daher diese Prozedur entsprechend so modifiziert, daß bei unterschiedlichen Zeichenketten, die durch ein Linefeed (#LF$) getrennt sind, diese Linefeed-Codes durch ein (im ASCII-Modus) bzw. zwei (im Unicode-Modus) Null-Bytes ersetzt werden. In diesem lauffähigen Beispiel wird unter HKEY_CURRENT_USER ein neuer Eintrag "Test" mit dem Schlüssel "Gateway" angelegt, in den zwei IP-Adressen eingetragen werden, die durch ein Null-Byte (ASCII) bzw. zwei Null-Bytes (Unicode) getrennt sind:

Code: Alles auswählen

Global Reg_ErrorNr.l, Reg_ErrorMsg.s

Procedure Reg_SetLastError(Error.l = 0)
  Protected Buffer.l
  If Error
    Reg_ErrorNr = Error
  Else
    Reg_ErrorNr = GetLastError_()
  EndIf
  FormatMessage_(#FORMAT_MESSAGE_ALLOCATE_BUFFER|#FORMAT_MESSAGE_FROM_SYSTEM, 0, Reg_ErrorNr, 0, @Buffer, 0, 0)
  If Buffer
    Reg_ErrorMsg = PeekS(Buffer)
    LocalFree_(Buffer)
  EndIf
EndProcedure

Procedure Reg_ResetError()
  Reg_ErrorNr = 0
  Reg_ErrorMsg = ""
EndProcedure

ProcedureDLL.l Reg_WriteMultiLineString(topKey.l, KeyName.s, ValueName.s, Value.s); write a StringField, separate with #LF$, to specified ValueName
  Protected Result.l, hKey.l, Error.l, dwDisposition.l, Mem.l, i.L, NumLF.L, LFPos.L
  Reg_ResetError()

  If Right(KeyName, 1) = "" : KeyName = Left(KeyName, Len(KeyName) - 1) : EndIf
  Error = RegCreateKeyEx_(topKey, KeyName, 0, 0, #REG_OPTION_NON_VOLATILE, #KEY_ALL_ACCESS, 0, @hKey, @dwDisposition)
  If Error = #ERROR_SUCCESS
    Mem = AllocateMemory((MemoryStringLength(@Value) + 2) * SizeOf(Character)) 
    If Mem
      PokeS(Mem, Value)
      NumLF = CountString(Value, #LF$)
      If NumLF
        For i = 1 To NumLF
          LFPos = FindString(Value, #LF$, LFPos + 1)
          PokeB(Mem + LFPos * SizeOf(Character) - SizeOf(Character), 0)
        Next i
      EndIf
      Error = RegSetValueEx_(hKey, ValueName, 0, #REG_MULTI_SZ, Mem, MemorySize(Mem))
      If Error = #ERROR_SUCCESS
        Result = #True
      Else
        Reg_SetLastError(Error)
      EndIf
      FreeMemory(Mem)
    Else
      Reg_ErrorNr = -1
      Reg_ErrorMsg = "can't allocate memory"
    EndIf
  Else
    Reg_SetLastError(Error)
  EndIf
  If hKey : RegCloseKey_(hKey) : EndIf
  ProcedureReturn Result
EndProcedure


Reg_WriteMultiLineString(#HKEY_CURRENT_USER, "Test", "Gateway", "192.168.0.1" + #LF$ + "192.168.0.2")
Neben der Entfernung der zwei in vorigen Postings beschriebenen Bugs habe ich in der Prozedur Reg_WriteMultiLineString() folgende Einfügung vorgenommen, um die Linefeed-Zeichen gegen Null-Bytes auszutauschen, was ja nur im Pufferbereich erfolgen darf, da ein Null-Byte in einem String bekanntlich ein String-Ende anzeigt:

Code: Alles auswählen

NumLF = CountString(Value, #LF$)
If NumLF
  For i = 1 To NumLF
    LFPos = FindString(Value, #LF$, LFPos + 1)
    PokeB(Mem + LFPos * SizeOf(Character) - SizeOf(Character), 0)
  Next i
EndIf

Verfasst: 16.03.2007 16:58
von jpd
Hallo Shardik,


erstmal Dankeschön!!

mit der von dir modifizierte Reg_WriteMultiLineString() procedur

und mit eingeschalteten unicode (compiler option)

ohne "Null" zeichen auszutauschen.

kann ich folgendes machen:

Code: Alles auswählen

ip_val.s=Reg_ReadMultiLineString(#HKEY_CURRENT_USER, "Test", "Gateway")
Reg_WriteMultiLineString(#HKEY_CURRENT_USER, "Test", "Gateway", ip_val + "192.168.0.2") 






und tut's wunderbar!!! :)

Ciao
jpd