Besserer Aufbau einer Funktion mit DllCalls

Stelle Fragen zur Programmierung mit Autohotkey

Moderator: jNizM

User avatar
jNizM
Posts: 3183
Joined: 30 Sep 2013, 01:33
Contact:

Besserer Aufbau einer Funktion mit DllCalls

18 Oct 2013, 05:44

Besserer Aufbau einer Funktion mit DllCalls

Wie wär der beste Aufbau (schneller / ressourcenschonender)? So wie hier? Object? Arrays? xyz?
Vor allem wegen immer wieder kehrende Abfragen nach dem aktuellen Stand.

Code: Select all

MsgBox,, GlobalMemoryStatusEx, % "GlobalMemoryStatusEx function /`n"
        . "MEMORYSTATUSEX structure`n`n"
        . "Lenght:`t`t`t"             GlobalMemoryStatusEx(0)  "`n`n"
        . "MemoryLoad:`t`t"           GlobalMemoryStatusEx(1)  " %`n`n"
        . "TotalPhys:`t`t`t"          GlobalMemoryStatusEx(2)  " MB`n"
        . "AvailPhys:`t`t`t"          GlobalMemoryStatusEx(3)  " MB`n`n"
        . "TotalPageFile:`t`t"        GlobalMemoryStatusEx(4)  " MB`n"
        . "AvailPageFile:`t`t"        GlobalMemoryStatusEx(5)  " MB`n`n"
        . "TotalVirtual:`t`t"         GlobalMemoryStatusEx(6)  " MB`n"
        . "AvailVirtual:`t`t"         GlobalMemoryStatusEx(7)  " MB`n`n"
        . "AvailExtendedVirtual:`t`t" GlobalMemoryStatusEx(8)

GlobalMemoryStatusEx(GMS = 1) {
    VarSetCapacity(MEMORYSTATUSEX, 64, 0)
    NumPut(64, MEMORYSTATUSEX)
    DllCall("GlobalMemoryStatusEx", "Ptr", &MEMORYSTATUSEX)
    return, % (GMS = "0") ? NumGet(MEMORYSTATUSEX,  0, "UInt")  : (GMS = "1") ? NumGet(MEMORYSTATUSEX,  4, "UInt")
            : (GMS = "2") ? NumGet(MEMORYSTATUSEX,  8, "Int64") : (GMS = "3") ? NumGet(MEMORYSTATUSEX, 16, "Int64")
            : (GMS = "4") ? NumGet(MEMORYSTATUSEX, 24, "Int64") : (GMS = "5") ? NumGet(MEMORYSTATUSEX, 32, "Int64")
            : (GMS = "6") ? NumGet(MEMORYSTATUSEX, 40, "Int64") : (GMS = "7") ? NumGet(MEMORYSTATUSEX, 48, "Int64")
            : (GMS = "8") ? NumGet(MEMORYSTATUSEX, 56, "Int64") : "FAIL"
}
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile
strobo
Posts: 125
Joined: 30 Sep 2013, 15:24

Re: Besserer Aufbau einer Funktion mit DllCalls

18 Oct 2013, 06:17

Code: Select all

gms := GlobalMemoryStatusEx()
msgbox,% gms[0] "`n" gms[1] "`n" "..."
GlobalMemoryStatusEx() {
    VarSetCapacity(MEMORYSTATUSEX, 64, 0)
    NumPut(64, MEMORYSTATUSEX)
    DllCall("GlobalMemoryStatusEx", "Ptr", &MEMORYSTATUSEX)
    return { 0 : NumGet(MEMORYSTATUSEX,  0, "UInt")
			,1 : NumGet(MEMORYSTATUSEX,  4, "UInt")
			,2 : NumGet(MEMORYSTATUSEX,  8, "Int64")
			...} ; und der Rest auch noch;) 			
}
User avatar
jNizM
Posts: 3183
Joined: 30 Sep 2013, 01:33
Contact:

Re: Besserer Aufbau einer Funktion mit DllCalls

18 Oct 2013, 07:06

Danke..
Aber kann auch jemand erklären warum das eine oder andere besser oder schneller bzw ressourcenschonender ist?
Will es ja auch verstehen =)
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile
strobo
Posts: 125
Joined: 30 Sep 2013, 15:24

