windows - Brug ChangeDisplaySettingsEx i Delphi til at indstille primære skærm

Indlæg af Hanne Mølgaard Plasc

Problem



Jeg forsøger at bruge ChangeDisplaySettingsEx i Delphi 7 til at indstille en bestemt skærm som primær.
I Windows.pas defineres det som


function ChangeDisplaySettingsEx(lpszDeviceName: PChar; var lpDevMode: TDeviceMode;
        wnd: HWND; dwFlags: DWORD; lParam: Pointer): Longint; stdcall;


I MSDN har dokumentationen til ChangeDisplaySettingsEx følgende kommentar til lpDevMode: 'Hvis lpDevMode er NULL, vil alle værdier i registreringsdatabasen blive brugt til displayindstillingen.' [12]


Mit mål er at ændre den primære skærm på et system med to aktive skærme uden at ændre noget andet - opløsning, bitdybde osv., Skal alle forblive de samme. Det lader til at passere lpDevMode som null (nul) er den metode, der er tilvejebragt for at opnå dette.


Imidlertid er lpDevMode defineret som en pakket posttype (TDeviceMode), ikke en pegertype, i Delphi's Windows.pas. Delphi-grænsefladen til Windows API udviser tilsyneladende oversættelsen til de peger, der bruges af Windows API 'bag kulisserne '.


Jeg forsøgte at kalde det sådan:


var
   alldevs : array[0..maxdev] of TDisplayDevice;
   lpDevMode : pointer;

begin
   lpDevMode := nil;
   lparam := nil;
   my\_hwnd := nil;

  {... snip....}

  with alldevs[NewPri] do
      ChangeDisplaySettingsEx(devicename,TDeviceMode(lpDevMode),my\_hwnd,CDS\_SET\_PRIMARY,lparam);


Det giver mig en ugyldig typecast fejl på 'TDeviceMode (lpDevMode)'. Hvordan kan jeg sende en nullpeger til ChangeDisplaySettingsEx? Eller er der en bedre måde at gøre dette på?

Bedste reference


Du kan prøve


ChangeDisplaySettingsEx(devicename, PDeviceMode(0)^, my\_hwnd, CDS\_SET\_PRIMARY,
  lparam);


det samler i det mindste på Delphi 2009. Jeg kan ikke teste det selv.





Ifølge de knappe oplysninger på nettet (dette er den mest detaljerede jeg kunne finde), ændres det primære display, det er ikke en simpel proces, så du kan mangle et skridt undervejs. Jeg har to skærme, men kan ikke ændre primær enhed overhovedet, ikke engang med kontrolpanelet - ser ud til at dual-head skærmkortdriveren ikke tillader det. Følgende er derfor ikke testet, men måske vil det hjælpe dig: [13]


For at indstille et nyt primært display skal du først flytte det nuværende primære display væk fra positionen (0, 0). Dette er mere vanskeligt, end det skal være, fordi filen Delphi Windows.pas har en ufuldstændig TDeviceMode-type. Det er givet som


\_devicemodeA = record
  dmDeviceName: array[0..CCHDEVICENAME - 1] of AnsiChar;
  ...
  dmOrientation: SHORT;
  dmPaperSize: SHORT;
  dmPaperLength: SHORT;
  dmPaperWidth: SHORT;
  dmScale: SHORT;
  dmCopies: SHORT;
  dmDefaultSource: SHORT;
  dmPrintQuality: SHORT;
  dmColor: SHORT;
  ...
end;


når det i stedet skal være


\_devicemodeA = record
  dmDeviceName: array[0..CCHDEVICENAME - 1] of AnsiChar;
  ...
  case boolean of
    FALSE: (
      dmOrientation: SHORT;
      dmPaperSize: SHORT;
      dmPaperLength: SHORT;
      dmPaperWidth: SHORT;
      dmScale: SHORT;
      dmCopies: SHORT;
      dmDefaultSource: SHORT;
      dmPrintQuality: SHORT;
    );
    TRUE: (
      dmPosition: TPoint;
      dmDisplayOrientation: DWORD;
      dmDisplayFixedOutput: DWORD;
    );
    dmColor: SHORT;
  ...
