Вопрос № 29699: Недавно начал изучать WinAPI. Изучаю его немного экстравогантным способом. У меня есть и книги, но читать про создание окон и элементов управления муторно, да и смутно верится мне в то, что если переписывать их вручную сильно возрастет производительн...Вопрос № 29720: Здравствуйте!
Подскажите, пожалйста, как мне при помощи LoadIcon(----) загрузить
иконку с изображением папки ? (С++)
..
Вопрос № 29.699
Недавно начал изучать WinAPI. Изучаю его немного экстравогантным способом. У меня есть и книги, но читать про создание окон и элементов управления муторно, да и смутно верится мне в то, что если переписывать их вручную сильно возрастет производительность приложения, оставлю это дело МФС. Вообщем поэтому изучаю сами функии и структуры по справке борланда С++ 5.0. Так вот первым делом захотелось мне про работу с файлами узнать. Открывать, закрывать, удалять понятно как. А вот с чтением появились непонятки, именно
непонятки, а не ошибки с проблемами. Вот описание функции:
BOOL ReadFile(
HANDLE hFile, // handle of file to read
LPVOID lpBuffer, // address of buffer that receives data
DWORD nNumberOfBytesToRead, // number of bytes to read
LPDWORD lpNumberOfBytesRead, // address of number of bytes read
LPOVERLAPPED lpOverlapped // address of structure for data
);
Что такое LPDWORD lpNumberOfBytesRead, // address of number of bytes read - мне вообще непонятно. Если тупо перевисти получается, что сюда надо пихать адрес предыдущего параметра. Иначе говоря вот пример:
HANDLE hFile;
unsigned long num_bytes = 20, *pnum_bytes = &num_bytes;
char buf[255];
ReadFile(hFile, buf, num_bytes, pnum_bytes, NULL);
Проверил все работает. Но вопрос у меня такой на кой черт ему адрес моей переменной, если мы ее и так передаем? Меня просто интерес изнутри сьедает.
И сразу еще хотел бы пару моментов уточнить. К чему приводит не закрытие handle ? Вот сейчас примерчик делал, создовал файл. Забыл указать CloseHandle() и файл у меня не появился. Потом указал и файл появился. Вроде сверхкритически плохого ничего не произошло, но хотелось бы узнать к чему могут приводить пободные промохи.
Второе. Когда мы читаем файл, можно указать любое кол-во байтов, только что проверил даже если задавать больше того кол-ва, что есть в файле - обработка происходит нормально. Эта обработка уже в саму Api заложено, или все же иногда это может привести в ошибкам ?
И еще какой тип данных HANDLE ? Это единственная вещь которая меня бесит - переопредление типов, мне проще работать с нормальным типами С/С++ чем с именами данными разработчиками, может потом войдет в привычку, но мне понятнее unsigned long или ULONG писать и char * вместо их аналогов в лице LPVOID,LPCSTR,DWORD и пободных. windef.h посмотрел нашел только на WORD,DWORD,lParam и т.п. HANDLE там тоже есть, но совсем другое, типа typedef HANDLE (HWnd). Еще немного покапался в winnt.h там вообще про handle пишется
что это void. Хотя я где-то слышал, что это вообще обычный int...
Отправлен: 17.11.2005, 07:29
Вопрос задал: RedDevil (статус: 1-ый класс)
Всего ответов: 4 Мини-форум вопроса >>> (сообщений: 4)
Отвечает: Лысков Игорь Витальевич
Здравствуйте, RedDevil!
1)Смыл LPDWORD lpNumberOfBytesRead, // address of number of bytes read следующий:
функция требует указать адрес переменной, куда она запишет сколько байт реально прочиталось (в отличие от предыдущегопараметра, где указываешь, сколько байт ты хочешь прочитать!- улавливаешь?). Разумеется, можно указать адрес той же переменной :)
2)Считается признаком хорошего тона, если программа после себя освобождает все востребованные ресурсы. Незакрытие некоторых handle может привести, например, к утечке ресурсов системы, в результате ОСь просто откажется работать! В случае файлов, именно закрытие handle приводит к окончательному формированию файла, ведь файл - это не только последовательность байт, это еще и некая служебная информация.
3)Ответ на вопрос о "любом количестве байт" вытекает из понимания первого вопроса :)
4)Если не нравится многообразие типов, переходи на Асм. Там только DWORD, WORD, BYTE. Как хочешь, так и интерпретируй!
Все типы сводятся в конце концов к DWORD, WORD, BYTE, ну и с плавающей точкой!
А вообще, ты не прав. Все эти типы помогают избежать ошибок несоответствия требуемых параметров и передаваемых значений! Вот представь: все типы отменили. Осталось только DWORD! Например, функция требует параметром адрес строки, а ты передаешь любой DWORD. И компилятор проглотит. И ты будешь долго искать, почему не работает! А так, подобные ошибки вылазят на этапе компиляции! Так что проникнись и пользуйся.
Да, HANDLE - это PVOID, по сути указатель на что-либо. Но, с учетом вышесказанного, надо использовать только там, где действительно требуется именно HANDLE.
--------- Удачи!
Ответ отправил: Лысков Игорь Витальевич (статус: 9-ый класс)
Отправлен: 17.11.2005, 10:19 Оценка за ответ: 5 Комментарий оценки: Без комментариев.
Отвечает: Jadd
Здравствуйте, RedDevil!
Про параметры Вам уже ответили. Отвечу на те вопросы, на которые не ответили предыдущие ораторы. :) Хэндлы нужно закрывать. ОСь вряд ли упадет, как тут некоторые опасались, т.к. по завершении процесса Хэндлы, ассоциированные с ним, закрываются. Но во время работы программы несвоевременное закрытие хэндлов может привести к плохим последствиям. Случай из моей практики: программисты, чей код я дебажил, забывали при отрисовке DIB'а закрывать его хэндл за ненадобностью после отрисовки. Получалась страшная картина:
при каждой перерисовке области, на которой находились эти DIB'ы, программа создавала новый DIB (тут пока все верно), отрисовывала и оставляла как есть (т.е. хэндл DIB'а не закрывался). Итогом было - утечка памяти, причем текло иногда до 2 Гигов виртуалки - масштабы ощущаешь? Особенно, если картинки не пару кило, а по 20 мегов (tiff-ы например). Вот и рассуждай потом. Память конечно потом освобождалась при закрытии программы, но на работу самой программы и стабильность ОС
и влияла.
Далее по списку...
Насчет считывания большего количества байт, чем размер - тут вроде уже ясно, что в данном случае интересующий Вас параметр просто вернет реально считанное число байт. Это очевидно.
Теперь про типы данных. HANDLE - это указатель на void. Т.е., иными словами, на что угодно. На практике HANDLE - это структура, содеращая некоторую информацию, причем в каждом случае она индивидуальна (т.е. для каждого объекта ядра она может содержать свои данные). Т.е. не правильно говорить, что это int чистой воды. Тут уже была подробное обсуждение содержания HANDLE. На некоторые вопросы и лично я отвечал. Поищите по сайту или посмотрите у Рихтера и других. Если что неясно будет - пишите мне на мыло, объясню.
Насчет использования-неиспользования типов винды. Есть правила хорошего тона в программировании. Их соблюдает любой программист помятуя о тех, кто будет дебажить код и тд и тп. Типы данных, которые предлагает винда, нужно использовать. Это дает унификацию данных и сделает приложения более понятными. Точно так же, не плохо было бы при программировании в винде пользоваться "венгерской нотацией", дабы сделать свой код читабельным. Эти прописные истины должны постигаться с самого начала программинга.
Удачи Вам в ваших начинаниях.
--------- Если в сердце дверь закрыта, нужно в печень постучаться
Ответ отправил: Jadd (статус: Специалист)
Отправлен: 17.11.2005, 11:43
Отвечает: estiGi
Здравствуйте, RedDevil!
Весьма любопытно... изучать Win32API, используя MFC по справке Борланда... надо выложить куда нить в юмор. Я бы назвал этот способ не экстравагантным, а дурацким. Я буду долго смеяться, когда тебе понадобится сделать что-то, что не сделать стандартными способами. И все же я бы посоветовал посмотреть, что такое окна, элементы управления и как они создаются и работают.
Насчет ReadFile. Использовать надо так:
HANDLE hFile;
DWORD size = 20, read = 0;
char buf[255];
ReadFile(hFile, buf, size, &read, NULL);
if (read != size) {
// some read error
}
CloseHandle делать желательно в любом случае. А подробности можно почитать в МСДН, так вполне четко описывается, зачем оно надо и к чему может привести незакрытие дескриптора.
А чтобы файл создавался и данные сохранялись после WriteFile, делай FlushFileBuffers.
HANDLE - это дескритор окна. Если бы ты изучал АПИ менее "экстравагантным" спосбом, ты бы знал, что такое дескриптор окна и какой тип он из себя представляет, а не просто "слышал что-то о нем".
Такие типа, как LPVOID и LPDWORD использовать вместо void* и DWORD* совсем не обязательно, это дело вкуса.
А вот WORD, DWORD, HANDLE, HINSTANCE etc использовать надо. Если ты пишешь под Windows, надо во-первых подерживать code conventions этой системы, во-вторых, так правильнее и код читабельнее, в-третьих, есть причина, по которой разработчики создавали новые типы, и о которой можно догадаться, если немного призадуматься :)
Такое изменение типов - это вообще нормальное явление. Если ты будешь сталкиваться с разными АПИ и разными ОС, то ты заметишь, что code conventions этого АПИ нередко изменяет вообще все типы языка
Ответ отправил: estiGi (статус: 7-ой класс)
Отправлен: 17.11.2005, 12:32
Отвечает: Raptor1
Здравствуйте, RedDevil!
LPDWORD lpNumberOfBytesRead - сюда будет сохранено значение количества реально прочитанных байт, ведь функция в С не может возвратить много значений вот и приходится пользоваться указателями. Это же ответ на второй твой вопрос - функция просто вернет в этой переменной количество реально прочитанных байт. Ну на самом деле HANDLE, void и int в WIN32 имеют один размер - 4 байта поэтому данные одни и те же, только назвать их можно по разному. А вообще по смыслу ведь понятно и удобно LPVOID - void* или long pointer
to void, LPCSTR - long pointer to const str, DWORD - double word (4 байта беззнаковое целое). Привыкнешь со временем.
Ответ отправил: Raptor1 (статус: 9-ый класс)
Отправлен: 18.11.2005, 00:02 Оценка за ответ: 5 Комментарий оценки: Спасибо за ответы.
Вопрос № 29.720
Здравствуйте!
Подскажите, пожалйста, как мне при помощи LoadIcon(----) загрузить
иконку с изображением папки ? (С++)
Отправлен: 17.11.2005, 13:53
Вопрос задал: Santey (статус: Посетитель)
Всего ответов: 1 Мини-форум вопроса >>> (сообщений: 0)
Отвечает: Jadd
Здравствуйте, Santey!
Откуда загрузить? Файл, ресурсы? Раз конкретного нету ответа, значит предположу, что самое простое - ресурс программы. Тогда делаем так:
HICON hIcon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(ID_MYICON)); //вместо ID_MYICON ставим идентификатор нашей иконки
//Дальше рисуем или еще что-то делаем. Раз у Вас не сказано куда грузить, тогда я просто нарисую
DrawIcon(hDC, 10, 10, hIcon); //соответственнонужно получить или создать DC, а тут я предполагаю, что оно есть и задаю произвольные координаты....
Удачи
--------- Если в сердце дверь закрыта, нужно в печень постучаться
Ответ отправил: Jadd (статус: Специалист)
Отправлен: 17.11.2005, 14:13 Оценка за ответ: 4