?

Log in

No-activate child windows

Objective:
We have a normal window, and we want to add such a button, which can be pressed in our window when it's inactive, and this won't steal the focus from the currently active window.

Example:
Touch keyboard button in the system taskbar of Windows 8/8.1/10:
   
Please note your active application is still active when you click this button, and loses the focus if you click in the taskbar's empty space.
    Classic solutions:

    • If we wanted to make a whole top-level window non-activatable, we could add WS_EX_NOACTIVATE to its ex-styles. Unfortunately, this style causes a lot of problems with top-level windows, and it cannot be applied to child windows.

    • Commonly used approach is to listen to WM_MOUSEACTIVATE message and answer MA_NOACTIVATE in case the control was clicked. This works, but only partially: The window won't be activated during the clicks, but the previously active window loses the active state, and GetForegroundWindow returns 0. This can be solved by remembering the last active window (either by periodical polling, or by monitoring EVENT_SYSTEM_FOREGROUND or HSHELL_WINDOWACTIVATED / HSHELL_RUDEAPPACTIVATED), and by forcibly restoring it.

    Win7-way of making this:
    Since Windows 7, there's a new undocumented API-function called SetChildWindowNoActivate, with ordinal 2005 in user32.dll. It can be declared like this (Delphi-style as usual :):

      function SetChildWindowNoActivate(ChildWnd: HWND): BOOL; stdcall;
        external 'user32.dll' index 2005;


    It is this function that is used in Windows 8/8.1/10 to make no-activate buttons like Touch keyboard, Virtual touchpad and Language switcher.

    Here's a screenshot of a sample application with a pushed no-activate button and an active Explorer window:
       
    ..., имеющее, однако, весьма существенное влияние на активацию карт в BaseCamp.

    До сих пор активация самодельных карт в BaseCamp всегда приводила к сбросу прописанного в карте ProductID в ноль, даже в том случае, если к навигатору была привязана какая-либо другая из подписок BirdsEye, скажем, BirdsEye TOPO (ProductID = 8).

    Однако, один из пользователей Global Mapper на днях выяснил, что пара байтов блока мета-информации в файлах JNX, ранее считавшиеся неиспользуемыми, на самом деле содержат идентификатор подписки, который используется BaseCamp при активации карты.
    Речь идет о втором и третьем байтах, следующих за строкой с названием продукта. И имеющиеся в данный момент JNX-конвертеры записывают в это поле ноль, что и приводит к сбросу номера подписки.

    Итак, вместо трех байтов с непонятным назначением имеем один байт непонятного назначения и два байта, в которых нужно дублировать значение ProductID из заголовка файла.

    Что касается оставшегося байта, следующего непосредственно за названием продукта, эксперименты показывают, что это на самом деле не нулевой байт, а строка нулевой длины. Если записать сюда произвольную строку в UTF-8, BaseCamp без проблем показывает карту, однако, записанная в этом поле строка нигде не отображается.
    Писать что-либо в это поле я бы не рекомендовал, так как в этом случае карта может не открываться в сторонних программах, поддерживающих формат JNX.

    Информация про эти новые два поля данных уже внесена в описание формата. Также необходимые исправления были сделаны в коде библиотеки JNXLib, использующейся в SAS.Planet (исправление уже ушло в свежую ночную сборку) и в Global Mapper (ожидается, что новая версия библиотеки будет включена в версию 15.1.8).

    Всем разработчикам инструментов с поддержкой сохранения карт JNX рекомендуется внести соответствующие исправления в свои программы для удобства пользователей.

    Метки:

    Файлы MTX в программе Mapsource Product Creator, фактически, выполняют точно те же функции, что и MP-файлы в GpsMapEdit, то есть содержат полное описание карты, передаваемое компилятору.
    Единственное отличие в том, что MTX создается MPC непосредственно перед передачей компилятору карт bld_gmap32.exe и удаляется сразу же после компиляции (если не установлена опция сохранения временных файлов).

    Никто не мешает сделать собственный файл в формате MTX и на его основе скомпилировать IMG-карту с практически произвольными параметрам и содержимым. Именно этот способ применяется в конвертере jnx2img (см. тут или тут).
    Ну или остановить компиляцию карты в MPC, взять промежуточный MTX и исправить его нужным образом.

    Описать структуру MTX-файла полностью я не смогу не только потому, что лень, но и по той простой причине, что меня интересовало только создание растровых IMG, так что всякие особенности векторных элементов я просто не изучал.

    Так что я просто приведу тот список параметров-опций (с префиксом H4), которые изучал в процессе подбора нужных мне параметров. Список в том виде, который валяется у меня на диске, особо не редактировал. Для некоторых параметров удалось установить, в каком поле заголовка TRE они хранятся - такие поля указаны в скобках.
        3d  - Map intended for 3d mesh display (TRE + 0x42, mask 20)
        ti  - map template ID
        af  - FTR address finder
        cp  - Include clip region in map
        csN - text packing
          N=2 - 8-bit SBCS Text packing
          N=3 - 8-bit DBCS Text packing
          N=4 - 8-bit Huffman SBCS Text packing
          N=5 - 8-bit Huffman DBCS Text packing
        cr  - copyright string
        ds  - driving side, 0 - right, 1 - left (TRE + 0x3f, mask 20)
        df  - DEM options
        erN - Extended resolution bits, N=0..4
        ffNNNN - FTR group enumeration
        fhMN
          M - .MDR-file version (must be 1 in GMP)
          N - Multi-body records in FTR
        ft  - .FTR file creation
        id  - Map identifier
        la  - language
        ll  - Create Link Location Records in .NET file
        maN - Maximum area vertices number
        mb  - Combinable Map (TRE + 0x043)
        mcN - map class
        mdN - Map display priority
        mf  - Map format. 1 - old, 2 - NT
        mg  - make GMP
        mlN - Maximum line vertices number
        mo  - transparent map (TRE + 0x3f, mask 02)
        mt  - 0 - full map / 1 - partial map (TRE + 0x3f, mask 01)
        ms  - Map series id (TRE + 0x45)
        nb  - Node blocking factor
        ns  - node block size
        nt  - .NET file creation
        pf  - Point-finder records
        pp  - Postal code displayed 0 - AFTER / 1 - BEFORE city or state (TRE + 0x3f, mask 08)
        hp  - House number displayed 0 - BEFORE / 1 - AFTER street name (TRE + 0x3f, mask 04)
        pnMN
          M=1 - Export POI phone numbers to MDR
          N=0 - Create formatted phone numbers
        sp  - Single-pass line simplification
        tf  - Generate a .ITF Traffic file
        tl  - Maximum text length
        wm  - Map background is WATER (TRE + 0x3f, mask 10)


    Что интересно, компилятор умеет делать 3 типа IMG - старый (не-NT), не-NTшный GMP, и честный NTшный GMP. Единственное отличие, если я правильно понимаю, заключается в столь долго не поддающейся реверсингу упаковке координат объектов в полноценном NT-формате.

    Метки:

    В различных частях контейнера IMG имеются блоки данных, длина которых задается одним или более байтами. Все источники информации о IMG, с которыми я до сих пор сталкивался, упоминают, что для определения количества байтов, задающих длину блока, используется младший бит первого байта - если он равен единице, то для кодирования длины используются остальные 7 битов первого байта, а данные блока начинаются со второго байта; если же младший бит равен нулю, то длина кодируется оставшимися 7 битами первого байта и вторым байтом целиком, данные же в этом случае начинаются с третьего байта.

    Исследования BaseCamp показывают, что описанный выше подход - лишь частный случай. На самом деле для указания длины используется до 4 первых байтов, а то, какое количество байтов должно быть использовано, определяется по младшим 3 битам первого байта. Для упрощения объяснения постараюсь изобразить все возможные комбинации схематично:

    1 случай - младший бит равен 1, для кодирования длины блока используются 7 старших битов первого байта:
      b7 b6 b5 b4 b3 0 0 | 1
      b7 b6 b5 b4 b3 0 1 | 1
      b7 b6 b5 b4 b3 1 0 | 1
      b7 b6 b5 b4 b3 1 1 | 1

    2 случай - младший бит равен 0, следующий бит равен 1, для кодирования используются 6 старших битов первого байта и второй байт целиком:
      byte1  b7 b6 b5 b4 b3 0 | 1 0
      byte1  b7 b6 b5 b4 b3 1 | 1 0

    3 случай - два младших бита равны 0, а следующий равен 1, длина блока задается 5 старшими битами первого байта, а также двумя следующими байтами:
      byte2 byte1  b7 b6 b5 b4 b3 | 1 0 0

    4 случай - все три младших бита первого байта равны 0, в этом случае длина блока опять же задается 5 старшими битами первого байта, но к ним добавляется уже 3 следующих байта:
      byte3 byte2 byte1  b7 b6 b5 b4 b3 | 0 0 0

    Для того, чтобы вычислить длину блока, можно проверить значения младших битов первого байта, а потом взять от 1 до 3 дополнительных байтов для вычисления самой длины - этот способ идеален при поточном чтении из файла.
    Другой способ ("арифметический") можно использовать, если весь блок данных уже есть в памяти, и просто требуется понять, где заканчивается очередной блок:
      unsigned long GetBlockLength(const unsigned char* &BufPtr) {
        const unsigned long masks[8]   =
          { 0x1FFFFFFF, 0x7F, 0x3FFF, 0x7F, 0x1FFFFF, 0x7F, 0x3FFF, 0x7F };
        const unsigned char counts[8]  =
          {          4,    1,      2,    1,        3,    1,      2,    1 };
        const unsigned char rshifts[8] =
          {          3,    1,      2,    1,        3,    1,      2,    1 };
      
        unsigned long CurValue   = *BufPtr;
        unsigned char Lower3Bits = CurValue & 7;
      
        unsigned long BlockLength = CurValue >> rshifts[Lower3Bits];
        BlockLength &= masks[Lower3Bits];
      
        BufPtr += counts[Lower3Bits];
      
        return BlockLength;
      }

    В принципе, можно обойтись и без and-масок, но по какой-то причине в BaseCamp код вычисления длины именно такой.

    Метки:

    Продолжение темы, поднятой в предыдущем посте.

    Возьмем тупое тестовое приложение вот такого видаЧитать дальше...Свернуть )

    В итоге имеем два способа получить символы в отладчике для 64х-битного модуля, откомпилированного в Delphi XE2:
    1. воспользоваться пропатченной версией map2dbg, либо руками исправить поле Machine в заголовке DBG-файла, чтобы просто загрузить символы, но без раскрутки стека;
    2. использовать пропатченную библиотеку dbghelp.dll, позволяющую загрузить DBG-файл без необходимости править в нем поле Machine, а также видеть корректные стековые фреймы.

    Пропатченные версии DBGHELP из комплекта WinSDK для Windows 8 доступны в этом архиве.

    Метки:

    Общеизвестный факт: замечательная утилита map2dbg позволяет взять MAP-файл, полученный при компиляции 32х-битного проекта на Delphi/Builder, и сделать из него DBG. С полученным DBG сможет работать WinDbg, Process Explorer, IDA Pro и ряд других программ.

    Веселье заканчивается при компиляции проекта под Win64. То есть map2dbg работает, делает DBG-файл, однако, этот файл отладчики не видят.
    WinDbg выдает при загрузке символов сообщение "DBGHELP: ... mismatched timestamp", а Process Explorer файл вообще не замечает.
    Читать дальше...Свернуть )

    Метки:

    В продолжение темы, затронутой в одной из предыдущих записей.

    Как выяснилось, под Windows 8 Release Preview атрибут WCA_CLIENTRENDERING_POLICY уже вовсе не 16, а 15.

    Метки:

    Как владелец гарминовского туристического навигатора, поддерживающего растровые карты, я очень заинтересован запихнуть эти самые растровые карты в свой навигатор наибольшим возможным количеством извратных способов.

    С форматом JNX, можно считать, разобрались. Настало время поковырять формат IMG.

    Изначально векторный, этот формат был некоторое время назад "прокачан" до поддержки DEM-слоев и спутниковых снимков местности в формате JPEG. В качестве примеров могу привести карты Garmin GB Discoverer (искать на файлопомойках) и свободно доступную карту острова Мэн.

    Читать дальше...Свернуть )

    Метки:

    JNX scale values explained

    Русская версия здесь.

    JNX format description contains the following "standard" set of scale values, which is recommended to use in the hand-made JNX maps: 75, 149, 298, 597, 1194, 2388, 4777, 9554, 19109, 38218, 76437, 152877, 305758, 611526, 1223072, 2446184.

    This set is an extension of the set used in BirdsEye subscription maps: 597, 1194, 4777 and 76437.
    Still, there were no explanation of what these numbers mean.

    Several days ago, I got a mail from Dmitry Sklyarov with quite logical reasoning.
    Читать дальше...Свернуть )

    Метки:

    English version is here.

    Описание формата JNX содержит следующий набор "стандартных" значений масштабов, которые рекомендуется использовать в файлах JNX: 75, 149, 298, 597, 1194, 2388, 4777, 9554, 19109, 38218, 76437, 152877, 305758, 611526, 1223072, 2446184.

    Это набор представляет собой расширение набора значений, применяемых в картах подписки BirdsEye, а именно 597, 1194, 4777 и 76437.
    Однако, пока не было сколько-либо внятного объяснения того, что на самом деле означают эти числа.
    На днях Дмитрий Скляров прислал письмо, содержащее достаточно подробное обоснование выбора именно этих значений.
    Читать дальше...Свернуть )

    Метки: