Autor Thema: NSFItemInfo: 64 Bit Problem?  (Gelesen 6610 mal)

Offline Johnson

  • Senior Mitglied
  • ****
  • Beiträge: 258
  • Geschlecht: Männlich
NSFItemInfo: 64 Bit Problem?
« am: 02.07.12 - 15:14:35 »
Hallo allerseits,

ich bastel gerade an einem Tool, welches alle Agenten von allen Datenbanken eines nach bestimmten Kriterien scannt. Bei einigen Eigentschaften von Agenten muss man bekanntlich auf die Notes-API zurückgreifen. Z.B. um die Laufzeiteinstellungen auszulesen.

Das Script läuft auf unseren Clients und auf unseren Servern, die OS-seitig noch auf 32Bit laufen, wunderprächtig.
Peau à peau werden die Server jedoch auf 64Bit Maschinen umgezogen.

Nun habe ich beim Aufruf der API-Funktion NSFItemInfo ein Problem. Beim ersten Analysieren auf einem 64Bit-System ist mir aufgefallen, dass nach dem Aufruf der Funktion NSFItemInfo Block der BLOCKIDs jeweils auf "0" gesetzt ist, was nicht so sein sollte.
Das hätte zur Folge, dass im nächsten Schritt, wenn die Funktion OSLockObject aufgerufen werden soll, sich die Maschine verabschiedet.

Nun weiß ich, dass sich einige Datentypen auf 64Bit Maschinen geändert haben. Zumindest die Größen der Datentypen. Hat hier die Notes-API ein Problem, oder habe ich hier was falsch deklariert?

Anbei ein Code für einen Testagenten:


Code
Option Public
Option Declare


Const wAPIModule = "nnotes"

Type AssistInfo
	Version As Integer
	TriggerType As Integer  ' 0 none, 1 schedule, 2 new mail, 3 paste, 4 manual, 5 update, 6 router
	SearchType As Integer  ' 0 none, 1 all, 2 new, 3 new/mod, 4 selected, 5 view, 6 unread, 7 prompt, 8 UI
	IntervalType As Integer  ' 0 none, 1 minutes, 2 days, 3 weeks, 4 months
	Interval As Integer
	Time1 As Variant  ' Start time (ms since midnight)
	Time2 As Variant  ' Long (weekday or day of month) or end time (ms since midnight)
	StartTime As Variant  ' Time/Date
	EndTime As Variant  ' Time/Date
	Flags As Long  ' 1 hidden, 2 no weekends, 4 store highlights, 8 mail/paste, 16 choose server
	Spare(15) As Long
End Type

Type BlockID
	hPool As Long
	Block As Long
End Type

Declare Private Function W64_NSFDbClose Lib wAPIModule Alias "NSFDbClose" (Byval DBHANDLE As Long) As Integer
Declare Private Function W64_NSFDbOpen Lib wAPIModule Alias "NSFDbOpen" (Byval strPathName As String, DBHANDLE As Long) As Integer
Declare Private Function W64_NSFItemInfo Lib wAPIModule Alias "NSFItemInfo" (Byval NOTEHANDLE As Long, Byval strItemName As String, Byval wItemNameLength As Integer,  BLOCKID_Item As BlockID, wDataType As Integer, BLOCKID_Value As BlockID, dwValueLength As Long) As Integer
Declare Private Function W64_NSFNoteClose Lib wAPIModule Alias "NSFNoteClose" (Byval NOTEHANDLE As Long) As Integer
Declare Private Function W64_NSFNoteOpen Lib wAPIModule Alias "NSFNoteOpen" (Byval DBHANDLE As Long, Byval NOTEID As Long, Byval WORD_FLAGS As Integer, NOTEHANDLE As Long) As Integer
Declare Private Function W64_OSLoadString Lib wAPIModule Alias "OSLoadString" (Byval HMODULE_hModule As Long, Byval STATUS_StringCode As Integer, Byval CharFar_RetBuffer As String, Byval WORD_BufferLength As Integer) As Integer
Declare Private Function W64_OSLockObject Lib wAPIModule Alias "OSLockObject" (Byval HANDLE As Double) As Double
Declare Private Function W64_OSPathNetConstruct Lib wAPIModule Alias "OSPathNetConstruct" (Byval lngPortName As Long, Byval strServerName As String, Byval strFileName As String, Byval strPathName As String) As Integer
Declare Private Function W64_OSUnlockObject Lib wAPIModule Alias "OSUnlockObject" (Byval HANDLE As Double) As Boolean


	
Sub Initialize
	
	Dim ai As AssistInfo
	Dim bid_item As BLOCKID
	Dim bid_value As BLOCKID
	Dim ag As NotesAgent
	Dim db As NotesDatabase
	Dim dbl_pointer As Double
	Dim doc As NotesDocument
	Dim int_apiresult As Integer
	Dim int_valuedatatype As Integer
	Dim lng_dbhandle As Long
	Dim lng_notehandle As Long
	Dim lng_noteid As Long
	Dim lng_valuelen As Long
	Dim s As NotesSession
	Dim str_filepath As String
	Dim str_netfilepath As String
	Dim str_server As String
	Dim str_unid As String
	Const NULLHANDLE = 0&
	Const NOERROR = 0
	Const ASSIST_INFO_ITEM = "$AssistInfo"
	
	
' ### initialize ###
	
	Set s = New NotesSession
	Set db = s.CurrentDatabase
	Set ag = s.CurrentAgent
	lng_dbhandle = NULLHANDLE
	
	
' ### get agent's design document ###
	
	str_unid = Strleft(Strright(ag.NotesURL, ".nsf/"), "?OpenAgent")
	Print {Universal ID = } & str_unid
	Set doc = db.GetDocumentByUNID(str_unid)
	If doc Is Nothing Then
		Print {Could not find agent's design document by universal ID "} & str_unid & {"!}
		Goto terminate
	End If
	
	
' ### get the network file name ###
	
	str_server = db.Server
	str_filepath = db.FilePath
	str_netfilepath = Space(1024)
	int_apiresult = W64_OSPathNetConstruct(0, str_server, str_filepath, str_netfilepath)
	If Not(int_apiresult = NOERROR) Then
		Print "Error due calling OSPathNetConstruct: " & APIError(int_apiresult)
		Goto terminate
	End If
	
	
' ### open database handle ###
	
	int_apiresult = W64_NSFDbOpen(str_netfilepath, lng_dbhandle)
	If Not(int_apiresult = NOERROR) Then
		Print "Error due calling NSFDbOpen: " & APIError(int_apiresult)
		Goto terminate
	Else
		Print "lng_dbhandle = " & lng_dbhandle
	End If
	
	
' ### open agent's note handle ###
	
	lng_noteid = Clng("&H" & doc.NoteID)
	Print "lng_noteid = " & lng_noteid
	int_apiresult = W64_NSFNoteOpen(lng_dbhandle, lng_noteid, 0, lng_notehandle)
	If Not(int_apiresult = 0) Then
		Print "Error due calling NSFNoteOpen: " & APIError(int_apiresult)
		Goto close_db_handle
	Else
		Print "lng_notehandle = " & lng_notehandle
	End If
	
	
' ### read assist info item ###
	
	int_apiresult = W64_NSFItemInfo(lng_notehandle, ASSIST_INFO_ITEM, Len(ASSIST_INFO_ITEM), bid_item, int_valuedatatype, bid_value, lng_valuelen)
	If Not(int_apiresult = NOERROR) Then
		Print "Error due calling NSFItemInfo: " & APIError(int_apiresult)
		Goto close_note_handle
	Else
		Print "bid_item.hPool = " & bid_item.hPool
		Print "bid_item.Block = " & bid_item.Block
		Print "int_valuedatatype = " & int_valuedatatype
		Print "bid_value.hPool = " & bid_value.hPool
		Print "bid_value.Block = " & bid_value.Block
		Print "lng_valuelen = " & lng_valuelen
	End If
	
	
' ### lock object ###
	
	' !!! because of a NULLBLOCK (bid_value.Block) the next call causes a PANIC on a server running on a 64 bit system
	'dbl_pointer = W64_OSLockObject(bid_value.hPool&) + (bid_value.Block&)
	
	
' ### unlock object ###
	
	'If W64_OSUnlockObject(bid_value.hPool) = False Then
	'	Print "Error due calling apiOSUnlockObject"
	'End If
	
	
' ### close note handle ###
	
close_note_handle:
	int_apiresult = W64_NSFNoteClose(lng_notehandle)
	If Not(int_apiresult = NOERROR) Then
		Print "Error due calling NSFNoteClose: " & APIError(int_apiresult)
		Goto terminate
	End If
	
	
' ### close database handle ###
	
close_db_handle:
	int_apiresult = W64_NSFDbClose(lng_dbhandle)
	If Not(int_apiresult = NOERROR) Then
		Print "Error due calling NSFDbClose: " & APIError(int_apiresult)
		Goto terminate
	End If
	
	
' ### termiante ####
	
terminate:
	Set doc = Nothing
	Set ag = Nothing
	Set db = Nothing
	Set s = Nothing
	
End Sub


Function APIError(int_code As Integer)
	Dim str_text As String
	str_text = String$(1024, " ")
	Call W64_OSLoadString(0, int_code And &H3FFF, str_text, 1024)
	If Not(Instr(str_text, Chr$(0)) = 0) Then str_text = Left$(str_text, Instr(str_text, Chr$(0)) - 1)
	If str_text = "" Or str_text = "No error" Then str_text = "Unknown error (&H" & Hex$(int_code) & ")"
	APIError = str_text
End Function
Gruß
Johnson

Offline pram

  • Gold Platin u.s.w. member:)
  • *****
  • Beiträge: 1.170
  • Geschlecht: Männlich
    • Foconis Object Framework
