2

我正在开发一个 Windows 7 应用程序,它必须防止 WinDVD 在插入时触发新的磁盘可用性(即插入 DVD)。

背景资料:

我正在为一家公司开发这个小应用程序,该公司必须同时比较两个电影播放器​​,同时从不同的驱动器播放同一张 DVD。

他们正在进行启发式质量测试,以确定目前最好的 DVD 播放器,以便将其捆绑到他们的新 PC 产品线中。

目前,他们最好的选择似乎是 WinDVD,因此必须针对它进行所有其他测试。问题是,当他们插入第一张 DVD 时,默认播放器 WinDVD 就可以启动了。

然后当他们插入第二张光盘时,默认播放器首先响应,因此他们被迫关闭窗口并打开他们正在测试的另一个播放器。

许多电影都是这样做的,这些电影代表了对专色渲染和图像质量的参考。用户在显示时关闭附加窗口变得乏味,因为此操作每周要重复数百次。

我的程序试图阻止默认玩家的第二次响应

我想拦截一条 WM_DEVICECHANGE 消息以某种方式为其创建一个全局挂钩。

问题是,拦截 WM_DEVICECHANGE 效果很好,但它不会阻止 WinDVD 触发新单元插入的能力,显然还是让消息被传递。因此,我开始考虑如何防止在我拦截后发送该消息。

为了实现我想到的这个全局钩子,我使用了这行代码:

CurrentHook:=setwindowshookex(WH_CALLWNDPROC,HookProcAdd,LibHandle,0);

链接到我的 DLL 中包含的回调,我可以看到 WM_DEVICECHANGE 被正确拦截,但正如我所说,消息仍被发送到整个系统。

任何建议表示赞赏。

更新:

@TOndrej:我尝试了以下内容:

var
  rlen         : DWORD;
  pRelen       : ^DWORD;
  h            : THandle;
  val : Boolean;
  pVal: ^Boolean;
  res : Boolean;
begin
  rlen := 0;
  val := True;
  pVal := @val;
  pRelen := @val;
  h := CreateFile(PChar('\\.\d:'), GENERIC_READ or GENERIC_WRITE, FILE_SHARE_READ or FILE_SHARE_WRITE, nil,
    OPEN_EXISTING, 0, 0);
  if h <> INVALID_HANDLE_VALUE then
  begin
    res:= DeviceIoControl(h,
                          IOCTL_STORAGE_MCN_CONTROL,
                          pVal,
                          SizeOf(val),
                          nil,
                          0,
                          rlen,
                          nil);
    if not res then
    begin

      ShowMessage('Error');
    end;

    CloseHandle(h);
  end;
end;

但 res 每次都是假的。我错过了什么?

4

3 回答 3

2

对于 IOCTL_STORAGE_MCN_CONTROL 控制代码,必须使用 FILE_READ_ATTRIBUTES 访问权限打开文件:

var
  rlen: DWORD;
  pVal: PBOOL;
  res: BOOL;
begin
  rlen := 0;

  GetMem(PVal,SizeOf(BOOL));
  pVal^ := TRUE;


  h := CreateFile(PChar('\\.\D:'),
    FILE_READ_ATTRIBUTES, 
    FILE_SHARE_READ OR FILE_SHARE_WRITE,
    nil, OPEN_EXISTING, 0, 0);

  if h <> INVALID_HANDLE_VALUE then
  begin
    res:= DeviceIoControl(h,
                          IOCTL_STORAGE_MCN_CONTROL,
                          pVal,
                          SizeOf(BOOL),
                          nil,
                          0,
                          rlen,
                          nil);
    if not res then
    begin
      ShowMessage('Error');
    end else
    begin
      ShowMessage('Device Notification Disabled');
    end;

    // close file handle
    CloseHandle(h);
    // After CloseHandle, file notification is restored...
  end;
end;

在我的测试中,在 CloseHandle 之后,设备通知恢复了......

于 2012-08-08T09:33:19.273 回答
1

处理此问题的正确、官方和记录的方法是以可编程的方式抑制 AutoRun。如果你的应用不在前台接收"QueryCancelAutoPlay"消息,你的全局钩子应该能够响应消息而不调度它。

于 2012-07-30T20:06:49.823 回答
0

为什么不通过设置注册表项来禁用 CD 自动运行功能HKLM\System\CurrentControlSet\Services\CDRom并将该键设置Autorun0而不是1

客户必须单独启动每个应用程序,或者选择“打开方式...”选项,但这应该非常适合基准测试。根据您的描述,他们正在测试运行时性能和播放质量,而不是自动运行能力。

于 2012-09-06T00:11:26.660 回答