简体   繁体   English

重新启动计算机后,SetDisplayConfig的配置无效

[英]Configs for SetDisplayConfig become invalid after computer restart

I'm using WINAPI to Enable/Disable my TV monitor by calling a method. 我正在使用WINAPI通过调用方法来启用/禁用电视监视器。

The method I found to work was saving the whole pathInfo and modeInfo arrays for both states 我发现可以使用的方法是为两种状态保存整个pathInfo和modeInfo数组
(Enabled/Disabled) and using them to restore to that state . (启用/禁用),并使用它们还原到该状态。

The method works properly but after restarting my computer, the settings become obsolete. 该方法可以正常工作,但是在重新启动计算机后,设置已过时。
It works fine if I just restart the program, so the serialization is correct. 如果我只是重新启动程序,它会很好地工作,因此序列化是正确的。

The goal was to Save/Serialize those settings ONCE on a computer, and be able to use them forever. 目的是在计算机上一次保存/序列化这些设置,并能够永久使用它们。

I've tried saving only the path and mode of the individual monitor that I'm interested on (by filtering the active displays only), but it turns out that the other screens' modes are affected as well when there is an extra display in the setup. 我尝试只保存我感兴趣的单个监视器的路径和模式(仅通过过滤活动显示),但是事实证明,当其中有多余的显示时,其他屏幕的模式也会受到影响。设置。

The main method is the method below, but you can find the whole class here! 主要方法是下面的方法,但是您可以在这里找到整个类!
(I'm using the User32 PInvoke lib on top of that) (我在上面使用User32 PInvoke lib

[Serializable]
public class TVSettings {
    public DISPLAYCONFIG_PATH_INFO[] Path;
    public DISPLAYCONFIG_MODE_INFO[] Mode;
    public TVSettings(DISPLAYCONFIG_PATH_INFO[] pathArray, DISPLAYCONFIG_MODE_INFO[] modeArray) {
        Path = pathArray;
        Mode = modeArray;
    }
}
// The preset of the settings which I serialize.
public static TVSettings Enabled;
public static TVSettings Disabled;

// The main method. Merged the Save & ChangeState branches to save space.
public static void ChangeTVState(bool ChangeState = false, bool Save = false) {
    uint numPathArrayElements = 0;
    uint numModeInfoArrayElements = 0;
    uint id = QDC_ALL_PATHS; // Searching for ALL PATHS because I want the disabled screen inside the array after the Query.

    // Initialize and Query all the Display Config info.
    int bufferError = GetDisplayConfigBufferSizes(id, ref numPathArrayElements, ref numModeInfoArrayElements);
    DISPLAYCONFIG_PATH_INFO[] pathArray = new DISPLAYCONFIG_PATH_INFO[numPathArrayElements];
    DISPLAYCONFIG_MODE_INFO[] modeArray = new DISPLAYCONFIG_MODE_INFO[numModeInfoArrayElements];

    QueryDisplayConfig(id, ref numPathArrayElements, pathArray, ref numModeInfoArrayElements, modeArray, IntPtr.Zero);

    // Grab the active Screens -- was previously used for tests.
    var active_modeArray = modeArray.Where(x => x.targetMode.targetVideoSignalInfo.activeSize.cx != 0).ToArray();
    var active_pathArray = pathArray.Where(x => x.flags != 0).ToArray();

    bool ThirdScreenIsConnected = active_pathArray.Length >= 3 && active_modeArray.Length >= 3;

    if (Save) {
        // Save on the appropriate Preset field.
        if (ThirdScreenIsConnected) { Enabled = new TVSettings(pathArray, modeArray); }
        else { Disabled = new TVSettings(pathArray, modeArray); }
    }

    if (ChangeState) {
        // Safety measures because I don't wanna mess up the settings too much.
        if (Enabled == null || Disabled == null) {
            Console.WriteLine("Enabled & Disabled Settings are not configured properly.");
            Console.WriteLine("Please save both and try again.");
            return;
        }

        // Use the settings of the other state
        // eg: if 3rd monitor is currently disabled, we use the Disabled preset.
        var Settings = ThirdScreenIsConnected ? Disabled : Enabled;
        pathArray = Settings.Path;
        modeArray = Settings.Mode;

        // Call SetDisplayConfig to update the display config.
        // It works fine on a single windows boot, but the settings are not valid if I reboot.
        uint flag = (SDC_APPLY | SDC_SAVE_TO_DATABASE | SDC_ALLOW_CHANGES | SDC_USE_SUPPLIED_DISPLAY_CONFIG);
        int errorID = SetDisplayConfig((uint)pathArray.Length, pathArray, (uint)modeArray.Length, modeArray, flag);

        if (errorID == 0) { Console.WriteLine("Successfully updated Screen setup!"); }
        else { Console.WriteLine("ERROR: " + errorID); }
    }

}

I would expect the settings to be valid on multiple windows sessions, but they are being deemed invalid instead. 我希望这些设置在多个Windows会话上均有效,但是它们却被视为无效。

The error that appears after restarting is : 87 -- INVALID PARAMETERS , which also appeared when I attempted to alter the individual settings of the monitor (in pathArray and modeArray ). 重新启动后出现的错误是: 87 -- INVALID PARAMETERS ,当我尝试更改监视器的各个设置(在pathArraymodeArray )时,也会出现该错误。

If you care enough to try this on your machine, here's some usable Save/Load functionality, together with a simple context menu for WPF 如果您足够在计算机上尝试此操作,则可以使用一些可用的“保存/加载”功能,以及用于WPF的简单上下文菜单。

(You have to exit via the "Exit" button on the context menu for the serialization to occur) (您必须通过上下文菜单上的“退出”按钮退出才能进行序列化)
(ps: you have to save twice -- once with 2nd screen Enabled and once with it Disabled) (ps:您必须保存两次-一次启用第二个屏幕,一次禁用)

Any help would be appreciated! 任何帮助,将不胜感激! :) :)

