Array mit Prozessen

Deutschsprachiges X#-Forum – German language forum

Moderator: wriedmann

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

Array mit Prozessen

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

Delegates

Post 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
Wolfgang Riedmann
Meran, South Tyrol, Italy
wolfgang@riedmann.it
https://www.riedmann.it - https://docs.xsharp.it
User avatar
robert
Posts: 4518
Joined: Fri Aug 21, 2015 10:57 am
Location: Netherlands

Delegates

Post 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
XSharp Development Team
The Netherlands
robert@xsharp.eu
User avatar
wriedmann
Posts: 3755
Joined: Mon Nov 02, 2015 5:07 pm
Location: Italy

Delegates

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

Delegates

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

Delegates

Post 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
Wolfgang Riedmann
Meran, South Tyrol, Italy
wolfgang@riedmann.it
https://www.riedmann.it - https://docs.xsharp.it
User avatar
Chris
Posts: 4898
Joined: Thu Oct 08, 2015 7:48 am
Location: Greece

Delegates

Post 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!
Chris Pyrgas

XSharp Development Team
chris(at)xsharp.eu
User avatar
wriedmann
Posts: 3755
Joined: Mon Nov 02, 2015 5:07 pm
Location: Italy

Delegates

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

Delegates

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

Delegates

Post 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
Wolfgang Riedmann
Meran, South Tyrol, Italy
wolfgang@riedmann.it
https://www.riedmann.it - https://docs.xsharp.it
Post Reply