Re[7]: Как "сэмулировать" драг-и-дроп?
От: Patalog Россия  
Дата: 30.10.03 10:57
Оценка:
Здравствуйте, alexqc, Вы писали:

[]

P>>Так бы и говорил сразу, а то я понял так, что тебе нужно засунуть все это дело в clipboard, дабы потом можно было в проводнике сделать paste...


A>Про клипбоард я вообще ни слова не говорил.


Ну это я почему-то так понял

[]

A>Я для проверки делал

A>    int size=strlen(lpDroppedText)+2+sizeof(DROPFILES);
A>    HGLOBAL drop_data = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE | GMEM_DDESHARE, size);

A>    struct DROP_DATA{
A>    DROPFILES df;
A>    char names[1];
A>    } *hal=(DROP_DATA*)GlobalLock(drop_data);

A>    memset(hal,0,size); // не нужно, у тебя же GMEM_ZEROINIT
    hal->>df.fNC=sizeof(DROPFILES);
A>    strcpy(hal->names,lpDroppedText);
A>    GlobalUnlock(drop_data); // Думается это надо делать после DragQueryFile

A>    int ret=DragQueryFile(HDROP (drop_data)
A>        ,UINT(0xFFFFFFFF), NULL,0);

A>    GlobalFree(drop_data);

A>получаю ret=0, т.е. ошибку.

A>Точно ли drop_data в этом случае тот самый HDROP? (об этом как раз в TFM нет ни слова )


Дык я же приводил цитату из TFM. К тому же реальность данная мне в ощущениях это подтверждает.

P>>ЗЗЫ Хотя ежели ты сообщение шлешь в другое приложение, тогда скорее всего в clipboard таки пихать придется, а в SendMessage отдавать то, что вернет SetClipboardData.


A>Что-то извратом пахнет, да и clipboard портить...


Ну clipboard то ты не испортишь, бо таким образом copy\paste в explorer (или еще куда) проще всего сделать.
Правда для WM_DROPFILES это не работает, собст. как я и думал из-за границ процесса.

Вобщем лови. Писано в MFC'ях, но думается под голое API переделать труда не составит. Запускаешь 2 экземпляра приложения и тащиш мышой из одного в другое.
class drop_names
{
    std::vector<TCHAR>    drop_data_;
    size_t                cur_index;
    bool                locked_;
public:
    drop_names() : cur_index(0), locked_(false) { }
    bool add(const TCHAR* name)
    {
        _ASSERTE(!locked_);
        if (locked_)
            return false;

        const size_t name_size = lstrlen(name);
        drop_data_.resize(cur_index + name_size + 1);
        memcpy(&drop_data_[0] + cur_index, name, name_size * sizeof(TCHAR));
        cur_index += name_size;
        drop_data_[cur_index] = _T('\0');
        ++cur_index;

        return true;
    }

    const TCHAR* lock()
    {
        _ASSERTE(!locked_);
        if (!locked_)
        {
            drop_data_.push_back(_T('\0'));
            ++cur_index;
            locked_ = true;
        }

        return &drop_data_[0];
    }

    size_t size() const { return cur_index * sizeof(TCHAR); }
};

void CNewView::OnLButtonDown(UINT nFlags, CPoint point)
{
    SetCapture();
}

void CNewView::OnLButtonUp(UINT nFlags, CPoint point)
{
    drop_names d_names;
    const TCHAR* name1 = "c:\\temp\\mycoolfile1.txt";
    const TCHAR* name2 = "c:\\temp\\mycoolfile2.txt";
    const TCHAR* name3 = "c:\\temp\\mycoolfile3.txt";
    
    d_names.add(name1);
    d_names.add(name2);
    d_names.add(name3);
    const TCHAR* names = d_names_.lock();
    const size_t names_size = d_names_.size();

    DROPFILES drop_struct = { sizeof(drop_struct), { 0, 0 }, 0, 0 };
    const size_t drop_size = sizeof(drop_struct) + names_size;

    std::vector<unsigned char> drop_data(drop_size);
    memcpy(&drop_data[0], &drop_struct, sizeof(drop_struct));
    memcpy(&drop_data[0] + sizeof(drop_struct), names, names_size);

    
    ClientToScreen(&point);
    CWnd* found_wnd = WindowFromPoint(point);
    _ASSERTE(found_wnd);

    DWORD process_id = 0;
    GetWindowThreadProcessId(found_wnd->GetSafeHwnd(), &process_id);
    HANDLE process = OpenProcess(PROCESS_ALL_ACCESS, FALSE, process_id);
    _ASSERTE(process);

    LPVOID address = VirtualAllocEx(process, NULL, drop_size, MEM_COMMIT, PAGE_READWRITE);
    _ASSERTE(address);

    SIZE_T bytes_written = 0;
    BOOL res = WriteProcessMemory(process, address, &drop_data[0], drop_size, &bytes_written);
    _ASSERTE(res && bytes_written == drop_size);

    found_wnd->SendMessage(WM_DROPFILES, (WPARAM)address, 0);

    res = VirtualFreeEx(process, address, 0, MEM_RELEASE);
    _ASSERTE(res);

    ReleaseCapture();
}

void CNewView::OnDropFiles(HDROP drop_info)
{
    CClientDC dc(this);

    int item_count = DragQueryFile(drop_info, 0xFFFFFFFF, NULL, 0);
    CString text;
    text.Format("Dropped %d files", item_count);
    dc.TextOut(100, 100, text);

    for (int i = 0; i < item_count; ++i)
    {
        TCHAR buffer[MAX_PATH] = { 0 };
        int buffer_size = DragQueryFile(drop_info, i, NULL, 0);
        DragQueryFile(drop_info, i, buffer, MAX_PATH);

        dc.TextOut(100, 120 + 20 * i, buffer);
    }
}


ЗЫ Ежели надо чтоб работало и под w9x, то придеться вместо VirtualAllocEx\WriteProcessMemory использовать внедрение dll. Подробнее об этом полно инфы тут на сайте, ну иеще конечно у Рихтера.
Почетный кавалер ордена Совка.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.