I found out that the issue was occuring because the adapterID of the GPU and motherboard were changing with each computer restart. 我发现发生此问题是因为随着每台计算机的重新启动,GPU和主板的adapterID都在变化。

I found a nice way to solve my issue without any serialization of the previous adapterID ! 我找到了一种无需对先前的adapterID进行任何序列化即可解决我的问题的好方法!
Here's the code for it: 这是它的代码:

static void UpdateAdapterID() {

    // Cache saved adapterIDs, for later comparison with the current ones.
    LUID savedAdapterID_GPU = Enabled.Path[0].sourceInfo.adapterId;
    LUID savedAdapterID_MB = Enabled.Path.First(x => x.sourceInfo.adapterId.LowPart != savedAdapterID_GPU.LowPart && x.sourceInfo.adapterId.LowPart != 0).sourceInfo.adapterId;

    bool isAdapterUpdated_GPU = savedAdapterID_GPU.LowPart == CurrentAdapterID_GPU.LowPart;
    bool isAdapterUpdated_MB = savedAdapterID_MB.LowPart == CurrentAdapterID_MB.LowPart;

    // Check if our saved states have already been updated.
    if (isAdapterUpdated_GPU && isAdapterUpdated_MB) { return; }

    for (int i = 0; i < Enabled.Path.Length; i++) {
        Update(ref Enabled.Path[i].sourceInfo.adapterId);
        Update(ref Enabled.Path[i].targetInfo.adapterId);
    }
    for (int i = 0; i < Disabled.Path.Length; i++) {
        Update(ref Disabled.Path[i].sourceInfo.adapterId);
        Update(ref Disabled.Path[i].targetInfo.adapterId);
    }

    for (int i = 0; i < Enabled.Mode.Length; i++) { Update(ref Enabled.Mode[i].adapterId); }
    for (int i = 0; i < Disabled.Mode.Length; i++) { Update(ref Disabled.Mode[i].adapterId); }



    void Update(ref LUID adapterID) {
        bool isInvalid = adapterID.LowPart == 0;
        bool isUpdated = adapterID.LowPart == CurrentAdapterID_GPU.LowPart || adapterID.LowPart == CurrentAdapterID_MB.LowPart;

        if (!isInvalid && !isUpdated) {
            bool adapterIsGPU = adapterID.LowPart == savedAdapterID_GPU.LowPart;
            if (adapterIsGPU) { adapterID = CurrentAdapterID_GPU; }
            else { adapterID = CurrentAdapterID_MB; }
        }
    }

    if (!isAdapterUpdated_GPU) { Console.WriteLine("Updated adapterID for GPU."); }
    if (!isAdapterUpdated_MB) { Console.WriteLine("Updated adapterID for MB."); }
}

Here's the whole script in case anyone can find it helpful :) 这是整个脚本,以防万一有人发现它有用:)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 重新启动计算机后,该文件包含空值而不是JSON对象 - File containing null values instead of JSON object after computer restart 重新启动计算机后,w8 metro live tile不会动画 - w8 metro live tile wont animate after computer restart 类文件使用记事本打开,计算机重新启动后完全空白 - Class file opens with notepad and is completely blank after computer restart 在浏览器刷新或计算机重新启动后永久存储 Swagger UI 令牌 - Store Swagger UI Tokens Permanently after Browser Refresh or Computer Restart 从WinForms应用程序重新启动计算机? - Restart computer from WinForms app? 重新启动计算机后,“ System.Security.Cryptography.CryptographicException”:密钥集不存在 - After computer restart, 'System.Security.Cryptography.CryptographicException' : Keyset does not exist 重新启动后重新启动安装程序 - Restart Setup after reboot 除非我重新启动计算机,否则HttpWebRequest每次都无法连接 - HttpWebRequest fails to connect everytime unless I restart the computer 反序列化后,JSON字段值变为null - JSON field values become null after deserialization 使用子句后,导航属性变为空 - Navigation Properties become null after using clause
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM