здравжелаю! разбирался тут с работой CreateFile, GlobalAlloc, ReadFile, CloseHandle и GlobalFree на Си++, но, в отличие от асма, что-то застопорилась тут работа. есть сл. кусок кода: //cut here/////////////////////////////////////////////// WIN32_FIND_DATA findData; HANDLE fHandle = FindFirstFile( "*", &findData ); DWORD fSize = findData.nFileSizeHigh * MAXDWORD + findData.nFileSizeLow; DWORD bytesRead; LPVOID pAlloc; if ( INVALID_HANDLE_VALUE == fHandle ) return; do { HANDLE hFile; if ( ( hFile = CreateFile( findData.cFileName, GENERIC_READ, FILE_SHARE_READ, NULL,OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_HIDDEN, NULL ) ) != INVALID_HANDLE_VALUE ) { if ( ( pAlloc = (LPVOID ) GlobalAlloc( GMEM_FIXED, fSize ) ) != NULL ) { if ( ReadFile( hFile, pAlloc, fSize, &bytesRead , NULL ) ) { CloseHandle( hFile ); /*подскажите, как можно теперь в цикле (или еще как-нить более продвинуто) пробежаться по всему куску памяти, на которую указывает указатель pAlloc и проверить ее на наличие опред. последовательности символов. бьюсь, бьюсь, а никак не могу 'выйти' на содержимое куска памяти, как бы я ни старался...:-( */ } GlobalFree( pAlloc ); } } } while ( FindNextFile( fHandle, &findData ) ); FindClose( fHandle ); //cut here/////////////////////////////////////////////// заранее пасиба. мэтров 'жанра' очень прошу сильно не пинаться, т.к. я прежде чем постить сюда этот вопрос, пробежался по Рихтеру, и не нашел похожих примеров с GlobalAlloc; там только описывается работа с CreateFileMapping, MapViewOfFile и HeapAlloc. может поясните, почему GlobalAlloc проигнорили?
varnie 1) нет проверки, не каталог ли это - сэкономишь на вызове CreateFile. 2) fSize нужно получать внутри цикла и не учитывать nFileSizeHigh: 4 Гб памяти всё равно не выделишь. Или лучше проверять — если файл слишком большой, то пропускать. 3) Сдалась тебе эта GlobalAlloc, она морально устарела ещё при Win98. Используй VirtualAlloc. 4) Закрывай хэндл файла вне зависимости от того, прочитался ли файл — главное, что он открылся, значит, нужно закрыть. 5) Для доступа к памяти используется оператор *. Учти, что он зависит от типа переменной: Код (Text): LPVOID pAlloc; BYTE b = *((LPBYTE)pAlloc); // обращение к байту DWORD d= *((LPDWORD)pAlloc); // обращение к дворду Для "пробега" по памяти просто инкреминтируй указатель, но запомни, что ((LPBYTE)pAlloc)++ переходит на 1 байт, а ((LPDWORD)pAlloc) — сразу на 4, то есть ((LPTYPE)pAlloc)++ == ((LPTYPE)pAlloc) += sizeof(TYPE); Иначе потом долго будешь думать, почему работает не так, как в асме. Это простым перебором: Код (Text): LPBYTE p = (LPBYTE)pAlloc; while(p++ < (((LPBYTE)pAlloc) + fSize)){ if(*p == 0xCC) break; } А насчёт более продвинутого — копай литературу по поиску.
IceStudent, большущий сенкс за существенную помощь! попробую прокомментировать твои пунты. 1) проверка есть, она в куске кода, кот-й идет у меня перед этим, запостенным. а этот (запостенный вначале) кусок получает управление, только если текущий файл - не каталог.тут все норма. 2) не очень понял. ты имеешь ввиду, что надо считать fSize только как findData.nFileSizeLow ? поясни, пожалуйста. или же через GetFileSize лучше? а насчет того, что надо fSize в цикле получать, согласен, я что-то упустил этот момент. спасибо за fix! 3) я в курсе=) но вот решил реализовать именно через GlobalAlloc, так сказать, для сравнения, как это было на асме, а теперь 'переносится' на Си++. 4) а вот это очень существенное замечание. я и подумать не мог, что у меня недочет тут. пасиба! очень признателен за твою помощь.
varnie Я имею ввиду, что nFileSizeLow - это DWORD, то есть, в нём поместится 4 гб-ый размер файла. Смею думать, такой файл ты не сможешь обработать, загрузив целиком его в память. Поэтому нет смысла в этой строке: findData.nFileSizeHigh * MAXDWORD + findData.nFileSizeLow, нужно делать проверку на размер файла, который ты сможешь обработать: if(nFileSizeLow > MAX_FILE_SIZE) continue; Так и на асме использовать GlobalAlloc нет смысла. Для небольший объёмов есть HeapAlloc, для больших - VirtualAlloc.
я что-то опять запутался. попробовал переписать свою писанину заменив GlobalAlloc/GlobalFree на VirtualAlloc/VirtualFree. Делаю PVOID pAlloc = VirtualAlloc( NULL, fSize, MEM_RESERVE, PAGE_READWRITE ); . VirtualAlloc выполняется успешно, затем я считываю в полученный зарезервированный регион адресного пространства физич. данные из файла, (CreateFile/ReadFile) - все ок, все считывается в память, но вот переменная pAlloc почему-то после этого дела заменяется адресом памяти, куда считан самый "конец файла". Поэтому в VirtualFree( pAlloc, 0, MEM_RELEASE ); вместо базового адреса зарезервированного региона в кач-ве первого аргумента передается ерундень, и есессно ничего не освобождается. как быть? и где я не прав? пробовал сдублить в др переменную рез-т от VirtualAlloc, а затем уже в VirtualFree сувать эту вторую переменную-дубликат, тогда все хорошо идет, и VirtualFree делает свое дело. но нутром чувствую, что это как-то ненормально так действовать. можете объяснить мне, почему исходная pAlloc затирается? или так и должно быть? заранее спасибо.
> "после этого дела заменяется адресом памяти, куда считан самый "конец файла" Ну дык, ты наверное в целях "пробежаться по считанному файлу" инкрементируешь сам адрес pAlloc, вот он у тебя и убегает на конец файла Нужно pAlloc "хранить как зеницу ока", а вот "бегать" с помощью вспомогательной переменной LPBYTE p = (LPBYTE)pAlloc, как тебе и посоветовал IceStudent
Давненько собираюсь уточнить некоторые вопросы с VirtualAlloc vs GlobalAlloc\HeapAlloc, а то многие "доброжелатели" легко и просто рекомедуют использовать Virtual, не упоминая о том на какие грабли тут можно наступить Ес-но GlobalAlloc тормозная и устаревшая, но эквивалентной заменой ей является HeapAlloc, а не Virtual. Дело в том, что экономная винда при запросе MEM_COMMIT не торопиться выделять физическую память, а ждет первого обращения на чтение\запись к странице памяти. При обращении к невыделенной странице ес-но возникает PageFault само по себе пожирающее немеряное число тиков, как и любое исключение. Винда обрабатывает исключение, выделяет физическую память, да еще и старательно забивает ее нулями (из соображений конфиденциальности - чтобы мы не сперли какую-нить секретную информацию . Ес-но при первом запросе достаточно большого блока памяти этих тормозов не избежать что при HeapAlloc, что при Virtual. Но если требуется использовать блок памяти многократно (как в рассматриваемой задаче), то не нужно каждый раз наступать на эти виндовые грабли. Ес-но лучше один раз выделить достаточно большой блок памяти и использовать его для чтения всех файлов (а не освобождать и выделять новый для каждого файла). В этом случае VirtualAlloc дает преимущества, т.к. можно зарезервировать достаточно большой диапазон адресов и наращивать MEM_COMMIT по мере необходимости (если размер очередного файла превышает размер commited). А вот если каждый раз выделять и освобождать память, то даже GlobalAlloc может работать быстрее Virtual, т.к. для блоков в несколько страниц GlobalFree\HeapFree просто помечают блок кучи как свободный, но оставлюят его commited, поэтому при повторных выделениях тормозов с PageFault'ами не возникает. Так-что куча придумана не зря и для многократных выделений небольших блоков лучше использовать HeapAlloc. Ну а Virtual - для больших блоков и для возможности увеличения размера блока on-place (т.к. HeapRealloc не гарантирует увеличения размера "на месте" и при реаллокации переписывает все данные в новый блок - дополнительные тормоза). PS: А читать файлы размером > 64Кб лучше с флагом FILE_FLAG_NOBUFFERING или блоками по 16-64К (см.тут)