2009-06-05 9 views
0

J'essaie d'utiliser ChangeDisplaySettingsEx dans Delphi 7 pour définir un moniteur spécifique comme principal. Dans Windows.pas, il est défini commeUtilisation de ChangeDisplaySettingsEx dans Delphi pour définir le moniteur principal

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

En MSDN, la documentation ChangeDisplaySettingsEx a le commentaire suivant pour LPDEVMODE: « Si LPDEVMODE est NULL, toutes les valeurs actuellement dans le registre seront utilisés pour l'affichage réglage."

Mon objectif est de changer le moniteur principal sur un système avec deux moniteurs actifs, sans rien changer d'autre - la résolution, la profondeur de bits, etc, devraient tous rester les mêmes. Il semble que passer lpDevMode comme null (nil) est la méthode fournie pour accomplir ceci. Toutefois, lpDevMode est défini comme un type d'enregistrement condensé (TDeviceMode), et non comme un type de pointeur, dans Windows.pas de Delphi. Apparemment, l'interface Delphi de l'API Windows effectue la traduction vers les pointeurs utilisés par l'API Windows «dans les coulisses».

J'ai essayé d'appeler comme ceci:

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); 

Cela me donne une erreur de conversion de type invalide "TDeviceMode (LPDEVMODE)". Comment puis-je passer un pointeur null à ChangeDisplaySettingsEx? Ou y a-t-il une meilleure façon de faire cela?

Répondre

1

Vous pouvez essayer

ChangeDisplaySettingsEx(devicename, PDeviceMode(0)^, my_hwnd, CDS_SET_PRIMARY, 
    lparam); 

ne compile au moins sur Delphi 2009. Je ne peux pas tester si.

Edit:

Selon les informations rares sur le net (this is the most detailed I could find) changer l'affichage principal est pas un processus simple, vous pouvez manquer une étape le long du chemin. J'ai deux moniteurs, mais je ne peux pas changer du tout l'appareil principal, même pas avec le panneau de contrôle - ressemble au pilote de la carte d'affichage à double tête ne le permet pas. Ce qui suit n'est donc pas testé, mais peut-être qu'il vous aidera:

Pour définir un nouvel affichage principal, vous devez d'abord déplacer l'affichage principal actuel de la position (0, 0). C'est plus compliqué que nécessaire car le fichier Delphi Windows.pas a un type TDeviceMode incomplet. Il est donné comme

_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; 

quand il devrait plutôt être

_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; 

Vous devez ajouter le type d'enregistrement fixé à vos sources, que vous avez besoin dmPosition pour régler l'origine des affichages. Il devrait aller quelque chose comme ceci:

// 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)); 
+0

Merci pour la suggestion. Cela compile, mais cela ne fonctionne pas vraiment. ChangeDisplaySettingsEx renvoie 0 (succès), mais le moniteur principal reste inchangé. – tim11g

+0

mghie - merci pour les informations détaillées. Je ne savais pas qu'il fallait ajuster les origines de l'affichage avant de régler le primaire. Je ne peux pas revenir à la résolution de ce problème en ce moment, mais quand je le ferai, je vous le ferai savoir et publierai n'importe quel code de travail ici. – tim11g

0

Je ne l'ai pas vérifié, mais il y a un poste dans le MSDN forums qui couvre cela et inclut le code C++. Le moniteur "principal" est celui à la position 0,0, vous devez donc réorganiser les positions des moniteurs pour que cela se produise.

0

Ceci est mes conclusions après avoir parcouru de nombreux messages C++ et Delphi sur Internet.

  • ne voulait pas déclarer un nouveau type de TMyDevMode avec des options syndicales pour les champs manquants
  • utilisation type TDevMode existante, mais définir des champs manquants avec Move() memcopy commande et 32bit signé variable temporaire
  • abandon courant primaire bureau à partir de 0,0 pos, n'appliquez pas encore les modifications
  • définir nouveau bureau principal actuel à 0,0 avec CDS_SET_PRIMARY drapeau, ne pas appliquer les modifications encore
  • xy position et la largeur, la hauteur ne doit pas se chevaucher, mais il semble que Win7 peut résoudre certains problèmes par lui-même
  • appel ChangeDisplaySettingsEx avec des paramètres nuls pour appliquer toutes les modifications en attente

Définissez les valeurs dmPosition.x et dmPosition.y, utilisez la mémoire offset:

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

Obtenir des valeurs dmPosition.x et dmPosition.y, utiliser le décalage de mémoire:

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

Définir le bureau principal de l'instance display1 à l'instance display2. Apportez les modifications, puis appliquez toutes les modifications en attente:

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); 
Questions connexes