1
0
Fork 0

Compare commits

..

No commits in common. "7f7d10aeee55d0af1b33408880440873dcd9425e" and "18828ca7207fbd11662b40ca5a9759ea6cdf348a" have entirely different histories.

19 changed files with 10324 additions and 257 deletions

View file

@ -1,16 +0,0 @@
#!/bin/bash
format() {
sed -e 's/^fix:/доза:/' \
-e '/^# ------------------------ >8 ------------------------$/,$d' \
-e '/^#/d'
}
translated="$(curl -s \
http://localhost:9000/translate \
-H 'Content-Type: text/html' \
--data-binary @- -o- < <(format < "$1") | \
tail -n +2 | \
perl -pe 's,<SPAN CLASS=UNKNOWN_WORD>(.*?)</SPAN>,\1,g')"
[ -n "$translated" ] && echo "$translated" > "$1"

4
.gitignore vendored
View file

@ -1,4 +1,6 @@
build/
.cache/ .cache/
/test
build/
cache/
cmake-build*/ cmake-build*/
compile_commands.json compile_commands.json

3
.gitmodules vendored
View file

@ -1,3 +0,0 @@
[submodule "puppy/include/http"]
path = puppy/include/http
url = https://github.com/yhirose/cpp-httplib

View file

@ -1,34 +0,0 @@
# promty
## Собирание
Чтобы строить проект, Вы нуждаетесь:
1. Получить **законную копию** &quot;X-переводчика ПРОМТ Magic Gooddy 6.0.0.205&quot; (да, мы фактически имеем эти DVD),
2. Установите это на вашей машине "Окна"
3. Бегите сервером SSH на той машине
4. Управляемый `puppy/scripts/prepare_environment.sh "WINDOWS_USER@WINDOWS_IP"`. Это будет тянуть все необходимые файлы и ключи регистр
5. Управляемый `docker compose up -d --build`
## Вклад
### Передайте Стиль
Эти использования проекта, для которых "обычное передает формат", передают сообщения.
```
напечатайте [возможности]: передайте описание
дополнительное тело
дополнительная нижняя
```
Мы используем только известный, стандартизированный передают типы как определено спецификацией:
| Напечатать | Описание |
|------------------------|-----------------------------------------------------------------------------------------------------------|
| `подвиг` | Добавляет, что новая особенность к codebase |
| `доза` | Залатать неполадки в codebase |
| `доктора` | Изменения только для докторов |
| `тест` | Сменить испытания |
| `хозяйственная работа` | Изменения, которые непосредственно не затрагивают кодекс, типа ударов версии или обновлений иждивенчества |

View file

@ -14,10 +14,6 @@ http://ядро.орг, http://*.ядро.орг {
# we don't want to flood the upstream from the same IP # we don't want to flood the upstream from the same IP
mode bypass mode bypass
ttl 30m ttl 30m
timeout {
backend 10m
}
} }
import Caddyfile.yadro proxy:80 import Caddyfile.yadro proxy:80
@ -27,24 +23,13 @@ http://ядро.орг, http://*.ядро.орг {
reverse_proxy { reverse_proxy {
dynamic a puppy 80 dynamic a puppy 80
lb_policy least_conn lb_policy least_conn
transport http {
response_header_timeout 10m
read_timeout 10m
write_timeout 10m
}
} }
cache { cache {
allowed_http_verbs POST allowed_http_verbs POST
ttl 7d ttl 7d
key {
headers X-Translation-Direction
}
timeout { timeout {
backend 10m backend 1m
} }
} }
} }

View file

@ -75,6 +75,6 @@ handle @surely_static {
redir @known_host https://{kernel}{uri} permanent redir @known_host https://{kernel}{uri} permanent
} }
# TODO: cache by path for 30 minutes # TOOO: cache by path for 30 minutes
reverse_proxy {args[0]} reverse_proxy {args[0]}

View file

@ -1,6 +1,8 @@
FROM caddy:builder AS builder FROM caddy:builder AS builder
RUN --mount=type=cache,target=/go/pkg/mod xcaddy build \ RUN --mount=type=cache,target=/go/pkg/mod xcaddy build \
--with github.com/caddyserver/cache-handler --with github.com/caddyserver/cache-handler
FROM caddy:latest FROM caddy:latest
COPY --from=builder /usr/bin/caddy /usr/bin/caddy COPY --from=builder /usr/bin/caddy /usr/bin/caddy

