Компиляция NW RFC SDK, win7+msvs 2010 / 2022+win10

SM59:

Распаковал в одну папку NW RFC SDK 32-bit и samples.cab оттуда же.
В качестве рабочей среды у меня MSVS 2010 и Win7x86.
В студии: идём Файл -> Создать проект из существующего кода и указываем распаковыванную папку
Свойства проекта – Выбираем Плафторму Win32

в следующем окне (“Debug configuration settings”) оставляем все поля пустыми.

Свойства для nmake:

Параметры в файле

Вместо функций из libsapucum.dll (sapuc.h) можно использовать стандартные w-функции Microsoft (wchar.h). В Windows тип данных “SAP_UC” эквивалентен “wchar_t”. Например, вместо printfU() можно использовать wprintf(), а вместо getcU() – _getws().

Запускаем и нажимаем в SM59 тест соединения:

UPD 2022: проект компилируется в msvs 2022 + win10

Capture audio loopback (C Builder)

implib basswasapi.lib
Recording by BASS_WASAPI_Init every 0.5 second

Winamp hotkeys Ctrl+Alt+PgDown/PgUp plugin

Форк Winamp multimedia keyboard plugin, добавил поддержку клавиш Ctrl+Alt+PgDown (следующая песня) и Ctrl+Alt+PgUp (WM_HOTKEY)

Скачать: gen_mmkb.dll.cab

Сырцы:

github/winamp_kbd_plugin

copy& и std::move&&

Базовый код с запретом копирования и присваивания

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

Вывод программы:

Пока что никаких неожиданностей. Стоит отметить, что вместо:

… можно написать:

… тем самым явно указав на то, что вас устраивают реализации по умолчанию.

Copy constructor

Объявим copy contructor:

Заметьте, что в нем мы имеем доступ к private полям второго экземпляра класса (obj), несмотря на то, что это другой экземпляр. Вывод программы:

Оба синтаксиса эквивалентны, в обоих случаях был вызван copy constructor. Конструктор для каждого объекта был вызван один раз. Можно было и не писать этот код, так как реализация copy constructor по умолчанию и так просто копирует атрибуты класса.

Copy assignment

Объявим copy assignment оператор:

Вывод:

Coord2D(x = 1, y = 2) created
Coord2D(x = 1, y = 2) copied
Coord2D(x = 1, y = 2) copied
Coord2D(x = 1, y = 2) copy-assigned
Hi!
Coord2D(x = 1, y = 2) destroyed
Coord2D(x = 1, y = 2) destroyed
Coord2D(x = 1, y = 2) destroyed

Заметьте, что деструктор при присвоении не вызывается. Это означает, что в реализации copy assignment следует освобождать старые ресурсы перед присвоением новых значений.

Move constructor

Перепишем код следующим образом:

Вывод:

Coord2D(x = 1, y = 2) created
id called
Coord2D(x = 1, y = 2) copied
Coord2D(x = 1, y = 2) destroyed
Hi!
Coord2D(x = -1, y = 2) destroyed

Как видите, мы создаем копию из временного объекта, после чего он сразу уничтожается. Для нас это не проблема, так как объект маленький. Но если бы он содержал в себе большие объемы данных, мы бы создали их полную копию, а затем одну из копий освободили бы. Для решения этой проблемы придумали move constructor:

Вывод:

Coord2D(x = 1, y = 2) created
id called
Coord2D(x = 1, y = 2) moved
Coord2D(x = 1, y = 2) destroyed
Hi!
Coord2D(x = -1, y = 2) destroyed

Move constructor вызывается вместо copy constructor в случае, когда объект, из которого создается копия, вот-вот будет уничтожен. В таком конструкторе обычно данные из временного объекта переносятся в новый объект, а полям временного объекта присваиваются nullptr или что-то такое. Важно понимать, что при выходе из move constructor оба объекта должны оставаться валидными и для обоих должен корректно отрабатывать деструктор. Ссылка T&& называется rvalue reference и означает ссылку на объект, который вот-вот будет уничтожен.

Move assignment

Аналогично move constructor, только для присваивания. Например, код:

… выведет:

Coord2D(x = 1, y = 2) created
Coord2D(x = 4, y = 5) created
Coord2D(x = 4, y = 5) copy-assigned
Coord2D(x = 4, y = 5) destroyed
Hi!
Coord2D(x = 4, y = 5) destroyed

Объявим move assignment оператор:

Вывод:

Coord2D(x = 1, y = 2) created
Coord2D(x = 4, y = 5) created
Coord2D(x = 4, y = 5) move-assigned
Coord2D(x = 4, y = 5) destroyed
Hi!
Coord2D(x = 4, y = 5) destroyed

Move assignment оператор позволяет применить те же оптимизации, что и move constructor. В move constructor поля объекта, переданного в качестве аргумента, обычно как-то зануляются. В move assignment лучше сделать swap полей в двух объектах. Это позволит избавиться от дублирования кода между оператором move assignment и деструктором.

std::move

Move constructor бывает трудно стриггерить. Например, код:

… выведет:

Coord2D(x = 1, y = 2) created
Coord2D(x = 5, y = 2) copied
Coord2D(x = 5, y = 2) destroyed
Hi!
Coord2D(x = 5, y = 2) destroyed

