Универсальный конвертер текста 1.0

Универсальный конвертер текста 1.0

Янв 1, 2018 Статьи

Очередной релиз от меня – программка для конвертации текста в разные представления и вычисления хэшей, написанная на ассемблере (masm32).
Имеется быстрое копирование и вставка текста, сохранение и открытие текстовых файлов.

Поддерживает конвертацию:
* Text -> URLEncode
* Text -> String.fromCharCode (ascii)
* Text -> String.fromCharCode (utf)
* Text -> base64
* Text -> MySQL char
* Text -> HEX
* Text -> BIN
* Text -> chr()
* Text -> MSSQL char
* Text -> PostgreSQL
* Text -> MD5
* Text -> SHA1
* Text -> &#xxx; (ascii)
* Text -> &#xxx; (utf)
* Text -> \xhh
* Text -> %XX
* Text -> VB chr$()
* Text -> C# (char)
* Text -> Транслит
* URLEncoded -> Text
* base64 -> Text

Скриншот:

Скачать exe (10кб) и исходные коды: ZIP

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

Я рассмотрю:
[+] как создавать формы в стиле XP (современный вид элементов управления) с помощью программы ResEd
[+] как создавать и использовать в программе Unicode-строки, в том числе на русском языке
[+] как делать всплывающие подсказки к текстовым полям
[+] как использовать Windows CryptoAPI для генерации хэшей
[+] как использовать буфер обмена Windows для копирования и вставки текста

Напомню, что я использую в коде некоторые удобные макросы из файла macros/macros.asm, входящего в пакет masm32.

1. Как создавать формы в стиле XP (современный вид элементов управления) с помощью программы ResEd?
ResEd – маленькая бесплатная утилита для удобного создания файлов ресурсов.
Скачать его можно отсюда: ResEd.
Открываем редактор, создаем новый проект (File – New Project), добавляем к нему новое диалоговое окно (Project – Add Dialog).
Устанавливаем желаемые параметры окна во вкладке справа внизу, добавляем необходимые элементы управления, устанавливаем их параметры.
Чтобы все элементы выглядели в стиле XP, нужно добавить XP Manifest (Project – Add XP Manifest).
Сохраняем проект – получаем два файла – сам проект *.rc и манифест (xpmanifest.xml).
После того, как мы сохранили проект и вышли из редактора, надо немного подготовить файл ресурсов перед его использованием.
Открываем файл ресурсов (*.rc) в блокноте и добавляем в начало строку:

#include "\masm32\include\resource.h"

После этого удаляем строку (необязательно, но без этого у меня проект не запускался):

#define имя_нашей_формы 1000

Сохраняем файл – он готов к использованию в проекте.
Как же скомпилировать исходный код в asm вместе с файлом ресурсов в exe?
Для этого я использовал такой bat-файл (допустим, назовем его COMPILE.bat):

@echo off
cls
SET PATH=C:\Masm32\bin
SET INCLUDE=C:\Masm32\INCLUDE
SET LIB=C:\Masm32\LIB

Rc.exe /v %1.rc

ML /nologo -c -coff %1.asm
if errorlevel 1 goto terminate

LINK /nologo %1.obj %1.res /SUBSYSTEM:WINDOWS /STUB:64stub.exe /FILEALIGN:512 /VERSION:4.0 /RELEASE /BASE:0x400000
if errorLevel 1 goto terminate

echo OK

:terminate

Вызывается этот батник так:
– положите его в папку вместе с исходным кодом и файлом ресурсов *.rc (файлы *.rc и *.asm должны называться одинаково, например, converter.asm и converter.rc, в той же папке должен лежать xpmanifest.xml)
– в командной строке (cmd) перейдите в директорию с этими файлами (с помощью команды cd)
– выполните команду COMPILE имя_проекта (например COMPILE converter)
Если будет выведено “OK” – exe-файл был успешно создан в той же директории.

