近一段时间刚刚接触C#,需要做一个修改外部程序界面上面的值 然后自动点击确认即可
修改界面如下 通过C#程序修改 仅做记录,以免以后忘记
我写一个C# 控制台程序
首先要用spy++来获取每个固定控件的ID
spy++ 地址 链接: https://pan.baidu.com/s/1gwuHMf2Umg_wtxVGFoRoDQ 提取码: mggv
简单介绍一下spy++的使用方法吧我也是刚接触
spy++打开界面如下
按下CTRL+F 搜索 或者手动点击界面上面一个望远镜的图标
点击Find Window 界面中的Finder Tool后面的 鼠标左键不松手 ,然后放到控件上面
放好之后,点击Find Windows下面OK按钮
其中Control ID 就是该控件的ID 该ID是唯一的,句柄是00350A30 这个是每次打开都会变掉的
环境:VS2015+win10 64位 台式机
下面开始放代码吧 仅供参考
using System;
using System.Runtime.InteropServices;
using System.Text;
using NS_INI;
using NS_TRACELOG;
using System.Diagnostics;
/*
* ModifyX265 -CModifyX265 主要用于配置H265软件安装出来的界面的配置
*/
namespace ModifyX265
{
public class CModifyX265
{
[DllImport("User32.dll", EntryPoint = "FindWindow")]
public extern static IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("User32.dll", EntryPoint = "FindWindowEx")]
public static extern IntPtr FindWindowEx(IntPtr hHandleParent, IntPtr hHandleChildAfter, string lpClassName, string lpWindowName);
[DllImport("User32.dll", EntryPoint = "FindEx")]
public static extern IntPtr FindEx(IntPtr hHandle, IntPtr hHandleChild, string lpClassName, string lpWindowName);
//[DllImport("user32.dll", EntryPoint = "GetWindowText")]
//public static extern int GetWindowText(int hHandle, string lpString, int cch);
//用于一般控件发送事件
[DllImport("User32.dll", EntryPoint = "SendMessage")]
private static extern int SendMessage(IntPtr hHandle, int Msg, IntPtr wParam, StringBuilder lParam);
//用于 edit 发送事件
[DllImport("User32.dll", EntryPoint = "SendMessage")]
private static extern int SendMessageString(IntPtr hHandle, int Msg, IntPtr wParam, string lParam);
[DllImport("User32.dll", EntryPoint = "SendMessage")]
private static extern int SendMessage_A(IntPtr hHandle, int Msg, int wParam, int lParam);
[DllImport("user32.dll ", EntryPoint = "GetDlgItem")]
public static extern IntPtr GetDlgItem(IntPtr hParent, int nIDParentItem);
[DllImport("user32.dll", EntryPoint = "GetWindowText")]
public static extern int GetWindowText(IntPtr hHandle, StringBuilder lpString, int cch);
[DllImport("user32.dll", EntryPoint = "GetDlgItemTextA")]
private static extern int GetDlgItemText(IntPtr hDlg, int nIDDlgItem, [Out]StringBuilder lpString, int nMaxCount);
#region 这里是根据spy++ 拿到H265配置界面上面的控件ID,根据控件ID即可操控控件的方法和属性
const int m_nPreSetHandle = 0x3F1; //preset句柄值
const int m_nTuningHandle = 0x3F2; //Tuning句柄值
const int m_nPrrofileHandle = 0x3F3; //Profile句柄值
const int m_nLevelHandle = 0x3F4; //Level句柄值
const int m_nFastDecodeHandle = 0x3F5; //FastDecode句柄值
const int m_nFastDecodeColorSpaceHandle = 0x415; //FastDecode后面要转换的句柄值
const int m_nZeroLatencyHandle = 0x3F6; //ZeroLatency句柄值
const int m_nRateControlHandle = 0x3F7; //RateControl句柄值
const int m_nRateControlTextHandle = 0x3F9; //RateControl设置后 Ratefactor或者Target bitrate句柄值
const int m_nCreateStatusFileHandle = 0x3FD; //CreateStatusFile句柄值
const int m_nOutputModeHandle = 0x401; //OutputMode句柄值
const int m_nVFWFourCCHandle = 0x402; //VFWFourCC句柄值
const int m_nVirtualDubHackHandle = 0x403; //VirtualDubHack句柄值
const int m_nSARWidthHandle = 0x407; //SAR Width句柄值
const int m_nSARHeightHandle = 0x408; //SAR Height句柄值
const int m_nLogLevelHandle = 0x409; //Log Level句柄值
const int m_nDisableAllCpuOptimizationsHandle = 0x40C; //Disable All Cpu Optimizations句柄值
const int m_nDisableDecoderSWHWHandle = 0x40D; //Disable Decoder SW/HW句柄值
const int m_nEnableHwDecoderHandle = 0x40E; //Enable Hw Decoder句柄值
const int m_nBtnOkHandle = 0x01; //确定按钮
const int m_nBtnCancelHandle = 0x02; //取消按钮
#endregion
#region 这里是windows消息映射对应需要对控件做相应操作
const int WM_SETTEXT = 0x0C; //设置框里面的值
const int WM_GETTEXT = 0x0D; //获取文本框里面的值
const int LB_SETCURSEL = 0x0186;
const int BM_SETCHECK = 0x00F1; //设置是否选中
const int BM_GETCHECK = 0x00F0; //获取是否选中
const int BM_CLICK = 0x00F5; //按钮单机
const int MB_OK = 0x00000000; //确认按钮
const int WM_SETFOCUS = 0x07; //获取焦点
const int WM_LBUTTONDOWN = 0x0201;
const int WM_LBUTTONUP = 0x0202;
const int WM_KEYDOWN = 0x0100;
const int WM_KEYUP = 0x0101;
const int WM_COMMAND = 0x0111;
const int CB_SELECTSTRING = 0x014D;
const int CB_SHOWDROPDOWN = 0x014F; //展开ComboBox列表框
const int CB_SETCURSEL = 0x014E;//修改下拉框 默认选中那一项 相当于MFC中的SetCurlSel
const int BST_UNCHECKED = 0x0000; //checkbox没有选中
const int BST_CHECKED = 0x0001; //check box 设置选中
#endregion
#region 这里是windows消息 键盘键位
const int VK_RETURN = 0x0D;
const int VK_SPACE = 0x20;
#endregion
//这里是主窗口句柄H265
public static IntPtr m_MainHandle;
//这里是每个具体控件对应的命名 主要用于读取配置文件和其他操作
public static int m_nPreset;
public static int m_nTuning;
public static int m_nProfile;
public static int m_nLevel;
public static int m_nFastDecode;
public static int m_nFastDecodeColorSpace;
public static int m_nZeroLatency;
public static int m_nRateControl;
public static int m_nRatefactorOrAveragebrtrate;
public static int m_nCreateStatusFile;
public static int m_nOutputMode;
public static int m_nVfwFourCC;
public static int m_nVirtualDubHack;
public static int m_nSarWidth;
public static int m_nSarHeight;
public static int m_nLogLevel;
public static int m_nDisableAllCpuOptimizations;
public static int m_nDisableDecoderSwHw;
public static int m_nEnableHwDecoder;
public static int m_nBtnOk;
public static int m_nBtnCancel;
/*
* strSession读取ini的session strKeyini的key IniType ini的类型 如int-0或者string-1
*/
public static string ReadIni(string strSession,string strKey,int IniType)
{
string strOut = "";
try
{
CIni.MstrFileName = Environment.CurrentDirectory + "\\config_x265.ini";
if (IniType == 1)
{//读取string类型的节点返回string值
strOut = CIni.IniReadString(strSession, strKey, "");
}else
if (IniType == 0)
{//读取string类型的节点返回int值
strOut = ( CIni.IniReadInt(strSession, strKey,-1) ).ToString();
}
}
catch(Exception e)
{
CTraceLog.TraceLog("读取ini异常,Session=" + strSession+ "Key="+ strKey);
strOut = "";
}
return strOut;
}
/*nType 类型combox textbox等 , edit - 1 ,combox- 2 ,checkbox - 3
* nTypeHandle 类型的句柄
* strData 从配置文件中读取的值 strMsg描述*/
public static void SetAllH265Item(int nType,int nTypeHandle,int nData,string strMsg)
{
StringBuilder buffer = new StringBuilder(1024);
IntPtr TypeHandle = GetDlgItem(m_MainHandle, nTypeHandle);
switch (nType)
{
case 1:
System.Threading.Thread.Sleep(10);
SendMessageString(TypeHandle, WM_SETTEXT, (IntPtr)nData, nData.ToString());
SendMessage(TypeHandle, WM_GETTEXT, (IntPtr)buffer.Capacity, buffer);
break;
case 2:
SendMessage_A(TypeHandle, CB_SHOWDROPDOWN, 1, 0); //展开ComboBox列表框
SendMessage_A(TypeHandle, CB_SETCURSEL, nData, 0); //指向需要写入的下标
SendMessage_A(TypeHandle, WM_SETFOCUS, 0, 0); //设置焦点
System.Threading.Thread.Sleep(10);
SendMessage_A(TypeHandle, WM_KEYDOWN, VK_RETURN, 0); //模拟鼠标按下
System.Threading.Thread.Sleep(10);
SendMessage_A(TypeHandle, WM_KEYUP, VK_RETURN, 0);//模拟鼠标放开
SendMessage(TypeHandle, WM_GETTEXT, (IntPtr)buffer.Capacity, buffer);//获取combox的值
break;
case 3:
if (nData == 1)
{ //配置文件按钮状态为选中
if (SendMessage_A(TypeHandle, BM_GETCHECK, 0, 0) != BST_CHECKED)
{ //如果没有选中 设置选中状态
System.Threading.Thread.Sleep(5);
SendMessage_A(TypeHandle, WM_KEYDOWN, VK_SPACE, 0); //模拟鼠标按下
System.Threading.Thread.Sleep(5);
SendMessage_A(TypeHandle, WM_KEYUP, VK_SPACE, 0);//模拟鼠标放开
}
}else
{ //配置文件中按钮状态为未选中
if (SendMessage_A(TypeHandle, BM_GETCHECK, 0, 0) == BST_CHECKED)
{ //如果按钮是选中的 那么再选一次 就变成了未选中状态
System.Threading.Thread.Sleep(5);
SendMessage_A(TypeHandle, WM_KEYDOWN, VK_SPACE, 0); //模拟鼠标按下
System.Threading.Thread.Sleep(5);
SendMessage_A(TypeHandle, WM_KEYUP, VK_SPACE, 0);//模拟鼠标放开
}
}
if (SendMessage_A(TypeHandle, BM_GETCHECK, 0, 0) == BST_CHECKED) //输出按钮选中状态
{
CTraceLog.TraceLog(strMsg + "是选中状态");
}
else
{
CTraceLog.TraceLog(strMsg + "不是选中状态");
}
break;
default:
break;
}
if (nType != 3)
{ //输出 combox 和edit 中获取到的值
CTraceLog.TraceLog(strMsg + "取到的值为=" + buffer.ToString());
}
buffer.Clear();
}
public static void SetH265Form()
{
try
{
int n_Time = Convert.ToInt32(ReadIni("SOFTWAIT", "TIME", 0)); //从配置文件中读取H265界面打开扫描时间,预防H265界面没有打开
int nWriteTime = n_Time;
//主要是为了检测H265配置界面是否打开
while (n_Time >= 0)
{
m_MainHandle = FindWindow(null, "x265vfw configuration"); //获得H265界面句柄
if (m_MainHandle != (IntPtr)0)
{
break;
}else
{
System.Threading.Thread.Sleep(1000);
n_Time --;
}
}
if (m_MainHandle != IntPtr.Zero)
{
//开始设置 Preset 下拉框默认选中第几行
m_nPreset = Convert.ToInt32( ReadIni("Preset", "INDEX",0 ));
SetAllH265Item(2, m_nPreSetHandle, m_nPreset, "Preset");
//开始设置 Tuning 下拉框默认选中第几行
m_nTuning = Convert.ToInt32(ReadIni("Tuning", "INDEX", 0));
SetAllH265Item(2, m_nTuningHandle, m_nTuning, "Tuning");
//开始设置 Profile 下拉框默认选中第几行
m_nProfile = Convert.ToInt32(ReadIni("Profile", "INDEX", 0));
SetAllH265Item(2, m_nPrrofileHandle, m_nProfile, "Profile");
//开始设置 Level 下拉框默认选中第几行
m_nLevel = Convert.ToInt32(ReadIni("Level", "INDEX", 0));
SetAllH265Item(2, m_nLevelHandle, m_nLevel, "Level");
//开始设置 Fast Decode checkbox 是否选中
m_nFastDecode = Convert.ToInt32(ReadIni("FastDecode", "ISCHECK", 0));
SetAllH265Item(3, m_nFastDecodeHandle, m_nFastDecode, "Fast Decode");
//开始设置 Fast Decode 后面colorspace 下拉框默认选中第几行
m_nFastDecodeColorSpace = Convert.ToInt32(ReadIni("Colorspace", "INDEX", 0));
SetAllH265Item(2, m_nFastDecodeColorSpaceHandle, m_nFastDecodeColorSpace, "Fast Decode ColorSpace");
//设置 Zero Latency checkbox是否选中 是否选中
m_nZeroLatency = Convert.ToInt32(ReadIni("ZeroLatency", "ISCHECK", 0));
SetAllH265Item(3, m_nZeroLatencyHandle, m_nZeroLatency, "Zero Latency");
//开始设置 RateControl CRF ABR 下拉框默认选中第几行
m_nRateControl = Convert.ToInt32(ReadIni("Ratecontrol", "INDEX", 0));
SetAllH265Item(2, m_nRateControlHandle, m_nRateControl, "RateControl CRF");
//开始设置 RateControl CRF ABR 后面的质量或者平均比特率 textbox 文本框
m_nRatefactorOrAveragebrtrate = Convert.ToInt32(ReadIni("Ratecontrol_CRF", "MINMAX", 0));
SetAllH265Item(1, m_nRateControlTextHandle, m_nRatefactorOrAveragebrtrate, " RateControl CRF ABR 后面的质量或者平均比特率");
//开始设置CreateStatusFile checkbox是否选中
m_nCreateStatusFile = Convert.ToInt32(ReadIni("CreateStatusFile", "ISCHECK", 0));
SetAllH265Item(3, m_nCreateStatusFileHandle, m_nCreateStatusFile, "Create Status File ");
//开始设置Output mode 下拉框默认选中第几行
m_nOutputMode = Convert.ToInt32(ReadIni("OutPutMode", "INDEX", 0));
SetAllH265Item(2, m_nOutputModeHandle, m_nOutputMode, "Output mode");
//开始设置 VFW FourCC 下拉框默认选中第几行
m_nVfwFourCC = Convert.ToInt32(ReadIni("VFWFourCC", "INDEX", 0));
SetAllH265Item(2, m_nVFWFourCCHandle, m_nVfwFourCC, "VFW FourCC");
//开始设置 VirtualDub Hack checkbox选中状态
m_nVirtualDubHack = Convert.ToInt32(ReadIni("VirtualDubHack", "ISCHECK", 0));
SetAllH265Item(3, m_nVirtualDubHackHandle, m_nVirtualDubHack, "VirtualDub Hack ");
//开始设置 SAR Width textbox
m_nSarWidth = Convert.ToInt32(ReadIni("SARWIDTH", "WIDTH", 0));
SetAllH265Item(1, m_nSARWidthHandle, m_nSarWidth, "SAR Width ");
//开始设置 SAR Height textbox
m_nSarHeight = Convert.ToInt32(ReadIni("SARHeight", "HEIGHT", 0));
SetAllH265Item(1, m_nSARHeightHandle, m_nSarHeight, "SAR Height ");
//开始设置 Log Level
m_nLogLevel = Convert.ToInt32(ReadIni("LogLevel", "INDEX", 0));
SetAllH265Item(2, m_nLogLevelHandle, m_nLogLevel, "Log Level ");
//开始设置 Disable all cpu optimizations
m_nDisableAllCpuOptimizations = Convert.ToInt32(ReadIni("DisableAllCpuOptimizations", "ISCHECK", 0));
SetAllH265Item(3, m_nDisableAllCpuOptimizationsHandle, m_nDisableAllCpuOptimizations, "DisableAllCpuOptimizations ");
//开始设置Disable Decoder Sw/hw
m_nDisableDecoderSwHw = Convert.ToInt32(ReadIni("DisableDecoderSWHW", "ISCHECK", 0));
SetAllH265Item(3, m_nDisableDecoderSWHWHandle, m_nDisableDecoderSwHw, "Disable Decoder Sw/hw ");
//开始设置 Enable Hw(DXVI) decoder
m_nEnableHwDecoder = Convert.ToInt32(ReadIni("DisableDecoderSWHW", "ISCHECK", 0));
SetAllH265Item(3, m_nEnableHwDecoderHandle, m_nEnableHwDecoder, "Enable Hw(DXVI) decoder");
System.Threading.Thread.Sleep(100);
//OK 确定按钮
IntPtr TypeHandle = GetDlgItem(m_MainHandle, m_nBtnOkHandle);
SendMessage_A(m_MainHandle, WM_COMMAND, m_nBtnOkHandle, m_nBtnOkHandle);
System.Threading.Thread.Sleep(100);
//SendMessageMain(TypeHandle, BM_CLICK, 0, 0);
}
else
{
CTraceLog.TraceLog("从配置文件中读取到配置" + nWriteTime.ToString() + "秒后还是未检测到窗口,关闭本程序");
}
}
catch (Exception e)
{
CTraceLog.TraceLog("配置出现异常: " + e.ToString());
}
}
//H265会报错 RunDLL
public static void CloseRunDll()
{
try
{
CTraceLog.TraceLog("开始关闭 RUN DLL窗口");
IntPtr rulGandle = FindWindow(null, "RunDLL"); //获得RunDLL界面句柄
//SendMessage_A(rulGandle, WM_KEYDOWN, VK_RETURN, 0);
}catch(Exception e)
{
CTraceLog.TraceLog("关闭RUN DLL异常=" + e.ToString());
}
}
private static IntPtr MAKEWPARAM(int m_nPreSetHandle, object cBN_SELCHANGE)
{
throw new NotImplementedException();
}
private static void SendMessage(IntPtr intPtr1, int m_nRatefactorOrAveragebrtrate, IntPtr intPtr2, string v)
{
throw new NotImplementedException();
}
}
class Program
{
static void Main(string[] args)
{
//设置日志文件名称 日志位于当前exe同级目录下面的log
CTraceLog.SetTraceLogFilePath("SetH265");
CTraceLog.TraceLog("配置H265界面开始");
//开始调用具体设置方法
CModifyX265.SetH265Form();
CModifyX265.CloseRunDll();
CTraceLog.TraceLog("配置H265界面结束\r\n");
}
}
}
总结一下吧
获取具体控件句柄的值
界面的句柄 = FindWindow(null, "需要查找界面的名称“); //获得H265界面句柄
具体控件的句柄=GetDlgItem(界面的句柄, 具体控件的ID); //具体控件ID可以根据SPY++获取到
修改COMBOX的值
SendMessage_A(COMBOX具体控件的句柄, CB_SHOWDROPDOWN, 1, 0); //展开ComboBox列表框
SendMessage_A(COMBOX具体控件的句柄, CB_SETCURSEL, nData, 0); //指向需要写入的下标
SendMessage_A(COMBOX具体控件的句柄, WM_SETFOCUS, 0, 0); //设置焦点
SendMessage_A(COMBOX具体控件的句柄, WM_KEYDOWN, VK_RETURN, 0); //模拟鼠标按下
SendMessage_A(COMBOX具体控件的句柄, WM_KEYUP, VK_RETURN, 0);//模拟鼠标放开 SendMessage(COMBOX具体控件的句柄, WM_GETTEXT, (IntPtr)buffer.Capacity, buffer);//获取combox的值
修改edit里面的值
SendMessageString(EDIT具体控件的句柄, WM_SETTEXT, (IntPtr)nData, nData.ToString());
获取EDIT里面的值
SendMessage(EDIT具体控件的句柄, WM_GETTEXT, (IntPtr)buffer.Capacity, buffer);
设置CHECK选中或者未选中 先根据BM_GETCHECK获取选中状态 然后在执行下面的2句 即可设置是否选中
通过SendMessage_A(CHECKBOX的句柄, BM_GETCHECK, 0, 0) != BST_CHECKED
如果为BST_CHECKED那么是选中执行下面2句为未选中状态
如果不为BST_CHECKED 那么是不选中执行下面2句为选中状态
SendMessage_A(CHECKBOX具体控件的句柄, WM_KEYDOWN, VK_SPACE, 0); //模拟鼠标按下
SendMessage_A(CHECKBOX具体控件的句柄, WM_KEYUP, VK_SPACE, 0);//模拟鼠标放开
一个界面中打开另一个子界面 修改子界面上面控件的值 步骤
界面的句柄 = FindWindow(null, "需要查找界面的名称“);
子界面的句柄 = ::GetWindow(界面的句柄 , GW_CHILD);
具体控件的句柄=GetDlgItem(子界面的句柄, 具体控件的ID); //具体控件ID可以根据SPY++获取到
MFC步骤和C#步骤类似 应该说更简单一点 因为C#需要导入user32.dll而MFC不需要
其他说明点:
对于自己来说中间遇到过用SPY++获取不到控件值的问题,过程是点击SPY++的按钮拖动到界面上 比如一个panle里面放了一个TEXT 只能获取到panle的值 而用SPY++获取不到TEXT的ID,这种情况用SPY++和SPYLITE两种工具每个都试下,我自己测试过程后,还没有说这两种工具都试不出来的情况
如果有朋友不懂 或者指正 在下面留言 我看到会回复的