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


Автор: neosapient 19.12.2006, 00:10
Здравствуйте.

Возникла проблема на ровном месте, немогу понять откуда лезет.
Задача. 
Открыть файл, считать оттуда данные определенной структуры, закрыть файл.

Решешал задачку так:
Создал диалог.
В момент прихода сообщения WM_INITDIALOG создается дополнительный поток AnalysFile(...).
В этой функции открываю файл test.txt на чтение побайтно. Создаю заполняемую структуру и указатель на нее. Далее пока файл не кончиться, заполняю побайтно через указатель все поля структуры. По окончании файла, закрываю соединение. Дополнительный поток закрываеться.

Код

#include <windows.h>
#include <stdio.h>
#include "resource.h"

LRESULT CALLBACK DialogProc (HWND hDlg,UINT msg,WPARAM wParam,LPARAM lParam);
DWORD WINAPI AnalysFile(LPVOID);

typedef struct DATA{
    char first;
    short second;
    int third;
};

WINAPI WinMain // точка входа в Windows программу
(HINSTANCE hInstance, HINSTANCE hPrevInstance,
 LPSTR lpCmdLine, int nCmdShow)
{
    DialogBox(hInstance,MAKEINTRESOURCE(IDD_DIALOG),0,(DLGPROC)DialogProc);
    return 0;
}

LRESULT CALLBACK DialogProc (HWND hDlg,UINT msg,WPARAM wParam,LPARAM lParam)
{
    static HANDLE hThread;
    switch(msg)
    {
    case WM_INITDIALOG :  
        hThread = CreateThread(NULL, 0, AnalysFile, (LPVOID)hDlg, 0, 0);
        break;
    case WM_COMMAND:  
        switch (LOWORD(wParam))
        {
        case IDCANCEL:
            TerminateThread(hThread,0);
            CloseHandle( hThread );
            EndDialog(hDlg, LOWORD(wParam));
            return TRUE;
        case IDOK:
            break;         
        }
    break;         
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        break;
    }
return 0;
}

DWORD WINAPI AnalysFile(LPVOID hDlg)
{
DATA Data;
char *pData;
pData = (char*) (&Data);
FILE* file;
if((file = fopen("test.txt","r"))==NULL){
    MessageBox((HWND)hDlg,"Не могу открыть файл","error",MB_OK);
    return 0;
}
int i;
do{
    for(i=0;i<sizeof(DATA);i++)
        *(pData+i)=getc(file);
}while(!feof(file));
fclose(file);
return 0;
}

Ну в общем начинаю я работать с дебагером, то все нормально отрабатывает,а то винда виснет, только мышка по экрану двигается. 

Подскажите, ЧТО не так делаю.

Доп. вопрос: когда происходит считывание байтов из файла и их побайтная запись в структуру, то создается такое впечатление, что char у меня в два байта?! В том смысле, что при i равном 1 из файла считывается значение b однако оно пишется в сокрытую область стуктуры. Может происходит какое то выравнивание длинны структуры до значения кратного 4 байтам?

Автор: dumb 19.12.2006, 02:27
Цитата(neosapient @  19.12.2006,  00:10 Найти цитируемый пост)
Может происходит какое то выравнивание длинны структуры до значения кратного 4 байтам?

почти угадал. только выравнивается не размер структуры, а сами поля. значение границ задается опциями, по умолчанию - компилер сам "придумывает" как выравнивать(например в твоем случае он выровнял первое поле до двух байт, чтоб вкупе со вторым они заняли 4 байта).
когда гоняешь структуры "наружу"(файл,сокет,итд), надо ставить для них выравнивание в 1.
Код

#pragma pack(push, 1)
typedef struct DATA{
    char first;
    short second;
    int third;
};
#pragma pack(pop)

Автор: Earnest 19.12.2006, 08:58
Нехорошо прерывать поток через TerminateThread. Это для аварийного прерывания, когда поток не отвечает. При этом не освобождаются ресурсы и не происходят другие правильные вещи. Для такой маленькой программы как твоя, это, возможно и ерунда, но для реальных проектов - отнюдь нет.
Поток должен завершаться сам. Для того чтобы завершить его извне, нужно создать, например, событие (event). Управляющий поток сигнализирует событие, а рабочий поток должен в своем цикле отслеживать, не активно ли событие, и завершаться, если это так.
Кроме того, поток вполне может завершить до того, как ты нажмешь Cancel. И это тоже нужно проверять.

