这个让我果断的很是纠结啊。网上找了个C++版的,我在改C#版。用于改变多显示器下的显示器位置布局。
但是遇到的问题是调用 QueryDisplayConfig 后,结果是错的。可能是Api内判断我调用时就错了直接返回错误码了吧。
贴下调用的代码,其他的代码在下面继续贴上来,求牛人帮忙解决。。static void Main(string[] args)
        {
            IntPtr hMod = LoadLibrary("user32.dll");
            SETDISPLAYCONFIGFUNC SetDisplayConfig = Marshal.GetDelegateForFunctionPointer(GetProcAddress(hMod, "SetDisplayConfig"), typeof(SETDISPLAYCONFIGFUNC)) as SETDISPLAYCONFIGFUNC;
            GETDISPLAYBUFFERSIZESFUNC GetDisplayConfigBufferSizes = Marshal.GetDelegateForFunctionPointer(GetProcAddress(hMod, "GetDisplayConfigBufferSizes"), typeof(GETDISPLAYBUFFERSIZESFUNC)) as GETDISPLAYBUFFERSIZESFUNC;
            QUERYDISPLAYCONFIGFUNC QueryDisplayConfig = Marshal.GetDelegateForFunctionPointer(GetProcAddress(hMod, "QueryDisplayConfig"), typeof(QUERYDISPLAYCONFIGFUNC)) as QUERYDISPLAYCONFIGFUNC;            if (SetDisplayConfig != null && GetDisplayConfigBufferSizes != null && QueryDisplayConfig != null)
            {
                UInt32 NumPathArrayElements = 0;
                UInt32 NumModeInfoArrayElements = 0;
                if (GetDisplayConfigBufferSizes(QDC_ALL_PATHS, ref NumPathArrayElements, ref NumModeInfoArrayElements) != 0)
                {
                    throw new Exception("");
                }                DISPLAYCONFIG_PATH_INFO[] pPathInfoArray = new DISPLAYCONFIG_PATH_INFO[100];
                DISPLAYCONFIG_MODE_INFO[] pModeInfoArray = new DISPLAYCONFIG_MODE_INFO[100];
                DisplayPathInfos displayPathInfos = new DisplayPathInfos();
                displayPathInfos.DISPLAYCONFIG_PATH_INFO_ARRAY = pPathInfoArray;
                
                DisplayConfigModeInfos displayConfigModeInfos = new DisplayConfigModeInfos();
                displayConfigModeInfos.DISPLAYCONFIG_MODE_INFO_ARRAY = pModeInfoArray;                if (GetDisplayConfigBufferSizes(QDC_ALL_PATHS, ref NumPathArrayElements, ref NumModeInfoArrayElements) != 0)
                {
                    throw new Exception("");
                }
                DISPLAYCONFIG_TOPOLOGY_ID topLOGYID = DISPLAYCONFIG_TOPOLOGY_ID.DISPLAYCONFIG_TOPOLOGY_CLONE;                byte[] pathArrayBytes = CommonHelper.StrutsToBytesArray(displayPathInfos);
                byte[] modeInfoArrayBytes = CommonHelper.StrutsToBytesArray(displayConfigModeInfos);                unsafe
                {
                    fixed (byte* bp = &pathArrayBytes[0])
                    {
                        fixed (byte* bp2 = &modeInfoArrayBytes[0])
                        {
                            QueryDisplayConfig(QDC_ALL_PATHS, ref NumPathArrayElements, bp, ref NumModeInfoArrayElements, bp2, ref topLOGYID);
                        }
                    }
                }                displayPathInfos = (DisplayPathInfos)CommonHelper.BytesToStruts(pathArrayBytes, typeof(DisplayPathInfos));                string sss = "";
                //if (SetDisplayConfig(NumPathArrayElements, ref pPathInfoArray, NumModeInfoArrayElements, ref pModeInfoArray, SDC_TOPOLOGY_CLONE | SDC_APPLY) != 0)
                //{
                //    throw new Exception("");
                //}            }
        }

解决方案 »

  1.   


    [DllImport("kernel32.dll", EntryPoint = "LoadLibrary", SetLastError = true)]
            public static extern IntPtr LoadLibrary(string lpFileName);        [DllImport("kernel32.dll", EntryPoint = "GetProcAddress", SetLastError = true)]
            public static extern IntPtr GetProcAddress(IntPtr hModule, string lpProceName);        struct LUID
            {
                UInt32 LowPart;
                UInt32 HighPart;
            }        struct POINTL      /* ptl  */
            {
                UInt32 x;
                UInt32 y;
            }        struct DISPLAYCONFIG_2DREGION
            {
                UInt32 cx;
                UInt32 cy;
            }        enum DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY
            {
                DISPLAYCONFIG_OUTPUT_TECHNOLOGY_OTHER = -1,
                DISPLAYCONFIG_OUTPUT_TECHNOLOGY_HD15 = 0,
                DISPLAYCONFIG_OUTPUT_TECHNOLOGY_SVIDEO = 1,
                DISPLAYCONFIG_OUTPUT_TECHNOLOGY_COMPOSITE_VIDEO = 2,
                DISPLAYCONFIG_OUTPUT_TECHNOLOGY_COMPONENT_VIDEO = 3,
                DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DVI = 4,
                DISPLAYCONFIG_OUTPUT_TECHNOLOGY_HDMI = 5,
                DISPLAYCONFIG_OUTPUT_TECHNOLOGY_LVDS = 6,
                DISPLAYCONFIG_OUTPUT_TECHNOLOGY_D_JPN = 8,
                DISPLAYCONFIG_OUTPUT_TECHNOLOGY_SDI = 9,
                DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DISPLAYPORT_EXTERNAL = 10,
                DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DISPLAYPORT_EMBEDDED = 11,
                DISPLAYCONFIG_OUTPUT_TECHNOLOGY_UDI_EXTERNAL = 12,
                DISPLAYCONFIG_OUTPUT_TECHNOLOGY_UDI_EMBEDDED = 13,
                DISPLAYCONFIG_OUTPUT_TECHNOLOGY_SDTVDONGLE = 14,
                DISPLAYCONFIG_OUTPUT_TECHNOLOGY_INTERNAL = 0x8000000,
                DISPLAYCONFIG_OUTPUT_TECHNOLOGY_FORCE_UINT32 = 0xFFFFFFF
            }        enum DISPLAYCONFIG_ROTATION
            {
                DISPLAYCONFIG_ROTATION_IDENTITY = 1,
                DISPLAYCONFIG_ROTATION_ROTATE90 = 2,
                DISPLAYCONFIG_ROTATION_ROTATE180 = 3,
                DISPLAYCONFIG_ROTATION_ROTATE270 = 4,
                DISPLAYCONFIG_ROTATION_FORCE_UINT32 = 0xFFFFFFF
            }        enum DISPLAYCONFIG_SCALING
            {
                DISPLAYCONFIG_SCALING_IDENTITY = 1,
                DISPLAYCONFIG_SCALING_CENTERED = 2,
                DISPLAYCONFIG_SCALING_STRETCHED = 3,
                DISPLAYCONFIG_SCALING_ASPECTRATIOCENTEREDMAX = 4,
                DISPLAYCONFIG_SCALING_CUSTOM = 5,
                DISPLAYCONFIG_SCALING_PREFERRED = 128,
                DISPLAYCONFIG_SCALING_FORCE_UINT32 = 0xFFFFFFF
            }
            struct DISPLAYCONFIG_RATIONAL
            {
                UInt32 Numerator;
                UInt32 Denominator;
            }
            enum DISPLAYCONFIG_SCANLINE_ORDERING
            {
                DISPLAYCONFIG_SCANLINE_ORDERING_UNSPECIFIED = 0,
                DISPLAYCONFIG_SCANLINE_ORDERING_PROGRESSIVE = 1,
                DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED = 2,
                DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED_UPPERFIELDFIRST = DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED,
                DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED_LOWERFIELDFIRST = 3,
                DISPLAYCONFIG_SCANLINE_ORDERING_FORCE_UINT32 = 0xFFFFFFF
            }        enum DISPLAYCONFIG_PIXELFORMAT
            {
                DISPLAYCONFIG_PIXELFORMAT_8BPP = 1,
                DISPLAYCONFIG_PIXELFORMAT_16BPP = 2,
                DISPLAYCONFIG_PIXELFORMAT_24BPP = 3,
                DISPLAYCONFIG_PIXELFORMAT_32BPP = 4,
                DISPLAYCONFIG_PIXELFORMAT_NONGDI = 5,
                DISPLAYCONFIG_PIXELFORMAT_FORCE_UINT32 = 0xfffffff
            }
            enum DISPLAYCONFIG_MODE_INFO_TYPE
            {
                DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE = 1,
                DISPLAYCONFIG_MODE_INFO_TYPE_TARGET = 2,
                DISPLAYCONFIG_MODE_INFO_TYPE_FORCE_UINT32 = 0xFFFFFFF
            }        enum DISPLAYCONFIG_TOPOLOGY_ID
            {
                DISPLAYCONFIG_TOPOLOGY_INTERNAL = 0x00000001,
                DISPLAYCONFIG_TOPOLOGY_CLONE = 0x00000002,
                DISPLAYCONFIG_TOPOLOGY_EXTEND = 0x00000004,
                DISPLAYCONFIG_TOPOLOGY_EXTERNAL = 0x00000008,
                DISPLAYCONFIG_TOPOLOGY_FORCE_UINT32 = 0xFFFFFFF
            }        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
            struct DISPLAYCONFIG_PATH_TARGET_INFO
            {
                LUID adapterId;
                UInt32 id;
                UInt32 modeInfoIdx;
                DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY outputTechnology;
                DISPLAYCONFIG_ROTATION rotation;
                DISPLAYCONFIG_SCALING scaling;
                DISPLAYCONFIG_RATIONAL refreshRate;
                DISPLAYCONFIG_SCANLINE_ORDERING scanLineOrdering;
                bool targetAvailable;
                UInt32 statusFlags;
            }        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
            struct DISPLAYCONFIG_PATH_SOURCE_INFO
            {
                LUID adapterId;
                UInt32 id;
                UInt32 modeInfoIdx;
                UInt32 statusFlags;
            }        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
            struct DISPLAYCONFIG_PATH_INFO
            {
                DISPLAYCONFIG_PATH_SOURCE_INFO sourceInfo;
                DISPLAYCONFIG_PATH_TARGET_INFO targetInfo;
                UInt32 flags;
            }        struct DISPLAYCONFIG_VIDEO_SIGNAL_INFO
            {
                UInt64 pixelRate;
                DISPLAYCONFIG_RATIONAL hSyncFreq;
                DISPLAYCONFIG_RATIONAL vSyncFreq;
                DISPLAYCONFIG_2DREGION activeSize;
                DISPLAYCONFIG_2DREGION totalSize;
                UInt32 videoStandard;
                DISPLAYCONFIG_SCANLINE_ORDERING scanLineOrdering;
            }        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
            struct DISPLAYCONFIG_TARGET_MODE
            {
                DISPLAYCONFIG_VIDEO_SIGNAL_INFO targetVideoSignalInfo;
            }        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
            struct DISPLAYCONFIG_SOURCE_MODE
            {
                UInt32 width;
                UInt32 height;
                DISPLAYCONFIG_PIXELFORMAT pixelFormat;
                POINTL position;
            }        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
            struct DISPLAYCONFIG_MODE_INFO
            {
                DISPLAYCONFIG_MODE_INFO_TYPE infoType;
                UInt32 id;
                LUID adapterId;            DISPLAYCONFIG_TARGET_MODE targetMode;
                DISPLAYCONFIG_SOURCE_MODE sourceMode;        }        [StructLayout(LayoutKind.Sequential)]
            class DisplayPathInfos
            {
                [MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)]
                public DISPLAYCONFIG_PATH_INFO[] DISPLAYCONFIG_PATH_INFO_ARRAY;
            }        [StructLayout(LayoutKind.Sequential)]
            class DisplayConfigModeInfos
            {
                [MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)]
                public DISPLAYCONFIG_MODE_INFO[] DISPLAYCONFIG_MODE_INFO_ARRAY;
            }        static UInt32 QDC_ALL_PATHS = 0x00000001;
            static UInt32 SDC_TOPOLOGY_INTERNAL = 0x00000001;
            static UInt32 SDC_TOPOLOGY_CLONE = 0x00000002;
            static UInt32 SDC_TOPOLOGY_EXTEND = 0x00000004;
            static UInt32 SDC_TOPOLOGY_EXTERNAL = 0x00000008;
            static UInt32 SDC_TOPOLOGY_SUPPLIED = 0x00000010;
            static UInt32 SDC_USE_DATABASE_CURRENT = (SDC_TOPOLOGY_INTERNAL | SDC_TOPOLOGY_CLONE | SDC_TOPOLOGY_EXTEND | SDC_TOPOLOGY_EXTERNAL);        static UInt32 SDC_USE_SUPPLIED_DISPLAY_CONFIG = 0x00000020;
            static UInt32 SDC_VALIDATE = 0x00000040;
            static UInt32 SDC_APPLY = 0x00000080;
            static UInt32 SDC_NO_OPTIMIZATION = 0x00000100;
            static UInt32 SDC_SAVE_TO_DATABASE = 0x00000200;
            static UInt32 SDC_ALLOW_CHANGES = 0x00000400;
            static UInt32 SDC_PATH_PERSIST_IF_REQUIRED = 0x00000800;
            static UInt32 SDC_FORCE_MODE_ENUMERATION = 0x00001000;
            static UInt32 SDC_ALLOW_PATH_ORDER_CHANGES = 0x00002000;        unsafe delegate long SETDISPLAYCONFIGFUNC(UInt32 numPathArrayElements,
                                    byte* pathArray,
                                    UInt32 numModeInfoArrayElements,
                                    byte* modeInfoArray,
                                    UInt32 Flags
                                            );        delegate long GETDISPLAYBUFFERSIZESFUNC(
                                     UInt32 Flags,
                                     ref  UInt32 pNumPathArrayElements,
                                     ref  UInt32 pNumModeInfoArrayElements
                                     );        unsafe delegate long QUERYDISPLAYCONFIGFUNC(
                                    UInt32 Flags,
                                    ref    UInt32 pNumPathArrayElements,
                                    byte* pPathInfoArray,
                                    ref    UInt32 pNumModeInfoArrayElements,
                                    byte* pModeInfoArray,
                                    ref   DISPLAYCONFIG_TOPOLOGY_ID pCurrentTopologyId
                                    );
      

  2.   

    CommonHelper.cs
    public class CommonHelper
        {
            public static byte[] StrutsToBytesArray(object structObj)
            {
                //得到结构体的大小   
                int size = Marshal.SizeOf(structObj);
                //创建byte数组   
                byte[] bytes = new byte[size];
                //分配结构体大小的内存空间   
                IntPtr structPtr = Marshal.AllocHGlobal(size);
                //将结构体拷到分配好的内存空间   
                Marshal.StructureToPtr(structObj, structPtr, false);
                //从内存空间拷到byte数组   
                Marshal.Copy(structPtr, bytes, 0, size);
                //释放内存空间   
                Marshal.FreeHGlobal(structPtr);
                //返回byte数组   
                return bytes;
            }
            public static object BytesToStruts(byte[] bytes, Type type)
            {
                //得到结构体的大小   
                int size = Marshal.SizeOf(type);
                //byte数组长度小于结构体的大小   
                if (size > bytes.Length)
                {
                    //返回空   
                    return null;
                }
                //分配结构体大小的内存空间   
                IntPtr structPtr = Marshal.AllocHGlobal(size);
                //将byte数组拷到分配好的内存空间   
                Marshal.Copy(bytes, 0, structPtr, size);
                //将内存空间转换为目标结构体   
                object obj = Marshal.PtrToStructure(structPtr, type);
                //释放内存空间   
                Marshal.FreeHGlobal(structPtr);
                //返回结构体   
                return obj;
            }
        }
      

  3.   

    哎, ChangeDisplaySettings 只能修改分辨率,Position修改不了。
    查了下,貌似 SetDisplayConfig可以,Win7下的。
    但是用的人很少,只有C++版的。改了一下午没头绪,只把代码转过来了,再往下找问题就没头绪了,哎
      

  4.   

    如果谁有兴趣,在调代码的话,麻烦说下,我等着结果呢,哎,好纠结的Api。
      

  5.   


    unsafe delegate long SETDISPLAYCONFIGFUNC(UInt32 numPathArrayElements,
                                    byte* pathArray,
                                    UInt32 numModeInfoArrayElements,
                                    byte* modeInfoArray,
                                    UInt32 Flags
                                            );        delegate long GETDISPLAYBUFFERSIZESFUNC(
                                     UInt32 Flags,
                                     ref  UInt32 pNumPathArrayElements,
                                     ref  UInt32 pNumModeInfoArrayElements
                                     );        unsafe delegate long QUERYDISPLAYCONFIGFUNC(
                                    UInt32 Flags,
                                    ref    UInt32 pNumPathArrayElements,
                                    byte* pPathInfoArray,
                                    ref    UInt32 pNumModeInfoArrayElements,
                                    byte* pModeInfoArray,
                                    ref   DISPLAYCONFIG_TOPOLOGY_ID pCurrentTopologyId
                                    );修改为
    unsafe delegate UInt32 SETDISPLAYCONFIGFUNC(UInt32 numPathArrayElements,
                                    byte* pathArray,
                                    UInt32 numModeInfoArrayElements,
                                    byte* modeInfoArray,
                                    UInt32 Flags
                                            );        delegate UInt32 GETDISPLAYBUFFERSIZESFUNC(
                                     UInt32 Flags,
                                     ref  UInt32 pNumPathArrayElements,
                                     ref  UInt32 pNumModeInfoArrayElements
                                     );        unsafe delegate UInt32 QUERYDISPLAYCONFIGFUNC(
                                    UInt32 Flags,
                                    ref    UInt32 pNumPathArrayElements,
                                    byte* pPathInfoArray,
                                    ref    UInt32 pNumModeInfoArrayElements,
                                    byte* pModeInfoArray,
                                    ref   DISPLAYCONFIG_TOPOLOGY_ID pCurrentTopologyId
                                    );返回的错误码是87,就是 非法参数,继续调试,如果有谁有想法的话给个提示,谢谢。
    分啊,分啊。你们都只看不顶贴,我的分就要全给第一个人了。
      

  6.   

    不知道楼主的问题解决没有,你声明的Win32 API函数有问题,我这有一个做法
     [DllImport("User32.dll")]
            public static extern Int32 GetDisplayConfigBufferSizes(UInt32 Flags,
            out UInt32 NumPathArrayElements, out UInt32 NumModeInfoArrayElements);        [DllImport("User32.dll")]
            public static extern Int32 QueryDisplayConfig(UInt32 Flags,
            [In, Out] ref UInt32 NumPathArrayElements, IntPtr pPathInfoArray,
            [In, Out] ref UInt32 NumModeInfoArrayElements, IntPtr pModeInfoArray,
            out UInt32 CurrentTopologyId);        [DllImport("User32.dll")]
            public static extern Int32 SetDisplayConfig(
            UInt32 NumPathArrayElements, IntPtr pPathInfoArray,
            UInt32 NumModeInfoArrayElements, IntPtr pModeInfoArray,
            UInt32 Flags);
    另外,这几个API都用到了结构体数组作为参数,而C#是没有这样的定义,调用的时候要先用指针IntPtr再用Marshal做转换,试例代码如下:UInt32 NumPathArrayElements = 0;
    UInt32 NumModeInfoArrayElements = 0;
    Int32 RetVal;RetVal = GetDisplayConfigBufferSizes(QDC_ALL_PATHS, out NumPathArrayElements, out NumModeInfoArrayElements);IntPtr pPathArray = Marshal.AllocHGlobal(4096);
    IntPtr pModeArray = Marshal.AllocHGlobal(4096);UInt32 CurrentTopologyId = 0;RetVal = QueryDisplayConfig(QDC_DATABASE_CURRENT, ref NumPathArrayElements, pPathArray,ref NumModeInfoArrayElements, pModeArray, out CurrentTopologyId);DISPLAYCONFIG_PATH_INFO[] pPathArray = new DISPLAYCONFIG_PATH_INFO[NumPathArrayElements];
    DISPLAYCONFIG_MODE_INFO[] pModeArray = new DISPLAYCONFIG_MODE_INFO[NumModeInfoArrayElements];for (int i = 0; i < NumPathArrayElements; i++)
    {
         pPathArray[i] = new DISPLAYCONFIG_PATH_INFO();
         Marshal.PtrToStructure(pPathArrayBuffer, pPathArray[i]);
         pPathArrayBuffer = pPathArrayBuffer + Marshal.SizeOf(pPathArray[i]);
                 
    }for (int i = 0; i < NumModeInfoArrayElements; i++)
    {
         pModeArray[i] = new DISPLAYCONFIG_MODE_INFO();
         Marshal.PtrToStructure(pModeArrayBuffer, pModeArray[i]);
         pModeArrayBuffer = pModeArrayBuffer + Marshal.SizeOf(pModeArray[i]);}
     对应的Struct的定义如下(这里只给出一个例子):[StructLayout(LayoutKind.Sequential)]
    public class DISPLAYCONFIG_PATH_INFO
    {
         DISPLAYCONFIG_PATH_SOURCE_INFO  sourceInfo;
         DISPLAYCONFIG_PATH_TARGET_INFO  targetInfo;
         [MarshalAs(System.Runtime.InteropServices.UnmanagedType.U4)]
         UInt32                          flags;
    }
      

  7.   

    By default, SetDisplayConfig never changes any supplied path, source mode, or target mode information. If best mode logic cannot find a solution without changing the specified display path information, SetDisplayConfig fails with ERROR_BAD_CONFIGURATION. In this case, the caller should specify the SDC_ALLOW_CHANGES flag to allow the function to tweak some of the specified source and mode details to allow the display path change to be successful.