Re: NSFItemInfo: 64 Bit Problem?
« Antwort #1 am: 02.07.12 - 20:24:18 »
Die Deklaration von OSLockObject ist
Code
void far * LNPUBLIC OSLockObject(DHANDLE Handle);
Rückgabe ist also ein 64-Bit Pointer (=Double) und DHANDLE ist ebenfalls 64bittig. Müsste passen

Aber BlockID hast du scheinbar falsch definiert richtig wäre:
Code
typedef struct {
  DHANDLE pool;  /* pool handle */
  BLOCK  block; /* block handle */
} BLOCKID;
typedef WORD BLOCK;  /* pool block handle */
Das sind 1x 64bit (DHANDLE)  + 1x 16 bit (BLOCK), also
Code
Type BlockID
	hPool As Double
	Block As Integer
End Type
Ein Double ist zwar grundsätzlich zum Speichern von 64-Bit Zeigern geeignet, aber Zeigerarithmetik geht dann nicht wie du sie hier machst:
Code
dbl_pointer = W64_OSLockObject(bid_value.hPool&) + (bid_value.Block&)
Mit einem Currency könnte es gehen (bid_value.Block müsste ggf durch 10000 dividiert werden oder ein "Type" mit 4 Integers mit memcpy in einen currency rein kopiert werden) oder was auch gehen könnte, wären 2 Longs, dann muss man sich allerdings um den Überlauf kümmern:

Code
Type W64BitPtr
	ptrLo As Long
	ptrHi As Long
end type
Type BlockID
	hPoolLo As Long
	hPoolHi As Long
	Block As Integer
End Type
Aber Achtung: Ggf. führt LotusScript aber unter 64 Bit auch ein 64bit Alignment durch, Longs werden auf 32bit-Systemen jedenfalls an 32bit-Grenzen ausgerichtet. Sowas hat mich schon mal viel Nerven gekostet:
Code
Type myDataType
	einInt as Integer
	' hier bleiben jetzt 2 Bytes frei
	einLong as Long
End type
myDataType ist somit 8 Byte groß, anstatt 6 wie ich das erwartet hätte.



Gruß
Roland
« Letzte Änderung: 02.07.12 - 22:11:18 von pram »
Roland Praml

IBM Certified Application Developer - Lotus Notes and Domino 8
Ich verwende das Foconis Object Framework

Offline Johnson

  • Senior Mitglied
  • ****
  • Beiträge: 258
  • Geschlecht: Männlich
Re: NSFItemInfo: 64 Bit Problem?
« Antwort #2 am: 03.07.12 - 17:57:56 »
Hm. Für deine Tipps bin ich erst einmal sehr dankbar. Alles irgendwie einleuchtend.

Ein kleines "aber": Einfach mal von der Funktion OSLockObject abgesehen, der Rückgabewert in bid_item.Block und bid_value.Block vom Aufruf der Funktion NSFItemInfo ist jedes Mal 0. Damit crasht Notes beim Aufruf der OSLockObject.
Also liegt mein Problem bereits bei der Funktion NSFItemInfo und sehr wahrscheinlich bei den Datentypen der BlockID-Struktur, was ja ein Test auf einer 32bit Maschine bestätigte. Dort ist jeweils der korrekte Wert angegeben.

