Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Системное программирование и WinAPI > IDropTarget и файлы


Автор: Emura 20.1.2011, 02:19
всем привет!

подскажите пожалуйста со следующим глючком.


- кидаем папку из эксплорера в окно (IDropTarget).
- обрабатываем файлы из папки(специфика программы).
окно эксплорера (откуда бралась папка) подвисает на время обработки.  


IDropTarget::Drop такого вида.

IDropTarget::Drop(...)
{
извлекаем путь папки
PostMessage( путь папки, ...);
}

из функции IDropTarget::Drop() успешно выходим перед тем как приходит сообщение от PostMessage, т.е. блокировать обработка не должна.. но.. smile как избежать этого зависания?


многопоточности нет, XP. 
всё дело встало, подскажите кто догадается, спасибо smile 


тестовый проект
Код

#include <windows.h>


static const wchar_t* const gWindowClassName =L"-TEST_CLASS_NAME-";
static const UINT WM_MAGIC =WM_APP + 0x4400;


    static LRESULT CALLBACK gWindowProc( HWND h, const UINT message, const WPARAM wParam, const LPARAM lParam )
    {

        switch ( message )
        {
        case WM_DESTROY:
            {
                ::PostQuitMessage(0);
                return 0;
                break;
            }
        case WM_MAGIC:
            {
                for ( int i=0; i<50; ++i )
                {
                    ::Sleep(100);
                }
                return 0;
                break;
            }
        }

        return ::DefWindowProcW( h, message, wParam, lParam );

    };


    class MyDropTarget : public IDropTarget
    {
    private:
        ULONG        m_refCount;
        HWND        m_owner;
        wchar_t        m_data[1024];
    public:
        MyDropTarget( HWND owner ):
          m_refCount    ( 1 ),
              m_owner        ( owner )
          {
          }
          virtual ~MyDropTarget()
          {
          }
          HRESULT __stdcall QueryInterface( REFIID id, void FAR* FAR* result )
          {
              if ( id==IID_IUnknown || 
                  id==IID_IDropTarget )
              {
                  *result =this;
                  AddRef();
                  return NOERROR;
              }
              *result =NULL;
              return ResultFromScode(E_NOINTERFACE);
          }
          ULONG __stdcall AddRef()    
          { 

              return ++m_refCount;
          }
          ULONG __stdcall Release()   
          { 
              if ( --m_refCount==0 ) 
              {
                  delete this; 
                  return 0;
              }
              return m_refCount; 
          }
          HRESULT __stdcall DragEnter( IDataObject* dataObject, DWORD grfKeyState, POINTL mousePos, DWORD* effect )
          {
              *effect =DROPEFFECT_COPY;
              return NOERROR;
          }
          HRESULT __stdcall DragOver( DWORD keyState, POINTL mousePos, DWORD* effect )
          {
              *effect =DROPEFFECT_COPY;
              return NOERROR;
          }
          HRESULT __stdcall DragLeave()
          {
              return NOERROR;
          }
          HRESULT __stdcall Drop( IDataObject* dataObject, DWORD keyState, POINTL mousePos, DWORD* effect )
          {
              BOOL r =::PostMessageW( m_owner, WM_MAGIC, 0, (LPARAM)0 );
              *effect =DROPEFFECT_COPY;
              return NOERROR;
          }
    };



    INT WINAPI WinMain( HINSTANCE, HINSTANCE, char*, INT )
    {

        ::OleInitialize(NULL);

        WNDCLASSEX wc;
        ::memset( &wc, 0, sizeof(wc) );
        wc.cbSize =sizeof(wc);
        wc.lpfnWndProc =(WNDPROC)gWindowProc;
        wc.cbWndExtra =4;
        wc.hInstance =::GetModuleHandleW(0);
        wc.lpszClassName =gWindowClassName;
        wc.hbrBackground =(HBRUSH)::GetStockObject( WHITE_BRUSH );
        wc.hCursor =::LoadCursorW( NULL, IDC_ARROW );
        ::RegisterClassExW( &wc );


        HWND h =::CreateWindowExW(
            0, 
            wc.lpszClassName,
            NULL,
            WS_OVERLAPPEDWINDOW, 
            100, 100,
            200, 200, 
            NULL, 
            NULL,
            ::GetModuleHandleW(0), 
            NULL );

        ::ShowWindow( h, SW_NORMAL );


        MyDropTarget dt(h);
        HRESULT result =::RegisterDragDrop( h, &dt );


        MSG m;
        while ( ::GetMessageW( &m, NULL, 0, 0 )>0 )
        {
            ::TranslateMessage( &m );
            ::DispatchMessageW( &m );
        }


        ::RevokeDragDrop( h );
        ::DestroyWindow( h );
        ::UnregisterClassW( gWindowClassName, ::GetModuleHandleW(0) );
        ::OleUninitialize();


        return 0;

    };





Автор: GremlinProg 20.1.2011, 10:51
поток-то все равно один, поэтому если эксплорер ждет какой-то синхронной с очередью сообщений реакции после Drop,
то он и будет висеть, пока WM_MAGIC не вернется

можно попробовать 2 варианта:

1. поставить в Drop таймер на несколько мс (чтобы отвязаться от эксплорера), на который, после срабатывания повесить обработку или посылку WM_MAGIC
2. пустить новый или возобновляющийся поток, исполняющий работу WM_MAGIC

Автор: Emura 20.1.2011, 12:10
GremlinProg,
да уж, думалось что PostMessage спасет, а получается что нет..

по поводу таймера, самому пришла такая идея в голову, да только как-то и так везде использую таймеры.. таймеры, которые уже ассоциируются с костылями... smile

на счет дополнительного потока хз.. для такой "мелочи".. smile 

попробую очередной ннннн-ый таймер smile 

интересную особенность заметил, если во время блока обработки( в тесте блок WM_MAGIC) выскакивает мессаджбокс(вызываемый алгоритмом обработки), то explorer размораживается.. магия виндовс блин smile 

Автор: GremlinProg 20.1.2011, 21:32
Цитата(Emura @  20.1.2011,  14:10 Найти цитируемый пост)
интересную особенность заметил, если во время блока обработки( в тесте блок WM_MAGIC) выскакивает мессаджбокс(вызываемый алгоритмом обработки), то explorer размораживается.. магия виндовс блин  

это нормально,
просто мессаджбокс имеет свой цикл обработки сообщений, поэтому любой вызов MessageBox или DialogBox в такой момент будет продолжать работу первичного цикла сообщений потока (того самого, который висит)

Автор: Emura 20.1.2011, 22:40
GremlinProg, очередной респект! таймер помог. smile 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)