Re: Besserer Aufbau einer Funktion mit DllCalls

18 Oct 2013, 07:18

Deine Version macht 9mal sowas:

Code: Select all

VarSetCapacity(MEMORYSTATUSEX, 64, 0)
NumPut(64, MEMORYSTATUSEX)
DllCall("GlobalMemoryStatusEx", "Ptr", &MEMORYSTATUSEX)
Meine Version macht das nur 1mal, dafür muss aber ein object gebaut werden (anzahl der Numget() bleibt sich gleich) und der Wert 9mal aus dem object geholt werden, gms.
Wenn der DllCall Zeit kostet, spart das nicht nur Schreibarbeit sondern auch CPU-Zeit.
just me
Posts: 9512
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Besserer Aufbau einer Funktion mit DllCalls

18 Oct 2013, 07:23

Hallo,

außerdem können die wiederholten Aufrufe dazu führen, dass die einzeln abgeholten Werte nicht einem Zustand zu einem bestimmten Zeitpunkt entsprechen, d.h. nicht zusammengehörig sind.
User avatar
jNizM
Posts: 3183
Joined: 30 Sep 2013, 01:33
Contact:

Re: Besserer Aufbau einer Funktion mit DllCalls

18 Oct 2013, 07:30

ok... dh ich setze das global irgendwo in den top bereich
global GMSEx := GlobalMemoryStatusEx()

rufe dann irgendwann mit SetTimer meine Funktion in bestimmten Abständen auf
GMSEx_A := GMSEx[2] / 1024**2

und unten hab ich dann die Funktion ansich
GlobalMemoryStatusEx() {...}
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile
HotKeyIt
Posts: 2364
Joined: 29 Sep 2013, 18:35
Contact:

Re: Besserer Aufbau einer Funktion mit DllCalls

18 Oct 2013, 07:36

Wenn geschwindigkeit so wichtig ist, kannst du es gerne mit AHK_H ausprobieren ;)

Code: Select all

gms:=GlobalMemoryStatusEx()
for k,v in gms
	MsgBox % k " - " v
; oder gleich for loop
for k,v in GlobalMemoryStatusEx()
	MsgBox % k " - " v
GlobalMemoryStatusEx(){
	static MEMORYSTATUSEX := "DWORD dwLength;DWORD dwMemoryLoad;DWORDLONG ullTotalPhys;DWORDLONG ullAvailPhys;DWORDLONG ullTotalPageFile;DWORDLONG ullAvailPageFile;DWORDLONG ullTotalVirtual;DWORDLONG ullAvailVirtual;DWORDLONG ullAvailExtendedVirtual"
	,ms:=Struct(MEMORYSTATUSEX,{dwLength:sizeof(MEMORYSTATUSEX)}),GlobalMemoryStatusEx:=DynaCall("GlobalMemoryStatusEx","t",ms[])
	return ms,GlobalMemoryStatusEx[]
}
User avatar
jNizM
Posts: 3183
Joined: 30 Sep 2013, 01:33
Contact:

Re: Besserer Aufbau einer Funktion mit DllCalls

18 Oct 2013, 07:37

@HotKeyIt:
Der Aufbau erinnert mich ja stark an dem von AutoIt.

Die Idee wär gut, wenn ich das nur für mich machen würde.
Da ich das ganze aber für alle Freigegeben habe http://ahkscript.org/boards/viewtopic.php?f=6&t=254 wäre AHK_L doch besser. =)

Und dort will ich versuchen soweit wie möglich eine Performance-Verbesserung rein zu bekommen.
D.h. jegliche Ideen zur Verbesserung (vor allem der Funktionen) nehme ich gerne an.
Last edited by jNizM on 18 Oct 2013, 07:43, edited 1 time in total.
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile
strobo
Posts: 125
Joined: 30 Sep 2013, 15:24

Re: Besserer Aufbau einer Funktion mit DllCalls

18 Oct 2013, 07:41

Für mit ohne ahk_h:
Du brauchst GMSEx nicht global setzen. Per SetTimer musst du die Funktion schon selbst ausführen, diese erzeugt ja erst das object, etwa so

Code: Select all

GMSEx := GlobalMemoryStatusEx()
GMSEx_A := GMSEx[2] / 1024**2
HotKeyIt
Posts: 2364
Joined: 29 Sep 2013, 18:35
Contact:

