xsharp.eu • Array mit Prozessen
Page 1 of 5

Array mit Prozessen

Posted: Wed Dec 18, 2019 11:07 am
by lagraf
ich versuche meine VO apps mit dem XPorter nach X# zu transportieren, bei den Spielerei apps kein Problem. Jetzt bin ich aber bei einer etwas anspruchsvolleren app angelangt, wo ich an 2 Stellen Probleme bekomme:

1) Delegate bei EnumWindows
aWindows := ArrayCreate(1024)
aWindows[1] := 0 // Anzahl der ermittelten Elemente
aWindows[2] := 1024 // maximale Anzahl der Elemente
aWindows[3] := 3 // Startelement-1
#warning Callback function modified to use a DELEGATE by xPorter. Please review.
// EnumWindows(@OGS_EnumAddItemToArray(),LONGINT(_CAST,aWindows))
STATIC LOCAL oOGS_EnumAddItemToArrayDelegate := OGS_EnumAddItemToArray AS OGS_EnumAddItemToArray_Delegate
EnumWindows(System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate(oOGS_EnumAddItemToArrayDelegate),LONGINT(_CAST,aWindows))

Die XIDE Meldungen dazu:
warning XS1030: Callback function modified to use a delegate ...
error XS0030 Cannot convert type ARRAY to INT

2) Die Umformung auf Delegate erhalte ich auch bei einer anderen Callback-Methode mit der ich ein Verzeichnis überwache:
#warning Callback function modified to use a DELEGATE by xPorter. Please review.
// ptrCallBack := @RunMethodWaitForChanges()
STATIC LOCAL oRunMethodWaitForChangesDelegate := RunMethodWaitForChanges AS RunMethodWaitForChanges_Delegate
ptrCallBack := System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate(oRunMethodWaitForChangesDelegate)

Was genau machen die Delegates, kann man den Code so lassen wie ihn der XPorter erstellt hat oder ist da noch etwas zu machen?

Wie ist der Fehler XS0030 zu korrigieren?

Delegates

Posted: Wed Dec 18, 2019 12:23 pm
by wriedmann
Hallo Franz,
das, was man in VO mit Callbacks so machen konnte, war sehr gefährlich. Daher lässt .NET das so auch nicht mehr zu.
Ein Delegate ist im Prinzip die Typisierung eines Funktions-Pointers, die sicherstellt, dass nur eine passende Funktionsadresse zurückgegeben werden kann.
Der XPorter macht hier, was er kann - und setzt explizit ein Warning an diese Stelle, mit der Aufforderung, diesen Code zu überprüfen. Denn eine komplett automatisierte Umsetzung ist nicht möglich - da eben auf VO-Seite diese Typisierung fehlt.
Kannst Du mal Deinen VO-Code zeigen?
Dann wird Dir sicher jemand zeigen, wie man den korrekt nach X# umsetzt.
Wolfgang
P.S. mein Code für EnumWindows schaut so aus (mit Hilfe von Chris):

Code: Select all

function XSGetWindowsArray() as array pascal
	local aWindows as array
	local oGCHandle as System.Runtime.InteropServices.GCHandle
	local oPtr as IntPtr
	local oDelegate as EnumWindowsProc_delegate
	static local oEnumWindowsProcDelegate := EnumWindowsProc as EnumWindowsProc_Delegate

	aWindows := {}
	oDelegate := EnumWindowsProc
	oGCHandle := System.Runtime.InteropServices.GCHandle.Alloc( aWindows )
	oPtr := System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate( oDelegate )
	EnumWindows( oPtr, System.Runtime.InteropServices.GCHandle.ToIntPtr( oGCHandle ) )

	return aWindows

delegate EnumWindowsProc_delegate( hWnd as ptr, aWindows as array ) as word

function EnumWindowsProc(hwnd as ptr, lParam as IntPtr) as logic
	local aWindows as array
	local gch as System.Runtime.InteropServices.GCHandle

	gch := System.Runtime.InteropServices.GCHandle.FromIntPtr(LParam)
	aWindows := (array)gch:Target
	AAdd( aWindows, hwnd )

	return true

Delegates

Posted: Wed Dec 18, 2019 12:37 pm
by robert
Wolfgang,

Your code does not show that so I am not sure if you have it, but when you call GCHandle.Alloc() you also need to call GcHandle.Free() on the oGcHandle that was returned by GcHandle.Alloc(), or otherwise you have introduced a memory leak.

Robert

Delegates

Posted: Wed Dec 18, 2019 12:44 pm
by wriedmann
Hi Robert,

you can be sure that there is no GcHandle.Free - clearly an error of mine.

Thank you very much!

I will add it immediatly.

Wolfgang
P.S. this is the fixed code:

Code: Select all

function XSGetWindowsArray() as array pascal
	local aWindows as array
	local oGCHandle as System.Runtime.InteropServices.GCHandle
	local oPtr as IntPtr
	local oDelegate as EnumWindowsProc_delegate
	static local oEnumWindowsProcDelegate := EnumWindowsProc as EnumWindowsProc_Delegate

	aWindows := {}
	oDelegate := EnumWindowsProc
	oGCHandle := System.Runtime.InteropServices.GCHandle.Alloc( aWindows )
	oPtr := System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate( oDelegate )
	EnumWindows( oPtr, System.Runtime.InteropServices.GCHandle.ToIntPtr( oGCHandle ) )
	oGCHandle:Free()

	return aWindows

delegate EnumWindowsProc_delegate( hWnd as ptr, aWindows as array ) as word

