2

I'm developing a Windows 7 application which has to prevent WinDVD from triggering new disc availability when inserted (i.e. inserting a DVD).

Background information:

I'm working out this little application for a company which has to compare two movie players at a time playing simultaneously the same DVD, from different drives.

They're doing heuristic quality testing to determine best DVD player at the moment to bundle it into their new line of PCs.

At the moment their best choice seem to be WinDVD, so every other test has to be conducted against it. Problem is, when they insert first DVD, it's all right the default player WinDVD starts.

Then when they insert the second disc, the default player responds first, so they are forced to close the window and open the other player they're testing.

This is done for many movies that represent a reference to them to spot color rendering and image quality. It becomes tedious for users to close the additional window when it shows up, as this operation is due to be repeated hundreds of times a week.

My program is trying to inhibit default player' second response

I thought to intercept a WM_DEVICECHANGE message to somehow create a global hook for it.

Problem is, intercepting WM_DEVICECHANGE works very well, but it doesn't block WinDVD's ability to trigger new units insertion, evidently letting the message being delivered anyways. Due to this I started thinking how to prevent that message being dispatched after my interception.

In order to realize this global hook I thought of, I'm using this line of code:

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

linked to the callback contained within a DLL of mine and I can see that WM_DEVICECHANGE is correctly intercepted, but as I said the message is still dispatched to the whole system.

Any suggestion appreciated.

Updates:

@TOndrej : I've tried what follows:

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;

but res is false every time. What am I missing?

Superc
  • 159
  • 1
  • 8
  • 2
    In the remarks section of the documentation for CallWndProc it says that you can't modify a message, so I guess you can't prevent a message from being dispatched that way: http://msdn.microsoft.com/en-us/library/windows/desktop/ms644975(v=vs.85).aspx – Jens Mühlenhoff Jul 30 '12 at 09:06
  • 2
    Perhaps you could instead try disabling the notification by sending [IOCTL_STORAGE_MCN_CONTROL](http://msdn.microsoft.com/en-us/library/windows/desktop/aa363415(v=vs.85).aspx) to the device. – Ondrej Kelle Jul 30 '12 at 10:05
  • 3
    Anyway, how about injecting a DLL into WinDVD. Then replace the window proc for the top level window. Pass on all other messages to the original window proc. So, let the message be sent, but intercept it before WinDVD can handle it. – David Heffernan Jul 30 '12 at 13:30
  • Regarding the code in the question, you failed to perform error checking. Call GetLastError. I note that a Windows BOOL is a 4 byte wide type that is completely different from Boolean. And are you sure you can use the save field for both input and output param? – David Heffernan Jul 30 '12 at 16:30
  • @DavidHeffernan : infact i've substitute variable bool with BOOL and inserted getlasterror. I receive however error 87 :ERROR_INVALID_PARAMETER. What do you mean by save field? – Superc Jul 31 '12 at 06:57
  • Typo, was meant to read same variable. – David Heffernan Jul 31 '12 at 07:20
  • @DavidHeffernan: I'm sorry, I don't understand, what you're talking about variable in the code above? – Superc Jul 31 '12 at 07:31
  • pRelen confused me. But now I see it's not used. I find it disappointing that we are expected to pick through stuff like that, code which is just not used. I assumed it was a parameter that you passed to the api call. Sigh. – David Heffernan Jul 31 '12 at 07:41

3 Answers3

2

For IOCTL_STORAGE_MCN_CONTROL control code, files must be opened with the FILE_READ_ATTRIBUTES access right:

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;

In my test, after CloseHandle, device notification is restored...

AndreaBoc
  • 3,077
  • 2
  • 17
  • 22
1

The correct, official, and documented way to handle this is to suppress AutoRun programmably. If your app is not in the foreground to receive the "QueryCancelAutoPlay" message, your global hook should be able to respond to the message without dispatching it.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • I forgot to mention one important condition ..... The program windvd must always open, and the problem occurs when you insert the media, if windvd was closed I would not trouble to set the autoplay. – Superc Jul 31 '12 at 08:53
  • If your code suppresses AutoRun, WinDVD should not be notified of the second disc being inserted, so it will continue playing the first disc. Your code can then manually open the second disc using whatever other player you need. – Remy Lebeau Jul 31 '12 at 19:45
0

Why not just disable the CD autorun capability by setting the registry key HKLM\System\CurrentControlSet\Services\CDRom and set the key Autorun to 0 instead of 1?

The customer must launch each application separately, or maybe choose an "open with..." option, but that should be perfectly suitable for benchmark testing. By your description they are testing runtime performance and playback quality, not autorun capability.

biegleux
  • 13,179
  • 11
  • 45
  • 52
JR-
  • 1