Re: Besserer Aufbau einer Funktion mit DllCalls

18 Oct 2013, 08:08

Dann kann ich nur empfehlen die variable als static zu deklarieren und zu initialisieren:

Code: Select all

GlobalMemoryStatusEx(){
 static MEMORYSTATUSEX,init:=VarSetCapacity(MEMORYSTATUSEX, 64, 0) &&  NumPut(64, MEMORYSTATUSEX,"UInt")
...
User avatar
jNizM
Posts: 3183
Joined: 30 Sep 2013, 01:33
Contact:

Re: Besserer Aufbau einer Funktion mit DllCalls

18 Oct 2013, 08:13

ergo so?

Code: Select all

GMSEx := GlobalMemoryStatusEx()

MsgBox,, GlobalMemoryStatusEx, % "GlobalMemoryStatusEx function /`n"
        . "MEMORYSTATUSEX structure`n`n"
        . "Lenght:`t`t`t"             GMSEx[0]  "`n`n"
        . "MemoryLoad:`t`t"           GMSEx[1]  " %`n`n"
        . "TotalPhys:`t`t`t"          GMSEx[2]  " bytes`n"
        . "AvailPhys:`t`t`t"          GMSEx[3]  " bytes`n`n"
        . "TotalPageFile:`t`t"        GMSEx[4]  " bytes`n"
        . "AvailPageFile:`t`t"        GMSEx[5]  " bytes`n`n"
        . "TotalVirtual:`t`t"         GMSEx[6]  " bytes`n"
        . "AvailVirtual:`t`t"         GMSEx[7]  " bytes`n`n"
        . "AvailExtendedVirtual:`t`t" GMSEx[8]

GlobalMemoryStatusEx() {
	static MEMORYSTATUSEX, init := VarSetCapacity(MEMORYSTATUSEX, 64, 0) && NumPut(64, MEMORYSTATUSEX, "UInt")
    DllCall("GlobalMemoryStatusEx", "Ptr", &MEMORYSTATUSEX)
    return, { 0 : NumGet(MEMORYSTATUSEX,  0, "UInt"),  1 : NumGet(MEMORYSTATUSEX,  4, "UInt")
            , 2 : NumGet(MEMORYSTATUSEX,  8, "Int64"), 3 : NumGet(MEMORYSTATUSEX, 16, "Int64")
            , 4 : NumGet(MEMORYSTATUSEX, 24, "Int64"), 5 : NumGet(MEMORYSTATUSEX, 32, "Int64")
            , 6 : NumGet(MEMORYSTATUSEX, 40, "Int64"), 7 : NumGet(MEMORYSTATUSEX, 48, "Int64")
            , 8 : NumGet(MEMORYSTATUSEX, 56, "Int64") }
}
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile
User avatar
jNizM
Posts: 3183
Joined: 30 Sep 2013, 01:33
Contact:

Re: Besserer Aufbau einer Funktion mit DllCalls

18 Oct 2013, 09:09

Danke an alle =)

Wenn ich daheim bin komme ich nochmal auf dich zu wegen einer weiteren Funktion ;)
Den alten Stand, den ich zusammengeschustert habe, lass ich dir schon mal da.

Code: Select all

ownPID := DllCall("GetCurrentProcessId")
MsgBox, % "BUILD: " GetVersionEx() " | PID: " ownPID " | " Round(GetProcessMemoryInfo(ownPID) / 1024, 0) " K"

GetVersionEx() {
	static OSVerEX, init := VarSetCapacity(OSVerEX, 284, 0) && Numput(284, OSVerEX, "UInt")
    DllCall(Kernel32.GetVersionEx, "Ptr", &OSVerEX)
    return, NumGet(OSVerEX, 12, "UInt")
}