Автор: neosapient 19.12.2006, 09:06
За "выравние полей" спасибо, не знал.

А по поводу основного вопроса:
Если я создаю доп поток не на сообщение WM_INITDIALOG, а на WM_COMMAND -> IDOK, то ничего не виснет. Щелкаю на кнопочку ОК и доп поток запускается.
Но мне хочется создавать доп поток на сообщение WM_INITDIALOG

Автор: Aleksandor 19.12.2006, 16:12
Кажись читал у Рихтера что нельзя пользовать CreateThread если используются функции run-time. Чтение из файла тоже как-то странно оформлено, имхо.

Автор: neosapient 23.12.2006, 21:45
Aleksandor, извени, а что относиться к run-time функциям? и на что их заменить?..

Цитата

Чтение из файла тоже как-то странно оформлено?

Ну, функции взяты из stdio.h

Автор: Aleksandor 23.12.2006, 22:27
Щас посмотрел, у диалоговой процедуры нет родительского окна. Процедура диалоговая и WinMain как-бы в одном стакане. Мне кажется это не есть хорошо. 

Run-time функции это те самые fopen, getc, time, strchr и т.д. Вместо CreateThread лучше заюзать _beginthreadex Почему-ищи в MSDN по слову _beginthreadex

Насчет странного это чтение из файла побайтово-это слишком неэффективно. Кстати, в файле может и не быть feof. Тогда чтение зависнет навеки веков  smile 
Лучше читать сразу весь файл или какую-то его часть в буфер, а потом анализировать. Или сделать file mapping - тогда и буфер не нужен.


Автор: neosapient 24.12.2006, 22:27
Цитата

Щас посмотрел, у диалоговой процедуры нет родительского окна. Процедура диалоговая и WinMain как-бы в одном стакане. Мне кажется это не есть хорошо. 

Ну попытался разделить... Создаю окно, делаю дочерний диалог, делаю поток. Все работает.
Второй эксперимент - Создаю окно, делаю дочерний диалог и показываю, делаю поток. Все виснет. (этот пример в приложении)

Подозрение на прорисовку окна. Как исправлять?

Цитата

Кстати, в файле может и не быть feof. 

Угу, так и есть, поставил временную заглушку.

Автор: Aleksandor 25.12.2006, 00:08
Вот, у меня вроде пашет...  smile 

Автор: oper54 25.12.2006, 12:07
Цитата

#pragma pack(push, 1)
typedef struct DATA{
    char first;
    short second;
    int third;
};
#pragma pack(pop)

по поводу вот этого... надо под твои данные глобально выделять
память GlobalAlloc, и тогда не надо будет ни каких смещений указывать,
и все потоки нормально будут работать с этим отрезком памяти...
хотя с прагмами тоже вариант, если не хо с памятью морочится... =)

ИМХО по меньше пользоватся надо дерективами компилера, ибо не у всех 
компилеров они такие есть =)

Автор: neosapient 25.12.2006, 21:37
Цитата

Вот, у меня вроде пашет... 

Aleksandor, а ты поставь брякпоинт на начало функции AnalysFile и будет тебе "шастъе"  smile 
В общем пока не пашет...


oper54, данные структурированы и я честно говоря не предсталяю как тут применить GlobalAlloc, вместо выравнивания полей. Поясни примером, что имелось в виду...

Автор: Aleksandor 25.12.2006, 22:04
Я конешно сильно извиняюсь... Но... зачем ставить breakpoint на начале AnalyseFile  smile 

Автор: neosapient 25.12.2006, 22:29
Цитата

зачем ставить breakpoint на начале AnalyseFile  

Чтоб, проверить правильность работы...

И вообще надо чтоб в любой части программы можно было ставить breakpoint, чтоб контролировать правильность работы.
А то как разобраться с кодом черного ящика...

