У меня 2 аккаунта на GitHub. И несколько разных репозиториев для разных проектов - некторые должны заливаться на GitHub под первым аккаунтом, другие - под вторым. Я использую Git-клиент TortoiseGit. И столкнулся со странной проблемой - под первым аккаунтом все хорошо работает, а под вторым Push обламывается в формулировкой “error code 128 git did not exit cleanly”. Оказалось, что иногда для второго аккаунта используется ssh-key от первого. Лечится проблема удалением ключей (Remove Key) из Pagent (PuTTY authentication client).
=== Перепечатка материалов блога разрешается с обязательной ссылкой на blog.coolsoftware.ru
Для вызова внешнего приложения из программы на Delphi обычно используется функция WinAPI CreateProcess. Но как получить то, что это приложение выводит в консоль, и, например, отобразить в логе программы? Варианта два. Первый: пере-направить вывод консольного приложения в файл и потом прочитать этот файл. Однако, создавать временный файл не охота. А кроме того, такой способ не всегда хорошо работает. Есть другой способ - использовать пайпы (pipes). Ниже приведен код процедуры RunDosCommand на Delphi, который использует этот способ. Весь вывод на консоль записывается в AMemo: TMemo.
functionRunDosCommand(ACmdString: String; AMemo: TMemo; AReadPipe, AWritePipe: THandle): Boolean; const ReadBuffer = 4200; var Security : TSecurityAttributes; ReadPipe, WritePipe: THandle; start : TStartUpInfo; ProcessInfo : TProcessInformation; Buffer : Pchar; BytesRead : DWord; begin Result := False; if AMemo <> nilthen begin AMemo.SelStart := Length(AMemo.Text); AMemo.SelText := ACmdString + #13#10; AMemo.SelStart := Length(AMemo.Text); Application.ProcessMessages; end; ReadPipe := AReadPipe; WritePipe := AWritePipe; with Security do begin nLength := SizeOf(TSecurityAttributes); bInheritHandle := true; lpSecurityDescriptor := nil; end; if (ReadPipe = 0) and (WritePipe = 0) then begin ifnot CreatePipe(ReadPipe, WritePipe, @Security, 0) then begin ReadPipe := 0; WritePipe := 0; end; end; if (ReadPipe <> 0) or (WritePipe <> 0) then begin if AMemo <> nilthen begin Buffer := AllocMem(ReadBuffer + 1); end; FillChar(Start, Sizeof(Start), #0); start.cb := SizeOf(start) ; start.hStdOutput := WritePipe; start.hStdError := WritePipe; start.hStdInput := ReadPipe; start.dwFlags := STARTF_USESTDHANDLES + STARTF_USESHOWWINDOW; start.wShowWindow := SW_HIDE; if CreateProcess(nil, PChar(ACmdString), @Security, @Security, true, NORMAL_PRIORITY_CLASS, nil, nil, start, ProcessInfo) then begin WaitForSingleObject(ProcessInfo.hProcess, INFINITE); if AMemo <> nilthen begin BytesRead := 0; ReadFile(ReadPipe, Buffer[0], ReadBuffer, BytesRead, nil); Buffer[BytesRead] := #0; AMemo.SelStart := Length(AMemo.Text); AMemo.SelText := String(Buffer); AMemo.SelStart := Length(AMemo.Text); Application.ProcessMessages; end; Result := True; endelse if AMemo <> nilthen begin AMemo.SelStart := Length(AMemo.Text); AMemo.SelText :='Command failed.'#13#10; AMemo.SelStart := Length(AMemo.Text); Application.ProcessMessages; end; if AMemo <> nilthen begin FreeMem(Buffer); end; CloseHandle(ProcessInfo.hProcess); CloseHandle(ProcessInfo.hThread); if (AReadPipe = 0) and (AWritePipe = 0) then begin CloseHandle(ReadPipe); CloseHandle(WritePipe); end; end; end;
=== Перепечатка материалов блога разрешается с обязательной ссылкой на blog.coolsoftware.ru
Наконец-то появилась версия ASProtect 1.65 в которой заявлена совместимость с Delphi XE и XE2. Я попробовал - созданный в Delphi XE2 и запакованный новым “аспром” exe действительно запускается и работает. Ошибок пока не замечено.
=== Перепечатка материалов блога разрешается с обязательной ссылкой на blog.coolsoftware.ru
Столкнулся с интересным багом при получении информации о версии из ресурсов (Visual Studio 10, C++).
Access Violation возникает при выполнении VerQueryValue (см. картинку). Причем, ошибка возникает только если используется Multi-Byte Character Set. А если выставить в свойствах проекта Use Unicode Character Set, то ошибка пропадает. Из этого можно сделать вывод, что баг именно в VerQueryValueA, а в VerQueryValueW его нет. Что ж, решение проблемы заключается в переписывании функции чтения информации о версии таким образом, чтобы всегда использовалась функция VerQueryValueW. Ниже приведен листинг готовой функции.
UPD 30.01.2014. Спустя полтора года выяснилось, что и с использованием VerQueryValueW возможен Access Violation. Что же, лучше поздно чем никогда. Дело в том, что эта функция рассчитана на то, чтобы быть использованной совместно GetFileVersionInfo. Возможно, VerQueryValue может в каких-то случаях модифицировать ресурс. В общем, фикс заключается в том, что нужно выделить участок памяти (например, с помощью LocalAlloc), скопировать в него информацию о версии из ресурса (CopyMemory), и использовать его при вызове VerQueryValue. Реализация приведена ниже.
3. Добавить в Переменную среды Path (Пуск->Панель инструментов->Система->Дополнительно->Переменные среды) путь к bin каталогу Qt (например, C:\\qt\\4.8.2\\bin)
Вот, в принципе, все. В Microsoft Visual Studio IDE должен появиться пункт меню Qt. А в диалоге New Project - типы проектов Qt4 Projects.
Есть только два нюанса:
1. Если хочется избавиться от Qt Runtime (статически прилинковать к exe файлу все необходимые библиотеки), то нужно пересобрать Qt с ключом -static:
2. По-умолчанию библиотеки Qt компилируются в режиме Multi-threaded DLL - /MD (для Debug - Multi-threaded Debug DLL - /MDd). Что означает наличие зависимостей от msvcr90.dll и msvcp90.dll. Т.е. при установке программы возможно потребуется устанавливать Microsoft Visual C++ 2008 Redistributable Package. Чтобы избавиться от этой зависимости нужно перед сборкой Qt поправить qmake.conf ( C:\qt\4.8.2 \mkspecs\win32-msvc2008\qmake.conf) следующим образом:
Чтобы убрать зависимость от Microsoft Visual C++ Runtime нужно в свойствах проекта выбрать Runtime Library: Multi-threaded (/MT). Получающийся при компиляции exe/dll будет несколько больше, зато не нужно будет устанавливать Visual C++ Redistributable Package.
=== Перепечатка материалов блога разрешается с обязательной ссылкой на blog.coolsoftware.ru
В моем посте про проверку серверного сертификата SSL в Delphi 7 проверка этого самого сертификата выполнялась вызовом функции CryptoAPI CertGetIssuerCertificateFromStore. Я столкнулся на практике со следующим: оказывается, что на эту функцию оказывает влияние Internet Explorer Enhanced Security (по умолчанию оно включено на всех серверах Windows 2003). Т.е. до тех пор, пока хост не будет включен в список доверенных, его сертификат тоже может не проходить проверку. Как-то так (слишком глубоко эту тему не копал). В общем, если на одном компьютере проверка сертификата работает, а на другом - нет (ошибка “Error connecting with SSL”), то следует проверить - включен ли IE Enhanced Security, и если да, то либо отключить его, либо добавить хост в список доверенных.
=== Перепечатка материалов блога разрешается с обязательной ссылкой на blog.coolsoftware.ru
ASProtect, к сожалению, не поддерживает приложения, сделанные в Delphi XE 2. Упакованные им exe-ки не запускаются. В Windows Application Log-е появляется соответствующая запись об ошибке в приложении.
Сообщение о несовместимости Delphi XE 2 и ASProtect на официальном форуме датировано 18 ноября 2011, но до сих пор решения нет. Последний ответ от 26 марта 2012 гласит:
Your problem in the queue for the decision and will be solved in the next release of ASProtect (will be released in the nearest future).
Ждем новую версию… Если в ближайшее время не появится, придется переходить на какой-нибудь другой протектор.
=== Перепечатка материалов блога разрешается с обязательной ссылкой на blog.coolsoftware.ru
Это не первый мой аккаунт в github, поэтому потребовалось как-то организовывать одновременный доступ к нему из под разных учеток, с разными SSHKey. По этому поводу маленький “трик” - как я все это сделал:
1. При установке Git for Windows создает такой ярлык для Git Bash:
Как мы видим текущий каталог Git Bash - %HOMEDRIVE%%HOMEPATH%. В нем хранятся все настройки git, каталог .ssh с SSHKey и проекты обычно тоже там.
Я создал в %HOMEDRIVE%%HOMEPATH% каталог Coolsoftware и в нем git.cmd следующего содержания:
Затем создал ярлык на этот git.cmd и вынес его на рабочий стол, обозвав “Git Bash - Coolsoftware”. Теперь при его запуске текущий каталог пользователя в “баше” %HOMEDRIVE%%HOMEPATH%\Coolsoftware, а при запуске старого ярлыка “Git Bash” текущий каталог %HOMEDRIVE%%HOMEPATH%. Таким образом получилось два “баша”, в каждом - свои настройки.
Далее запустил “Git Bash - Coolsoftware” произвел установку github в соответствии с инструкцией и выложил проект VHashedStringList - оптимизированный список строк, доступ к элементам которого организован с помощью хеш-индекса.
TVHashedStringList - аналог стандартного THashedStringList (фактически, он сделан на его основе, хотя наследуется не от него, а от TStringList).
Существенное отличие от THashedStringList заключается в том, что оптимизированы операции перестроения индекса при изменении списка.
В THashedStringList полное перестроение индекса требуется после любого изменения, что приводит к значительным задержкам в реальных приложениях.
Например, в следующем примере полное перестроение индекса будет произведено 3 раза:
procedureChangeList(lst: THashedStringList); begin lst.Values['key1'] := 'Value1'; lst.Values['key2'] := 'Value2'; //неявный вызов IndexOfName и перестроение индекса lst.Values['key3'] := 'Value3'; //неявный вызов IndexOfName и перестроение индекса lst.Values['key4'] := 'Value4'; //неявный вызов IndexOfName и перестроение индекса end;
В отличие от THashedStringList, TVHashedStringList не требует полного перестроения индекса после добавления нового элемента в конец списка или
при изменении значений элементов списка. Перестроение происходит только после вставки нового элемента в список или удаления из списка.
Поэтому в следующем примере полного перестроения индекса не произойдет ни разу.
procedure ChangeList(lst: TVHashedStringList); begin lst.Values['key1'] := 'Value1'; //индекс модифицирован и не требует перестроения lst.Values['key2'] := 'Value2'; //индекс модифицирован и не требует перестроения lst.Values['key3'] := 'Value3'; //индекс модифицирован и не требует перестроения lst.Values['key4'] := 'Value4'; //индекс модифицирован и не требует перестроения end;
===
Перепечатка материалов блога разрешается с обязательной ссылкой на blog.coolsoftware.ru