GetProcessMemoryInfo(PID) {
    pu := ""
    if (GetVersionEx() >= "7600")
    {
        size := (A_PtrSize = "8" ? "80" : "44")
        VarSetCapacity(PMCEX, size, 0), NumPut(size, PMCEX)

        hProcess := DllCall("OpenProcess", "UInt", 0x001F0FFF, "Int", 0, "UInt", PID)
        if (hProcess)
        {
            if (DllCall("Kernel32.dll\K32GetProcessMemoryInfo", "Ptr", hProcess, "UInt", &PMCEX, "UInt", size))
                pu := NumGet(PMCEX, (A_PtrSize = "8" ? "72" : 40), (A_PtrSize = 8 ? "Int64" : "Int"))
            DllCall("Kernel32.dll\CloseHandle", "Int", hProcess)
        }
    }
    else
    {
        size := (A_PtrSize = "8" ? "72" : "40")
        VarSetCapacity(PMC, size, 0), NumPut(size, PMC)
        
        hProcess := DllCall("OpenProcess", "UInt", 0x001F0FFF, "Int", 0, "UInt", PID)
        if (hProcess)
        {
            if (DllCall("psapi.dll\GetProcessMemoryInfo", "Ptr", hProcess, "UInt", &PMC, "UInt", size))
                pu := NumGet(PMC, (A_PtrSize = 8 ? 56 : 32), (A_PtrSize = 8 ? "Int64" : "Int"))
            DllCall("psapi.dll\CloseHandle", "Ptr", hProcess)
        }
    }
    return % pu
}
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile
User avatar
nnnik
Posts: 4500
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: Besserer Aufbau einer Funktion mit DllCalls

18 Oct 2013, 09:20

Oder direkt eine Klasse :D

Code: Select all

Class GlobalMemoryStatusEx{
__new()
{
this.ptr:=DllCall("HeapAlloc","UPtr",DllCall("GetProcessHeap"),"UInt",8,"UPtr",64)	
NumPut(64, this.ptr+0, "UInt")
DllCall("GlobalMemoryStatusEx", "Ptr", this.ptr)
this.offset:={Length:0,MemoryLoad:4,TotalPhys:8,AvailPhys:16,TotalPageFile:24,AvailPageFile:32,TotalVirtual:40,AvailVirtual:48,AvailExtendedVirtual:56}
this.type:={Length:"uint",MemoryLoad:"uint",TotalPhys:"int64",AvailPhys:"int64",TotalPageFile:"int64",AvailPageFile:"int64",TotalVirtual:"int64",AvailVirtual:"int64",AvailExtendedVirtual:"int64"}
}
__get(p)
{
return numget(this.ptr+0,this.offset[p],this.type[p])
}
refresh()
{
DllCall("GlobalMemoryStatusEx", "Ptr", this.ptr)
}
}

Mem:=new GlobalMemoryStatusEx()
Msgbox % mem.length
Recommends AHK Studio
HotKeyIt
Posts: 2364
Joined: 29 Sep 2013, 18:35
Contact:

Re: Besserer Aufbau einer Funktion mit DllCalls

18 Oct 2013, 09:38

Für die Klasse brauchst du einen weg die werte zu aktualisieren, andernfalls wirst du nicht die aktuellen werte bekommen.
Werte bei jedem get zu aktualisieren macht auch kein Sinn, also bleibt nur A_TickCount zu überprüfen und je nach dem wie alt der letzte Aufruf ist zu aktualisieren.

Das verlangsamt leider alles und ist eher nicht empfehlenswert meiner Ansicht nach.
User avatar
nnnik
Posts: 4500
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: Besserer Aufbau einer Funktion mit DllCalls

18 Oct 2013, 11:14

Ähm mem.refresh() ?
Recommends AHK Studio
User avatar
jNizM
Posts: 3183
Joined: 30 Sep 2013, 01:33
Contact:

Re: Besserer Aufbau einer Funktion mit DllCalls

18 Oct 2013, 11:20