function EnumWindowsProc(hwnd as ptr, lParam as IntPtr) as logic
	local aWindows as array
	local gch as System.Runtime.InteropServices.GCHandle

	gch := System.Runtime.InteropServices.GCHandle.FromIntPtr(LParam)
	aWindows := (array)gch:Target
	AAdd( aWindows, hwnd )

	return true

Delegates

Posted: Wed Dec 18, 2019 3:11 pm
by lagraf
Hallo Wolfgang,
ich ermittle mit dieser Funktion in VO die Titel der laufenden Programme, vielleicht gibt es dafür bereits eine fertige Funktion für X#, der Aufruf gibt ein Array der Titel zurück: aWin := OGS_EnumWindows()

Code: Select all

FUNCTION OGS_EnumWindows() AS ARRAY PASCAL  // ohne Fehlerabfrage bei mehr als 1024 Tasks!
LOCAL aWindows AS ARRAY
	
aWindows := ArrayCreate(1024)
aWindows[1] := 0			        // Anzahl der ermittelten Elemente
aWindows[2] := 1024		                // maximale Anzahl der Elemente
aWindows[3] := 3		                // Startelement-1
EnumWindows(@OGS_EnumAddItemToArray(),LONGINT(_CAST,aWindows))
aWindows := ADel(aWindows,1)                 		// Vorspann entfernen (3 Elemente)
aWindows := ADel(aWindows,1)
aWindows := ADel(aWindows,1)
aWindows := ASize(aWindows,ALen(aWindow)-3)
RETURN aWindows

STATIC FUNCTION OGS_EnumAddItemToArray(ptrWnd AS PTR , aWindows AS ARRAY) AS WORD CALLBACK
IF aWindows[1] <= aWindows[2]							// Anzahl Elemente <= Max. Anzahl Elemente?
	aWindows[++aWindows[3]] := ptrWnd					// Handle abspeichern
	aWindows[1] := ++aWindows[1]						// Anzahl erhöhen
ELSE													// Array zu klein dimensioniert?
	aWindows[1] := -1									// Fehlercode retour
	RETURN 0
ENDIF
RETURN 1

Delegates

Posted: Wed Dec 18, 2019 3:20 pm
by wriedmann
Hallo Franz,
die Funktion, die ich weiter oben reingeschrieben habe, gibt Dir ein Array aller Handles aller Fenster zurück. Und das ist genau das, was Deine Funktion auch macht.
Wolfgang

Delegates

Posted: Wed Dec 18, 2019 6:28 pm
by Chris
Franz,

One of the very good things about .Net, is that there is a huge amount of people using it, so any question you have, has already been answered somewhere before. So, for whatever you are looking for, just search for it, I guarantee you you will find it! Just a tip, it usually helps to include "c#' as a term in your search, to make sure you get results regarding .Net. The results will be showing c# code, but it will be usually very easy to translate to X#.

So for this specific case, I opened googled and entered this search text: "c# get all apps working". This gave those results to me:

https://www.google.gr/search?ei=8Gz6XYK ... CAo&uact=5

The very first search results is: https://stackoverflow.com/questions/204 ... in-windows

Follow this, and you will see immediately the solution, you need to use Process.GetProcesses() to get an array of all processes currently running in the system. Admittedly, this specific answer is incomplete, it does not mention that the namespace of the Process class is System.Diagnostics, so you would actually need to use System.Diagnostics.Process.GetProcesses() or

USING System.Diagnostics
Process.GetProcesses()

And here's a "complete" sample:

Code: Select all

USING System.Diagnostics

FUNCTION Start() AS VOID
	FOREACH oProcess AS Process IN Process.GetProcesses()
		? "Process name:", oProcess:ProcessName
		? "Process title:", oProcess:MainWindowTitle
	NEXT
RETURN
As you can see, a lot of things (with some very notable exceptions though) can be done in .Net in A LOT easier and in a more intuitive way than what we were used to in VO!

Delegates

Posted: Wed Dec 18, 2019 9:18 pm
by wriedmann
Hi Chris,
I cannot agree more.... and therefore my VO applications are using more and more COM modules.
One of the latest things is that I'm using COM modules to access data from different SQL engines, from SQLite, MS SQL, MySQL to PostgreSQL. And why? Because using a .NET connection I don't need any configuration on the cxlient machine - only a few .NET DLLs. No more ODBC hassles or driver installations....
Wolfgang

Delegates

Posted: Thu Dec 19, 2019 7:09 am
by lagraf
Hi Chris
is there a FOREACH in XSharp? How can I do this without FOREACH?
This is my code but I think its not the best :)

Code: Select all

LOCAL oProcess AS OBJECT
LOCAL x AS DWORD
FOR x := 1 TO ALen(Process.GetProcesses())
	oProcess := Process.GetProcesses()[x]
	? oProcess:ProcessName
NEXT

Delegates

Posted: Thu Dec 19, 2019 7:52 am
by wriedmann
Hi Franz,
there is a foreach in X# - the code Chris has given you IS X# code.

Process.GetProcesses() is documented here:
https://docs.microsoft.com/en-us/dotnet ... mework-4.8
It returns an array - but a .NET array, ALen() does not works.

Code: Select all

local aProcess as Process[]
local nI as int
local nLen as int

aProcess := Process.GetProcesses()
nLen := aProcess:Length
for nI := 1 upto nLen
  ? "Process name:", aProcess[nI]:ProcessName
  ? "Process title:", aProcess[nI]:MainWindowTitle
next
Wolfgang