OSDN Git Service

Fix bugs of displaying icons in the local file list.
[ffftp/ffftp.git] / OleDragDrop.c
1 /**************************************************************************\r
2 \r
3         OleDragDrop.c\r
4 \r
5         (C) Copyright 1996-2002 By Tomoaki Nakashima. All right reserved.       \r
6                 http://www.nakka.com/\r
7                 nakka@nakka.com\r
8 \r
9 **************************************************************************/\r
10 \r
11 /**************************************************************************\r
12         Include Files\r
13 **************************************************************************/\r
14 \r
15 #define _INC_OLE\r
16 #include <windows.h>\r
17 #undef  _INC_OLE\r
18 \r
19 #include <oleidl.h>\r
20 #include <objidl.h>\r
21 \r
22 #include "OleDragDrop.h"\r
23 \r
24 \r
25 /* Clipboard format から Type of storage medium を取得 */\r
26 static DWORD FormatToTymed(const UINT cfFormat)\r
27 {\r
28         switch(cfFormat)\r
29         {\r
30         case CF_BITMAP:\r
31                 return TYMED_GDI;\r
32 \r
33         case CF_METAFILEPICT:\r
34                 return TYMED_MFPICT;\r
35 \r
36         case CF_ENHMETAFILE:\r
37                 return TYMED_ENHMF;\r
38         }\r
39         return TYMED_HGLOBAL;\r
40 }\r
41 \r
42 \r
43 /******************************************************************************\r
44 \r
45         IDropTarget\r
46 \r
47 ******************************************************************************/\r
48 \r
49 static HRESULT STDMETHODCALLTYPE OLE_IDropTarget_QueryInterface(LPDROPTARGET pThis, REFIID riid, LPVOID *ppvObject);\r
50 static ULONG STDMETHODCALLTYPE OLE_IDropTarget_AddRef(LPDROPTARGET pThis);\r
51 static ULONG STDMETHODCALLTYPE OLE_IDropTarget_Release(LPDROPTARGET pThis);\r
52 static HRESULT STDMETHODCALLTYPE OLE_IDropTarget_DragEnter(LPDROPTARGET pThis, LPDATAOBJECT pdo, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect);\r
53 static HRESULT STDMETHODCALLTYPE OLE_IDropTarget_DragOver(LPDROPTARGET pThis, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect);\r
54 static HRESULT STDMETHODCALLTYPE OLE_IDropTarget_DragLeave(LPDROPTARGET pThis);\r
55 static HRESULT STDMETHODCALLTYPE OLE_IDropTarget_Drop(LPDROPTARGET pThis, LPDATAOBJECT pdo, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect);\r
56 static HRESULT APIPRIVATE OLE_IDropTarget_Internal_SendMessage(LPDROPTARGET pThis, UINT uNotify, LPDATAOBJECT pdo, DWORD grfKeyState, POINTL *ppt, LPDWORD pdwEffect);\r
57 static HRESULT APIPRIVATE DropTarget_GetData(LPDATAOBJECT pdo, UINT cfFormat, LPSTGMEDIUM psm);\r
58 static HRESULT APIPRIVATE DropTarget_QueryGetData(LPDATAOBJECT pdo, UINT cfFormat);\r
59 \r
60 /* IDropTarget Virtual Table */\r
61 static IDropTargetVtbl dtv = {\r
62         OLE_IDropTarget_QueryInterface,\r
63         OLE_IDropTarget_AddRef,\r
64         OLE_IDropTarget_Release,\r
65         OLE_IDropTarget_DragEnter,\r
66         OLE_IDropTarget_DragOver,\r
67         OLE_IDropTarget_DragLeave,\r
68         OLE_IDropTarget_Drop\r
69 };\r
70 \r
71 typedef struct _IDROPTARGET_INTERNAL{\r
72         LPVOID lpVtbl;\r
73         ULONG m_refCnt;\r
74         HWND hWnd;\r
75         UINT uCallbackMessage;\r
76         UINT *cFormat;\r
77         int cfcnt;\r
78         IDROPTARGET_NOTIFY dtn;\r
79 }IDROPTARGET_INTERNAL , *LPIDROPTARGET_INTERNAL;\r
80 \r
81 /* OLEのドロップターゲットとして登録する */\r
82 BOOL APIPRIVATE OLE_IDropTarget_RegisterDragDrop(HWND hWnd, UINT uCallbackMessage, UINT *cFormat, int cfcnt)\r
83 {\r
84         static IDROPTARGET_INTERNAL *pdti;\r
85 \r
86         pdti = GlobalAlloc(GPTR, sizeof(IDROPTARGET_INTERNAL));\r
87         if(pdti == NULL){\r
88                 return FALSE;\r
89         }\r
90         pdti->lpVtbl = (LPVOID)&dtv;\r
91         pdti->m_refCnt = 0;\r
92         pdti->hWnd = hWnd;                                                                                                      /* メッセージを受け取るウィンドウ */\r
93         pdti->uCallbackMessage = uCallbackMessage;                                                      /* メッセージ */\r
94         pdti->cFormat = (UINT *)GlobalAlloc(GPTR, sizeof(UINT) * cfcnt);                /* 対応しているクリップボードフォーマット */\r
95         if(pdti->cFormat == NULL){\r
96                 GlobalFree(pdti);\r
97                 return FALSE;\r
98         }\r
99         CopyMemory(pdti->cFormat, cFormat, sizeof(UINT) * cfcnt);\r
100         pdti->cfcnt = cfcnt;                                                                                            /* クリップボードフォーマットの数 */\r
101         return (S_OK == RegisterDragDrop(hWnd, (LPDROPTARGET)pdti));\r
102 }\r
103 \r
104 /* OLEのドロップターゲットを解除する */\r
105 void APIPRIVATE OLE_IDropTarget_RevokeDragDrop(HWND hWnd)\r
106 {\r
107         RevokeDragDrop(hWnd);\r
108 }\r
109 \r
110 static HRESULT STDMETHODCALLTYPE OLE_IDropTarget_QueryInterface(LPDROPTARGET pThis, REFIID riid, PVOID *ppvObject)\r
111 {\r
112         //要求されたIIDと同じ場合はオブジェクトを返す\r
113         if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDropTarget)){\r
114                 *ppvObject = (LPVOID)pThis;\r
115                 ((LPUNKNOWN)*ppvObject)->lpVtbl->AddRef((LPUNKNOWN)*ppvObject);\r
116                 return S_OK;\r
117         }\r
118         *ppvObject = NULL;\r
119         return ResultFromScode(E_NOINTERFACE);\r
120 }\r
121 \r
122 static ULONG STDMETHODCALLTYPE OLE_IDropTarget_AddRef(LPDROPTARGET pThis)\r
123 {\r
124         CONST LPIDROPTARGET_INTERNAL pdti = (LPIDROPTARGET_INTERNAL)pThis;\r
125 \r
126         /* reference countをインクリメントする */\r
127         pdti->m_refCnt++;\r
128         return pdti->m_refCnt;\r
129 }\r
130 \r
131 static ULONG STDMETHODCALLTYPE OLE_IDropTarget_Release(LPDROPTARGET pThis)\r
132 {\r
133         CONST LPIDROPTARGET_INTERNAL pdti = (LPIDROPTARGET_INTERNAL)pThis;\r
134 \r
135         /* reference countをデクリメントする */\r
136         pdti->m_refCnt--;\r
137 \r
138         /* reference countが 0 になった場合はオブジェクトの解放を行う */\r
139         if(pdti->m_refCnt == 0L){\r
140                 if(pdti->cFormat != NULL){\r
141                         GlobalFree(pdti->cFormat);\r
142                 }\r
143                 GlobalFree(pdti);\r
144                 return 0L;\r
145         }\r
146         return pdti->m_refCnt;\r
147 }\r
148 \r
149 static HRESULT STDMETHODCALLTYPE OLE_IDropTarget_DragEnter(LPDROPTARGET pThis, LPDATAOBJECT pdo, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)\r
150 {\r
151         return OLE_IDropTarget_Internal_SendMessage(pThis, IDROPTARGET_NOTIFY_DRAGENTER, pdo, grfKeyState, &pt, pdwEffect);\r
152 }\r
153 \r
154 static HRESULT STDMETHODCALLTYPE OLE_IDropTarget_DragOver(LPDROPTARGET pThis, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)\r
155 {\r
156         return OLE_IDropTarget_Internal_SendMessage(pThis, IDROPTARGET_NOTIFY_DRAGOVER, NULL, grfKeyState, &pt, pdwEffect);\r
157 }\r
158 \r
159 static HRESULT STDMETHODCALLTYPE OLE_IDropTarget_DragLeave(LPDROPTARGET pThis)\r
160 {\r
161         return OLE_IDropTarget_Internal_SendMessage(pThis, IDROPTARGET_NOTIFY_DRAGLEAVE, NULL, 0, NULL, NULL);\r
162 }\r
163 \r
164 static HRESULT STDMETHODCALLTYPE OLE_IDropTarget_Drop(LPDROPTARGET pThis, LPDATAOBJECT pdo, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)\r
165 {\r
166         return OLE_IDropTarget_Internal_SendMessage(pThis, IDROPTARGET_NOTIFY_DROP, pdo, grfKeyState, &pt, pdwEffect);\r
167 }\r
168 \r
169 static HRESULT APIPRIVATE OLE_IDropTarget_Internal_SendMessage(LPDROPTARGET pThis, UINT uNotify, LPDATAOBJECT pdo, DWORD grfKeyState, POINTL *ppt, LPDWORD pdwEffect)\r
170 {\r
171         CONST LPIDROPTARGET_INTERNAL pdti = (LPIDROPTARGET_INTERNAL)pThis;\r
172         CONST LPIDROPTARGET_NOTIFY pdtn = &(pdti->dtn);\r
173         STGMEDIUM sm;\r
174         UINT cfFormat = 0;\r
175         int i;\r
176 \r
177         if(pdo){\r
178                 /* 対応しているクリップボードフォーマットがあるか調べる */\r
179                 for(i = 0;i < pdti->cfcnt;i++){\r
180                         if(DropTarget_QueryGetData(pdo, pdti->cFormat[i]) == S_OK){\r
181                                 cfFormat = pdti->cFormat[i];\r
182                                 break;\r
183                         }\r
184                 }\r
185                 /* クリップボードフォーマットからデータを取得する */\r
186                 if(cfFormat != 0){\r
187                         if (DropTarget_GetData(pdo, cfFormat, &sm) != S_OK){\r
188                                 cfFormat = 0;\r
189                         }\r
190                 }\r
191         }\r
192         pdtn->ppt = ppt;                                        /* マウスポインタの位置 */\r
193         pdtn->grfKeyState = grfKeyState;        /* キー、マウスボタンの状態 */\r
194         pdtn->cfFormat = cfFormat;                      /* クリップボードフォーマット */\r
195         pdtn->hMem = sm.hGlobal;                        /* 実データ */\r
196         pdtn->pdo = pdo;                                        /* IDataObject */\r
197 \r
198         /* ウィンドウにイベントを通知する */\r
199         SendMessage(pdti->hWnd, pdti->uCallbackMessage, (WPARAM)uNotify, (LPARAM)pdtn);\r
200 \r
201         /* クリップボード形式のデータの解放 */\r
202         if(cfFormat){\r
203                 ReleaseStgMedium(&sm);\r
204         }\r
205 \r
206         /* 効果の設定 */\r
207         if(pdwEffect){\r
208                 *pdwEffect &= pdtn->dwEffect;\r
209 \r
210                 if((*pdwEffect & DROPEFFECT_MOVE) && (*pdwEffect & DROPEFFECT_COPY)){\r
211                         *pdwEffect ^= DROPEFFECT_COPY;\r
212                         pdtn->dwEffect ^= DROPEFFECT_COPY;\r
213                 }\r
214         }\r
215         return S_OK;\r
216 }\r
217 \r
218 static HRESULT APIPRIVATE DropTarget_GetData(LPDATAOBJECT pdo, UINT cfFormat, LPSTGMEDIUM psm)\r
219 {\r
220         FORMATETC fmt;\r
221 \r
222         /* IDataObjectにクリップボード形式のデータを要求する */\r
223         fmt.cfFormat = cfFormat;\r
224         fmt.ptd = NULL;\r
225         fmt.dwAspect = DVASPECT_CONTENT;\r
226         fmt.lindex = -1;\r
227         fmt.tymed = FormatToTymed(cfFormat);\r
228         return pdo->lpVtbl->GetData(pdo, &fmt, psm);\r
229 }\r
230 \r
231 static HRESULT APIPRIVATE DropTarget_QueryGetData(LPDATAOBJECT pdo, UINT cfFormat)\r
232 {\r
233         FORMATETC fmt;\r
234 \r
235         /* IDataObjectに指定のクリップボードフォーマットが存在するか問い合わせる */\r
236         fmt.cfFormat = cfFormat;\r
237         fmt.ptd = NULL;\r
238         fmt.dwAspect = DVASPECT_CONTENT;\r
239         fmt.lindex = -1;\r
240         fmt.tymed = FormatToTymed(cfFormat);\r
241         return pdo->lpVtbl->QueryGetData(pdo, &fmt);\r
242 }\r
243 \r
244 \r
245 /******************************************************************************\r
246 \r
247         IEnumFORMATETC\r
248 \r
249 ******************************************************************************/\r
250 \r
251 static HRESULT STDMETHODCALLTYPE OLE_IEnumFORMATETC_QueryInterface(LPENUMFORMATETC lpThis, REFIID riid, LPVOID FAR* lplpvObj);\r
252 static ULONG STDMETHODCALLTYPE OLE_IEnumFORMATETC_AddRef(LPENUMFORMATETC lpThis);\r
253 static ULONG STDMETHODCALLTYPE OLE_IEnumFORMATETC_Release(LPENUMFORMATETC lpThis);\r
254 static HRESULT STDMETHODCALLTYPE OLE_IEnumFORMATETC_Next(LPENUMFORMATETC lpThis, ULONG celt, FORMATETC *rgelt, ULONG *pceltFetched);\r
255 static HRESULT STDMETHODCALLTYPE OLE_IEnumFORMATETC_Skip(LPENUMFORMATETC lpThis, ULONG celt);\r
256 static HRESULT STDMETHODCALLTYPE OLE_IEnumFORMATETC_Reset(LPENUMFORMATETC lpThis);\r
257 static HRESULT STDMETHODCALLTYPE OLE_IEnumFORMATETC_Clone(LPENUMFORMATETC lpThis, IEnumFORMATETC **ppenum);\r
258 \r
259 /* IEnumFORMATETC Virtual Table */\r
260 static IEnumFORMATETCVtbl efv = {\r
261         OLE_IEnumFORMATETC_QueryInterface,\r
262         OLE_IEnumFORMATETC_AddRef,\r
263         OLE_IEnumFORMATETC_Release,\r
264         OLE_IEnumFORMATETC_Next,\r
265         OLE_IEnumFORMATETC_Skip,\r
266         OLE_IEnumFORMATETC_Reset,\r
267         OLE_IEnumFORMATETC_Clone\r
268 };\r
269 \r
270 typedef struct _IENUMFORMATETC_INTERNAL{\r
271         LPVOID lpVtbl;\r
272         ULONG m_refCnt;\r
273         LPUNKNOWN m_pUnknownObj;\r
274         ULONG m_currElement;\r
275         ULONG m_numFormats;\r
276         LPFORMATETC m_formatList;\r
277 }IENUMFORMATETC_INTERNAL , *LPIENUMFORMATETC_INTERNAL;\r
278 \r
279 static HRESULT STDMETHODCALLTYPE OLE_IEnumFORMATETC_QueryInterface(LPENUMFORMATETC lpThis, REFIID riid, LPVOID FAR* lplpvObj)\r
280 {\r
281         //要求されたIIDと同じ場合はオブジェクトを返す\r
282         if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IEnumFORMATETC)){\r
283                 *lplpvObj = (LPVOID) lpThis;\r
284                  ((LPUNKNOWN)*lplpvObj)->lpVtbl->AddRef(((LPUNKNOWN)*lplpvObj));\r
285                 return S_OK;\r
286         }\r
287         *lplpvObj = NULL;\r
288         return ResultFromScode(E_NOINTERFACE);\r
289 }\r
290 \r
291 static ULONG STDMETHODCALLTYPE OLE_IEnumFORMATETC_AddRef(LPENUMFORMATETC lpThis)\r
292 {\r
293         CONST LPIENUMFORMATETC_INTERNAL pefi = (LPIENUMFORMATETC_INTERNAL)lpThis;\r
294 \r
295         /* reference countをインクリメントする */\r
296         pefi->m_refCnt++;\r
297         /* 親オブジェクトのreference countを加える */\r
298         pefi->m_pUnknownObj->lpVtbl->AddRef(pefi->m_pUnknownObj);\r
299         return pefi->m_refCnt;\r
300 }\r
301 \r
302 static ULONG STDMETHODCALLTYPE OLE_IEnumFORMATETC_Release(LPENUMFORMATETC lpThis)\r
303 {\r
304         CONST LPIENUMFORMATETC_INTERNAL pefi = (LPIENUMFORMATETC_INTERNAL)lpThis;\r
305 \r
306         /* reference countをデクリメントする */\r
307         pefi->m_refCnt--;\r
308         /* 親オブジェクトのreference countを減らす */\r
309         pefi->m_pUnknownObj->lpVtbl->Release(pefi->m_pUnknownObj);\r
310 \r
311         /* reference countが 0 になった場合はオブジェクトの解放を行う */\r
312         if(pefi->m_refCnt == 0L){\r
313                 if(pefi->m_formatList != NULL){\r
314                         GlobalFree(pefi->m_formatList);\r
315                 }\r
316                 GlobalFree(pefi);\r
317                 return 0L;\r
318         }\r
319         return pefi->m_refCnt;\r
320 }\r
321 \r
322 static HRESULT STDMETHODCALLTYPE OLE_IEnumFORMATETC_Next(LPENUMFORMATETC lpThis, ULONG celt, FORMATETC *rgelt, ULONG *pceltFetched)\r
323 {\r
324         ULONG i;\r
325         ULONG cReturn=0L;\r
326         LPIENUMFORMATETC_INTERNAL lpefi = ((LPIENUMFORMATETC_INTERNAL)lpThis);\r
327 \r
328         if(pceltFetched){\r
329                 *pceltFetched = 0L;\r
330         }\r
331         if(lpefi->m_formatList == NULL){\r
332                 return ResultFromScode(S_FALSE);\r
333         }\r
334 \r
335         if(rgelt == NULL){\r
336                 if(celt == 1){\r
337                         return ResultFromScode(S_FALSE);\r
338                 }else{\r
339                         return ResultFromScode(E_POINTER);\r
340                 }\r
341         }\r
342 \r
343         if(lpefi->m_currElement >= lpefi->m_numFormats){\r
344                 return ResultFromScode(S_FALSE);\r
345         }\r
346 \r
347         for(i = 0;i < celt && lpefi->m_currElement < lpefi->m_numFormats;i++, lpefi->m_currElement++){\r
348                 *rgelt = lpefi->m_formatList[lpefi->m_currElement];\r
349                 rgelt++;\r
350         }\r
351 \r
352         if(pceltFetched != NULL){\r
353                 *pceltFetched = i;\r
354         }\r
355         return S_OK;\r
356 \r
357 }\r
358 \r
359 static HRESULT STDMETHODCALLTYPE OLE_IEnumFORMATETC_Skip(LPENUMFORMATETC lpThis, ULONG celt)\r
360 {\r
361         LPIENUMFORMATETC_INTERNAL lpefi = ((LPIENUMFORMATETC_INTERNAL)lpThis);\r
362 \r
363         lpefi->m_currElement += celt;\r
364 \r
365         if(lpefi->m_currElement > lpefi->m_numFormats){\r
366                 lpefi->m_currElement = lpefi->m_numFormats;\r
367                 return ResultFromScode(S_FALSE);\r
368         }\r
369         return S_OK;\r
370 }\r
371 \r
372 static HRESULT STDMETHODCALLTYPE OLE_IEnumFORMATETC_Reset(LPENUMFORMATETC lpThis)\r
373 {\r
374         LPIENUMFORMATETC_INTERNAL lpefi = ((LPIENUMFORMATETC_INTERNAL)lpThis);\r
375 \r
376         lpefi->m_currElement = 0L;\r
377         return S_OK;\r
378 }\r
379 \r
380 static HRESULT STDMETHODCALLTYPE OLE_IEnumFORMATETC_Clone(LPENUMFORMATETC lpThis, IEnumFORMATETC **ppenum)\r
381 {\r
382         LPIENUMFORMATETC_INTERNAL pNew;\r
383         LPIENUMFORMATETC_INTERNAL lpefi = ((LPIENUMFORMATETC_INTERNAL)lpThis);\r
384         UINT i;\r
385 \r
386         /* IEnumFORMATETCを作成する */\r
387         pNew = GlobalAlloc(GPTR, sizeof(IENUMFORMATETC_INTERNAL));\r
388         if(pNew == NULL){\r
389                 return ResultFromScode(E_OUTOFMEMORY);\r
390         }\r
391         pNew->lpVtbl = (LPVOID)&efv;\r
392         pNew->m_refCnt = 0;\r
393         pNew->m_currElement = 0;\r
394 \r
395         pNew->m_pUnknownObj = lpefi->m_pUnknownObj;\r
396         pNew->m_numFormats = lpefi->m_numFormats;\r
397 \r
398         /* クリップボードフォーマットのリストをコピーする */\r
399         pNew->m_formatList = GlobalAlloc(GPTR, sizeof(FORMATETC) * pNew->m_numFormats);\r
400         if(pNew->m_formatList != NULL){\r
401                 for(i = 0;i < pNew->m_numFormats;i++){\r
402                           pNew->m_formatList[i] = lpefi->m_formatList[i];\r
403                 }\r
404         }\r
405 \r
406         *ppenum = (struct IEnumFORMATETC *)pNew;\r
407         if(pNew == NULL){\r
408                 return ResultFromScode(E_OUTOFMEMORY);\r
409         }\r
410         ((LPENUMFORMATETC)pNew)->lpVtbl->AddRef(((LPENUMFORMATETC)pNew));\r
411         pNew->m_currElement = lpefi->m_currElement;\r
412         return S_OK;\r
413 }\r
414 \r
415 \r
416 /******************************************************************************\r
417 \r
418         IDataObject\r
419 \r
420 ******************************************************************************/\r
421 \r
422 static HRESULT STDMETHODCALLTYPE OLE_IDataObject_QueryInterface(LPDATAOBJECT lpThis, REFIID riid, LPVOID FAR *lplpvObj);\r
423 static ULONG STDMETHODCALLTYPE OLE_IDataObject_AddRef(LPDATAOBJECT lpThis);\r
424 static ULONG STDMETHODCALLTYPE OLE_IDataObject_Release(LPDATAOBJECT lpThis);\r
425 static HRESULT STDMETHODCALLTYPE OLE_IDataObject_GetData(LPDATAOBJECT lpThis, FORMATETC *pFormatetc, STGMEDIUM *pmedium);\r
426 static HRESULT STDMETHODCALLTYPE OLE_IDataObject_GetDataHere(LPDATAOBJECT lpThis, FORMATETC *pFormatetc, STGMEDIUM *pmedium);\r
427 static HRESULT STDMETHODCALLTYPE OLE_IDataObject_QueryGetData(LPDATAOBJECT lpThis, FORMATETC *pFormatetc);\r
428 static HRESULT STDMETHODCALLTYPE OLE_IDataObject_GetCanonicalFormatEtc(LPDATAOBJECT lpThis, FORMATETC *pFormatetcIn, FORMATETC *pFormatetcOut);\r
429 static HRESULT STDMETHODCALLTYPE OLE_IDataObject_SetData(LPDATAOBJECT lpThis, FORMATETC *pFormatetc, STGMEDIUM *pmedium, BOOL fRelease);\r
430 static HRESULT STDMETHODCALLTYPE OLE_IDataObject_EnumFormatEtc(LPDATAOBJECT lpThis, DWORD dwDirection, IEnumFORMATETC **ppenumFormatetc);\r
431 static HRESULT STDMETHODCALLTYPE OLE_IDataObject_DAdvise(LPDATAOBJECT lpThis, FORMATETC *pFormatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection);\r
432 static HRESULT STDMETHODCALLTYPE OLE_IDataObject_DUnadvise(LPDATAOBJECT lpThis, DWORD dwConnection);\r
433 static HRESULT STDMETHODCALLTYPE OLE_IDataObject_EnumDAdvise(LPDATAOBJECT lpThis, IEnumSTATDATA **ppenumAdvise);\r
434 \r
435 /* IDataObject Virtual Table */\r
436 static IDataObjectVtbl dov = {\r
437         OLE_IDataObject_QueryInterface,\r
438         OLE_IDataObject_AddRef,\r
439         OLE_IDataObject_Release,\r
440         OLE_IDataObject_GetData,\r
441         OLE_IDataObject_GetDataHere,\r
442         OLE_IDataObject_QueryGetData,\r
443         OLE_IDataObject_GetCanonicalFormatEtc,\r
444         OLE_IDataObject_SetData,\r
445         OLE_IDataObject_EnumFormatEtc,\r
446         OLE_IDataObject_DAdvise,\r
447         OLE_IDataObject_DUnadvise,\r
448         OLE_IDataObject_EnumDAdvise\r
449 };\r
450 \r
451 typedef struct _IDATAOBJECT_INTERNAL{\r
452         LPVOID lpVtbl;\r
453         ULONG m_refCnt;\r
454         UINT m_numTypes;\r
455         UINT m_maxTypes;\r
456         FORMATETC *m_typeList;\r
457         HWND hWnd;\r
458         UINT uCallbackMessage;\r
459 }IDATAOBJECT_INTERNAL , *LPIDATAOBJECT_INTERNAL;\r
460 \r
461 \r
462 static HRESULT STDMETHODCALLTYPE OLE_IDataObject_QueryInterface(LPDATAOBJECT lpThis, REFIID riid, LPVOID FAR *lplpvObj)\r
463 {\r
464         //要求されたIIDと同じ場合はオブジェクトを返す\r
465         if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDataObject)){\r
466                 *lplpvObj = lpThis;\r
467                  ((LPUNKNOWN)*lplpvObj)->lpVtbl->AddRef(((LPUNKNOWN)*lplpvObj));\r
468                 return S_OK;\r
469         }\r
470         *lplpvObj = NULL;\r
471         return ResultFromScode(E_NOINTERFACE);\r
472 }\r
473 \r
474 static ULONG STDMETHODCALLTYPE OLE_IDataObject_AddRef(LPDATAOBJECT lpThis)\r
475 {\r
476         CONST LPIDATAOBJECT_INTERNAL pdoi = (LPIDATAOBJECT_INTERNAL)lpThis;\r
477 \r
478         /* reference countをインクリメントする */\r
479         pdoi->m_refCnt++;\r
480         return pdoi->m_refCnt;\r
481 }\r
482 \r
483 static ULONG STDMETHODCALLTYPE OLE_IDataObject_Release(LPDATAOBJECT lpThis)\r
484 {\r
485         CONST LPIDATAOBJECT_INTERNAL pdoi = (LPIDATAOBJECT_INTERNAL)lpThis;\r
486 \r
487         /* reference countをデクリメントする */\r
488         pdoi->m_refCnt--;\r
489 \r
490         /* reference countが 0 になった場合はオブジェクトの解放を行う */\r
491         if(pdoi->m_refCnt == 0L){\r
492                 if(pdoi->m_typeList != NULL){\r
493                         GlobalFree(pdoi->m_typeList);\r
494                 }\r
495                 GlobalFree(pdoi);\r
496                 return 0L;\r
497         }\r
498         return pdoi->m_refCnt;\r
499 }\r
500 \r
501 static HRESULT STDMETHODCALLTYPE OLE_IDataObject_GetData(LPDATAOBJECT lpThis, FORMATETC *pFormatetc, STGMEDIUM *pmedium)\r
502 {\r
503         CONST LPIDATAOBJECT_INTERNAL pdoi = (LPIDATAOBJECT_INTERNAL)lpThis;\r
504         HGLOBAL hMem;\r
505         UINT i;\r
506 \r
507         /* 要求されたクリップボードフォーマットが存在するか調べる */\r
508         for(i = 0;i < pdoi->m_numTypes;i++){\r
509                 if(pdoi->m_typeList[i].cfFormat == pFormatetc->cfFormat){\r
510                         break;\r
511                 }\r
512         }\r
513         if(i == pdoi->m_numTypes){\r
514                 /* 要求されたクリップボードフォーマットをサポートしてない場合 */\r
515                 return ResultFromScode(DV_E_FORMATETC);\r
516         }\r
517 \r
518         // マウスのドラッグ中は WM_GETDATA を送らないようにする。(2007.9.3 yutaka)\r
519         if (GetAsyncKeyState(VK_LBUTTON) & 0x8000 ||\r
520                 GetAsyncKeyState(VK_RBUTTON) & 0x8000) {\r
521                 return ResultFromScode(DV_E_FORMATETC);\r
522         }\r
523 \r
524         /* ウィンドウにデータの要求を行う */\r
525         SendMessage(pdoi->hWnd, pdoi->uCallbackMessage, (WPARAM)pdoi->m_typeList[i].cfFormat, (LPARAM)&hMem);\r
526         if(hMem == NULL){\r
527                 return ResultFromScode(STG_E_MEDIUMFULL);\r
528         }\r
529         pmedium->hGlobal = hMem;\r
530         pmedium->tymed = FormatToTymed(pFormatetc->cfFormat);\r
531         pmedium->pUnkForRelease = NULL;\r
532         return S_OK;\r
533 }\r
534 \r
535 static HRESULT STDMETHODCALLTYPE OLE_IDataObject_GetDataHere(LPDATAOBJECT lpThis, FORMATETC *pFormatetc, STGMEDIUM *pmedium)\r
536 {\r
537         return ResultFromScode(E_NOTIMPL);\r
538 }\r
539 \r
540 static HRESULT STDMETHODCALLTYPE OLE_IDataObject_QueryGetData(LPDATAOBJECT lpThis, FORMATETC *pFormatetc)\r
541 {\r
542         CONST LPIDATAOBJECT_INTERNAL pdoi = (LPIDATAOBJECT_INTERNAL)lpThis;\r
543         UINT i;\r
544 \r
545         /* 要求されたクリップボードフォーマットが存在するか調べる */\r
546         for(i = 0;i < pdoi->m_numTypes;i++){\r
547                 if(pdoi->m_typeList[i].cfFormat == pFormatetc->cfFormat){\r
548                         return S_OK;\r
549                 }\r
550         }\r
551         return ResultFromScode(DV_E_FORMATETC);\r
552 }\r
553 \r
554 static HRESULT STDMETHODCALLTYPE OLE_IDataObject_GetCanonicalFormatEtc(LPDATAOBJECT lpThis, FORMATETC *pFormatetcIn, FORMATETC *pFormatetcOut)\r
555 {\r
556         return ResultFromScode(E_NOTIMPL);\r
557 }\r
558 \r
559 static HRESULT STDMETHODCALLTYPE OLE_IDataObject_SetData(LPDATAOBJECT lpThis, FORMATETC *pFormatetc, STGMEDIUM *pmedium, BOOL fRelease)\r
560 {\r
561         return ResultFromScode(E_NOTIMPL);\r
562 }\r
563 \r
564 static HRESULT STDMETHODCALLTYPE OLE_IDataObject_EnumFormatEtc(LPDATAOBJECT lpThis, DWORD dwDirection, IEnumFORMATETC **ppenumFormatetc)\r
565 {\r
566         CONST LPIDATAOBJECT_INTERNAL pdoi = (LPIDATAOBJECT_INTERNAL)lpThis;\r
567         static IENUMFORMATETC_INTERNAL *pefi;\r
568         UINT i;\r
569 \r
570         if(ppenumFormatetc == NULL){\r
571                 return ResultFromScode(E_INVALIDARG);\r
572         }\r
573 \r
574         if(dwDirection != DATADIR_GET){\r
575                 *ppenumFormatetc = NULL;\r
576                 return ResultFromScode(E_NOTIMPL);\r
577         }\r
578 \r
579         /* IEnumFORMATETCを作成する */\r
580         pefi = GlobalAlloc(GPTR, sizeof(IENUMFORMATETC_INTERNAL));\r
581         if(pefi == NULL){\r
582                 return E_OUTOFMEMORY;\r
583         }\r
584         pefi->lpVtbl = (LPVOID)&efv;\r
585         pefi->m_refCnt = 0;\r
586         pefi->m_currElement = 0;\r
587         pefi->m_pUnknownObj = (struct IUnknown *)lpThis;\r
588         pefi->m_numFormats = pdoi->m_numTypes;\r
589 \r
590         /* クリップボードフォーマットのリストをコピーする */\r
591         pefi->m_formatList = GlobalAlloc(GPTR, sizeof(FORMATETC) * pefi->m_numFormats);\r
592         if(pefi->m_formatList != NULL){\r
593                 for(i = 0;i < pefi->m_numFormats;i++){\r
594                           pefi->m_formatList[i] = pdoi->m_typeList[i];\r
595                 }\r
596         }\r
597 \r
598         ((LPENUMFORMATETC)pefi)->lpVtbl->AddRef(((LPENUMFORMATETC)pefi));\r
599 \r
600         *ppenumFormatetc = (struct IEnumFORMATETC *)pefi;\r
601         if(*ppenumFormatetc == NULL){\r
602                 return E_OUTOFMEMORY;\r
603         }\r
604         return S_OK;\r
605 }\r
606 \r
607 static HRESULT STDMETHODCALLTYPE OLE_IDataObject_DAdvise(LPDATAOBJECT lpThis, FORMATETC *pFormatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection)\r
608 {\r
609         return ResultFromScode(OLE_E_ADVISENOTSUPPORTED);\r
610 }\r
611 \r
612 static HRESULT STDMETHODCALLTYPE OLE_IDataObject_DUnadvise(LPDATAOBJECT lpThis, DWORD dwConnection)\r
613 {\r
614         return ResultFromScode(OLE_E_NOCONNECTION);\r
615 }\r
616 \r
617 static HRESULT STDMETHODCALLTYPE OLE_IDataObject_EnumDAdvise(LPDATAOBJECT lpThis, IEnumSTATDATA **ppenumAdvise)\r
618 {\r
619         return ResultFromScode(OLE_E_ADVISENOTSUPPORTED);\r
620 }\r
621 \r
622 \r
623 /******************************************************************************\r
624 \r
625         IDropSource\r
626 \r
627 ******************************************************************************/\r
628 \r
629 static HRESULT STDMETHODCALLTYPE OLE_IDropSource_QueryInterface(LPDROPSOURCE lpThis, REFIID riid, LPVOID FAR* lplpvObj);\r
630 static ULONG STDMETHODCALLTYPE OLE_IDropSource_AddRef(LPDROPSOURCE lpThis);\r
631 static ULONG STDMETHODCALLTYPE OLE_IDropSource_Release(LPDROPSOURCE lpThis);\r
632 static HRESULT STDMETHODCALLTYPE OLE_IDropSource_QueryContinueDrag(LPDROPSOURCE lpThis, BOOL fEscapePressed, DWORD grfKeyState);\r
633 static HRESULT STDMETHODCALLTYPE OLE_IDropSource_GiveFeedback(LPDROPSOURCE lpThis, DWORD dwEffect);\r
634 \r
635 /* IDropSource Virtual Table */\r
636 static IDropSourceVtbl dsv = {\r
637         OLE_IDropSource_QueryInterface,\r
638         OLE_IDropSource_AddRef,\r
639         OLE_IDropSource_Release,\r
640         OLE_IDropSource_QueryContinueDrag,\r
641         OLE_IDropSource_GiveFeedback,\r
642 };\r
643 \r
644 typedef struct _IDROPSOURCE_INTERNAL{\r
645         LPVOID lpVtbl;\r
646         ULONG m_refCnt;\r
647         DWORD m_keyState;\r
648         DWORD m_button;\r
649         HWND m_hWnd;\r
650         UINT m_uCallbackDragOverMessage;\r
651 }IDROPSOURCE_INTERNAL , *LPIDROPSOURCE_INTERNAL;\r
652 \r
653 static HRESULT STDMETHODCALLTYPE OLE_IDropSource_QueryInterface(LPDROPSOURCE lpThis, REFIID riid, LPVOID FAR *lplpvObj)\r
654 {\r
655         //要求されたIIDと同じ場合はオブジェクトを返す\r
656         if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDropSource)){\r
657                 *lplpvObj = (LPVOID) lpThis;\r
658                 ((LPUNKNOWN)*lplpvObj)->lpVtbl->AddRef(((LPUNKNOWN)*lplpvObj));\r
659                 return S_OK;\r
660         }\r
661         *lplpvObj = NULL;\r
662         return ResultFromScode(E_NOINTERFACE);\r
663 \r
664 }\r
665 \r
666 static ULONG STDMETHODCALLTYPE OLE_IDropSource_AddRef(LPDROPSOURCE lpThis)\r
667 {\r
668         CONST LPIDROPSOURCE_INTERNAL pdsi = (LPIDROPSOURCE_INTERNAL)lpThis;\r
669 \r
670         /* reference countをインクリメントする */\r
671         pdsi->m_refCnt++;\r
672         return pdsi->m_refCnt;\r
673 }\r
674 \r
675 static ULONG STDMETHODCALLTYPE OLE_IDropSource_Release(LPDROPSOURCE lpThis)\r
676 {\r
677         CONST LPIDROPSOURCE_INTERNAL pdsi = (LPIDROPSOURCE_INTERNAL)lpThis;\r
678 \r
679         /* reference countをデクリメントする */\r
680         pdsi->m_refCnt--;\r
681 \r
682         /* reference countが 0 になった場合はオブジェクトの解放を行う */\r
683         if(pdsi->m_refCnt == 0L){\r
684                 GlobalFree(pdsi);\r
685                 return 0L;\r
686         }\r
687         return pdsi->m_refCnt;\r
688 }\r
689 \r
690 static HRESULT STDMETHODCALLTYPE OLE_IDropSource_QueryContinueDrag(LPDROPSOURCE lpThis, BOOL fEscapePressed, DWORD grfKeyState)\r
691 {\r
692         CONST LPIDROPSOURCE_INTERNAL pdsi = (LPIDROPSOURCE_INTERNAL)lpThis;\r
693 \r
694         if(fEscapePressed){\r
695                 /* エスケープが押された場合はキャンセルにする */\r
696                 return ResultFromScode(DRAGDROP_S_CANCEL);\r
697         }\r
698 \r
699         // Mouse overの通知 (yutaka)\r
700         SendMessage(pdsi->m_hWnd, pdsi->m_uCallbackDragOverMessage, 0, 0);\r
701 \r
702         /* 指定のキーやマウスが離された場合はドロップにする */\r
703         if(pdsi->m_button == 0){\r
704                 if(grfKeyState != pdsi->m_keyState){\r
705                         return ResultFromScode(DRAGDROP_S_DROP);\r
706                 }\r
707         }else{\r
708                 if(!(grfKeyState & pdsi->m_button)){\r
709                         return ResultFromScode(DRAGDROP_S_DROP);\r
710                 }\r
711         }\r
712         return S_OK;\r
713 }\r
714 \r
715 static HRESULT STDMETHODCALLTYPE OLE_IDropSource_GiveFeedback(LPDROPSOURCE lpThis, DWORD dwEffect)\r
716 {\r
717         return ResultFromScode(DRAGDROP_S_USEDEFAULTCURSORS);\r
718 }\r
719 \r
720 /* ドラッグ&ドロップの開始 */\r
721 int APIPRIVATE OLE_IDropSource_Start(HWND hWnd, UINT uCallbackMessage, UINT uCallbackDragOverMessage, UINT *ClipFormtList, int cfcnt, int Effect)\r
722 {\r
723         static IDATAOBJECT_INTERNAL *pdoi;\r
724         static IDROPSOURCE_INTERNAL *pdsi;\r
725         DWORD lpdwEffect;\r
726         DWORD keyState;\r
727         int i;\r
728         int ret;\r
729 \r
730         /* IDataObjectの作成 */\r
731         pdoi = GlobalAlloc(GPTR, sizeof(IDATAOBJECT_INTERNAL));\r
732         if(pdoi == NULL){\r
733                 return -1;\r
734         }\r
735         pdoi->lpVtbl = (LPVOID)&dov;\r
736         pdoi->m_refCnt = 0;\r
737         pdoi->m_numTypes = cfcnt;\r
738         pdoi->m_maxTypes = cfcnt;\r
739         /* 有効なクリップボードフォーマットを設定する */\r
740         pdoi->m_typeList = GlobalAlloc(GPTR, sizeof(FORMATETC) * cfcnt);\r
741         if(pdoi->m_typeList == NULL){\r
742                 GlobalFree(pdoi);\r
743                 return -1;\r
744         }\r
745         for(i = 0;i < cfcnt;i++){\r
746                 pdoi->m_typeList[i].cfFormat = ClipFormtList[i];\r
747                 pdoi->m_typeList[i].ptd = NULL;\r
748                 pdoi->m_typeList[i].dwAspect = DVASPECT_CONTENT;\r
749                 pdoi->m_typeList[i].lindex = -1;\r
750                 pdoi->m_typeList[i].tymed = FormatToTymed(ClipFormtList[i]);\r
751         }\r
752         pdoi->hWnd = hWnd;\r
753         pdoi->uCallbackMessage = uCallbackMessage;\r
754         ((LPDATAOBJECT)pdoi)->lpVtbl->AddRef((LPDATAOBJECT)pdoi);\r
755 \r
756         /* IDropSourceの作成 */\r
757         pdsi = GlobalAlloc(GPTR, sizeof(IDROPSOURCE_INTERNAL));\r
758         if(pdsi == NULL){\r
759                 /* IDataObjectを解放する */\r
760                 ((LPDATAOBJECT)pdoi)->lpVtbl->Release((LPDATAOBJECT)pdoi);\r
761                 return -1;\r
762         }\r
763         pdsi->lpVtbl = (LPVOID)&dsv;\r
764         pdsi->m_refCnt = 0;\r
765         pdsi->m_hWnd = hWnd; // yutaka\r
766         pdsi->m_uCallbackDragOverMessage = uCallbackDragOverMessage;\r
767 \r
768         /* 有効なキーとマウスの状態 */\r
769         if(GetKeyState(VK_RBUTTON) & 0x8000){\r
770                 pdsi->m_button = MK_RBUTTON;\r
771         }else{\r
772                 pdsi->m_button = MK_LBUTTON;\r
773         }\r
774 \r
775         /* 現在のキーとマウスの状態 */\r
776         keyState = 0;\r
777         if(GetKeyState(VK_SHIFT) & 0x8000){\r
778                 keyState |= MK_SHIFT;\r
779         }\r
780         if(GetKeyState(VK_CONTROL) & 0x8000){\r
781                 keyState |= MK_CONTROL;\r
782         }\r
783         if(GetKeyState(VK_MENU) & 0x8000){\r
784                 keyState |= MK_ALT;\r
785         }\r
786         if(GetKeyState(VK_LBUTTON) & 0x8000){\r
787                 keyState |= MK_LBUTTON;\r
788         }\r
789         if(GetKeyState(VK_MBUTTON) & 0x8000){\r
790                 keyState |= MK_MBUTTON;\r
791         }\r
792         if(GetKeyState(VK_RBUTTON) & 0x8000){\r
793                 keyState |= MK_RBUTTON;\r
794         }\r
795         pdsi->m_keyState = keyState;\r
796         ((LPDROPSOURCE)pdsi)->lpVtbl->AddRef((LPDROPSOURCE)pdsi);\r
797 \r
798         lpdwEffect = 0;\r
799 \r
800         /* ドラッグ&ドロップの開始 */\r
801         ret = DoDragDrop((LPDATAOBJECT)pdoi, (LPDROPSOURCE)pdsi, Effect, &lpdwEffect);\r
802 \r
803         /* IDataObjectを解放する */\r
804         ((LPDATAOBJECT)pdoi)->lpVtbl->Release((LPDATAOBJECT)pdoi);\r
805         /* IDropSourceを解放する */\r
806         ((LPDROPSOURCE)pdsi)->lpVtbl->Release((LPDROPSOURCE)pdsi);\r
807 \r
808         if(ret == DRAGDROP_S_DROP){\r
809                 /* ドロップ先のアプリケーションが設定した効果を返す */\r
810                 return lpdwEffect;\r
811         }\r
812         return -1;\r
813 }\r
814 /* End of source */\r