11use std:: ffi:: { OsString , c_void} ;
22use std:: os:: windows:: ffi:: OsStringExt ;
33use std:: path:: PathBuf ;
4- use std:: ptr;
4+ use std:: ptr:: { self , null_mut } ;
55use std:: sync:: atomic:: { AtomicUsize , Ordering } ;
6-
76use dpi:: PhysicalPosition ;
87use tracing:: debug;
9- use windows_sys:: Win32 :: Foundation :: { DV_E_FORMATETC , HWND , POINT , POINTL , S_OK } ;
8+ use windows_sys:: Win32 :: Foundation :: { DV_E_FORMATETC , E_NOINTERFACE , HWND , POINT , POINTL , S_OK } ;
109use windows_sys:: Win32 :: Graphics :: Gdi :: ScreenToClient ;
1110use windows_sys:: Win32 :: System :: Com :: { DVASPECT_CONTENT , FORMATETC , TYMED_HGLOBAL } ;
1211use windows_sys:: Win32 :: System :: Ole :: { CF_HDROP , DROPEFFECT_COPY , DROPEFFECT_NONE } ;
1312use windows_sys:: Win32 :: UI :: Shell :: { DragFinish , DragQueryFileW , HDROP } ;
1413use windows_sys:: core:: { GUID , HRESULT } ;
1514use winit_core:: event:: WindowEvent ;
16-
1715use crate :: definitions:: {
1816 IDataObject , IDataObjectVtbl , IDropTarget , IDropTargetVtbl , IUnknown , IUnknownVtbl ,
1917} ;
2018
19+ const IID_IUNKNOWN : GUID = GUID {
20+ data1 : 0x00000000 ,
21+ data2 : 0x0000 ,
22+ data3 : 0x0000 ,
23+ data4 : [ 0xC0 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x46 ] ,
24+ } ;
25+
26+ const IID_IDROP_TARGET : GUID = GUID {
27+ data1 : 0x00000122 ,
28+ data2 : 0x0000 ,
29+ data3 : 0x0000 ,
30+ data4 : [ 0xC0 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x46 ] ,
31+ } ;
32+
33+ fn guid_eq ( a : & GUID , b : & GUID ) -> bool {
34+ a. data1 == b. data1 &&
35+ a. data2 == b. data2 &&
36+ a. data3 == b. data3 &&
37+ a. data4 == b. data4
38+ }
39+
2140#[ repr( C ) ]
2241pub struct FileDropHandlerData {
2342 pub interface : IDropTarget ,
@@ -49,13 +68,26 @@ impl FileDropHandler {
4968
5069 // Implement IUnknown
5170 pub unsafe extern "system" fn QueryInterface (
52- _this : * mut IUnknown ,
53- _riid : * const GUID ,
54- _ppvObject : * mut * mut c_void ,
71+ this : * mut IUnknown ,
72+ riid : * const GUID ,
73+ ppvObject : * mut * mut c_void ,
5574 ) -> HRESULT {
56- // This function doesn't appear to be required for an `IDropTarget`.
57- // An implementation would be nice however.
58- unimplemented ! ( ) ;
75+ if riid. is_null ( ) || ppvObject. is_null ( ) {
76+ return E_NOINTERFACE ;
77+ }
78+
79+ let drop_handler_data =unsafe { Self :: from_interface ( this) } ;
80+ let requested = unsafe { & * riid } ;
81+
82+ if guid_eq ( requested, & IID_IUNKNOWN ) || guid_eq ( requested, & IID_IDROP_TARGET ) {
83+ unsafe { * ppvObject =this as * mut c_void } ;
84+ drop_handler_data. refcount . fetch_add ( 1 , Ordering :: Release ) ;
85+ return S_OK ;
86+ }
87+
88+ // Interface not supported
89+ unsafe { * ppvObject = null_mut ( ) } ;
90+ E_NOINTERFACE
5991 }
6092
6193 pub unsafe extern "system" fn AddRef ( this : * mut IUnknown ) -> u32 {
@@ -238,3 +270,61 @@ static DROP_TARGET_VTBL: IDropTargetVtbl = IDropTargetVtbl {
238270 DragLeave : FileDropHandler :: DragLeave ,
239271 Drop : FileDropHandler :: Drop ,
240272} ;
273+
274+ #[ cfg( test) ]
275+ mod tests {
276+ use super :: * ;
277+ use std:: ptr:: null_mut;
278+ use windows_sys:: Win32 :: Foundation :: HWND ;
279+ use windows_sys:: core:: GUID ;
280+
281+
282+ #[ test]
283+ fn test_file_drop_handler_query_interface ( ) {
284+ let handler = FileDropHandler :: new (
285+ 0 as HWND , // null window handle
286+ Box :: new ( |event| {
287+ println ! ( "WindowEvent: {:?}" , event) ;
288+ } ) ,
289+ ) ;
290+
291+ unsafe {
292+ let mut ppv: * mut std:: ffi:: c_void = null_mut ( ) ;
293+ let hr_iunknown = FileDropHandler :: QueryInterface (
294+ handler. data as * mut IUnknown ,
295+ & IID_IUNKNOWN ,
296+ & mut ppv as * mut _ ,
297+ ) ;
298+ assert_eq ! ( hr_iunknown, S_OK ) ;
299+ assert ! ( !ppv. is_null( ) ) ;
300+
301+ ppv = null_mut ( ) ;
302+
303+ let hr_idroptarget = FileDropHandler :: QueryInterface (
304+ handler. data as * mut IUnknown ,
305+ & IID_IDROP_TARGET ,
306+ & mut ppv as * mut _ ,
307+ ) ;
308+ assert_eq ! ( hr_idroptarget, S_OK ) ;
309+ assert ! ( !ppv. is_null( ) ) ;
310+
311+ let unknown_guid = GUID {
312+ data1 : 0x12345678 ,
313+ data2 : 0x1234 ,
314+ data3 : 0x5678 ,
315+ data4 : [ 0x90 , 0xAB , 0xCD , 0xEF , 0x00 , 0x11 , 0x22 , 0x33 ] ,
316+ } ;
317+ ppv = null_mut ( ) ;
318+ let hr_unknown = FileDropHandler :: QueryInterface (
319+ handler. data as * mut IUnknown ,
320+ & unknown_guid,
321+ & mut ppv as * mut _ ,
322+ ) ;
323+ assert_eq ! ( hr_unknown, E_NOINTERFACE ) ;
324+ assert ! ( ppv. is_null( ) ) ;
325+ }
326+
327+ // Drop the handler manually
328+ unsafe { FileDropHandler :: Release ( handler. data as * mut IUnknown ) } ;
329+ }
330+ }
0 commit comments