Willkommen im cgboard - classic games Forum! Deine gemütliche Retro Gaming Community. Besuche uns auch im Discord Chat.

[Problem] Bekomme eine Grafik API nicht angesprochen in QB64
#1
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:
Code:
0
-> 0 x 0

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.
Zitieren
#2
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.
Zitieren
#3
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.
Zitieren
#4
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.  Cry
Zitieren
#5
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.
Zitieren
#6
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

[Bild: face-palm.gif]
Zitieren
#7
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.
Zitieren


Möglicherweise verwandte Themen…
Thema Verfasser Antworten Ansichten Letzter Beitrag
  [Problem] Kleines QB64 Problem zwecks Maus und Buttons SagaraS 3 525 12.03.2023, 23:17
Letzter Beitrag: SagaraS
  SagaraS QB64 Programme SagaraS 4 1.476 30.06.2021, 20:56
Letzter Beitrag: Atreyu
  Win10 - Energie sparen geht nicht mehr Atreyu 12 6.948 23.05.2019, 06:01
Letzter Beitrag: Juttar
  [Problem] Regedit funktioniert nicht donald 4 3.614 09.10.2018, 11:55
Letzter Beitrag: donald
  [Grafik] Bräuchte mal eine kleine Hilfe für ein Dekompression Algorithmus für ILBM Bild Dateien SagaraS 7 3.726 14.12.2017, 18:30
Letzter Beitrag: tomwatayan

Gehe zu:


Benutzer, die gerade dieses Thema anschauen: 1 Gast/Gäste