View file

@ -1,35 +1,33 @@
services: services:
puppies: puppies:
networks: [promty] networks:
- promty
build: puppy build: puppy
hostname: puppy hostname: puppy
stop_signal: SIGINT
volumes: volumes:
- /dev/shm/puppy-temp:/tmpfs - /dev/shm/puppy-temp:/tmpfs
- ./cache:/cache
deploy: deploy:
mode: replicated mode: replicated
replicas: 3 replicas: 1
endpoint_mode: vip endpoint_mode: vip
update_config:
order: start-first
proxy: proxy:
networks: [promty] networks:
- promty
container_name: proxy container_name: proxy
build: proxy build: proxy
depends_on:
puppies:
condition: service_healthy
caddy: caddy:
networks: [promty] networks:
- promty
container_name: caddy container_name: caddy
build: caddy build: caddy
volumes: volumes:
- ./caddy:/etc/caddy - ./caddy:/etc/caddy
depends_on: [proxy]
ports: ports:
- 80:80 - 80:80
- 9000:9000
networks: networks:
promty: promty:

10
domains
View file

@ -25,7 +25,7 @@
линукс.ядро.орг linux.kernel.org линукс.ядро.орг linux.kernel.org
саял.ядро.орг lkml.kernel.org саял.ядро.орг lkml.kernel.org
уздечка.ядро.орг lore.kernel.org уздечка.ядро.орг lore.kernel.org
кольчуга.ядро.орг mail.kernel.org почта.ядро.орг mail.kernel.org
социальные.сми.ядро.орг media.social.kernel.org социальные.сми.ядро.орг media.social.kernel.org
край.зеркал.ядро.орг mirrors.edge.kernel.org край.зеркал.ядро.орг mirrors.edge.kernel.org
зеркала.ядро.орг mirrors.kernel.org зеркала.ядро.орг mirrors.kernel.org
@ -33,7 +33,7 @@
уздечка.сппн.ядро.орг nntp.lore.kernel.org уздечка.сппн.ядро.орг nntp.lore.kernel.org
нью-йоркские.зеркала.ядро.орг ny.mirrors.kernel.org нью-йоркские.зеркала.ядро.орг ny.mirrors.kernel.org
источник.нук.ядро.орг nyc.source.kernel.org источник.нук.ядро.орг nyc.source.kernel.org
прокладка.ядро.орг pad.kernel.org клавиатура.ядро.орг pad.kernel.org
доктора.париж.ядро.орг parisc.docs.kernel.org доктора.париж.ядро.орг parisc.docs.kernel.org
путаница.ядро.орг patchwork.kernel.org путаница.ядро.орг patchwork.kernel.org
люди.ядро.орг people.kernel.org люди.ядро.орг people.kernel.org
@ -43,13 +43,13 @@
источник.греха.ядро.орг sin.source.kernel.org источник.греха.ядро.орг sin.source.kernel.org
пппп.ядро.орг smtp.kernel.org пппп.ядро.орг smtp.kernel.org
уздечка.пппп.ядро.орг smtp.lore.kernel.org уздечка.пппп.ядро.орг smtp.lore.kernel.org
подпространство.пппп.ядро.орг smtp.subspace.kernel.org подместо.пппп.ядро.орг smtp.subspace.kernel.org
пппп1.ядро.орг smtp1.kernel.org пппп1.ядро.орг smtp1.kernel.org
пппп2.ядро.орг smtp2.kernel.org пппп2.ядро.орг smtp2.kernel.org
пппп3.ядро.орг smtp3.kernel.org пппп3.ядро.орг smtp3.kernel.org
социальное.ядро.орг social.kernel.org социальный.ядро.орг social.kernel.org
редкие.доктора.ядро.орг sparse.docs.kernel.org редкие.доктора.ядро.орг sparse.docs.kernel.org
подпространство.ядро.орг subspace.kernel.org подместо.ядро.орг subspace.kernel.org
зеркала.резюме.ядро.орг sv.mirrors.kernel.org зеркала.резюме.ядро.орг sv.mirrors.kernel.org
сай.отражает.ядро.орг sy.mirrors.kernel.org сай.отражает.ядро.орг sy.mirrors.kernel.org
мпук.ядро.орг vger.kernel.org мпук.ядро.орг vger.kernel.org