[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile
User avatar
nnnik
Posts: 4500
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: Besserer Aufbau einer Funktion mit DllCalls

18 Oct 2013, 11:53

Wegen dem zweiten:
Da fragst du per If-Abfrage ab ob das OS system gleich oder größer als 7600 ist.
Du könntest diese If abfrage 1 mal ausführen und daraufhin per Func objekt eine andere Funktion definieren, die dann immer aufgerufen wird:

Code: Select all

Class GetOwnMemory{
__new()
{
this.ownPID := DllCall("GetCurrentProcessId")
VarSetCapacity(OSVerEX, 284, 0)
Numput(284, OSVerEX,0, "UInt")
DllCall("GetVersionEx", "Ptr", &OSVerEX)
NumGet(OSVerEX, 12, "UInt")
If this.hProcess := DllCall("OpenProcess", "UInt", 0x001F0FFF, "Int", 0, "UInt", this.ownPID)
{
if (NumGet(OSVerEX, 12, "UInt")>= "7600")
this.fnc:=func("GetProcessMemoryInfo1")
Else
this.fnc:=func("GetProcessMemoryInfo2")
}
Else
this.fnc:=func("Error")
}
Info()
{
return this.fnc.(this)
}
}

GetProcessMemoryInfo1(this) {
        static PCMEX:="",size := (A_PtrSize = "8" ? "80" : "44"),init:=VarSetCapacity(PMCEX, size, 0)&& NumPut(size, PMCEX)
            if (DllCall("K32GetProcessMemoryInfo", "Ptr", this.hProcess, "UInt", &PMCEX, "UInt", size))
                return NumGet(PMCEX, (A_PtrSize = "8" ? "72" : 40), (A_PtrSize = 8 ? "Int64" : "Int"))
}
 GetProcessMemoryInfo2(this)
    {
       static PCM:="",size := (A_PtrSize = "8" ? "72" : "40"), init:=VarSetCapacity(PMC, size, 0)&& NumPut(size, PMC) 
            if (DllCall("psapi.dll\GetProcessMemoryInfo", "Ptr", this.hProcess, "UInt", &PMC, "UInt", size))
              return, NumGet(PMC, (A_PtrSize = 8 ? 56 : 32), "ptr")
    }

Error(this)
{
return "Error"
}
Recommends AHK Studio
User avatar
jNizM
Posts: 3183
Joined: 30 Sep 2013, 01:33
Contact:

Re: Besserer Aufbau einer Funktion mit DllCalls

18 Oct 2013, 14:10

Warum bekomm ich hier die Meldung: Error: Duplicate declaration? (bei static PMC size & init)
Durch if else wird doch eh nur eins zutreffen?

Code: Select all

ownPID := DllCall("GetCurrentProcessId")
MsgBox, % "BUILD: " GetVersionEx() " | PID: " ownPID " | " Round(GetProcessMemoryInfo(ownPID) / 1024, 0) " K"

GetVersionEx() {
    static OSVerEX, init := VarSetCapacity(OSVerEX, 284, 0) && Numput(284, OSVerEX, "UInt")
    DllCall("GetVersionEx", "Ptr", &OSVerEX)
    return, NumGet(OSVerEX, 12, "UInt")
}


GetProcessMemoryInfo(PID) {
    pu := ""
    hProcess := DllCall("OpenProcess", "UInt", 0x001F0FFF, "Int", 0, "UInt", PID)
    if (hProcess)
    {
        if (GetVersionEx() >= "7600")
        {
            static PMCEx, size := (A_PtrSize = "8" ? "80" : "44"), init := VarSetCapacity(PMCEx, size, 0) && NumPut(size, PMCEx)
            if (DllCall("Kernel32.dll\K32GetProcessMemoryInfo", "Ptr", hProcess, "UInt", &PMCEx, "UInt", size))
                pu := NumGet(PMCEx, (A_PtrSize = "8" ? "72" : 40), (A_PtrSize = 8 ? "Int64" : "Int"))
            DllCall("Kernel32.dll\CloseHandle", "Int", hProcess)
        }
        else
        {
            static PMC, size := (A_PtrSize = "8" ? "72" : "40"), init := VarSetCapacity(PMC, size, 0) && NumPut(size, PMC)
            if (DllCall("psapi.dll\GetProcessMemoryInfo", "Ptr", hProcess, "UInt", &PMC, "UInt", size))
                pu := NumGet(PMC, (A_PtrSize = 8 ? 56 : 32), (A_PtrSize = 8 ? "Int64" : "Int"))
            DllCall("psapi.dll\CloseHandle", "Ptr", hProcess)
        }
    }
    return, % pu
}
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile
User avatar
nnnik
Posts: 4500
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: Besserer Aufbau einer Funktion mit DllCalls

18 Oct 2013, 14:37

static Variablen werden auch vor Scriptstart ausgelesen.
Die Definition ist deshalb doppelt weil die statics nicht von der If-Abfrage abhängig sind.
Recommends AHK Studio

Return to “Ich brauche Hilfe”

Who is online

Users browsing this forum: No registered users and 29 guests