BLOCKID

Zitat
A memory block consists of a "pool" subdivided in to "blocks". The pool member of a BLOCKID stores the handle to an allocated area of memory. The block member of a BLOCKID stores an offset to some position in the pool.

Pool enthält in meinem Fall immer das Handle des Dokumentes (lng_notehandle). Block ist nach der Dokumentation zu urteilen also dann die Stelle des Speicher, in dem der Feldname (bid_item.Block) bzw. der Feldwert (bid_value.Block) steht. Da der 0 ist, kann ich mir sehr gut vorstellen, warum dann die Funktion OSLockObject den Server "runterfährt".

Hier habe ich die Tipps jeweils ausprobiert und mir den Wert nach Aufruf von NSFItemInfo ausgeben lassen:


hPool As Long

Code
Type BlockID
	hPool As Long
	Block As Integer
End Type

Zitat
Universal ID = A815346C35057EE2C1257A2F00389499
lng_dbhandle = 610
lng_noteid = 1817006
lng_notehandle = 11261
bid_item.hPool = 11261
Bin(bid_item.hPool) = 10101111111101
bid_item.Block = 0
int_valuedatatype = 17
bid_value.hPool = 11261
Bin(bid_value.hPool) = 10101111111101
bid_value.Block = 0
lng_valuelen = 104


hPool As Double

Code
Type BlockID
	hPool As Double
	Block As Integer
End Type

Zitat
Universal ID = A815346C35057EE2C1257A2F00389499
lng_dbhandle = 623
lng_noteid = 1817006
lng_notehandle = 14377
bid_item.hPool = 0
Bin(bid_item.hPool) = 0
bid_item.Block = 0
int_valuedatatype = 17
bid_value.hPool = 0
Bin(bid_value.hPool) = 0
bid_value.Block = 0
lng_valuelen = 104


hPool As Currency

Code
Type BlockID
	hPool As Currency
	Block As Integer
End Type

Zitat
Universal ID = A815346C35057EE2C1257A2F00389499
lng_dbhandle = 570
lng_noteid = 1817006
lng_notehandle = 11208
bid_item.hPool = 1078895785,876
Bin(bid_item.hPool) = 1000000010011101010010010101010
bid_item.Block = 0
int_valuedatatype = 17
bid_value.hPool = 1133871367,2648
Bin(bid_value.hPool) = 1000011100101011000000100000111
bid_value.Block = 0
lng_valuelen = 104


hPoolLo As Long & hPoolHi as Long

Code
Type BlockID2
	hPoolLo As Long
	hPoolHi As Long
	Block As Integer
End Type

Zitat
Universal ID = A815346C35057EE2C1257A2F00389499
lng_dbhandle = 707
lng_noteid = 1817006
lng_notehandle = 10974
bid_item.hPoolLo = 10974
bid_item.hPoolHi = 0
Bin(bid_item.hPoolLo) = 10101011011110
Bin(bid_item.hPoolHi) = 0
bid_item.Block = 0
int_valuedatatype = 17
bid_value.hPoolLo = 10974
bid_value.hPoolHi = 0
Bin(bid_value.hPoolLo) = 10101011011110
Bin(bid_value.hPoolHi) = 0
bid_value.Block = 0
lng_valuelen = 104

Stehe ich hier grad so dermaßen auf dem Schlauch?
Gruß
Johnson

Offline pram

  • Gold Platin u.s.w. member:)
  • *****
  • Beiträge: 1.170
  • Geschlecht: Männlich
    • Foconis Object Framework
Re: NSFItemInfo: 64 Bit Problem?
« Antwort #3 am: 03.07.12 - 22:01:08 »
Hallo Johnson, Hab hier evtl noch einen Fehler gefunden:

NSFItemInfo
Code
STATUS LNPUBLIC NSFItemInfo(
NOTEHANDLE note_handle,   // 64 bit -> currency oder 2x Long in LotusScript
const char far *item_name,   // hoffe mal das LS hier mittels byVal einen richtigen Pointer erzeugt
WORD name_len,                  // 16 bit -> Integer
BLOCKID far *item_blockid,   // Blockid -> siehe letzter Post
WORD far *value_datatype,  // 16 bit -> Integer
BLOCKID far *value_blockid,
DWORD far *value_len);        // 32bit -> Long
NOTEHANDLE ist ein DHANDLE und somit 64 bit
http://www-12.lotus.com/ldd/doc/tools/c/8.5.2/api852ref.nsf/852561bd0045e8e785255b3c005a57bb
/9778558d7d50086b482573fb003214e0?OpenDocument