View file

@ -1,15 +1,10 @@
FROM golang:1.23-alpine AS builder FROM golang:1.23-alpine AS builder
WORKDIR /build WORKDIR /build
COPY . . COPY . .
RUN --mount=type=cache,target=/go/pkg/mod go build
RUN --mount=type=cache,target=/go/pkg/mod go build;
FROM alpine AS runner FROM alpine AS runner
WORKDIR /app WORKDIR /app
COPY --from=builder /build/proxy . COPY --from=builder /build/proxy .
EXPOSE 80/tcp EXPOSE 80/tcp
CMD ./proxy CMD ./proxy

View file

@ -23,7 +23,6 @@ func main() {
// We only support gzip decoding // We only support gzip decoding
r.Out.Header.Set("Accept-Encoding", "gzip") r.Out.Header.Set("Accept-Encoding", "gzip")
r.Out.Header.Set("User-Agent", "ядро.орг/1.0")
}, },
ModifyResponse: func(r *http.Response) error { ModifyResponse: func(r *http.Response) error {
// Disable security policy because of the domain restrictions. // Disable security policy because of the domain restrictions.
@ -68,7 +67,7 @@ func main() {
return original_raw return original_raw
} }
return []byte("https://" + yadro + "/") return []byte("http://" + yadro + "/") // TODO: https
}))) })))
} }
@ -88,15 +87,11 @@ func main() {
http.ListenAndServe("0.0.0.0:80", proxy) http.ListenAndServe("0.0.0.0:80", proxy)
} }
func replaceDomains(response string) string { func replaceDomains(response []byte) []byte {
re := regexp.MustCompile(`(?i)[A-Za-z\-\.]*\.?kernel\.org`) re := regexp.MustCompile(`(?i)[A-Za-z\-\.]*\.?kernel\.org`)
response = strings.NewReplacer(
"%3F", "?",
"%26", "&",
).Replace(response)
response = re.ReplaceAllStringFunc(response, func(original_raw string) string { response = re.ReplaceAllFunc(response, func(original_raw []byte) []byte {
kernel := strings.ToLower(original_raw) kernel := strings.ToLower(string(original_raw))
// Strip `www.` // Strip `www.`
kernel = strings.TrimPrefix(kernel, "www.") kernel = strings.TrimPrefix(kernel, "www.")
@ -108,46 +103,42 @@ func replaceDomains(response string) string {
return original_raw return original_raw
} }
return yadro return []byte(yadro)
}) })
response = bytes.ReplaceAll(response, []byte("%3F"), []byte("?"))
response = bytes.ReplaceAll(response, []byte("%26"), []byte("&"))
response = bytes.ReplaceAll(response, []byte("https"), []byte("http")) // TODO: TEMP
return response return response
} }
func translateWithPromtPuppies(response string) string { func translateWithPromtPuppies(response []byte) []byte {
// Don't try to translate empty body (30x, etc) // Don't try to translate empty body (30x, etc)
if len(response) == 0 { if len(response) == 0 {
return response return response
} }
req, _ := http.NewRequest("POST", "http://caddy:9000/translate", strings.NewReader(response)) req, _ := http.NewRequest("POST", "http://caddy:9000/translate", bytes.NewReader(response))
req.Header.Add("Content-Type", "text/html") req.Header.Add("Content-Type", "text/html")
resp, err := http.DefaultClient.Do(req) resp, err := http.DefaultClient.Do(req)
if err != nil { if err != nil {
fmt.Fprintln(os.Stderr, "Error in while translating", err) fmt.Fprintln(os.Stderr, "Error in first", err)
return "" return []byte{0}
} }
var translated strings.Builder response, _ = io.ReadAll(resp.Body)
io.Copy(&translated, resp.Body)
resp.Body.Close() resp.Body.Close()
return translated.String() return response
}
func enfunnify(response string) string {
return strings.NewReplacer(
"tarball", "tar ball",
).Replace(response)
} }
func modifyResponse(response []byte) []byte { func modifyResponse(response []byte) []byte {
s := string(response) response = translateWithPromtPuppies(response)
s = enfunnify(s) response = replaceDomains(response)
s = translateWithPromtPuppies(s) return response
s = replaceDomains(s)
return []byte(s)
} }

View file

