Partager via


Internet Explorer 11 hosting a Drag & Drop ActiveX control advances from onDragEnter to OnDrop instead of onDragEnter -> onDragOver on Windows 10 x86 and x64 iexplore processes.

The issue as stated in the title is reproducible on fast dragging. See details below.

This happens only when the ActiveX is hosted in IE11. The issue does not occur when the same ActiveX control is hosted on a Win Form application.

To repro the issue here is what you need to do:

Please refer to the attached sample ActiveX control named: myactivexcontrol
Build & register MyActiveXControl. I have also attached myactivexcontrol_ocx which you can directly register & use.
Place any text file named ReadMe.txt in C:\Temp folder. Of course you can change the location from the ActiveX code.

Create a sample HTML file named TestPage.html and open this in IE 11 to test the issue.
Here are the contents of the HTML file:

<HTML>
<HEAD>
<TITLE>Drag & Drop Test</TITLE>

</HEAD>
<BODY>
<CENTER>

<!--
This is the key to the example.  The OBJECT
tag is a new tag used to download ActiveX
components.  Once the ActiveX component is available,
you can set its properties by using the PARAM tag.
-->

<OBJECT
CLASSID="clsid:90EDC5CE-75EE-47F2-AB0E-7E7444FD9257"
ID="MYACTIVEXCONTROL.MyActiveXControlCtrl.1"
</OBJECT>

<ondragover="window.event.returnValue=false;">

</CENTER>
</BODY>
</HTML>

The ActiveX is the one as shown below in an ellipse (which I draw in CMyActiveXControlCtrl::OnDraw() ). I associate a simple text file with the ActiveX window (see CMyActiveXControlCtrl::OnLButtonDown() ). You need to drag that text file from the ActiveX to say Desktop. 

snip1

In fast dragging (even if left mouse button is down) we see only this log:

[3508] grfKeyState is: 0
[3508] DRAGDROP_S_DROP <= The files drops to the same IE window.
grfKeyState never changed to 1 – which is the issue. This however does not happen on Windows 7 OS (32 bit & 64 bit both).

grfKeyState changes to 1 only when you click on the ActiveX and wait for the small arrow (shown below) to appear. This however is not required on Windows 7 OS.

snip2

Is there a workaround that exists?
Yes. This is how I fixed it and has worked from Windows 7 to Windows 10.

Please refer to the attached sample ActiveX control named: MyActiveXControl.ZIP
File Name: DropSource.h
Function Name: HRESULT CDropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState);

WORKAROUND 1
============
Instead of relying on grfKeyState, I checked the mouse button state using GetKeyState() API and return DRAGDROP_S_DROP when the mouse button is released. I have tested it and it works fine.// Modified QueryContinueDrag() codeHRESULT CDropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
{
DWORD my_grfKeyState  = 0;
// If the high-order bit is 1, the key is down; otherwise, it is up.
if((GetKeyState(VK_LBUTTON) & 0x80) != 0)
{
my_grfKeyState = 1;
}

TCHAR buffer[100];
swprintf_s(buffer, 100, L"grfKeyState is: %d", grfKeyState);

::OutputDebugString(buffer);
swprintf_s(buffer, 100, L"my_grfKeyState is: %d", my_grfKeyState);
::OutputDebugString(buffer);

if (fEscapePressed)
{
::OutputDebugString(L"DRAGDROP_S_CANCEL");
return DRAGDROP_S_CANCEL;
}

if (!(my_grfKeyState & (MK_LBUTTON | MK_RBUTTON)))
{
::OutputDebugString(L"DRAGDROP_S_DROP");
return DRAGDROP_S_DROP;
}

::OutputDebugString(L"S_OK");
return S_OK;
}

WORKAROUND 2
============
I made some changes in CDropSource::QueryContinueDrag() (see below) to test PeekMessage(). PeekMessage seems to be working fine. So the only anomaly what we see in case of the ActiveX hosted in IE11, is for the first time when grfKeyState never changes to 1 from 0.
if ((msg.message >= WM_MOUSEFIRST) && (msg.message <= WM_MOUSELAST)) never becomes TRUE.

