CreateWindowsへのドラッグ&ドロップ(ファイルではない)

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
ROA

CreateWindowsへのドラッグ&ドロップ(ファイルではない)

#1

投稿記事 by ROA » 8年前

Webブラウザ上のリンクを、PCのブラウザにドラッグ&ドロップすると「.urlファイル」が作成されます。
作成される前にWindows側でドラッグ&ドロップした内容を取得していると考えています。

しかし、CreateWindowにて表示したウィンドウには、Webブラウザのリンクをドラッグ&ドロップしようとすると、マウスカーソルが「No」になりドラッグ&ドロップが出来ません。
ドラッグ&ドロップを出来るようにするには、どうすれば良いでしょうか。

みえ
記事: 23
登録日時: 8年前

Re: CreateWindowsへのドラッグ&ドロップ(ファイルではない)

#2

投稿記事 by みえ » 8年前

ウィンドウに対してドラッグ & ドロップを有効にするコードは、以下のサイトが参考になると思います。

http://eternalwindows.jp/ole/oledrag/oledrag01.html

ドラッグされてきたオブジェクトの情報が IDropTarget::DragEnter で取得できるので、そのときに何の種類のオブジェクトを許可して、カーソルを何に替えるか、などを決めることができます。

Web ブラウザーからのハイパーリンクの判別方法がちょっと難しいですね。↓ のページ等を参考にしたのですがちゃんと動いてくれないので、もうちょっと調べてみます。その間にどなたか別の方から回答があればいいのですが。

What a drag: Dragging a Uniform Resource Locator (URL) – The Old New Thing
https://blogs.msdn.microsoft.com/oldnew ... 0/?p=23133

c++ - Drag-and-drop from IE 9 into my application - Stack Overflow
http://stackoverflow.com/questions/1447 ... pplication

みえ
記事: 23
登録日時: 8年前

Re: CreateWindowsへのドラッグ&ドロップ(ファイルではない)

#3

投稿記事 by みえ » 8年前

URL の情報が文字列として送られてくることが分かりましたので、以下のコードで、その文字列を MessageBox で表示することができました。
Win10 上の Chrome、Firefox、IE、Edge で動作確認済みです。

コード:

#include <windows.h>
#include <atlbase.h>

static WCHAR window_name[] = L"window.drag-n-drop";
const UINT WM_POPUPMSGBOX = WM_USER + 1;

class CDropTarget : public IDropTarget {
private:
  const DWORD preferredEffect = DROPEFFECT_LINK;
  LONG refcount;
  HWND owner;
  bool supported;

public:
  CDropTarget(HWND hwnd)
    : refcount(1), owner(hwnd), supported(false) {}
  virtual ~CDropTarget() {}

  // IUnknown

  STDMETHODIMP_(ULONG) AddRef() {
    return InterlockedIncrement(&refcount);
  }

  STDMETHODIMP_(ULONG) Release() {
    if (InterlockedDecrement(&refcount) == 0) {
      delete this;
      return 0;
    }
    return refcount;
  }

#pragma warning(push)
#pragma warning(disable : 4838)
  STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject) {
    const QITAB QITable[] = {
        QITABENT(CDropTarget, IDropTarget),
        { 0 },
    };
    return QISearch(this, QITable, riid, ppvObject);
  }
#pragma warning(pop)

  // IDropTarget

  STDMETHODIMP DragEnter(IDataObject *pDataObj,
                         DWORD grfKeyState,
                         POINTL pt,
                         DWORD *pdwEffect) {
    FORMATETC formatetc = {};
    formatetc.cfFormat = CF_UNICODETEXT;
    formatetc.dwAspect = DVASPECT_CONTENT;
    formatetc.lindex = -1;
    formatetc.tymed = TYMED_HGLOBAL;
    if (SUCCEEDED(pDataObj->QueryGetData(&formatetc))) {
      supported = true;
      *pdwEffect = preferredEffect;
    }
    else {
      supported = false;
      *pdwEffect = DROPEFFECT_NONE;
    }
    return S_OK; 
  }

  STDMETHODIMP DragOver(DWORD grfKeyState,
                        POINTL pt,
                        DWORD *pdwEffect) {
    *pdwEffect = supported ? preferredEffect : DROPEFFECT_NONE;
    return S_OK;
  }

  STDMETHODIMP DragLeave() {
    return S_OK;
  }

  STDMETHODIMP Drop(IDataObject *pDataObj,
                    DWORD grfKeyState,
                    POINTL pt,
                    DWORD *pdwEffect) {
    FORMATETC formatetc = {};
    formatetc.cfFormat = CF_UNICODETEXT;
    formatetc.ptd = nullptr;
    formatetc.dwAspect = DVASPECT_CONTENT;
    formatetc.lindex = -1;
    formatetc.tymed = TYMED_HGLOBAL;

    STGMEDIUM medium = {};
    HRESULT hr = pDataObj->GetData(&formatetc, &medium);
    if (SUCCEEDED(hr)) {
      *pdwEffect = preferredEffect;
      LPVOID locked = GlobalLock(medium.hGlobal);
      if (locked) {
        CComBSTR msg(static_cast<LPCWSTR>(locked));
        PostMessage(owner, WM_POPUPMSGBOX, 0, reinterpret_cast<LPARAM>(msg.Detach()));
        GlobalUnlock(medium.hGlobal);
      }
      ReleaseStgMedium(&medium);
    }
    else {
      *pdwEffect = DROPEFFECT_NONE;
    }

    return hr;
  }
};