end;


Du skal tilføje den faste optagelsestype til dine kilder, som du har brug for dmPosition for at justere skærmens oprindelse. Det skulle gå noget som dette:


// get current display settings
EnumDisplaySettings(PChar(AOldPrimaryDevice), ENUM\_REGISTRY\_SETTINGS, DevMode1);
EnumDisplaySettings(PChar(ANewPrimaryDevice), ENUM\_REGISTRY\_SETTINGS, DevMode2);

// move old primary display to new position
DevMode1.dmFields := DM\_POSITION;
DevMode1.dmPosition.x := DevMode2.dmPelsWidth;
DevMode1.dmPosition.y := 0;
Win32Check(ChangeDisplaySettingsEx(PChar(AOldPrimaryDevice), DevMode1, 0,
  CDS\_UPDATEREGISTRY or CDS\_NORESET, nil)):

// move old secondary display to (0, 0) and make the primary display
DevMode2.dmFields := DM\_POSITION;
DevMode2.dmPosition.x := 0;
DevMode2.dmPosition.y := 0;
Win32Check(ChangeDisplaySettingsEx(PChar(ANewPrimaryDevice), DevMode2, 0,
  CDS\_SET\_PRIMARY or CDS\_UPDATEREGISTRY or CDS\_NORESET or DM\_DISPLAYFLAGS, nil)):

// magic ???
Win32Check(ChangeDisplaySettingsEx(nil, PDeviceMode(0)^, 0, 0, nil));

Andre referencer 1


Jeg har ikke verificeret det, men der er et indlæg i MSDN fora, der dækker dette og indeholder C ++ kode. Den 'primære' skærm er den i position 0,0, så du skal omarrangere skærmens positioner for at få det til at ske. [14]

Andre referencer 2


Dette er mine resultater efter at have gennemgået mange C ++ og Delphi indlæg omkring internettet.



  • ønskede ikke at erklære en ny TMyDevMode-type med fagvalg for manglende felter

  • brug eksisterende TDevMode type, men angiv manglende felter med Move () memcopy kommando og 32bit signeret midlertidig variabel

  • Flyt nuværende primære desktop fra 0,0 pos, anvend ikke ændringer endnu

  • Indstil nyt nuværende primært skrivebord til 0,0 med CDS\_SET\_PRIMARY flag, anvend ikke ændringer endnu

  • xy position og bredde, højden bør ikke overlappe, men det forekommer Win7 kan løse nogle problemer af sig selv

  • ring ChangeDisplaySettingsEx med nullparametre for at anvende alle ventende ændringer



Indstil dmPosition.x og dmPosition.y værdier, brug hukommelsesforskydning:


var dm: TDevMode;
var tempx, tempy: Integer;
Move(tempx, dm.dmOrientation, sizeOf(tempx));
Move(tempy, dm.dmPaperLength, sizeOf(tempy));


Få dmPosition.x og dmPosition.y værdier, brug hukommelsesforskydning:


var dm: TDevMode;
var tempx, tempy: Integer;
Move(dm.dmOrientation, tempx, sizeOf(tempx));
Move(dm.dmPaperLength, tempy, sizeOf(tempy));


Indstil primære skrivebord fra display1 for at vise2 forekomst. Lav ændringer, og anvend derefter alle ventende ændringer:


flags := CDS\_UPDATEREGISTRY or CDS\_NORESET;
ChangeDisplaySettingsEx('\.DISPLAY1', devMode1, 0, flags, nil);
flags := CDS\_UPDATEREGISTRY or CDS\_SET\_PRIMARY or CDS\_NORESET;
ChangeDisplaySettingsEx('\.DISPLAY2', devMode2, 0, flags, nil);
ChangeDisplaySettingsEx(nil, PDeviceMode(0)^, 0, 0, nil);