Так происходит, потому что метод setX возвращает lvalue reference, а у move constructor на входе совершенно другой тип, rvalue reference. Чтобы явно показать, что временный объект мы больше использовать не будем, предусмотрен std:move. Если переписать код так:

… программа выведет:

Coord2D(x = 1, y = 2) created
Coord2D(x = 5, y = 2) moved
Coord2D(x = 5, y = 2) destroyed
Hi!
Coord2D(x = 5, y = 2) destroyed

В сущности, std::move просто кастует lvalue reference (T&) в rvalue reference (T&&), больше ничего. При чтении кода std::move как бы говорит нам, что мы отдаем владение объектом в этом месте и далее не собираемся его использовать.

std::forward

Шаблон std::forward предназначен исключительно для написания шаблонных методов, способных принимать на вход как lvalue, так и rvalue, в зависимости от того, что передал пользователь, и передавать соответствующий тип далее без изменений. Техника получила название perfect forwarding.

Рассмотрим пример. Определим оператор сложения двух координат:

Вывод:

Coord2D(x = 1, y = 1) created
Coord2D(x = 1, y = 2) created
Coord2D(x = 1, y = 3) created
Creating Coord2D t
Coord2D(x = 1, y = 1) copied
Coord2D t created!
Coord2D(x = 2, y = 3) copied
Coord2D(x = 2, y = 3) destroyed
Creating Coord2D t
Coord2D(x = 2, y = 3) moved
Coord2D t created!
[…]

Смотрите, что происходит. При первом вызове оператора сложения переменная t инициализируется при помощи copy constructor, так как c1 не является временным объектом. Однако при втором вызове первым аргументом передается временный объект c1 + c2, и из него переменная t инициализируется уже при помощи move constructor. То есть, фактически std::forward позволил написать процедуру один раз, вместо того, чтобы писать две версии — одну, принимающую первым аргументом lvalue reference, и вторую, работающую с rvalue reference.

Заключение

Заметьте, что думать про всякие move semantics и perfect forwarding нужно только при работе с объектами, держащими в себе много данных, и только если вы часто копируете или присваиваете такие объекты. Это исключительно оптимизация, и без нее все будет совершенно корректно работать (более того, ничего этого не существовало до появления C++11). Пока профайлер не говорит вам, что вы во что-то такое не уперлись, возможно, не стоит заморачиваться. Помните также, что компилятор зачастую может избавляться от лишнего копирования объектов, см return value optimization (RVO) и copy elision.

С другой стороны, теорию понимать стоит независимо от того, упирается ваш код в копирование и перемещение объектов, или нет. Как минимум, move semantics и иже с ним может использоваться в чужом коде. В частности, он используется в STL, см например метод emplace_back класса std::vector или метод emplace класса std::map. Кроме того, понимание move semantics будет весьма нелишним при использовании умных указателей.

Дополнительные материалы:

Александр Алексеев (“R2AUK”) eax.me/cpp-copying-and-moving

LoadString (BCB Builder)

Скриншот из сервиса Windows 7

Программа-сервис Windows XP, делающая снимки экрана, после переноса на Windows 7 начала сохранять вместо снимков просто белый фон.
Чтобы использовать основанную на коде ниже программу ru1smake, распакуйте архив в отдельную папку, установите ее как сервис (командой ru1smake.exe /install), задайте параметры в конфигурационном файле ru1smake.conf и запускайте через диспетчер служб. Удаление – командой ru1smake.exe /uninstall. Программа будет автоматически делать снимки экрана согласно указанным в конфиге параметрам.

Скачать программу ru1smake
версия 0.1 (07.08.10) | 0.3 Мб | stable

Дело в том, что начиная с Windows Vista, служба, запущенная от имени SYSTEM, более не может взаимодействовать с рабочим столом – службы теперь запускаются в изолированном сеансе (сессии) и загрузка своего процесса приведет к попытке запуска в неверном (вошедшего в систему пользователя) сеансе. Решить проблему можно, получив сессию залогинившегося пользователя. Вкратце, этот код делает следующее:

  1. Получает токен вошедшего в систему в данный момент пользователя, используя функцию WtsGetActiveConsoleSessionID
  2. Далее получает пользовательский токен, назначенный процессу (токен для службы от имени SYSTEM)
  3. Затем этот токен дублируется
  4. У скопированного токена изменяется сеанс (на вошедшего пользователя)
  5. Используя CreateProcessAsUser запускается процесс с измененным пользовательским токеном
  6. Процесс с системными правами, но будучи запущенным от имени вошедшего в систему пользователя в Windows 7, также позволит корректно работать GUI-программе как и любой другой.

Подготовка отладки операционной системы в VMware (v.6)

На хосте msvs (192.168.86.1):

На VM (192.168.86.130):

где b.d.f это Busnumber, Devicenumber, Functionnumber из команды powerShell выше
Ключ я быстро беру из msvs

Установить WinDbg из ms store, например, или отсюда.
Запускаем отладчик

Вводим настройки: windbg -k net:port=55555,key=1.2.3.4,target=192.168.86.130


Подключаемся

и включаем VM

Write < operator overloading (to use like std::cout)

Regex in BCB Builder

Отправка Ident с данными серверу

https://ru.wikipedia.org/wiki/Ident

tcpserver.pl:

github.com/tcpserver.pl

Insert math as
Block
Inline
Additional settings
Formula color
Text color
#333333
Type math using LaTeX
Preview
\({}\)
Nothing to preview
Insert