void OnCreate(HWND hwnd) {
  if (SUCCEEDED(OleInitialize(nullptr))) {
    CDropTarget *target = new CDropTarget(hwnd);
    if (target) {
      SetWindowLongPtr(hwnd,
                       GWLP_USERDATA,
                       reinterpret_cast<LONG_PTR>(target));
      RegisterDragDrop(hwnd, target);
    }
  }
}

void OnDestroy(HWND hwnd) {
  RevokeDragDrop(hwnd);
  auto p = GetWindowLongPtr(hwnd, GWLP_USERDATA);
  if (p) {
    reinterpret_cast<CDropTarget*>(p)->Release();
  }
  OleUninitialize();
  PostQuitMessage(0);
}

void OnPopup(HWND hwnd, LPARAM lParam) {
  CComBSTR msg;
  msg.Attach(reinterpret_cast<BSTR>(lParam));
  MessageBox(hwnd, msg, L"Dropped!", MB_OK);
}

LRESULT CALLBACK WindowProc(HWND hwnd,
                            UINT uMsg,
                            WPARAM wParam,
                            LPARAM lParam) {
  switch (uMsg) {
  case WM_CREATE:
    OnCreate(hwnd);
    break;
  case WM_DESTROY:
    OnDestroy(hwnd);
    break;
  case WM_POPUPMSGBOX:
    OnPopup(hwnd, lParam);
    break;
  default:
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
    break;
  }
  return 0;
}

int WINAPI WinMain(HINSTANCE hinst,
                   HINSTANCE hinstPrev,
                   LPSTR lpszCmdLine,
                   int nCmdShow) {
  WNDCLASSEX wc = {};
  wc.cbSize = sizeof(WNDCLASSEX);
  wc.lpfnWndProc = WindowProc;
  wc.hInstance = hinst;
  wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
  wc.hbrBackground = reinterpret_cast<HBRUSH>(BLACK_BRUSH);
  wc.lpszClassName = window_name;

  if (RegisterClassEx(&wc)) {
    HWND hwnd = CreateWindow(window_name,
                             window_name,
                             WS_OVERLAPPEDWINDOW,
                             CW_USEDEFAULT,
                             CW_USEDEFAULT,
                             400,
                             150,
                             /*hWndParent*/nullptr,
                             /*hMenu*/nullptr,
                             hinst,
                             /*lpParam*/nullptr);
    if (hwnd) {
      ShowWindow(hwnd, nCmdShow);
      UpdateWindow(hwnd);

      MSG msg = {};
      while (GetMessage(&msg, nullptr, 0, 0) > 0) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
      }
    }
  }

  return 0;
}
ただし IE には追加の考慮が必要です。既定では、IE の保護モードが有効なときにはドラッグ & ドロップが許可されません。

Understanding and Working in Protected Mode Internet Explorer
https://msdn.microsoft.com/en-us/librar ... s.85).aspx
Allowing Drag and Drop Operations in your Application
By default, Protected Mode prompts the user before allowing web content to be copied to a higher integrity process.
You can register your application to avoid this prompt and silently accept web content from a drag-and-drop operation by creating a DragDrop policy. DragDrop policies must have a globally unique identifier (GUID) associated with them. Use CreateGuid to create a new GUID for your policy. Next, add a key to the following location.
IE からのドラッグ & ドロップを有効にするには、許可するためのポリシー設定を exe ファイル毎にレジストリに追加する必要があります。プログラム内から書き込むのがベストですが、とりあえず以下のようなバッチファイルを作ったところ IE でも動きました。

コード:

set SUBKEY=HKLM\SOFTWARE\Microsoft\Internet Explorer\Low Rights\DragDrop
set APPGUID={任意の GUID}
reg add "%SUBKEY%\%APPGUID%" /f /v Policy /t REG_DWORD /d 3
reg add "%SUBKEY%\%APPGUID%" /f /v AppName /t REG_SZ /d your_application.exe
reg add "%SUBKEY%\%APPGUID%" /f /v AppPath /t REG_SZ /d X:\path_to_exe

ROA

Re: CreateWindowsへのドラッグ&ドロップ(ファイルではない)

#4

投稿記事 by ROA » 8年前

えみさん

ご教示頂き、誠にありがとうございます!!m(_ _*)m
実は、質問書いた後に「IDropTarget」に辿り着き、何とか自力で作成出来ました。すみません。。。
「createWindowに設定するだけで出来ないんかぁぁぁい!!」となりました(汗)

>ただし IE には追加の考慮が必要です。既定では、IE の保護モードが有効なときにはドラッグ & ドロップが許可されません。
なんと!?
私のIEだと出来ていたので、絶対気付けないないようですね・・・。とても助かります。ありがとうございます!!

返信

“C言語何でも質問掲示板” へ戻る