2. Как создавать и использовать в программе Unicode-строки,, в том числе и на русском языке?
В последней версии пакета masm32 имеется поддержка Unicode-строк и функций, но вот создать с его помощью русскую
Unicode-строку проблематично. Я для этого использовал набор макросов с wasm.ru, который позволяет делать русские Unicode-строки.
К сожалению, макрос создания строк содержит недостаток – каждый 120-й символ просто убирается из строки.
Я поправил недочет этого макроса, скачать исправленный можно тут: windows.asm.

Теперь, чтобы создать русскую Unicode-строку, подключаем макрос с помощью include к коду и пишем так:

.data
$$$STRINGW имя_переменной,"текст"
dw 0 ;терминирующие два нулевых байта

;или можно так:
$$$ZSTRINGW имя_переменной,"текст"

Соответственно, такие строки сожно использовать в любых Unicode-функциях (с постфиксом W, например, MessageBoxW).

3. Как делать всплывающие подсказки к текстовым полям?
Начиная с Win XP, у элементов управления Edit появилась возможность создавать всплывающие подсказки, как на первом скриншоте, я покажу, как такое реализовать.
Для показа такой подсказки необходимо послать текстовому полю сообщение EM_SHOWBALLOONTIP, а самой подсказкой управляет структура EDITBALLOONTIP.
Странно, но в inc-файлах масма32 такой структуры не оказалось, поэтому приходится задавать ее самим:

EDITBALLOONTIP STRUCT
    cbStruct dd ? ;размер структуры в байтах = 16
    pszTitle dd ? ;указатель на Unicode-строку с заголовком
    pszText dd ?  ;указатель на Unicode-строку с текстом
    ttiIcon dd ?  ;иконка структуры - TTI_INFO, TTI_WARNING, TTI_ERROR, TTI_NONE или TTI_INFO_LARGE, TTI_WARNING_LARGE, TTI_ERROR_LARGE
EDITBALLOONTIP ENDS

Далее, если у нас есть Edit-контрол с id=1003, то отобразить подсказку можно так:

.data
  $$$STRINGW pszTitle,"Заголовок" ;эти макросы описаны в п.2
  dw 0
  $$$STRINGW pszText,"Текст подсказки"
  dw 0
.data?
  btt EDITBALLOONTIP <>
.code
    mov btt.pszTitle,offset  ;заполняем структуру
    mov btt.pszText,offset pszText
    mov btt.ttiIcon,TTI_INFO
    mov btt.cbStruct,16

    invoke SendDlgItemMessage,hWnd,1004,EM_SCROLLCARET,0,0 ;скроллим поле ввода, чтобы была видна каретка - подсказка отображается именно в этом месте
    invoke SendDlgItemMessage,hWnd,1004,EM_SHOWBALLOONTIP,0,offset btt ;отображаем подсказку

4. Как использовать Windows CryptoAPI для генерации хэшей?
Для примера я покажу, как генерировать хэши MD5 и SHA1 для заданных строк.
Во-первых, для работы с крипто апи необходимо подключить inc-файл advapi32.inc и lib-файл advapi32.lib.
Приведу пример с комментариями из кода конвертора:

;здесь я определяю типы данных и константы, которых почему-то не оказалось в windows.inc
HCRYPTHASH equ dd
HCRYPTPROV equ dd
ALG_CLASS_HASH equ 32768

;...

.data? ;в секции неинициализированных данных определяю несколько переменных
        hHash HCRYPTHASH ?
        hProv HCRYPTPROV ?
        hash_size dd ?     ;сюда будет возвращаться размер хэша
        hash db 41 dup(?)  ;а сюда сам хэш

;...

.code

