Delphi, Asm, C, WinAPI, PHP, ..., FAQ |
Добро пожаловать, гость ( Вход | Регистрация )
Delphi, Asm, C, WinAPI, PHP, ..., FAQ |
-=CHE@TER=- |
Nov 11 2011, 15:15
Сообщение
#61
|
Walter Sullivan Группа: Root Admin Сообщений: 1,361 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 314 раз(а) |
У Delphi такой смешной оптимизатор (компилирую программу через DCC32HACK - там глюки и косяки сразу хорошо видно, т.к. программа маленькая и без мусора):
CODE Const Chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'; Делает копию этой строки в каждом (!) месте программы где она используется. Если же написать так: CODE Const Chars: String = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'; То только в первом - все остальные на неё ссылаются. А вот так: CODE Const Chars: String[36] = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'; Вообще загоняет строку отдельно в секцию DATA. Спасибо сказали:
|
Siberian GRemlin |
Nov 11 2011, 15:25
Сообщение
#62
|
Advanced Member Группа: CTPAX-X Сообщений: 537 Регистрация: 4-February 08 Пользователь №: 2 Спасибо сказали: 221 раз(а) |
Как я понимаю при конкатенации (дурацкое слово) строк создаётся новый элемент типа string, и если потерять указатели на строки из которых складывалась новая, т.е. например S:=S+S, или добавлять вручную значение, например S:=S+'s', то будет утечка памяти? Хочу вспомнить как правильно и не громоздко работать на строками на D7, а то работа на Java расслабляет...
|
-=CHE@TER=- |
Nov 11 2011, 20:39
Сообщение
#63
|
Walter Sullivan Группа: Root Admin Сообщений: 1,361 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 314 раз(а) |
Похоже долго ты на Java писал. (*улыбается*)
Нет, насколько я помню, Delphi хранит указатели на сложные типы данных и количество переменных ссылающихся на них. Как только количество = 0, то переменная уничтожается. Если же ты делаешь T:=S;, то у тебя в T не хранится строка S, а только указатель на неё. Реально память выделяется, если я правильно помню, только когда ты начинаешь изменять T, например: T:=T + 's'; Уже не помню, где об этом читал, где-то статья была, может даже здесь (на форуме) ссылку давали. О, нашёл - там нет якорей, так что крути вниз до главы "Как же это происходит?". Так это происходит или нет, судить не берусь, но, вроде бы, в этой главе походит на правду. Спасибо сказали:
|
-=CHE@TER=- |
Nov 14 2011, 13:41
Сообщение
#64
|
Walter Sullivan Группа: Root Admin Сообщений: 1,361 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 314 раз(а) |
Siberian GRemlin!
До меня, кажется, дошло, почему ты спросил. (*улыбается*) CODE Const Chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'; Делает копию этой строки в каждом (!) месте программы где она используется. Это моё замечание (как и другие из того сообщения) относились не к динамическому размещению строк в памяти во время работы программы, а к размещению данных в .EXE файле. Т.е. в приведённом случае в .EXE файле на диске будет три раза продублированна в разных местах эта строка. Таким образом, к примеру, в случае большого массива, размером, предположим в 64 Кб (скажем, для расшифровывания чего-нибудь) на диске такое безобразие будет занимать 64*3 Кб + код программы, где 3 - количество обращений к этому массиву (в данном случае у меня их было 3). |
-=CHE@TER=- |
Jan 14 2012, 13:26
Сообщение
#65
|
Walter Sullivan Группа: Root Admin Сообщений: 1,361 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 314 раз(а) |
Писал я недавно патч для включения крови в German версии Turok 2. Решил, чтобы не маяться с CreateWindow(), сделать диалог в ресурсах. Взял из FASM пример EXAMPLES\DIALOG\DIALOG.ASM и переколбасил его под свои нужды. Всё работает, но странности начались, когда я решил навести последний штрих - добавить manifest для XP/Vista/7.
Программа стала сразу выходить после запуска. Офигев от такого безобразия начал отлаживать - выяснилось, что DialogBoxParam() сразу выходит даже не отображая окно. Убираем манифест - всё снова работает. Пошёл гуглить и натолкнулся вот на такую статью: Особенность InitCommonControlsEx в Windows XP (кстати, там на сайте и другие статьи интересные есть - их немного, так что пробегитесь по ним, кому интересно) В общем, суть такова: чтобы программы с манифестом и DialogBoxParam() работали как надо, нужно чтобы в импорте была библиотека COMCTL32.DLL. Это можно сделать, вызвав, к примеру, InitCommonControls(). Я решил её не вызывать (толку-то всё равно не будет), а просто перепрыгнуть: CODE jmp @ICC invoke InitCommonControls @ICC: Мне главное, чтобы в импорте COMCTL32.DLL была, а если ни одна функция оттуда не вызывается, то компилятор удаляет её из импорта. Вот такая фигня. Спасибо сказали:
|
-=CHE@TER=- |
Mar 7 2012, 20:37
Сообщение
#66
|
Walter Sullivan Группа: Root Admin Сообщений: 1,361 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 314 раз(а) |
Вчерась ковырял одну игрушку, где данные были упакованы deflate. Как и всегда использовал puff.c + puff.h из zlib. Внезапно, при распаковке, получаю ошибку записи в память по адресу 0, программа падает. <...> Наконец-то обновили - забираем.Спасибо сказали:
|
-=CHE@TER=- |
Mar 12 2012, 09:13
Сообщение
#67
|
Walter Sullivan Группа: Root Admin Сообщений: 1,361 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 314 раз(а) |
У Delphi такой смешной оптимизатор (компилирую программу через DCC32HACK - там глюки и косяки сразу хорошо видно, т.к. программа маленькая и без мусора): Кто-нибудь знает, как можно сразу, без этих приседаний, загонять константы в секцию .DATA? Может переключатель {$..} какой есть? А то Delphi их дублирует, скотина, в .CODE размещать не хочу, а для каждой строки писать String[кол-во_символов] = '...'; очень нудно. |
Siberian GRemlin |
Mar 12 2012, 11:07
Сообщение
#68
|
Advanced Member Группа: CTPAX-X Сообщений: 537 Регистрация: 4-February 08 Пользователь №: 2 Спасибо сказали: 221 раз(а) |
для каждой строки писать String[кол-во_символов] = '...'; очень нудно. Я для InnoSetup писал прогу в которой вставляешь строки, а она выдаёт код с массивом строковых констант. Возможно и тебе это будет проще делать.Спасибо сказали:
|
Siberian GRemlin |
Mar 24 2012, 09:13
Сообщение
#69
|
Advanced Member Группа: CTPAX-X Сообщений: 537 Регистрация: 4-February 08 Пользователь №: 2 Спасибо сказали: 221 раз(а) |
Кто-нибудь знает где можно взять готовый код под PHP4 для генерации картинки с текстом? Наподобие того как это сделано для телефона продавца на сайте avito.ru - нужно открыть какое-нибудь объявление и там будет "показать телефон продавца". Пробовал разные запросы, но поисковик выдаёт сайты на которых можно ввести текст, выбрать шрифт и пр. и он выдаст какую-нибудь красивую картинку.
|
-=CHE@TER=- |
Mar 24 2012, 11:58
Сообщение
#70
|
Walter Sullivan Группа: Root Admin Сообщений: 1,361 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 314 раз(а) |
Вот тут (за номером 7 самый простой, и ниже - до конца, уже сложнее) натыкался когда-то на генератор на PHP, который добавляет текст на изображение. Посмотри что да как, лишнее выкини. Все эти функции описаны в справке по PHP. Если я не ошибаюсь это расширение GD2 Lib, которое на современных серверах должно быть.
Если же у тебя вообще голый PHP без расширений, то можно самому сгенерировать и выводить .BMP файл, правда занимать он будет больше (впрочем, можно немного поприседать и сделать ч/б, чтобы меньше весил). Спасибо сказали:
|
-=CHE@TER=- |
Apr 14 2012, 15:39
Сообщение
#71
|
Walter Sullivan Группа: Root Admin Сообщений: 1,361 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 314 раз(а) |
В Си есть такая замечательная функция, как sprintf(), которая позволяет формировать строчку со всякими '%s', '%03d' и прочим. Эта функция есть в msvcrt.dll, однако, я не люблю эту библиотеку, так как на чистой Windows 98 SE у меня её не было - она ставится только с какой-нибудь программой, да и вообще, в ядро системы не входит.
Зато в ядро системы входит wsprintf(). К сожалению, в Delphi она криво объявлена, в результате чего ей нельзя пользоваться. Как мы помним, у всех таких функций может быть разное количество аргументов - это, оказывается, решается ключевым словом "varargs": CODE function wsprintf2(Output: PChar; Format: PChar): Integer; cdecl; varargs; external 'user32.dll' name {$IFDEF UNICODE}'wsprintfW'{$ELSE}'wsprintfA'{$ENDIF}; Вот такое объявление (я его уже не помню где нашёл в Интернете) - работает. cdecl, как мы помним, говорит о том, что в отличие от stdcall, вызываемая функция не знает сколько параметров сложено на стек, так что об их снятии со стека после работы функции должна позаботиться вызывающая сторона, что в данном случае логично. Нужно только помнить пару вещей: 1) В MSDN настоятельно не рекомендуют пользоваться этой функцией (небезопасна, если криво используется), но в Windows 7 и ниже она есть (в Windows 98 есть только wsprintfA). 2) В этой функции ограничение на 1025 байт для ANSI и 1025*2 для UNICODE буфера - т.е. если строчка больше, то она просто будет отрезана. 3) Она поддерживает далеко не все возможности, которые есть в sprintf (кажется, с дробными числами не работает - см. MSDN). Пример использования (S - переменная типа String): CODE // максимальный размер буфера SetLength(S, 1025); // отрезаем по границе - сколько реально было использовано SetLength(S, wsprintf2(PChar(S), '%03d - %s', 45, PChar('Hello World!'))); P.S. Да, в Delphi есть FmtStr(), но она подключается вместе с SysUtils и ещё кучей мусора, что для небольших программ на WinAPI просто неприемлемо. |
-=CHE@TER=- |
Apr 15 2012, 10:32
Сообщение
#72
|
Walter Sullivan Группа: Root Admin Сообщений: 1,361 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 314 раз(а) |
И ещё о нескольких устаревших (по мнению MSDN, где ими не советуют пользоваться) функциях.
Часто программе нужно где-то хранить настройки. Вариантов хранения два: 1) В файле. 2) В реестре. Microsoft настоятельно рекомендует пункт 2 и пользоваться для этих целей веткой реестра HKEY_CURRENT_USER \ Software, чтобы у каждого пользователя были свои настройки - т.е. каждый вошедший в систему пользователь мог настроить программу "под себя" (так как ему нравится). Как известно HKEY_CURRENT_USER загружается автоматически вместе с текущим профилем пользователя при входе в систему и у каждого пользователя эта ветка реестра будет своя (разумеется, кроме тех одинаковых вещей, которые по умолчанию добавляет туда сама система при создании профиля для нового пользователя). К слову, HKEY_LOCAL_MACHINE - это глобальная ветка, настройки в которой доступны всем пользователям (вернее будет сказать, что это настройки для всего компьютера), посему и писать туда не имея прав администратора вообще нельзя. Хранение же настроек в файле чревато тем, что у всех пользователей будут одни и те же настройки, а если каждый захочет менять под себя... будет мало хорошего. В принципе, можно хранить настройки в каталоге пользователя C:\Documents and Settings\USERNAME\Application Data\<ИМЯ ПРОГРАММЫ> (т.н. каталог %APPDATA% - который, как и ветка реестра, у каждого пользователя свой). Однако, и реестр и каталог пользователя "болеют" одной проблемой: при удалении программы, все эти вещи остаются. Т.е. система получается загажена неиспользуемыми данными - "мусором". Можно, конечно, сделать установщик, который будет все эти вещи чистить при удалении программы. Однако же: 1) Надо писать установщик. 2) Надо писать логику и обработку удаления программы. 3) Программа перестаёт быть portable (портативной - переносной, ей обязательно нужен будет доступ для записи либо в реестр, либо на жёсткий диск). Самый серьёзный пункт - это пункт 3. Но даже не в этом дело, а в том, что многие пользователи до сих пор, "по привычке", удаляют программу через SHIFT+DELETE, вместо "Установки и удаления", что сводит все старания из п.п. 1 и 2 на нет. Наконец, для программ, которые являются каким-то разовыми утилитами и которыми не пользуешься каждый день, все эти вещи просто лишние. И вот тут нас выручают настройки сохранённые в файл в каталоге программы - по завершении работы весь каталог с программой можно безболезненно удалить. И всё вернётся на круги своя. Настройки можно хранить и в своём формате, но гораздо удобнее, на тот случай, если программа навернётся при запуске из-за кривого файла настроек, делать это в .INI формате, который очень просто и быстро в таких ситуациях можно подправить ручками, а не писать для этого специальную программу-редактор. Уф, ладно, со вступлением закончил. (*улыбается*) Теперь переходим к практике. Для работы с .INI файлами есть в WinAPI следующие функции: GetPrivateProfile* - для чтения WritePrivateProfile* - для записи * - означает, что есть несколько функций, которые начинаются на эту строку, но имеют разные окончания. Для примера рассмотрим вот такой тестовый "test.ini" файл: CODE [Main] Param1=123 StrVal=String! Для того, чтобы прочитать оттуда нужно сделать следующее: CODE Var S: String; X: Integer; Begin ... // максимальный размер строки - 100 символов SetLength(S, 100); // меняем на тот, сколько реально было прочитано SetLength(S, GetPrivateProfileString('Main', 'StrVal', '', @S[1], Length(S), '.\test.ini')); X:=GetPrivateProfileInt('Main', 'Param1', 0, '.\test.ini'); Ну и писать, точно также, только через WritePrivateProfile*. Кстати, чтобы удалить из .INI достаточно написать (Nil - в качестве значения параметра, чтобы удалить): CODE WritePrivateProfileString('Main', 'StrVal', Nil, '.\test.ini'); И StrVal вообще исчезнет из .INI файла. Важные замечания: 1) Не путайте (Get/Write)PrivateProfile* и просто (Get/Write)Profile* - последние функции (без Private в названии) пишут в системный файл "WIN.INI"! А его лучше не трогать, к тому же доступа на запись в системный каталог может не быть. 2) Не забывайте писать '.\' в начале имени файла. Это важно - если написать просто 'test.ini', то этот файл будет сохранён в "C:\Windows\test.ini" - а прав записи туда может не быть. 3) Функций гораздо больше (не только *String и *Int) - см. справку по MSDN. Я, кстати, здесь не объяснил некоторые параметры (значения по умолчанию, например, если параметра в файле нет) - за всем этим, а также другими удобными вещами и прочими тонкостями - см. MSDN. 4) Как я уже говорил, MSDN настоятельно рекомендует не пользоваться этими функциями и посылает всех в реестр, однако же, они вполне себе спокойно работают и под Windows 7. P.S. В Delphi есть IniFiles при подключении которого через uses появится класс TIniFile работающий с .INI файлами и независящий от перечисленных WinAPI функций, однако же, как я уже писал в сообщении выше, для небольших программ на WinAPI подключение этого модуля чудовищно раздувает размер кода. |
-=CHE@TER=- |
Apr 19 2012, 13:23
Сообщение
#73
|
Walter Sullivan Группа: Root Admin Сообщений: 1,361 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 314 раз(а) |
Проводя очередную чистку системы, натолкнулся на файл:
C:\WINDOWS\Perflib_Perfdata_*.dat который не хотел удаляться. Внутри была видна как-то информация от долбанного .NET. Unlocker показал, что этот файл "держит" процесс G6FTPServer.exe (Gene6 FTP Server 3.8.0.34). Как выяснилось, это система чего-то пишет, при запросе статистики об используемой памяти, процессорного времени и т.д. Отключается сиё безобразие переименованием или удалением файла: C:\Program Files\Gene6 FTP Server\Plugins\g6_log_system.dll Не забудьте перед этим остановить службу FTP-сервера, а потом снова включить. Там оно ещё и в реестр постоянно лезет из-за этого. В результате отключения этой .DLL информации о загрузке системы в логах не будет, но мне она и так никуда нафиг не упёрлась. |
Grom PE |
Apr 19 2012, 19:05
Сообщение
#74
|
Advanced Member Группа: CTPAX-X Сообщений: 84 Регистрация: 7-February 08 Из: i@grompe.org.ru Пользователь №: 3,120 Спасибо сказали: 95 раз(а) |
Сам у себя встречал такие файлы. Полюбопытствовал, что и как.
Выяснилось, что можно взять и применить регу: CODE REGEDIT4 Тогда ни одна программа не будет создавать эти файлы.[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib] "Disable Performance Counters"=dword:00000001 А последствия - монитор производительности системы ничего не будет показывать. Спасибо сказали:
|
-=CHE@TER=- |
Apr 24 2012, 12:14
Сообщение
#75
|
Walter Sullivan Группа: Root Admin Сообщений: 1,361 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 314 раз(а) |
В очередной раз зайдя на сайт товарища Siberian GRemlin'а и увидев надпись (да, я таки поставил себе NoScript):
QUOTE Для отображения ссылок необходимо разрешить выполнение 'JavaScript' в вашем обозревателе! гласящую, что без JS на сайте ничего нельзя увидеть, я всё же решился дать ему ссылку тут на полезную статью, о том, как AJAX'ом пользоваться не надо: Блеск и нищета Ajax (хотя бы со слов: "Вот, пожалуй, и все об этом. А теперь тех, кто не уснул за чтением первой части статьи..." и далее), если, конечно, никакая индексация в поисковых системах (т.е. попытка спрятать сайт от поисковых роботов) не является частью какого-нибудь Хитрого Плана. (*улыбается*) |
Siberian GRemlin |
Apr 24 2012, 13:16
Сообщение
#76
|
Advanced Member Группа: CTPAX-X Сообщений: 537 Регистрация: 4-February 08 Пользователь №: 2 Спасибо сказали: 221 раз(а) |
Я так понимаю, ты знаешь способ создания динамичных страниц на голом HTML. Никого AJAX'а, кстати, тоже нет.
|
-=CHE@TER=- |
Apr 24 2012, 15:37
Сообщение
#77
|
Walter Sullivan Группа: Root Admin Сообщений: 1,361 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 314 раз(а) |
Я так понимаю, ты знаешь способ создания динамичных страниц на голом HTML. Никого AJAX'а, кстати, тоже нет. AJAX = Asynchronous Javascript and XML (асинхронный JavaScript и XML).Ну, у тебя там нет XML, а ты просто кусок сайта через массивы подгружаешь - в принципе, тоже какой-то вариант хранения данных. Я про саму мысль, что у тебя там здоровенный список игр на какой-либо странице, но через поисковую систему на твой сайт не выйдешь с запросом имени игры и перевода, так как поисковые пауки индексируют сайт без JS. Это всё к чему: у тебя хостер PHP или какие-либо другие серверные языки не разрешает использовать? Только голый HTML? У тебя же, вроде бы, собственный домен? Просто тогда можно было бы нормально генерить страницы на стороне сервера. Если же только голый HTML, то это жесть, честно говоря. Есть один способ - как я на народе выкручивался: делал шаблон сайта и парсер. Парсер выдирал контент (содержимое) из *.HTM файлов рекурсивно обходя все каталоги сайта. То что считалось за тело (т.е. не шапка, не подвал и не меню) помечалось как: CODE <!-- Content --> тут тело документа <!-- /Content --> оно выдералось и вставлялось в шаблон. Т.е. я мог поменять хоть весь дизайн сайта - мне достаточно было только изменить шаблон, запустить скрипт-компилятор и залить новые файлы на сайт. Но, видишь что, у меня списков постоянно меняющихся нет, я там, в основном, статьи пишу и ручками всё правлю. Тебе, возможно, будет проще сделать БД, где хранить списки игр и при компиляции сайта вставлять в нужное место. Скажем в документе пишешь %%GAMELIST_RU%%, а уже при компиляции заменяешь это слово на список нужных игр. Тебе тогда нужно будет делать несколько шаблонов: один общий для сайта (шапка, меню, подвал), а другой для каждой страницы, ну и готовые странички в отдельный каталог складывать. Можно даже перезаписывать только те, которые изменились, чтобы по дате отсортировать и на сервер только новые закидывать. Вот такие варианты могу предположить. Это не наезд, просто у тебя столько работы пропадает, потому что никак не индексируется - вот что грустно. |
Siberian GRemlin |
Apr 24 2012, 15:49
Сообщение
#78
|
Advanced Member Группа: CTPAX-X Сообщений: 537 Регистрация: 4-February 08 Пользователь №: 2 Спасибо сказали: 221 раз(а) |
Месяц назад я только договорился с админом и мне включили PHP, жаль только что 4-ой версии, а не 5-ой. Пока не было времени код переписать. Планирую сделать PHP+XML. Если есть идеи, то готов выслушать.
Спасибо сказали:
|
-=CHE@TER=- |
Apr 24 2012, 16:19
Сообщение
#79
|
Walter Sullivan Группа: Root Admin Сообщений: 1,361 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 314 раз(а) |
О, блин, 4-ый PHP это уже здорово, чем вообще ничего!
Я не знал об этом, поэтому и предложил вот это всё. Думаю с PHP у тебя уже проблем не будет. Предложить особо нечего - если MySQL или какой-либо БД нет, то тогда действительно только в .XML хранить БД и парсить её при генерации страниц сайта на PHP. simplexml_load_file(), к сожалению, только в PHP 5 появилась, смотри в сторону xml_parser_create() и других функций - они, судя по руководству к PHP, есть и в 4-ой версии. Вот годная статья: XML и PHP, парсинг для чайников. Спасибо сказали:
|
-=CHE@TER=- |
May 30 2012, 10:22
Сообщение
#80
|
Walter Sullivan Группа: Root Admin Сообщений: 1,361 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 314 раз(а) |
Нашёл в Delphi 7 охрененный косяк, который вынес мне мозг.
1) Создаём новую программу - пустую форму и вешаем обработчик на событие OnActivate (нам нужно показать окно с некоторой заполненной информацией в ListBox). 2) Кидаем на форму ListBox и вешаем обработчик на событие OnClick. 3) Пишем туда такой код: CODE procedure TForm1.ListBox1Click(Sender: TObject); begin // if Sorted changed in FormActivate you'll see this only with keyboard ShowMessage('OnClick'); end; procedure TForm1.FormActivate(Sender: TObject); var i: integer; begin for i:=1 to 10 do ListBox1.Items.Add(IntToStr(i)); ListBox1.Sorted:=True // <-- bye-bye OnClick, DblClick and mouse events! end; 4) Долбанный стыд - при изменении Sorted (неважно в True или False) внутри OnActivate - OnClick, OnDblClick у ListBox и все прочие события с мышки перестают обрабатываться. Работает только клавиатура... |
Упрощённая версия | Сейчас: 12th November 2024 - 12:25 |