【问题标题】:Display master volume control slider (sndvol.exe) programmatically in correct position [closed]以编程方式在正确位置显示主音量控制滑块(sndvol.exe)[关闭]
【发布时间】:2013-01-21 02:31:06
【问题描述】:

刚买了一个新的东芝Satellite Z930,很失望地发现没有提供音量增大/减小功能键。但是,超级本确实在电源按钮旁边有两个可编程键,所以我正在尝试开发一个小型 C++ 应用程序,我可以通过这些键调用。

到目前为止,我的所有代码都可以很好地根据传递给程序的命令行参数来增加/减少音量。我遇到的唯一问题是我想显示主音量滑块以让用户知道操作有效,并且我希望它出现在您单击扬声器图标时出现的正常位置通知区域。

ATM 我只是使用 CreateProcess() 来运行“sndvol.exe -f”,它可以工作,但会在一个奇怪的位置(大约 {100, 400})显示窗口。因此,我尝试通过 EnumWindows() 和 GetWindowThreadProcessId() 获取窗口句柄,并使用 SetWindowPos() 将其移动到我想要的位置,但这没有效果。我可以成功获得进程顶层窗口的句柄,但不能移动它!

谁能解释这种行为?这与将焦点从滑块窗口关闭的事实有关吗? This 页面表明我想要实现的目标可能的,那么我做错了什么?

MTIA :D

【问题讨论】:

  • 感谢您的超快速回复,但不,这无济于事:( 如果我将 si.dwX 和 si.dwY 都设置为 5,它们在 CreateProcess 调用后仍然保持这个值,但是窗口仍然出现在原始位置:( TA
  • (我在此期间尝试过并删除了评论。请参阅我的答案,这对我有用。)
  • 为什么不将按键重新映射到硬件音量控制键?
  • @RaymondChen 如果我知道怎么做就太好了!大声笑:P
  • 您可以发送输入扫描码。

标签: c++ windows-8


【解决方案1】:

这个有趣的 STARTUPINFO 和 SetWindowPos 组合似乎起作用了:

#include "windows.h"
#include <iostream>

BOOL CALLBACK EnumWindowsProc(HWND hWnd, LPARAM lParam) {
    const DWORD myProcessId = (DWORD) lParam;

    DWORD processId;
    GetWindowThreadProcessId(hWnd, &processId);
    if (processId == myProcessId) {
        SetWindowPos(hWnd, 0, 1, 1, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
    }
    return TRUE;
}

int _tmain(int argc, _TCHAR* argv[])
{
    STARTUPINFO si;
    ZeroMemory(&si, sizeof(si));
    si.cb = sizeof(si);
    si.wShowWindow = SW_SHOWNORMAL;
    si.dwFlags = STARTF_USESHOWWINDOW;
    wchar_t cmdline[33000] = L" -f";
    PROCESS_INFORMATION pi;
    BOOL x = CreateProcess(L"c:\\Windows\\System32\\sndvol.exe", &cmdline[0], 0, 0, true, 0, 0, 0, &si, &pi);
    //std::cerr << x << " " << GetLastError() << std::endl;
    WaitForInputIdle(pi.hProcess, 100);

    for (int i = 0; i < 200; ++i)
    {
        x = EnumWindows(EnumWindowsProc, (LPARAM) pi.dwProcessId);
        //std::cerr << x << " " << GetLastError() << std::endl;
        Sleep(20);
    }

    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
    return 0;
}

您可能想尝试更多以获得更好的解决方案(例如,观察回调是否成功移动窗口至少k 次。我试过检查一次是否成功,但它并没有总是移动窗口。另外请确保检查您的进程句柄是否仍然引用有效进程 - 您不想编写无限循环。)。

尽管经过最新的修改,该解决方案变得相当可靠。

【讨论】:

  • 非常感谢您尝试提供帮助,但这对我不起作用...将您的代码逐字复制到一个新的 VC++ 控制台项目中并运行它,但得到的结果与我自己的应用程序中的结果相同:(您在什么操作系统上运行此代码?我在 Windows 8 上,所以也许这就是罪魁祸首...
  • 您好! WaitForInputIdle() 在某些情况下似乎等待的时间太短(对我来说,它在 Debug 中有效,但在 Release 中无效)。将其更改为 Sleep(1000) 效果更好。已在 Windows 7 和 8 上尝试过。您可能需要进行更多试验以获得更好的解决方案(例如,观察回调是否成功移动窗口至少 k 次。)。
  • 好的,是的,我明白你的意思了......我只是按照你的建议将 WaitForInputIdle() 调用更改为 Sleep() 调用,我第一次运行它时,它起作用了!但是现在我无法让它再次工作......我已经为 Sleep() 的 dwMilliseconds 参数尝试了许多不同的值,但都无济于事:( 那么我们怎么才能让它一直可靠地工作呢? !?! 这真的开始给我发邮件了...但再次感谢您的帮助!:)
  • 让它更可靠。多次移动窗口似乎可以确保覆盖默认位置。
  • 是的,这效果更好;再次感谢您!移动窗口后,我也从 EnumWindowsProc() 返回了 FALSE,所以这也干扰了进程!但是现在一切都很好,谢谢你! :D
【解决方案2】:

从“开箱即用”开始,而不是从代码中处理窗口的位置,而是在 CreateProcess 调用中添加命令行参数,您可以考虑 herehere。显然,示例中的字母参数可以省略。 我不确定我是否可以自己做数学,不熟悉坐标从哪里开始,但这似乎是一个可能的解决方案。

【讨论】:

    猜你喜欢
    • 2023-03-06
    • 2020-03-30
    • 1970-01-01
    • 1970-01-01
    • 2019-05-03
    • 1970-01-01
    • 1970-01-01
    • 2020-02-03
    • 1970-01-01
    相关资源
    最近更新 更多