HRESULT CDropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
{
TCHAR buffer[100];
MSG msg;
DWORD my_grfKeyState  = 0;

    swprintf_s(buffer, 100, L"my_grfKeyState before PeekMessage is: %d", my_grfKeyState);
::OutputDebugString(buffer);
//auto HaveAnyMouseMessages = [&]() -> BOOL
//{
//    return PeekMessage(&msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE);
//};

    // Busy wait until a mouse or escape message is in the queue
while (!PeekMessage(&msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE))
{
// Note: all keyboard messages except escape are tossed. This is
// fairly reasonable since the user has to be holding the left
// mouse button down at this point. They can't really be doing
// too much data input one handed.
if ((PeekMessage(&msg, 0, WM_KEYDOWN, WM_KEYDOWN, PM_REMOVE)
|| PeekMessage(&msg, 0, WM_SYSKEYDOWN, WM_SYSKEYDOWN, PM_REMOVE))
&& msg.wParam == VK_ESCAPE)
{
fEscapePressed = TRUE;
break;
}
}

    if (!fEscapePressed)
{
if ((msg.message >= WM_MOUSEFIRST) && (msg.message <= WM_MOUSELAST))
{
my_grfKeyState = GetControlKeysStateOfParam(msg.wParam);
swprintf_s(buffer, 100, L"my_grfKeyState after PeekMessage is: %d", my_grfKeyState);
::OutputDebugString(buffer);
}
}

    DWORD my_grfKeyState1  = 0;
if((GetKeyState(VK_LBUTTON) & 0x80) != 0)
{
my_grfKeyState1 = 1;
}
//// DWORD my_grfKeyState = GetAsyncKeyState(VK_LBUTTON); //GetKeyState(VK_LBUTTON);

    swprintf_s(buffer, 100, L"my_grfKeyState1 from GetKeyState() is: %d", my_grfKeyState1);
::OutputDebugString(buffer);
//swprintf_s(buffer, 100, L"my_grfKeyState is: %d", my_grfKeyState);
//::OutputDebugString(buffer);if (fEscapePressed)
{
::OutputDebugString(L"DRAGDROP_S_CANCEL");
return DRAGDROP_S_CANCEL;
}

    // if (!(my_grfKeyState & (MK_LBUTTON | MK_RBUTTON)))
// if(my_grfKeyState == 0 && grfKeyState == 0)
if (!(my_grfKeyState & (MK_LBUTTON | MK_RBUTTON)))
{
::OutputDebugString(L"DRAGDROP_S_DROP");
return DRAGDROP_S_DROP;
}

     ::OutputDebugString(L"S_OK");
return S_OK;
}

Output:

[8452] OnLButtonDown
[8452] GetUIObjectOfFile succeeded
[8452] DoDragDrop
[8452] my_grfKeyState before PeekMessage is: 0
[8452] my_grfKeyState after PeekMessage is: 1
[8452] my_grfKeyState1 from GetKeyState() is: 1
[8452] S_OK
[8452] my_grfKeyState before PeekMessage is: 0
[8452] my_grfKeyState1 from GetKeyState() is: 1
[8452] DRAGDROP_S_DROP

However we do have an official fix for this issue from Microsoft.

KB 3179574 (Link: https://support.microsoft.com/en-us/kb/3179574) -  fixes the issue on Windows 8.1 .

Test Results
=========
Operating System: Windows 8.1 x64 (Version 6.3, Build: 9600)
ole32.dll version: 6.3.9600.18256

Issue exists with this version.

Downloaded https://support.microsoft.com/en-us/kb/3179574
Installed this KB. Restarted the machine.
ole32.dll version: 6.3.9600.18403

Issue not reproducible.

For Windows 10 and above OS's, apply KB 3201845 (Link: https://support.microsoft.com/en-us/kb/apply KB 3201845). This comes via the Windows Update. In the KB you will find a statement saying "Addressed issue with OLE drag and drop that prevents users from downloading a SharePoint document library as a file".