;...

      .if eax==9 || eax==10 ;если мы генерируем MD5 или SHA1 хэш
        push eax
        mov textlen,FUNC(lstrlen,membuf) ;записываем длину введенного текста в первое поле ввода
        invoke CryptAcquireContext,offset hProv, NULL, NULL, PROV_RSA_FULL, 0 ;создаем контекст для создания хэшей
        ;PROV_RSA_FULL как раз позволяет генерировать мд5 и sha1 (тут - подроблее).

        pop eax
        ;создаем хэш
        .if eax==9 ;если генерируем md5
          invoke CryptCreateHash,hProv,CALG_MD5,0,0,offset hHash ;тут мы указываем провайдер для криптования - hProv, для которого ранее создали контекст
        .else ;если sha1
          invoke CryptCreateHash,hProv,CALG_SHA1,0,0,offset hHash
        .endif

        invoke CryptHashData,hHash,membuf,textlen,0 ;генерируем хэш из строки в памяти membuf с длиной textlen
        invoke CryptGetHashParam,hHash,HP_HASHSIZE,offset hash_size,offset dwSize,0 ;получаем длину хэша
        invoke CryptGetHashParam,hHash,HP_HASHVAL,offset hash,offset hash_size,0 ;получаем его значение
        invoke CryptDestroyHash,hHash ;удаляем хэш
        invoke CryptReleaseContext,hProv,0 ;освобождаем контекст

        mov esi,membuf2
        mov edi,offset hash

        mov ecx,0
      hash_get: ;начинаем преобразовывать хэш в приемлемый текстовый вид
        push ecx
        movzx eax,byte ptr [edi]
        invoke wsprintf,esi,chr$("%2.2x"),eax

        inc edi
        add esi,2

        pop ecx
        inc ecx
        cmp ecx,hash_size
      jne hash_get

      ;теперь в памяти membuf2 содержится хэш в текстовом виде, и его можно вывести или использовать по своему усмотрению

5. Как использовать буфер обмена Windows для копирования и вставки текста?
Опять-таки приведу пару примеров из кода конвертора.

Копирование текста из текстового поля с id=1004:

      invoke OpenClipboard,hWnd ;откроем буфер обмена
      test eax,eax
      jz endcopy ;если не удалось открыть - выходим

      invoke EmptyClipboard ;очищаем буфер обмена


      invoke GetDlgItemText,hWnd,1004,membuf,buflen-1 ;получаем текст из текстового поля в память membuf
      inc eax

      mov clipboard,FUNC(GlobalAlloc,GMEM_MOVEABLE,eax) ;выделяем память для копирования
      test eax,eax
      jz endcopy2 ;если не удалось выделить - выходим и закрываем буфер обмена

      invoke GlobalLock,clipboard ;блокируем память и получаем указатель на первый байт этой памяти

      invoke lstrcpy,eax,membuf ;копируем туда текст

      invoke GlobalUnlock,clipboard ;разблокируем память

      invoke SetClipboardData,CF_TEXT,clipboard ;записываем данные в буфер обмена


      endcopy2:
      invoke CloseClipboard ;закрываем буфер обмена

      endcopy:

Вставка текста в поле с id=1003:

      invoke IsClipboardFormatAvailable,CF_TEXT ;есть ли в буфере обмена текстовые данные в ASCII?
      test eax,eax
      jz endpaste ;если нет - выходим

      invoke OpenClipboard,hWnd ;откроем буфер обмена
      test eax,eax
      jz endpaste ;если не удалось открыть - выходим

      mov clipboard,FUNC(GetClipboardData,CF_TEXT) ;получаем указатель на первый байт памяти
      test eax,eax
      jz endpaste2 ;если не удалось - выходим и закрываем буфер

      invoke GlobalLock,eax ;блокируем память и получаем указатель на первый байт этой памяти
      test eax,eax
      jz endpaste2 ;если не удалось - выходим и закрываем буфер

      invoke SetDlgItemText,hWnd,1003,eax ;устанавливаем текст в поле для ввода из этой памяти

      invoke GlobalUnlock,clipboard ;разблокируем память

      endpaste2:
      invoke CloseClipboard ;закрываем буфер обмена

      endpaste: