Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Программирование и базы данных (http://forum.oszone.net/forumdisplay.php?f=21)
-   -   Текст в ListView и проч. (http://forum.oszone.net/showthread.php?t=93622)

pva 06-11-2007 22:54 673859

Текст в ListView и проч.
 
1. Это только у меня ListView в режиме LVS_REPORT отображает только примерно 100 символов в ячейке, или у всех так? хранит ведь полностью строчку
2. я так и не понял, в каких случаях ReadDirectoryChanges возвращает несколько записей и почему они все одинаковые?
дальше приведён кусочек кода с комментариями. Он опирается на STL и самописную библиотеку напоминающую упрощённую смесь QT и Swing
Код:

class DirectoryChanges  // класс для ReadDirectoryChangesW
{
    HANDLE          fdirectory;
    OVERLAPPED      foverlapped;
    vector<unsigned char> fbuffer;  // буфер 4К для чтения
    StringEvent*    fevent; // класс с одной пустой виртуальной функцией virtual void put(const wstring&) = 0;
    void restart();
    static void __stdcall _competed(unsigned long, unsigned long, OVERLAPPED*); // FileIoCompletionRoutine
public:
    DirectoryChanges(const wstring& dir);
    ~DirectoryChanges();
    void setEvent(StringEvent* event)  {fevent=event;}
};

// каждый раз, при появлении данных, в ListView добавляется строчка
// вследтсвие вызова fevent->put()

DirectoryChanges::DirectoryChanges(const wstring& dir) :
    fdirectory(CreateFile (    // кусок прямо из хелпа
          dir.c_str(),
          FILE_LIST_DIRECTORY,                // access (read-write) mode
          FILE_SHARE_READ|FILE_SHARE_DELETE,  // share mode
          0,                                  // security descriptor
          OPEN_EXISTING,                      // how to create
          FILE_FLAG_OVERLAPPED|FILE_FLAG_BACKUP_SEMANTICS, // file attributes
          0)),                              // file with attributes to copy
    foverlapped (),
    fbuffer    (4096)
{
    if (fdirectory==(HANDLE)-1)
    {
        ostringstream ss;
        ss << "DirectoryChanges::DirectoryChanges error=" << GetLastError();
        throw runtime_error(ss.str());
    }

    foverlapped.hEvent = reinterpret_cast<HANDLE>(this); // т.к. не используется в FileIoCompletionRoutine, микрософт не против
}

DirectoryChanges::~DirectoryChanges()
{
//    stopListening();
    CloseHandle(fdirectory);
}

void __stdcall DirectoryChanges::_competed(unsigned long code, unsigned long bytes_transfered, OVERLAPPED* ovlp)
{
  // это место выполняется "асинхронным вызовом процедуры", в главном цикле, который обрабатывает сообщения,
  // функцией MsgWaitForMultipleObjectsEx.
    if (code==0)
    {
        try
        {
          // разглядываем что прочитали
            DirectoryChanges* this1 = reinterpret_cast<DirectoryChanges*>(ovlp->hEvent);
            FILE_NOTIFY_INFORMATION* info = reinterpret_cast<FILE_NOTIFY_INFORMATION*>(&this1->fbuffer[0]);

            if (this1->fevent)
            {

                // 1. для начала посмотрим в виде HEX

                wostringstream ss;

                ss.fill('0');
                ss.flags(ios::hex|ios::fixed);

                for (unsigned n=0; n<bytes_transfered; ++n)
                {
                    ss << ' ';
                    ss.width(2);
                    ss << unsigned(this1->fbuffer[n]);
                }

                // выводим полученную строчку в ListView
                this1->fevent->put(ss.str());

              // теперь разбираем результат, как написано в хелпе
                for (;;)  // назовём его "цикл №2"
              {
                    // закидываем строчку в ListView
                    // опытным путём нашёл, что info->FileNameLength измеряется в байтах
                    this1->fevent->put(wstring(info->FileName, info->FileNameLength>>1));

                    if (!info->NextEntryOffset) break; // типа если дошли до конца

                    info = reinterpret_cast<FILE_NOTIFY_INFORMATION*>( // продвигаем указатель
                        reinterpret_cast<char*>(info) + info->NextEntryOffset);
                }

                this1->restart(); // когда закончили с буфером, отправляем читать дальше
            }
        }
// подстраховка, чтобы не порушить стек MsgWaitForMultipleObjectsEx
// потому что у моего компилятора не сильно совместимая система откатов от исключений
        catch (exception& e)
        {
            MessageBoxA(0, e.what(), 0, MB_OK);
        }
        catch (...)
        {
        }
    }
}

void DirectoryChanges::restart()
{
  // читаем всё сподряд
    if (!ReadDirectoryChangesW(fdirectory, &fbuffer[0], fbuffer.size(), true,
                    FILE_NOTIFY_CHANGE_DIR_NAME|
                    FILE_NOTIFY_CHANGE_FILE_NAME|
                    FILE_NOTIFY_CHANGE_ATTRIBUTES|
                    FILE_NOTIFY_CHANGE_SIZE|
                    FILE_NOTIFY_CHANGE_LAST_WRITE|
                    FILE_NOTIFY_CHANGE_LAST_ACCESS|
                    FILE_NOTIFY_CHANGE_CREATION|
                    FILE_NOTIFY_CHANGE_SECURITY, 0, &foverlapped, _competed))
    {
        ostringstream ss;
        ss << "DirectoryChanges::start error=" << GetLastError();
        throw runtime_error(ss.str());
    }
}



class Form1 : public Form
{
    struct event1 : StringEvent {
        Form1* form;
        event1(Form1* f) : form(f) {}
        void put(const wstring&);
    };

    ListView view1;
    DirectoryChanges directory_changes;
    struct event1 event1;

public:
    Form1();
    //void perform(Message&);
};

void Form1::event1::put(const wstring& s)
{
    // void ListView::insertItem(/*позиция*/ control_Id, /*то,что я пожелаю*/ application_Id, /*строчка*/ text, /*ну ещё там кой-чего, инициализируется по умолчанию*/);
    form->view1.insertItem(0, 0, s);

    // чистый API: читаю, что записалось в ListView (может он урезал строчку?)
    vector<wchar_t> buf(4096);
    LV_ITEM lvi = LV_ITEM();
    lvi.mask    = LVIF_TEXT;
    lvi.pszText = &buf[0];
    lvi.cchTextMax = buf.size();

    unsigned size1 = SendMessage(form->view1.handle(), LVM_GETITEMTEXT, 0, long(&lvi));

    // дублирую
    lvi.iSubItem = 2;
    SendMessage(form->view1.handle(), LVM_SETITEMTEXT, 0, long(&lvi));

  // сколько же информации я прочитал?
  wostringstream ss;
    ss << size1;

// ListView::setItemText(unsigned control_id, unsigned control_col_Id, const wstring& str);
    form->view1.setItemText(0, 1, ss.str());

    // когда это место было раскомментировано, я убедился, что строчка хранится в ListView полностью
    // но тогда начинал "глючить" ReadDirectoryChangesW. Он каждый следующий раз говорил, что
    // изменится мой project1 Debug.exe, причём количество одинаковых записей увеличивалось на 1.
    // то есть первый раз выдалась одна запись
    // второй раз 2 одинаковые ("цикл №2" сработал 2 раза)
    // и так далее, в бесконечном цикле

    //MessageBox(0, &buf[0], 0, MB_OK); 
}

Form1::Form1() :
    view1  (*this, ListView::style_report),
    directory_changes(wstr("d:\\")),
    event1  (this)
{
    directory_changes.setEvent(&event1);
    directory_changes.start();

// ListView::insertColumn(unsigned column_Id, const wstring& str, unsigned width, ...)
    view1.insertColumn(0, wstr("Directory"), 5000);
    view1.insertColumn(1, wstr("Size"), 100);
    view1.insertColumn(2, wstr("Directory 2"), 5000);
    setCenter(&view1); // ну типа растягивается теперь на всю форму
}


pva 07-11-2007 12:36 674107

более продолжительные тесты показали, что ReadDirectoryChangesW может выдавать разные сообщения за один присест. По ходу дела он эти сообщения накапливает у себя. А вот с ListView пока не понял.


Время: 11:58.

Время: 11:58.
© OSzone.net 2001-