@ -1,47 +1,41 @@
#check=skip=JSONArgsRecommended #check=skip=JSONArgsRecommended
FROM debian:12-slim AS builder
FROM debian:13-slim AS builder
RUN apt-get update && DEBIAN_FRONTEND=noninteracive apt-get install -y \ RUN apt-get update && DEBIAN_FRONTEND=noninteracive apt-get install -y \
--no-install-recommends cmake g++-mingw-w64-i686-posix g++ make && \ --no-install-recommends cmake g++-mingw-w64-i686-posix g++ make && \
apt-get clean && rm -rf /var/lib/apt/lists/*; apt-get clean && rm -rf /var/lib/apt/lists/*
WORKDIR /build WORKDIR /build
COPY . .
COPY app/healthcheck.cpp app/healthcheck.cpp RUN g++ -o healthcheck -I./include ./app/healthcheck.cpp
COPY include/http include/http
RUN g++ -o healthcheck -I./include ./app/healthcheck.cpp;
COPY app app
COPY include include
COPY src src
COPY CMakeLists.txt .
RUN --mount=type=cache,target=cmake-build cmake -B cmake-build \ RUN --mount=type=cache,target=cmake-build cmake -B cmake-build \
-DCMAKE_CXX_COMPILER=i686-w64-mingw32-g++ && cmake --build cmake-build -j$(nproc) && \ -DCMAKE_CXX_COMPILER=i686-w64-mingw32-g++ && cmake --build cmake-build -j$(nproc) && \
cp cmake-build/promt-puppy.exe .; cp cmake-build/promt-puppy.exe .
FROM debian:12-slim AS runner
FROM debian:13-slim AS runner
ENV WINEPREFIX=/wineprefix \ ENV WINEPREFIX=/wineprefix \
XDG_RUNTIME_DIR=/tmp/ \ DEBIAN_FRONTEND=noninteracive
DEBIAN_FRONTEND=noninteracive \
WINEDEBUG=-all
RUN dpkg --add-architecture i386 && apt-get update && \ RUN dpkg --add-architecture i386 && apt-get update && \
apt-get install -y --no-install-recommends \ apt-get install -y --no-install-recommends \
wine wine64 wine32:i386 && \ wine wine64 wine32:i386 && \
apt-get clean && rm -rf /var/lib/apt/lists/* && \ apt-get clean && rm -rf /var/lib/apt/lists/* && \
mkdir -p /tmpfs $WINEPREFIX/drive_c && ln -sf /tmpfs $WINEPREFIX/drive_c/tmpfs; wineboot -i && echo "Sleeping for 15 seconds..." && sleep 15 && \
mkdir /tmpfs && ln -sf /tmpfs $WINEPREFIX/drive_c/tmpfs
COPY build/ $WINEPREFIX/drive_c COPY build/ $WINEPREFIX/drive_c
RUN wine regedit $WINEPREFIX/drive_c/registry.reg && \
echo "Sleeping for 15 seconds" && sleep 15
WORKDIR /app WORKDIR /app
COPY --from=builder /build/promt-puppy.exe /build/healthcheck . COPY --from=builder /build/promt-puppy.exe /build/healthcheck .
HEALTHCHECK --start-period=30s --start-interval=1s CMD ./healthcheck;
HEALTHCHECK CMD ./healthcheck
EXPOSE 80/tcp EXPOSE 80/tcp
VOLUME /cache VOLUME /cache
STOPSIGNAL SIGINT
COPY docker-entrypoint.sh /entrypoint.sh ENV WINEDEBUG=-all
ENTRYPOINT ["/entrypoint.sh"]
CMD exec wine promt-puppy.exe

View file

@ -1,4 +1,4 @@
#include "http/httplib.h" #include "httplib.hpp"
int main() { int main() {
auto res = httplib::Client("127.0.0.1", 80).Get("/health"); auto res = httplib::Client("127.0.0.1", 80).Get("/health");

View file

@ -1,62 +1,18 @@
#include "http/httplib.h" #include "httplib.hpp"
#include <csignal>
#include <cstdint>
#include <cstdlib>
#include <filesystem> #include <filesystem>
#include <fstream> #include <fstream>
#include <functional>
#include <iostream> #include <iostream>
#include <mutex> #include <mutex>
#include <windows.h>
#include <winternl.h>
#include "PromtCtlDocument.hpp" #include "PromtCtlDocument.hpp"
#include "PromtFTManager.hpp" #include "PromtFTManager.hpp"
#define EPOCH_DIFF 116444736000000000LL
#define TICKS_PER_SEC 10000000LL
static LARGE_INTEGER fake_time;
static NTSTATUS WINAPI HookedNtQuerySystemTime(PLARGE_INTEGER time)
{
if (time)
time->QuadPart = fake_time.QuadPart;
fake_time.QuadPart += TICKS_PER_SEC;
return 0;
}
static void InstallTimeHook()
{
HMODULE ntdll = GetModuleHandleA("ntdll.dll");
if (!ntdll)
return;
auto target = (BYTE *)GetProcAddress(ntdll, "NtQuerySystemTime");
if (!target)
return;
DWORD old;
VirtualProtect(target, 5, PAGE_EXECUTE_READWRITE, &old);
intptr_t rel = (BYTE *)HookedNtQuerySystemTime - target - 5;
target[0] = 0xE9; // jmp rel32
*(int32_t *)(target + 1) = (int32_t)rel;
VirtualProtect(target, 5, old, &old);
const char *env = std::getenv("FAKETIME");
long long unix_ts = env ? std::strtoll(env, nullptr, 10) : 0;
fake_time.QuadPart = unix_ts * TICKS_PER_SEC + EPOCH_DIFF;
}
static inline std::string random_filename(int len = 65) { static inline std::string random_filename(int len = 65) {
static const char ASCII_PRINTABLE[] = "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; static const char ASCII_PRINTABLE[] = "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
static std::random_device random_device; std::random_device random_device;
static std::mt19937 generator(random_device()); std::mt19937 generator(random_device());
static std::uniform_int_distribution distribution(0, static_cast<int>(strlen(ASCII_PRINTABLE) - 1)); std::uniform_int_distribution distribution(0, static_cast<int>(strlen(ASCII_PRINTABLE) - 1));
std::string random_string; std::string random_string;
random_string.reserve(len); random_string.reserve(len);
for (int i = 0; i < len; ++i) for (int i = 0; i < len; ++i)
@ -105,20 +61,11 @@ static inline auto read_file(const std::string &filename) {
size = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, 0, 0); size = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, 0, 0);
std::string out; std::string out;
out.resize(size - 1); out.resize(size);
WideCharToMultiByte(CP_UTF8, 0, wstr, -1, out.data(), size - 1, 0, 0); WideCharToMultiByte(CP_UTF8, 0, wstr, -1, out.data(), size, 0, 0);
delete[] wstr; delete[] wstr;
std::string out_lf; return out;
out_lf.reserve(out.size());
for (auto c : out) {
if (c == '\r')
continue;
out_lf.push_back(c);
}
return out_lf;
} }
class WebServer { class WebServer {
@ -195,8 +142,7 @@ class WebServer {
public: public:
WebServer() { WebServer() {
if (!std::filesystem::exists(TMP_FOLDER)) if (!std::filesystem::exists(TMP_FOLDER)) std::filesystem::create_directory(TMP_FOLDER);
std::filesystem::create_directory(TMP_FOLDER);
m_svr.Post("/translate", [this](const httplib::Request &req, httplib::Response &res) { m_svr.Post("/translate", [this](const httplib::Request &req, httplib::Response &res) {
TranslateHandler(req, res); TranslateHandler(req, res);
@ -213,7 +159,6 @@ class WebServer {
} }
void listen(const char *host = "0.0.0.0", unsigned short port = 80) { void listen(const char *host = "0.0.0.0", unsigned short port = 80) {
print("started!");
m_svr.listen(host, port); m_svr.listen(host, port);
} }
@ -224,23 +169,12 @@ class WebServer {
} }
}; };
static std::function<void(int)> signal_action;
void signal_handler(int signal) {
signal_action(signal);
}
int main() { int main() {
InstallTimeHook(); print("Starting...");
CoInitializeEx(NULL, COINIT_MULTITHREADED); CoInitializeEx(NULL, COINIT_MULTITHREADED);
CoInitializeSecurity(nullptr, -1, nullptr, nullptr, RPC_C_AUTHN_LEVEL_NONE, RPC_C_IMP_LEVEL_IDENTIFY, nullptr, EOAC_NONE, nullptr); CoInitializeSecurity(nullptr, -1, nullptr, nullptr, RPC_C_AUTHN_LEVEL_NONE, RPC_C_IMP_LEVEL_IDENTIFY, nullptr, EOAC_NONE, nullptr);
WebServer ws; WebServer ws;
signal_action = [&](int x) { ws.stop(); };
std::signal(SIGTERM, signal_handler);
std::signal(SIGINT, signal_handler);
ws.listen(); ws.listen();
} }

View file

@ -1,12 +0,0 @@
#!/bin/bash
# shellcheck disable=SC2155
echo 'initializing wine...'
wineboot -i
echo 'copying registy values...'
wine regedit "$WINEPREFIX"/drive_c/registry.reg
export FAKETIME="$(cat "$WINEPREFIX"/drive_c/build-date)"
echo "starting with date $(date -d @"$FAKETIME")..."
exec wine /app/promt-puppy.exe

@ -1 +0,0 @@
Subproject commit adf58bf474fac638160592d6c3f67da4ebc7df20

10243
puppy/include/httplib.hpp Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,25 +1,15 @@
#!/bin/bash -e #!/bin/bash -e
# shellcheck disable=SC1091
SCRIPT_DIR="$(dirname "$(dirname "$(readlink -e "$0")")")" cd "$(basename "$(basename "$(readlink "$0")")")"
SSH_HOST="${1:?Missing SSH host}" SSH_HOST="${1:?Missing SSH host}"
mkdir -p build/{"Program Files (x86)/Common Files",ProgramData} mkdir -p build/{"Program Files (x86)/Common Files",ProgramData}
scp "$SCRIPT_DIR/scripts/dump_registry.ps1" "$SSH_HOST:" # scp ./scripts/dump_registry.ps1 "$SSH_HOST:"
ssh "$SSH_HOST" "powershell .\dump_registry.ps1" # ssh "$SSH_HOST" "powershell .\dump_registry.ps1"
scp "$SSH_HOST:promt-registry.reg" build/registry.reg scp "$SSH_HOST:promt-registry.reg" build/registry.reg
ssh "$SSH_HOST" powershell -c 'rm promt-registry.reg' ssh "$SSH_HOST" powershell -c 'rm promt-registry.reg'
scp -r "$SSH_HOST:/Program Files (x86)/Common Files/PROject MT" "$SCRIPT_DIR/build/Program Files (x86)/Common Files/PROject MT" scp -r "$SSH_HOST:/Program Files (x86)/Common Files/PROject MT" "./build/Program Files (x86)/Common Files/PROject MT"
scp -r "$SSH_HOST:/Program Files (x86)/PRMT6" "$SCRIPT_DIR/build/Program Files (x86)/PRMT6" scp -r "$SSH_HOST:/Program Files (x86)/PRMT6" "./build/Program Files (x86)/PRMT6"
scp -r "$SSH_HOST:/ProgramData/PROject MT" "$SCRIPT_DIR/build/ProgramData/PROject MT" scp -r "$SSH_HOST:/ProgramData/PROject MT" "./build/ProgramData/PROject MT"
export WINETRICKS_LIB=1
. winetricks 2>/dev/null
winetricks_init
winetricks_vcrun6_helper
w_try_cabextract "${W_CACHE}"/vcrun6/vcredist.exe -d "$SCRIPT_DIR/build/windows/" -F "mfc42*.dll"
mkdir -p "$SCRIPT_DIR/build/windows/system32"
date +'%s' > "$SCRIPT_DIR/build/build-date"

View file

@ -1,16 +1,15 @@
#include "COMWrapper.hpp" #include "COMWrapper.hpp"
#include <cstdio> #include <cstdio>
#include <stdexcept>
#include <windows.h> #include <windows.h>
#include <comdef.h>
void COMWrapper::Raise(const HRESULT hr, const char *const ctx) const { void COMWrapper::Raise(const HRESULT hr, const char *const ctx) const {
if (hr != 0) { if (hr != 0) {
char msg[1024]; char msg[128];
_com_error err(hr); snprintf(msg, 128, "[%s] Non-zero HRESULT value: 0x%x at: %s\n", classname(), hr, ctx);
snprintf(msg, 1024, "[%s] Error: %s (0x%lx) at: %s\n", classname(), err.ErrorMessage(), hr, ctx); printf(msg);
printf("%s\n", msg); throw std::runtime_error(msg);
exit(1);
} }
} }