Beiträge: 132
Themen: 21
Registriert seit: 03.05.2016
0 Hallo,
Wieder mal ein Problem wo ich die Lösung vermutlich nicht sehe. Vermutlich wieder irgendwas falsch oder es fehlt noch was.
Das Problem:
Ich möchte ein Programm schreiben, das mir alle möglichen Auflösungen der aktuellen Grafikkarte auflistet.
Dazu wollte ich mir die EnumDisplaySettingsA Funktion aus der USER32.DLL zunutze machen.
Leider bekomme ich kein Ergebnis der Funktion.
Programmiersprache ist QB64: https://qb64.com/
Hier mal der Code:
Code: TYPE DEVMODE
dmDeviceName AS STRING * 32
dmSpecVersion AS INTEGER
dmDriverVersion AS INTEGER
dmSize AS INTEGER
dmDriverExtra AS INTEGER
dmFields AS LONG
dmOrientation AS INTEGER
dmPaperSize AS INTEGER
dmPaperLength AS INTEGER
dmPaperWidth AS INTEGER
dmScale AS INTEGER
dmCopies AS INTEGER
dmDefaultSource AS INTEGER
dmPrintQuality AS INTEGER
dmColor AS INTEGER
dmDuplex AS INTEGER
dmYResolution AS INTEGER
dmTTOption AS INTEGER
dmCollate AS INTEGER
dmFormName AS STRING * 32
dmUnusedPadding AS INTEGER
dmBitsPerPel AS INTEGER
dmPelsWidth AS LONG
dmPelsHeight AS LONG
dmDisplayFlags AS LONG
dmDisplayFrequency AS LONG
END TYPE
DECLARE DYNAMIC LIBRARY "User32"
FUNCTION EnumDisplaySettings& ALIAS "EnumDisplaySettingsA" (_
lpszDeviceName AS LONG, _
iModeNum AS LONG, _
lpDevMode AS DEVMODE)
END DECLARE
DIM result AS LONG
DIM i AS LONG
DIM DevM AS DEVMODE
result = EnumDisplaySettings&(0, i, DevM)
PRINT result
PRINT "-> " + STR$(DevM.dmPelsWidth) + " x " + STR$(DevM.dmPelsHeight)
Ergebnis Ausgabe:
Hab ein ähnliches Tool schon in VB6 und C++ geschrieben, da ging es aber.
Hier verstehe ich halt nicht was da nun falsch sein sollte.
Beiträge: 6.845
Themen: 127
Registriert seit: 18.02.2006
0 lpszDeviceName AS LONG <- laut Doku muss da ein LPCSTR hin. Auf dieser Seite steht, dass man das in QB64 erreicht, wenn man BYVAL lpDeviceName AS _UNSIGNED _OFFSET schreibt.
Beiträge: 132
Themen: 21
Registriert seit: 03.05.2016
0 Naja, lpszDeviceName ist quasi welche Grafikkarte man grad verwendet bzw. die die auf Platz 0 ist. Du kannst es auch als long deklarieren. In diesem Fall steht der Wert 0 für den ersten Grafiktreiber der in der Liste steht.
Also 0 für die erste Karte.
Hab das grad mit C++ noch mal gemacht, da geht es genauso.
Code: #include <windows.h>
int GetAllDisplayScreens(long iModeNum) {
int result;
DEVMODE devMode;
devMode.dmSize = sizeof(DEVMODE);
result = EnumDisplaySettings (NULL, iModeNum, &devMode);
return result;
// Diese Werte müssen noch übergeben werden!!!
//arr[0] = devMode.dmPelsWidth;
//arr[1] = devMode.dmPelsHeight;
//arr[2] = devMode.dmBitsPerPel;
}
Diesen Code könnte ich auch in QB64 einbinden. Funktioniert sogar auch. Er liefert eine 1 zurück.
Müsste nur noch ausknobeln wie ich die anderen 3 Werte mit übergeben kann an QB64.
So binde ich es in QB64 ein:
Code: DECLARE LIBRARY "Display"
FUNCTION GetD% ALIAS GetAllDisplayScreens (BYVAL iModeNum AS LONG)
END DECLARE
DIM result AS INTEGER
DIM i AS LONG
DO
result = GetD(i)
i = i + 1
PRINT result; i
LOOP WHILE result <> 0
Der liefert solange eine 1 zurück solange eine Modi an Auflösungs Einstellung existiert.
Der liefert erst eine 0 zurück, wenn keine Modis mehr vorhanden ist.
Beiträge: 132
Themen: 21
Registriert seit: 03.05.2016
0 Habe jetzt erst mal eine Lösung gefunden. Die finde ich aber nicht all zu cool xD
Lieber wäre es mir das komplett über QB64 zu lösen. Ich denke mir einfach mal das der falsche Speicher bzw. das Abfragen des Speichers falsch läuft.
Hier mal die funktionierende Hybrid Lösung aus C++ und QB64
Display.h
Code: #include <windows.h>
int GetAllScreenModes(long iModeNum) {
DEVMODE devMode;
return EnumDisplaySettings (NULL, iModeNum, &devMode);
}
long GetDisplayWidth(long iModeNum) {
DEVMODE devMode;
int result = EnumDisplaySettings (NULL, iModeNum, &devMode);
return devMode.dmPelsWidth;
}
long GetDisplayHeight(long iModeNum) {
DEVMODE devMode;
devMode.dmSize = sizeof(DEVMODE);
int result = EnumDisplaySettings (NULL, iModeNum, &devMode);
return devMode.dmPelsHeight;
}
long GetDisplayDepth(long iModeNum) {
DEVMODE devMode;
devMode.dmSize = sizeof(DEVMODE);
int result = EnumDisplaySettings (NULL, iModeNum, &devMode);
return devMode.dmBitsPerPel;
}
Und das dazugehörige QB64 Programm:
Code: DECLARE LIBRARY "Display"
FUNCTION GetMode% ALIAS GetAllScreenModes(BYVAL iModeNum AS LONG)
FUNCTION GetWidth& ALIAS GetDisplayWidth (BYVAL iModeNum AS LONG)
FUNCTION GetHeight& ALIAS GetDisplayHeight (BYVAL iModeNum AS LONG)
FUNCTION GetDepth& ALIAS GetDisplayDepth (BYVAL iModeNum AS LONG)
END DECLARE
REDIM Feld(0) AS STRING
CALL GetAllScreenRes(Feld())
FOR i = 0 TO UBOUND(Feld)
PRINT "'" + Feld(i) + "'"
NEXT i
SUB GetAllScreenRes (Array() AS STRING)
DIM lResult AS LONG
DIM i AS LONG
DIM Res AS STRING
DIM Old AS STRING
DIM max AS INTEGER
DIM WDepth AS LONG
DIM Wwidth AS LONG
DIM Wheight AS LONG
REDIM Array(0) AS STRING
DO
lResult = GetMode(i)
IF lResult = 0 THEN EXIT DO
WDepth = GetDepth(i)
Wwidth = GetWidth(i)
Wheight = GetHeight(i)
Res = LTRIM$(STR$(Wwidth)) + "x" + LTRIM$(STR$(Wheight))
IF WDepth = 32 THEN
IF Res <> Old THEN
IF Wwidth >= 640 THEN
IF Wheight >= 480 THEN
IF Wwidth > 3840 THEN
ELSE
IF Wheight > 2160 THEN
ELSE
REDIM _PRESERVE Array(max) AS STRING
Array(max) = Res
max = max + 1
END IF
END IF
END IF
END IF
END IF
Old = Res
END IF
i = i + 1
LOOP
END SUB
Das listet mir jetzt alle Auflösungen zwecks Breite und Höhe auf und ignoriert die Frequenzen und andere Parameter.
Sprich jede mögliche Auflösung ist nur 1x aufgelistet die zwischen 640x480 und 3840x2160 ist.
Das ganze Prozedere brauch ich für ein anderes Tool.
Wie gesagt.... diese Hybrid Variante gefällt mir nicht so sonderlich. Würde das lieber wie im Start Post lösen. Nur da muss vermutlich der Speicher anders angesprochen werden.
Würde vermuten das lpDevMode AS DEVMODE in der Function EnumDisplaySettings& ein Speicherabbild braucht? Mit _OFFSET oder _MEM den Speicherblock wo die Daten drin sind irgendwie in diese Datenstructur von DEVMODE bringen. kA wie das von Statten gehen soll. Wenn das die Lösung sein sollte?
Bin da echt überfragt. Habe da auch schon diverse Versuche gemacht. Aber irgendwie wende ich es falsch an oder es ist von mir gar ein falscher Ansatz.
Beiträge: 6.845
Themen: 127
Registriert seit: 18.02.2006
0 Der Datenblock sieht jetzt auf den zweiten Blick wirklich nicht ganz passend aus. Bezieht sich der eventuell auf eine frühere Windows-Version?
dmUnusedPadding AS INTEGER <-- gibt es nicht mehr.
Und nach dmDisplayFrequency müssten noch folgen:
dmICMMethod AS LONG
dmICMIntent AS LONG
dmMediaType AS LONG
dmDitherType AS LONG
dmReserved1 AS LONG
dmReserved2 AS LONG
dmPanningWidth AS LONG
dmPanningHeight AS LONG
Obwohl ich mich wundere, dass das ein Problem ist, weil wenn du vom Rückgabeobjekt zu wenig einliest, sollte doch trotzdem der Boolean eine 1 (bzw. nonzero) zurückliefern, wenn der Funktionsaufruf an sich stattgefunden hat. Aber damit kenne ich mich auch überhaupt nicht aus, welche Bedingungen mit komplexen Objekten vorliegen. Wenn ich in der Vergangenheit eine Windows-API aufgerufen habe, war das meistens eine ganz einfache wie z.B. SetConsoleTitleA.
Beiträge: 132
Themen: 21
Registriert seit: 03.05.2016
19.03.2023, 11:45
(Dieser Beitrag wurde zuletzt bearbeitet: 19.03.2023, 12:41 von SagaraS.)
0 Deswegen heißt die Variable dmUnusedPadding, weil sie ungenutzt ist. Sie ist aber dennoch vorhanden. Den selben DEVMODE Type nutze ich ja auch in VB6 und da funktioniert er.
Nur in VB6 konnte ich den Parameter lpDevMode von EnumDisplaySettingsA als ANY deklarieren.
Das geht ja jetzt nicht mehr. Ich vermute mal das da auch der Grund des Fehlers ist. Weil der vermutlich die Speicheradresse nicht findet und irgendwo ein leeren Speicher dafür reserviert und abgreift.
Denke mal das dieser Parameter als _OFFSET oder _MEM deklariert werden müsste.
[EDIT]
Hab das jetzt hinbekommen xD
Code: TYPE DEVMODE
dmDeviceName AS STRING * 32
dmSpecVersion AS INTEGER
dmDriverVersion AS INTEGER
dmSize AS INTEGER
dmDriverExtra AS INTEGER
dmFields AS LONG
dmOrientation AS INTEGER
dmPaperSize AS INTEGER
dmPaperLength AS INTEGER
dmPaperWidth AS INTEGER
dmScale AS INTEGER
dmCopies AS INTEGER
dmDefaultSource AS INTEGER
dmPrintQuality AS INTEGER
dmColor AS INTEGER
dmDuplex AS INTEGER
dmYResolution AS INTEGER
dmTTOption AS INTEGER
dmCollate AS INTEGER
dmFormName AS STRING * 32
dmUnusedPadding AS INTEGER
dmBitsPerPel AS LONG
dmPelsWidth AS LONG
dmPelsHeight AS LONG
dmDisplayFlags AS LONG
dmDisplayFrequency AS LONG
END TYPE
DECLARE DYNAMIC LIBRARY "user32"
FUNCTION EnumDisplaySettings& ALIAS "EnumDisplaySettingsA" (_
BYVAL lpszDeviceName AS long, _
BYVAL iModeNum AS LONG, _
lpDevMode AS DEVMODE)
END DECLARE
REDIM Feld(0) AS STRING
CALL GetAllScreenRes(Feld())
FOR i = 0 TO UBOUND(Feld)
PRINT "'" + Feld(i) + "'"
NEXT i
SUB GetAllScreenRes (Array() AS STRING)
DIM lResult AS LONG
DIM i AS LONG
DIM DevM AS DEVMODE
DIM Res AS STRING
DIM Old AS STRING
DIM max AS INTEGER
REDIM Array(0) AS STRING
DO
lResult = EnumDisplaySettings(0, i, DevM)
IF lResult = 0 THEN EXIT DO
Res = LTRIM$(STR$(DevM.dmPelsWidth)) + " x " + LTRIM$(STR$(DevM.dmPelsHeight))
IF DevM.dmBitsPerPel = 32 THEN
IF Res <> Old THEN
IF DevM.dmPelsWidth >= 640 THEN
IF DevM.dmPelsHeight >= 480 THEN
IF DevM.dmPelsWidth > 3840 THEN
ELSE
IF DevM.dmPelsHeight > 2160 THEN
ELSE
REDIM _PRESERVE Array(max) AS STRING
Array(max) = Res
max = max + 1
END IF
END IF
END IF
END IF
END IF
Old = Res
END IF
i = i + 1
LOOP
END SUB
Man sollte schon mal bei der Parameter Deklaration das BYVAL nicht vergessen xD
Konnte ja nicht laufen, da die Funktion so keine Daten bekommen hat xD
Beiträge: 6.845
Themen: 127
Registriert seit: 18.02.2006
0 Freut mich, dass es geklappt hat. Die Wichtigkeit der Nennung von BYVAL in QB64 kannte ich leider nicht. In anderen Sprachen ist das ja in der Regel die automatische Annahme für alle Zahlendatentypen, wenn man sonst nichts angibt.
|