PDA

Показать полную графическую версию : Текст в ListView и проч.


pva
06-11-2007, 22:54
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
более продолжительные тесты показали, что ReadDirectoryChangesW может выдавать разные сообщения за один присест. По ходу дела он эти сообщения накапливает у себя. А вот с ListView пока не понял.




© OSzone.net 2001-2012