el- Если GlobalReAlloc возвращает ноль, никакая дельта уже не поможет. В таком случае надо тихо завершить программу и начать искать ошибку в коде, ведь ноль чаще является следствием ошибки в параметрах функции, чем реальной нехватки памяти. Тогда в коде придётся ещё и GlobalLock()/GlobalUnlock() использовать. От этого легче не станет.
дык к чему я и вел с самого начала ... что мол GlobalReAlloc ноль возвращает, а вы блин тока глумитесь, оскарбляете ... да и еще дельта смещение суда припесали ): ну в этом я ничего страшно не вижу ... хотя если есть шанс не использовать эти функции, поведуйте плиз про него ... вабще конечно же хотелось бы, что бы адрес выделенной памяти не менялся, но как я понял такое не возможно ... зы. получается, после реаллока мне надо залочить память, а когда следующий раз буду делать реаллок сново разлочить ?
1) Винда тоже косячит и выдает GetLastError = 8 на все случаи жизни - даже если вместо hMem = NULL или инвалидный указатель на блок, освобожденный GlobalFree 2) При GlobalRealloc флаг GMEM_ZEROINIT ес-но означает зануление не всего блока, а только дополнительно выделенной части (а GMEM_FIXED = 0 и поэтому GPTR = GMEM_ZEROINIT). Никаких MOVEABLE ес-но тут не нужно, т.к. это кроме мороки ничего не даст 3) el-, с чего ты взял, что вылет происходит на самом первом GlobalRealloc - если ты только по MessageBox'у судишь, то вылет может происходить при втором вызове как и положено если pConfig стал инвалидным указателем - добавь вывод nNumSection, если будет > 0, то все ясно PS: Ну ты блин, даешь ! Ты чего никак въехать не можешь ? Если у тебя при первом (втором, третьем - любом) вызове GlobalRealloc перемещает твой блок на новое место, то старый указатель pConfig она уничтожает и он становится инвалидным, а ты в очередной раз как баран с этим инвалидным указателем лезешь в GlobalRealloc - вот она те 0 и возвращает и ты получаешь свой MessageBox, не подозревая, что он выскочил не при первом вызове, а при втором или еще каком Хрена толку то, все твои указатели все равно изменятся если произойдет реаллокация на новое место
короче попробуй одному и тому же указателю присваивать значения реаллока. т.е. его же передавать в ф-ю и ему же присваивать возвращаемое значение.
с этим спорить не буду, не знаю (: ну это понятно, по дефалту и так GMEM_FIXED стоит ... блин ну ты меня ваааабще за козла какого считаешь ... ))): ясен пень я пробовал и вот к чему мои тесты привели ... если выделять память с флагом GPTR и потом реаллокать её с тем же флагом, функция возвращает NULL ... а вот если выделить память с флагом GHND, а потом реаллокать с любым флагом ( я пробовал с GPTR ), то все работает нормально ... причем такие косяки только в этой конкретной проге ... ага инвалидным ? дык объясни мне тогда не въехавшему как же это срабатывает pSections[ nNumSection ].pszSectionName = pszSections; если pSections указывает на старый блок, который уже реаллокнут ... где ошибка ??? ... см. ответ выше ... да блин в этом проблемы нету ... я после каждого реалока все указатели пересчитаю ... впринципе так тоже можно, но все равно придется еще как минемум два указателя пересчитывать ... leo: я прошу не надо думать, что я такой тупой ... я действительно пробовал много вариантов, даже не обязательно выводить новер секции .. достаточно просто влупить мессадже бокс внутрь иф ..т.е. Код (Text): if ( ( dwTestDword = ( DWORD )GlobalReAlloc( pConfig, dwMemSize, GPTR ) ) ) { MessageBox( NULL, "ok", "ok", MB_OK ); pSections[ nNumSection ].pszSectionName = pszSections; } // end if else { MessageBox( NULL, "fuck1", "fuck1", MB_OK ); ExitProcess( 0 ); } исходя из твоих соображений вылетит сначало ok, а потом fuck1 ... но вылетает сразу fuck1 ... вот в чем дело ... да и ошибка бы вылетила ... т.к. pSections указывает в никуда, после реаллока .... только когда основной блок памяти выделяю с GHND все работает нормально ... но основной прикол не в этом ... вот этот код например работает нормально Код (Text): char *pszLOL = ( char * )GlobalAlloc( GPTR, 1024 ); if ( ( pszLOL = ( char * )GlobalReAlloc( pszLOL, 2048, GPTR ) ) ) { MessageBox( NULL, "ok", "ok", MB_OK ); } else { MessageBox( NULL, "fuck", "fuck", MB_OK ); } GlobalFree( pszLOL ); так что я думаю что косяк где то в нутри проги немного выши GlobalReAlloc'a но найти его у меня чето не получается ... ))):
el- Забудь про свой NULL и пойми, что результат GlobalRealloc это не просто индикатор ошибки, а новое значение указателя на твой блок pConfig - в некоторых случаях он может и не измениться, а в общем случае твои данные будут переписаны на новое место, старый указатель станет не действительным и передача этого указателя в GlobalRealoc приведет к ошибке. Куча не зря называется кучей - в общем случае в ней вперемежку могут чередоваться занятые и свободные блоки разных размеров. Причем винда при загрузке процесса сама пользуется его кучей и пишет, и удаляет, и оставляет в ней всякий служебный мусор. Плюс высокоуровневые компиляторы могут при инициализации добавлять свой "мусор". Поэтому в зависимости от ситуации твой GlobalAlloc может выделить память или в конце кучи или найти подходящую "дырку" между занятыми блоками, чтобы всунуть между ними твой блок. Если новый блок окажется в конце, то твой ненадежный код может отработать без ошибок, т.к. ему есть куда расти и GlobalRealloc будет просто увеличивать размер блока не изменяя его указатель. А если менеджер кучи втиснет твой блок между двумя занятыми блоками, то увеличить его размер на том же месте (on the place) не удастcя - придется выделить новый блок по другому адресу и переписать туда твои данные, после чего "удалить" старый блок за ненадобностью (пометить его как свободный) и вернуть тебе указатель на новый блок. Поэтому надежные программы должны не отбрасывать результат GlobalRealloc, а использовать его как новый указатель и при необходимости производить коррекцию других свзязанных с ним адресов. А использование старого инвалидного указателя может приводить к ошибкам, как явным (как в твоем случае - GlobalRealloc возвращает NULL), так и к завуалированным, т.к. ты продолжаешь читать\писать данные на старое место и можешь либо прочитать вместо своих данных служебные параметры менеджера кучи или при записи затереть следующие занятые блоки - где и когда эти ошибки могут проявиться неизвестно PS: Для особо упертых поясняю: старый "удаляемый" блок просто помечается как свободный, в обычном неотладочном режиме менеджер кучи затирает только первые 8 байт старого блока, а остальное остается как есть, а в режиме оладки вся оставшаяся часть затирается спецсигнатурой 0xFEEEFEEE. НО для обычного чтения\записи эти адреса остаются валидными, т.е. можно преспокойно читать весь этот мусор и преспокойно самому гадить не только по этим адресам, но залезть на соседние блоки - вот только чем все это в итоге закончится ?! А инвалидность старого указателя проявляется только при вызове функций кучи - тут менеджер первым делом проверяет свои "водяные знаки" и обнаруживает, что блок то удален и выдает тебе большой и жирный NULL-КУКИШЬ, но ты видать и бревно в своем глазу замечать не хочешь, не то что какие-то кукиши
агррррррр.... вот ты заладил ... я и сам прекрасно понимаю, что ReAlloc дает новый указатель на блок памяти ... я и так знаю как работает куча и что если что то не так, это проявится только после следуюего вызова функции работающей с кучей Global* ... но до этого НЕ ДОХОДИТ ВАААААБЩЕ !!! я выделяю память ... Код (Text): pConfig = ( PCONFIG )GlobalAlloc( GPTR, dwMemSize ); if ( pConfig ) { делаю необходимые расчеты, читаю в память имена всех секций Код (Text): pConfig -> pszCfgPath = pszPathCfg; pszSections = pConfig -> pszSections = ( char * )pConfig + sizeof( CONFIG ); dw dwTemp = GetPrivateProfileSectionNames( pConfig -> pszSections, dwSize, pszPathCfg ); pszKeys = pConfig -> pszKeys = pszSections + dwTemp + 1; dwTemp = ( dw )pConfig + dwMemSize; pSections = pConfig -> pSections = ( PSECTIONS )dwTemp; dwMemSize += sizeof( SECTIONS ); nNumSection = 0; , делаю первый ReAlloc и он возвращает NULL!! все ... Код (Text): do { dwMemSize += sizeof( SECTIONS ); if ( ( pConfig = GlobalReAlloc( pConfig, dwMemSize, GPTR ) ) ) { // даже если сделать так, ВСЕ РАВНО НЕ ПАШЕТ !!! } // end if nNumSection ++; } while ( ( pszSections = elnextstr( pszSections ) ) ); // end do нету никаких инвалидных указателей, есть только первый и единственный который возвращает GlobalAlloc его я пушаю в GlobalReAlloc ... и он несрабатывает ... В САМЫЙ ПЕРВЫЙ РАЗ из этого следует, что нету никаких новых указателей, нету никаких расчетов новых смещений по сравнению со старым указателем НЕТУ НИФИГА ... и еще раз ... ты разве не можешь этого понять ... что я вызываю ВСЕГО ЛИШЬ ОДИН РАЗ GlobalReAlloc передавая ей указатель на блок памяти выделеный GlobalAlloc, и после этого она ( GlobalReAlloc ) не возвращает мне никаких новых указателей и т.д и т.п. она возвращает ноль что говорит о том, что ПРОИЗОШЛА ОШИБКА .... но если я выделяю память GlobalAlloc с флагом GHND, то все работает нормально ... и GlobalReAlloc срабатывает для каждой секции ... зы.: может я просто не могу понять твой глубокий смысл который ты хочешь донести до меня ...?
el- Мда, с GHND ты оказывается прав - мелкософты подложили жирную свинью, выкинув из msdn нормальное описание флагов GlobalRealloc (( А вот в старом добром WinHelp хотя и не достаточно четко, но все же сказано, что если при GlobalRealloc задан флаг GMEM_MOVEABLE (независимо от флагов GlobalAlloc), то блок при реаллокации может быть перемещен на другое место - тут остается домыслить, что если он не задан, то перемещение невозможно и функция может завершиться отказом. Попробовал - действительно так, с 0 или GPTR можно нарваться на отказ, а с GHND или GMEM_MOVEABLE в этих же условиях блок нормально перелоцируется на другое место. Значит с Global получается шиворот на выворот - при HeapRealloc по умолчанию блок может быть перемещен и если мы хотим оставить его на месте, то нужно задавать флаг HEAP_REALLOC_IN_PLACE_ONLY. А в GlobalRealloc все наоборот - по умолчанию (GMEM_FIXED = 0) блок не перемещается и для возможности перемещения нужно задавать GMEM_MOVEABLE. Вот такая ботва PS: в GlobalAlloc можно задавать GMEM_FIXED, чтобы не возиться с Lock\Unlock, а в GlobalRealloc - GMEM_MOVEABLE для возможности перемещения блока Но все-таки тебе придется предусмотреть возможность изменения указателя pConfig - так что от дельта-смещений никуда не деться Или другой вариант - переходить на VirtualAlloc и сразу резервировать блок адресов достаточного размера
слава богу ... я уж думал меня опять тупым назовут (: понятно ... это мне пригодится (: это я давно понял ... я просто пытался до вас донести, что до дельта смещения еще далеко ... т.к. ошибка намного раньше ... (: кстати можно небольшой примерчик как с ней работать ... или ссылку на её описание ...
leo Если этот размер заранее посчитать нет возможности (если бы было можно, то зачем тогда вообще realloc юзать?!), лучше заюзать приватный хип: HeapCreate, HeapAlloc, HeapReAlloc.
Quantum ??? Я говорю о Virtual как альтернативе Realloc, чтобы избежать использования смещений или пересчета адресов в случае перелокации блока памяти на другое место. Если не задать размер приватной кучи заранее (т.е. сделать ее растущей фиг знает с каким размером резерва по умолчанию), то опять можно нарваться на перелокацию. Если же задать максимальный размер кучи, то спрашивается чем этот вариант "лучше" VirtualAlloc ? По моему ничем не лучше, а только хуже, т.к. приличная часть этой кучи будет занята служебными структурами самой кучи А максимальный размер в данном случае должен быть примерно известен, т.к. насколько я понял это просто парсер ini-файла - можно поразмыслить мозгом, а если лень то можно на шару брать хоть 10 размеров файла - резерв каши не просит
leo Чтоб память не двигалась, вместо realloc можно заюзать ещё один alloc (в конце программы можно всё разом освободить, если куча приватная). Получается, что realloc в приватной куче не нужен. Виртуал - это из пушки по воробьям.
Quantum Если ты имеешь в виду вообще отказаться от Realloc и выделять все структуры отдельными HeapAlloc, то да - это будет гораздо проще Но вот фраза "Виртуал - это из пушки по воробьям" здесь выглядит неуместной, т.к. если Virtual это пушка, то HeapCreate это целая мотострелковая дивизия ) Мало того, что новая куча создается и наращивается теми же VirtualAlloc, но плюс к этому еще создаются и инициализируются нехилые служебные структуры (заголовок кучи и список свободных блоков), которые попусту поедают память и время, да еще и при каждом аллоке вместо того чтобы просто "по партизански" проверить NewSize <= CommitedSize и работать дальше, мы идем окольным путем, делая официальный запрос HeapAlloc в штаб дивизии, где тщательно проверят наши документы, выравняют наш запрос на 8 байт и прикляет в нагрузку 8 байт заголовока - а как же - все должно быть учтено и сброшюровано полистно с подписью и печатью . А в итоге получаем тоже самое, только с бОльшими затратами памяти и времени. Но на что не пойдешь ради "простоты"
leo Да, но она сама решает сколько физ. страниц наращивать и нужно ли это делать при каждом вызове. Да, около страницы уходит на заголовок Зато получаем безопасность при обращении из разных потоков... Какую-никакую защиту от кривых рук при выходе за границы выделенной памяти. Всё равно это быстрее, чем GlobalReAlloc
Quantum Все верно. Но думаю ты также должен согласиться с тем , что VirtualAlloc при наличии прямых рук и трезвого ума выглядит более легким и скорострельным вооружением, чем приватный хип
Сделал аналог контейнера std::vector, заработало, но проблема в выделении памяти, сначала использовал фиксированную память(GMEM_FIXED), память расширяется, если в блоке кучи есть свободное место, если нет, то ошибка выделении памяти. В общем, сейчас использую флаг перемещаемой памяти(GMEM_MOVEABLE), и не понял зачем нужна функция GlobalUnlock. Код работает без GlobalUnlock, память вектора несколько раз переместилось без проблем. Тогда зачем в 7-ке GlobalUnlock? Код выложу позже в проекте с 19 ферзей.
Research, ну наверное тогда имеет смысл сделать затычку типа так. Код (C++): void* GlobalGetMem(HGLOBAL hglb){ void* mem = GlobalLock(hglb); GlobalUnlock(hglb); return mem; } Хотя может ещё как-то по другому назвать функцию.
Intro, GetGlobalMemoryPointer Спойлер: Ещё варианты 1. GrabAndForgetToRelease 2. MemorySnatcher 3. QuickLockAndGo 4. SpeedyMemoryGrabbler 5. FastAndLooseMemory 6. RushAndRelax 7. HastyMemoryHandler 8. SwiftLocker 9. ZippyGlobalGetter 10. FlyingMemoryGuy 11. InstantMemoryLifter 12. SuperSpeedyMemMan 13. RapidLockMaster 14. LightningLocksmith 15. FlashyMemThief 16. BlazingMemoryBuddy 17. TurboMemoryRetriever 18. DashingMemoryDude 19. WhirlwindMemoryWizard 20. ZoomingMemoryMagician