Du hast aber einen Long verwendet. Probier mal:

Declare Private Function W64_NSFItemInfo Lib wAPIModule Alias "NSFItemInfo" (Byval NOTEHANDLE As Currency, Byval strItemName As String, Byval wItemNameLength As Integer,  BLOCKID_Item As BlockID, wDataType As Integer, BLOCKID_Value As BlockID, dwValueLength As Long) As Integer

ODER

Declare Private Function W64_NSFItemInfo Lib wAPIModule Alias "NSFItemInfo" (Byval NOTEHANDLE_LO As Long, Byval NOTEHANDLE_HI As Long,  Byval strItemName As String, Byval wItemNameLength As Integer,  BLOCKID_Item As BlockID, wDataType As Integer, BLOCKID_Value As BlockID, dwValueLength As Long) As Integer

Die Anzahl der Parameter muss nicht mit der C-Deklaration übereinstimmen, lediglich die Gesamtanzahl der Bytes, die beim DLL-Call auf den Stack geschoben werden. (du könntest auch 8 einzelne Byte-Variablen als NOTEHANDLE übergeben)

Noch was: Du kannst (zumindest unter 32 Bit) auf die undokumentierte Variable NotesDocument.Handle zugreifen, dann kannst du dir das Öffnen über die C-API sparen (Du musst dir den Agent halt als Dokument holen, z.B. mit einer DesignCollection)

Und nun der evtl entscheidende Tipp: Wenns dir nur um das Auslesen bestimmter Einstellungen geht, wäre vielleicht der Weg über DXL-Export der deutlich einfachere, v.a. plattformunabhängiger (Man kann über DXL-Import auch Einstellungen mit geringen Einschränkungen zurückschreiben)

Gruß
Roland
Roland Praml

IBM Certified Application Developer - Lotus Notes and Domino 8
Ich verwende das Foconis Object Framework

Offline Johnson

  • Senior Mitglied
  • ****
  • Beiträge: 258
  • Geschlecht: Männlich
Re: NSFItemInfo: 64 Bit Problem?
« Antwort #4 am: 09.07.12 - 15:53:08 »
Hallo Roland,

ich habe deinen evtl. entscheidenden Tipp befolgt und den Scanner so umgebaut, dass er die Eigenschaften des Agenten über NotesDXLExporter ausliest.

Ansicht hat alles geklappt. Nur können wir so keine Agenten auslesen, deren Datenbanken ein verstecktes Design haben. "DXL exporter operation failed".
Und wie bekommt man raus, ob das Design einer Datenbank versteckt ist? Über die DBREPLICAINFO-Struktur und die Notes API.  :-:
Das werde ich noch versuchen einzubauen und dann ist erstmal Schluss. Einen größeren Aufwand lässt der Nutzen nicht mehr zu. ;-)
Wäre aber toll gewesen, wenn's geklappt hätten.

Vielen Dank für die Mühen! Evtl. werde ich mich wieder daran zu schaffen machen, wenn ich mal ein bisschen Luft hab.

Schöne Grüße aus dem sonnigen Stuttgart
Johnson
Gruß
Johnson

Offline pram

  • Gold Platin u.s.w. member:)
  • *****
  • Beiträge: 1.170
  • Geschlecht: Männlich
    • Foconis Object Framework
Re: NSFItemInfo: 64 Bit Problem?
« Antwort #5 am: 09.07.12 - 16:05:35 »
Probier mal das Roh-DXL  zu exportieren, dabei werden die Items nicht in das Design zurückkonvertiert (ForceNoteFormat = true)
Ggf. auch im DXL Exporter ExitOnFirstError = false setzen und das Exporter-Log kontrollieren.

Gruß
Roland

Roland Praml

IBM Certified Application Developer - Lotus Notes and Domino 8
Ich verwende das Foconis Object Framework

 

Impressum Atnotes.de  -  Powered by Syslords Solutions  -  Datenschutz