Автор: Aleksandor 25.12.2006, 22:37
Не обязательно  smile  Тут можно скорее запутаться. Гораздо проще и эффективнее поставить например Beep(5000, 200); в нужной точке чтобы проконтролировать прохождение кода. К тому же результат работы виден сразу  smile 

Автор: neosapient 25.12.2006, 22:45
Цитата

Гораздо проще и эффективнее поставить например Beep(5000, 200); в нужной точке чтобы проконтролировать прохождение кода

А как контролировать поля структур далее???  smile 

Автор: Aleksandor 25.12.2006, 22:54
Ну например распечатать в файл их значения, или сравнить с образцом или посмотреть в отладчике...

Автор: neosapient 26.12.2006, 09:03
И я про это, а отладчик виснет вместе с операционкой

Автор: Aleksandor 26.12.2006, 15:41
Может что с отладчиком? Прога простейшая, там и виснуть то нечему  smile  Попробуй мой проект в VC 6. Ничего не виснет.

Автор: neosapient 26.12.2006, 16:10
Цитата

Прога простейшая, там и виснуть то нечему  

И я так счетаю, сократил все до нельзя, а баг остался.

Цитата

Может что с отладчиком?.. Попробуй мой проект в VC 6. Ничего не виснет.

У меня VC 7. Позже попробую на VC 6 (сейчас времени нет устанавливать).
И как я понял при установке breakpiont`a на начале ф-ии AnalysFile, у тебя также виснет всё.

Автор: Aleksandor 26.12.2006, 16:32
Да ничего не виснет, даже с брейкпойнтом (я ваще ими не пользуюсь никогда)  smile 
А если убрать вот этот кусок
Код

 int i,n=0;
 do {
    for(i=0;i<sizeof(DATA);i++)
        *(pData+i)=getc(file);
    n++;
 } while((!feof(file))&&(n<2));


тоже виснет? Попробуй без брейкпойнта, например так
Код

DWORD WINAPI AnalysFile(PVOID pvParam)
{
DATA Data;
char *pData;
pData = (char*) (&Data);
FILE* file;

if((file = fopen("test.txt","rb"))==NULL){
    MessageBox(NULL,"Íå ìîãó îòêðûòü ôàéë",NULL,MB_OK);
    return 0L;
}

 /*
int i,n=0;
 do {
    for(i=0;i<sizeof(DATA);i++)
        *(pData+i)=getc(file);
    n++;
 } while((!feof(file))&&(n<2));
*/
   fclose(file);
    Beep(4000, 300); // we are here, now exiting the thread ) 
return 0L;
}

Автор: neosapient 26.12.2006, 18:55
Я понял в чем проблема  smile 
У меня стоит Norton AntiVirus (2004, но год не важен)
Видать, недели полторы назад закачался updata, и теперь этот антивир отлавливает все подозрительные действия с потоками. Кстати, чтение из файла вообще не причем, освободил тушку AnalysFile (делал сразу ретурн), всеравно виснет.
Отключаешь антивир, и все впорядке.  smile 


Думаю, какой антивир поставить.
Каспер еще три года назад начал выкидывать подобные трюки (я его тогда и снес).
На руках есть NOD32 и F-Secure. Програмить под ними не пробовал, но склоняюсь к F-Secure.
А какой антивир у тебя?

Впрочем стоит сделать голосование "какой антивир не мешает программированию под Windows"...

С этим вопросом все.

Автор: Aleksandor 26.12.2006, 21:46
У меня вообще антивиря нет  smile  Файер есть, а антивирь не стоит. Просто я не скачиваю и не запускаю ничего лишнего, и не даю троянам лезть через IE. Имхо, все эти страшилки с троянами и вирусами придуманы для повышения продаж этих самых антивирей. Раньше был не таким осторожным и подцепил какую-то дрянь, было заметно по поведению компа. Вот тогда сканировал антивирем, было дело. Но самая лучшая защита, имхо, это вовремя делать бакапы, и сносить винду периодически с форматированием дисков  smile  

Автор: neosapient 26.12.2006, 22:06
Цитата

Но самая лучшая защита, имхо, это вовремя делать бакапы, и сносить винду периодически с форматированием дисков 

Я тоже так считаю. И делаю бекапы примерно раз в две недели...  smile 

Ну да ладно...

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