Вадим Смоленский

Пользователи
  • Публикаций

    177
  • Зарегистрирован

  • Посещение

  • Победитель дней

    3

Весь контент Вадим Смоленский

  1. Вадим Смоленский

    Постоянная потеря фокуса под Wine

    В феврале я сетовал, что мое Windows-приложение не хочет нормально запускаться в Linux под Wine 3.0. Но время идет, вышел Wine 3.6 - и теперь один из тестировщиков радостно сообщил, что всё заработало, за вычетом одного досадного момента. А именно: приложение способно сохранять фокус ввода лишь долю секунды, потом теряет. Соответственно, невозможно ничего ввести в текстовые боксы, разве только одну-две буквы. Можно щелкнуть по заголовку приложения, оно опять получит фокус - и через мгновение снова потеряет. Куда именно при этом переходит фокус, непонятно. Тестировщик утверждает, что только мое приложение ведет себя так, все остальные работают нормально. Нет ли у кого-нибудь идей? Что нужно проверить?
  2. Год назад в одной из веток проскочила ссылка на китайский сайт (http://www.raysoftware.cn/?p=559), где предлагалось готовое решение для показа анимированных гифок средствами FireMonkey на любых платформах. Сейчас эта ссылка, как и весь сайт raysoftware.cn, упорно не открывается; по счастью, контент сохранился в гугловском кэше. Я скопировал оттуда код юнита и перевел гуглом все китайские комментарии на английский, добавив их в скобках. Там был еще сопроводительный текст, в котором автор излагал мотивы, побудившие его взяться за эту проблему; каких-то важных технических деталей я в этом тексте не увидел. Привожу весь юнит ниже и очень надеюсь, что кто-нибудь из продвинутых коллег объяснит мне, как именно этим кодом можно воспользоваться, чтобы показать пользователю анимированный файл в формате GIF. Моей программерской квалификации, к сожалению, не хватает.
  3. Вадим Смоленский

    Обработка анимированных GIF по рецепту китайского коллеги

    Хорошо, если получится исправить. В моем-то проекте гифки самые простые, без прозрачности и черезстрочности, так что я ничего такого и не заметил.
  4. Вадим Смоленский

    Хук на клавиатуру

    В декабре я задавал здесь вопрос о борьбе с перехватами нажатий клавиш компонентом TWebBrowser. Продвинутый пользователь Kami посоветовал тогда, раз уж меня интересует только Windows, поставить хук на клавиатуру. Поделился полезной ссылкой. Добавил, что можно еще много чего нагуглить. Что-то действительно нагуглилось - но не в том объеме, чтобы я смог четко понять, как это следует делать. Вопросов много. Куда именно должна быть воткнута функция KeyboardProc? Что в ней должно содержаться, чтобы управление передавалось уже написанному обработчику события FormKeyDown? Многие также упоминают о возникающих проблемах с юникодом, и хорошо было бы понять, как уберечься от них. Буду очень признателен, если кто-нибудь осветит эту темную для меня материю.
  5. Вадим Смоленский

    Хук на клавиатуру

    Да нет, всё понятно теперь. Я просто упустил из вида, что внутри функции CallNextHookEx еще много всякого разного может происходить и ее выходное значение в данном случае - не самое главное. Кстати, в отладчике посмотрел - оно в штатном режиме действительно получается нулевым. Так что теперь в тех случаях, когда нажатие клавиши точно обработано моим приложением и я больше не хочу от него никаких сюрпризов, просто присваиваю Result:=1. Всё работает, как часы. Огромное спасибо!
  6. Вадим Смоленский

    Хук на клавиатуру

    Это непонятно. Какой именно <>0? Любой кроме ноля? А если, как советуют, присвоить CallNextHookEx(CurrentHook, nCode, wParam, lparam), то это всегда будет ноль, что ли?
  7. Вадим Смоленский

    Хук на клавиатуру

    Такого раздела там нет. Вы, видимо, имели в виду раздел "Return value". В частности, там сказано, что CallNextHookEx нужно вызывать в том случае, если (цитирую) the hook procedure did not process the message. То есть, насколько я понял, если моя процедура FormKeyDown установила Key:=0, то это можно трактовать в том ключе, что message обработан, и тогда CallNextHookEx вызывать необязательно. Так или не так? Ваши рекомендации меня запутали: строчку убирать не надо, я должен вызвать следующий хук, но лучше этот вызов пропустить. Как это всё трактовать в терминах конкретных действий? Я так и не смог понять разницы между WH_KEYBOARD_LL и WH_KEYBOARD. Мне казалось, что лишь первый вариант относится ко всей системе целиком и проверяется всеми приложениями, где есть хук, в то время как второй ограничен лишь одним-единственным приложением. Всё сложнее?
  8. Вадим Смоленский

    Хук на клавиатуру

    Вы имеете в виду, убрать эту строчку: Result := CallNextHookEx(CurrentHook, nCode, wParam, lparam); Я полагал, что "следующий хук" относится к возможному нажатию следующей клавиши, которое хранится в очереди. Разве это не так? И что присваивать результату в таком случае? Ноль?
  9. Вадим Смоленский

    Хук на клавиатуру

    Выявилась проблемка. Когда FormKeyDown вызывался как обработчик события, в самом его конце выполнялся оператор Key:=0. Это обнуляло нажатие клавиши, гарантировало, что оно не сработает каким-то дополнительным, непредвиденным образом. В новой конфигурации это не работает, я уже столкнулся с досадными побочными эффектами. Нажатие нужно обнулить в обработчике хука KeyboardProc. Но как?
  10. Вадим Смоленский

    Хук на клавиатуру

    Да, с виртуальным кодом клавиши проблем нет. Сложнее оказалось с параметром Shift - но нагуглилась страничка с хорошим примером, там я взял всё, что мне было нужно. Вот как теперь выглядит функция: function KeyboardProc(nCode: integer; wParam: integer; lParam: integer ): LongWord; stdcall; var W: Word; C: Char; KeyUp : Boolean; KeyState: TKeyboardState; TheShift: TShiftState; begin if (nCode < 0) then begin Result := CallNextHookEx(CurrentHook, nCode, wParam, lParam); Exit; end; KeyUp := ((lParam AND (1 shl 31)) <> 0); if not KeyUp then begin W:=wParam; C:=Chr(wParam); TheShift:=[]; if GetKeyboardState(KeyState) then begin if (lParam AND (1 shl 29))<>0 then TheShift:=[ssAlt]; if (GetKeyState(VK_CONTROL) AND (1 shl 15))<>0 then TheShift:=TheShift+[ssCtrl]; if (GetKeyState(VK_SHIFT) AND (1 shl 15))<>0 then TheShift:=TheShift+[ssShift]; end; Form1.FormKeyDown(Form1,W,C,TheShift); end; Result := CallNextHookEx(CurrentHook, nCode, wParam, lparam); end; Придирчиво еще не тестировал, но в первом приближении всё работает.
  11. Вадим Смоленский

    Хук на клавиатуру

    Загвоздка в моей дремучести, которую не ликвидировать враз. Нашел описание GetAsyncKeyState, но это несколько не о том, туда надо передавать параметром уже известный код клавиши. А что за снанкод? Где про него можно узнать?
  12. Вадим Смоленский

    Хук на клавиатуру

    Попробовал, и получилось! С веббраузером проблем не наблюдается - даже когда фокус на нем, управление переходит в KeyboardProc. Осталось последнее: понять, как из KeyboardProc(nCode: integer; wParam: integer; lParam: integer) вызвать FormKeyDown(Sender: TObject; var Key: Word; var KeyChar: Char; Shift: TShiftState). В идеале хотелось бы суметь передать без искажений все три параметра: Key, KeyChar и Shift.
  13. Вадим Смоленский

    Хук на клавиатуру

    RaiseLastOSError помог установить причину: System Error. Code: 1428. Cannot set nonlocal hook without a module handle Только не знаю пока, как это трактовать и что с этим делать. Интересно и то, что с WH_KEYBOARD_LL хук срабатывает: CurrentHook ненулевой, и по нажатию клавиши управление переходит в KeyboardProc. Но ведь это, как я понял, глобальный хук, он будет перехватывать нажатия у других приложений. А это уже будет лишним.
  14. Вадим Смоленский

    Хук на клавиатуру

    Ссылка внятная, спасибо. Но пока не помогло. Вот такой конструктор формы у меня: constructor TForm1.Create(AOwner: TComponent); begin inherited; CurrentHook := SetWindowsHookEx(WH_KEYBOARD, @KeyboardProc, HInstance, 0); end; На отладчике вижу, что после его выполнения CurrentHook как был равен нулю, так и остался. Одно это уже подозрительно. И в функцию KeyboardProc управление не попадает, какие клавиши ни нажимай. Кстати, в комментариях по ссылке вот еще что пишут: У меня 64. Не в этом ли закавыка? Или же сказанное относится лишь к WH_KEYBOARD_LL ? Я не смог понять.
  15. Вадим Смоленский

    Хук на клавиатуру

    Очень обяжете. Можно даже сразу на электронную почту: vsСОБАКАsusi.ru
  16. Вадим Смоленский

    Конвертация HString в string

    Как преобразовать тип HString в обычную строку? Нагуглил упоминания о функции TWindowsString.HStringToString, которая должна находиться в System.WinrtHelpers. Но такого юнита в поставке Delphi не наблюдаю. Может, его можно где-нибудь раздобыть? Или существуют иные способы?
  17. Вадим Смоленский

    Конвертация HString в string

    Точно, есть! Спасибо.
  18. Вадим Смоленский

    Доступ к классу ApplicationData

    Пытаясь разобраться с проблемой размещения файлов в UWP-приложениях, пришел к необходимости создать в своем коде объект класса ApplicationData. Этот класс описан на соответствующей странице майкрософтовской документации, где в самом начале обозначено следующее: Namespace: Windows.Storage Assemblies: Windows.Storage.dll, Windows.dll Юнита с именем Windows.Storage или Winapi.Windows.Storage я в поставке Delphi не наблюдаю. Неудивительно, что попытки вставить соответствующие идентификаторы в раздел uses ни к чему не ведут. Как в таких случаях поступают? Откуда берут необходимое?
  19. Вадим Смоленский

    Доступ к классу ApplicationData

    Простите мне мое невежество, но в каком именно месте можно на них взглянуть?
  20. Хочу еще раз обратиться к коллективному разуму в надежде все-таки разобраться с тем, как должен быть устроен пакет appx для размещения в Microsoft Store. А именно - как организовать размещение настроек и пользовательских файлов в специально отведенных для этого папках, а не в установочном каталоге, что запрещено. Вся информация, которую я смог к сегодняшнему дню накопать, размещена на этой странице майкрософтовской документации и сводится к тому, что при инсталляции пакета appx автоматически создается хранилище пользовательских данных из трех папок. Цитирую: one for local files, one for roaming files, and one for temporary files. В общем-то, это удобно - по крайней мере, не нужно заботиться о деинсталляции: ровно эти же папки при удалении программы и сотрутся. Вопрос в том, как к этому хранилищу обратиться. В идеале, конечно же, хотелось бы иметь возможность уже в Deployment Manager обозначить для некоторых файлов, что они должны быть положены в это хранилище, а не в установочный каталог. Но как это можно сделать и можно ли сделать вообще, мне понять не удалось. Списка констант для параметра Remote Path я найти не смог, а отдельные упоминаемые тут и там константы ('res', 'assets', 'classes', 'library') явно относятся к мобильным платформам, а не к Windows. Если так поступить нельзя, остается класть всё в установочный каталог, а при первом запуске приложения переносить в нужное место. Но опять же: как приложению заполучить полный адрес этого места? Ведь это вовсе не привычные нам CSIDL_APPDATA и не CSIDL_COMMON_APPDATA, это нечто новое, доселе невиданное, в документации называемое "local app data store". На той же странице есть пример соответствующего кода с использованием класса ApplicationData, но он написан на незнакомом мне C#. Там есть также ссылки на описание класса ApplicationData, но по ссылкам тоже C# и C++. Был бы очень признателен, если бы кто-нибудь показал мне, как заполучить адрес local app data store средствами Delphi.
  21. На форуме Эмбаркадеро этот вопрос я задал еще на прошлой неделе - то ли в четверг, то ли в пятницу. Получил сообщение: мол, ваш вопрос будет опубликован после того, как его просмотрит модератор. Сегодня уже среда, а модератор всё спит. Довольно странно функционирует этот форум, я уже не в первый раз замечаю. Существуют ли, интересно, способы как-то на них воздействовать? Обращался также к известному дельфийскому эксперту Марко Канту по электронной почте. Он несколько раз ответил - но видно было, что даже он в этих вопросах пока плавает. Теперь вовсе замолчал. Если в конце концов разберусь, то статья будет, обещаю. Но буксую уже второй месяц, и уверенности, что разберусь, всё меньше.
  22. Неловко спрашивать о таком на третьем десятке лет программирования на Delphi, но всё же спрошу. Вот предельно простой код: program MyProgram; uses MyUnit in 'MyUnit.pas' {MyForm}; var MyVariable: Boolean=False; {$R *.res} begin Application.Initialize; Application.CreateForm(TMyForm, MyForm); Application.Run; end. Как мне обратиться к переменной MyVariable из юнита MyUnit?
  23. Проверил, в FMX под Windows не работает. После выполнения GetProcAddress отладчик показывает, что i=nil. Да и бог с ним, что не работает. Я вижу, что тривиального решения нет - именно это и хотел узнать. А способ с отдельным юнитом меня вполне устраивает.
  24. Специального смысла нет. Я просто был уверен, что существует некий способ такого обращения, и мне было досадно, что я его не знаю. В практическом же плане меня вполне устроит и подсказанный способ - тем более, что юнит с глобально используемыми процедурами в моем проекте уже есть, мне просто не пришло в голову разместить там же глобальные переменные.
  25. Выходит, только так, а напрямую нельзя. Ну что ж, буду знать теперь, спасибо.