ekt: implement cx7000 printer

This commit is contained in:
2025-09-03 16:58:22 +02:00
parent 57d23726e8
commit 3327548ca6
25 changed files with 1338 additions and 230 deletions

View File

@ -26,7 +26,7 @@ void touch_screen_config_load(struct touch_screen_config *cfg, const wchar_t *fi
cfg->cursor = GetPrivateProfileIntW(L"touch", L"cursor", 1, filename);
}
void printer_config_load(struct printer_config *cfg, const wchar_t *filename)
void printer_chc_config_load(struct printer_chc_config *cfg, const wchar_t *filename)
{
assert(cfg != NULL);
assert(filename != NULL);
@ -84,3 +84,67 @@ void printer_config_load(struct printer_config *cfg, const wchar_t *filename)
cfg->wait_time = GetPrivateProfileIntW(L"printer", L"waitTime", 0, filename);
}
void printer_cx_config_load(struct printer_cx_config *cfg, const wchar_t *filename){
assert(cfg != NULL);
assert(filename != NULL);
char filenameA[MAX_PATH];
size_t n = wcstombs(filenameA, filename, MAX_PATH);
for (int i = n; i < MAX_PATH; i++)
{
filenameA[i] = '\0';
}
cfg->enable = GetPrivateProfileIntW(L"printer", L"enable", 1, filename);
GetPrivateProfileStringA(
"printer",
"firmwareVersion",
"V04-03B",
cfg->printer_firm_version,
_countof(cfg->printer_firm_version),
filenameA);
GetPrivateProfileStringA(
"printer",
"configVersion",
"V01-75",
cfg->printer_config_version,
_countof(cfg->printer_config_version),
filenameA);
GetPrivateProfileStringA(
"printer",
"tableVersion",
"V01-E0",
cfg->printer_table_version,
_countof(cfg->printer_table_version),
filenameA);
GetPrivateProfileStringA(
"printer",
"cameraVersion",
"00.19",
cfg->printer_camera_version,
_countof(cfg->printer_camera_version),
filenameA);
GetPrivateProfileStringW(
L"printer",
L"printerOutPath",
L"DEVICE\\print",
cfg->printer_out_path,
_countof(cfg->printer_out_path),
filename);
GetPrivateProfileStringW(
L"printer",
L"printerDataPath",
L"DEVICE\\cx7000_data.bin",
cfg->printer_data_path,
_countof(cfg->printer_data_path),
filename);
}

View File

@ -4,8 +4,10 @@
#include "hooklib/dvd.h"
#include "hooklib/touch.h"
#include "hooklib/printer.h"
#include "hooklib/printer_chc.h"
#include "hooklib/printer_cx.h"
void dvd_config_load(struct dvd_config *cfg, const wchar_t *filename);
void touch_screen_config_load(struct touch_screen_config *cfg, const wchar_t *filename);
void printer_config_load(struct printer_config *cfg, const wchar_t *filename);
void printer_chc_config_load(struct printer_chc_config *cfg, const wchar_t *filename);
void printer_cx_config_load(struct printer_cx_config *cfg, const wchar_t *filename);

211
common/hooklib/imageutil.c Normal file
View File

@ -0,0 +1,211 @@
#include <windows.h>
#include <stdbool.h>
#include "imageutil.h"
// copy pasted from https://dev.s-ul.net/domeori/c310emu
#define BITMAPHEADERSIZE 0x36
int ConvertDataToBitmap(
DWORD dwBitCount,
DWORD dwWidth, DWORD dwHeight,
PBYTE pbInput, DWORD cbInput,
PBYTE pbOutput, DWORD cbOutput,
PDWORD pcbResult,
bool pFlip) {
if (!pbInput || !pbOutput || dwBitCount < 8) return -3;
if (cbInput < (dwWidth * dwHeight * dwBitCount / 8)) return -3;
PBYTE pBuffer = (PBYTE)malloc(cbInput);
if (!pBuffer) return -2;
BYTE dwColors = (BYTE)(dwBitCount / 8);
if (!dwColors) {
free(pBuffer);
return -1;
}
UINT16 cbColors;
RGBQUAD pbColors[256];
switch (dwBitCount) {
case 1:
cbColors = 1;
break;
case 2:
cbColors = 4;
break;
case 4:
cbColors = 16;
break;
case 8:
cbColors = 256;
break;
default:
cbColors = 0;
break;
}
if (cbColors) {
BYTE dwStep = (BYTE)(256 / cbColors);
for (UINT16 i = 0; i < cbColors; ++i) {
pbColors[i].rgbRed = dwStep * i;
pbColors[i].rgbGreen = dwStep * i;
pbColors[i].rgbBlue = dwStep * i;
pbColors[i].rgbReserved = 0;
}
}
DWORD dwTable = cbColors * sizeof(RGBQUAD);
DWORD dwOffset = BITMAPHEADERSIZE + dwTable;
// calculate the padded row size, again
DWORD dwLineSize = (dwWidth * dwBitCount / 8 + 3) & ~3;
BITMAPFILEHEADER bFile = {0};
BITMAPINFOHEADER bInfo = {0};
bFile.bfType = 0x4D42; // MAGIC
bFile.bfSize = dwOffset + cbInput;
bFile.bfOffBits = dwOffset;
bInfo.biSize = sizeof(BITMAPINFOHEADER);
bInfo.biWidth = dwWidth;
bInfo.biHeight = dwHeight;
bInfo.biPlanes = 1;
bInfo.biBitCount = (WORD)dwBitCount;
bInfo.biCompression = BI_RGB;
bInfo.biSizeImage = cbInput;
if (cbOutput < bFile.bfSize) {
free(pBuffer);
return -1;
}
// Flip the image (if necessary) and add padding to each row
if (pFlip) {
for (size_t i = 0; i < dwHeight; i++) {
for (size_t j = 0; j < dwWidth; j++) {
for (size_t k = 0; k < dwColors; k++) {
// Calculate the position in the padded buffer
// Make sure to also flip the colors from RGB to BRG
size_t x = (dwHeight - i - 1) * dwLineSize + (dwWidth - j - 1) * dwColors + (dwColors - k - 1);
size_t y = (dwHeight - i - 1) * dwWidth * dwColors + j * dwColors + k;
*(pBuffer + x) = *(pbInput + y);
}
}
}
} else {
for (size_t i = 0; i < dwHeight; i++) {
for (size_t j = 0; j < dwWidth; j++) {
for (size_t k = 0; k < dwColors; k++) {
// Calculate the position in the padded buffer
size_t x = i * dwLineSize + j * dwColors + (dwColors - k - 1);
size_t y = (dwHeight - i - 1) * dwWidth * dwColors + j * dwColors + k;
*(pBuffer + x) = *(pbInput + y);
}
}
}
}
memcpy(pbOutput, &bFile, sizeof(BITMAPFILEHEADER));
memcpy(pbOutput + sizeof(BITMAPFILEHEADER), &bInfo, sizeof(BITMAPINFOHEADER));
if (cbColors) memcpy(pbOutput + BITMAPHEADERSIZE, pbColors, dwTable);
memcpy(pbOutput + dwOffset, pBuffer, cbInput);
*pcbResult = bFile.bfSize;
free(pBuffer);
return 0;
}
int WriteDataToBitmapFile(
LPCWSTR lpFilePath, DWORD dwBitCount,
DWORD dwWidth, DWORD dwHeight,
PBYTE pbInput, DWORD cbInput,
PBYTE pbMetadata, DWORD cbMetadata,
bool pFlip) {
if (!lpFilePath || !pbInput) return -3;
HANDLE hFile;
DWORD dwBytesWritten;
hFile = CreateFileW(
lpFilePath,
GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH,
NULL);
if (hFile == INVALID_HANDLE_VALUE) return -1;
// calculate the padded row size and padded image size
DWORD dwLineSize = (dwWidth * dwBitCount / 8 + 3) & ~3;
DWORD dwImageSize = dwLineSize * dwHeight;
DWORD cbResult;
DWORD cbBuffer = dwImageSize + 0x500;
PBYTE pbBuffer = (PBYTE)calloc(cbBuffer, 1);
if (!pbBuffer) return -2;
if (ConvertDataToBitmap(dwBitCount, dwWidth, dwHeight, pbInput, dwImageSize, pbBuffer, cbBuffer, &cbResult, pFlip) < 0) {
cbResult = -1;
goto WriteDataToBitmapFile_End;
}
WriteFile(hFile, pbBuffer, cbResult, &dwBytesWritten, NULL);
if (pbMetadata)
WriteFile(hFile, pbMetadata, cbMetadata, &dwBytesWritten, NULL);
CloseHandle(hFile);
cbResult = dwBytesWritten;
WriteDataToBitmapFile_End:
free(pbBuffer);
return cbResult;
}
int WriteArrayToFile(LPCSTR lpOutputFilePath, LPVOID lpDataTemp, DWORD nDataSize, BOOL isAppend) {
#ifdef NDEBUG
return nDataSize;
#else
HANDLE hFile;
DWORD dwBytesWritten;
DWORD dwDesiredAccess;
DWORD dwCreationDisposition;
if (isAppend) {
dwDesiredAccess = FILE_APPEND_DATA;
dwCreationDisposition = OPEN_ALWAYS;
} else {
dwDesiredAccess = GENERIC_WRITE;
dwCreationDisposition = CREATE_ALWAYS;
}
hFile = CreateFileA(
lpOutputFilePath,
dwDesiredAccess,
FILE_SHARE_READ,
NULL,
dwCreationDisposition,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH,
NULL);
if (hFile == INVALID_HANDLE_VALUE) {
return FALSE;
}
WriteFile(hFile, lpDataTemp, nDataSize, &dwBytesWritten, NULL);
CloseHandle(hFile);
return dwBytesWritten;
#endif
}

View File

@ -0,0 +1,21 @@
#pragma once
#include <windows.h>
#include <stdbool.h>
int ConvertDataToBitmap(
DWORD dwBitCount,
DWORD dwWidth, DWORD dwHeight,
PBYTE pbInput, DWORD cbInput,
PBYTE pbOutput, DWORD cbOutput,
PDWORD pcbResult,
bool pFlip);
int WriteDataToBitmapFile(
LPCWSTR lpFilePath, DWORD dwBitCount,
DWORD dwWidth, DWORD dwHeight,
PBYTE pbInput, DWORD cbInput,
PBYTE pbMetadata, DWORD cbMetadata,
bool pFlip);
int WriteArrayToFile(LPCSTR lpOutputFilePath, LPVOID lpDataTemp, DWORD nDataSize, BOOL isAppend);

View File

@ -21,6 +21,8 @@ hooklib_lib = static_library(
'dvd.h',
'fdshark.c',
'fdshark.h',
'imageutil.c',
'imageutil.h',
'path.c',
'path.h',
'reg.c',
@ -31,7 +33,9 @@ hooklib_lib = static_library(
'spike.h',
'touch.c',
'touch.h',
'printer.c',
'printer.h',
'printer_chc.c',
'printer_chc.h',
'printer_cx.c',
'printer_cx.h',
],
)

View File

@ -9,7 +9,9 @@
chc (emihiok)
*/
#include "hooklib/printer.h"
// ReSharper disable CppParameterNeverUsed
// ReSharper disable CppDFAConstantFunctionResult
#include "hooklib/printer_chc.h"
#include <assert.h>
#include <math.h>
@ -1150,9 +1152,9 @@ static struct hook_symbol printdll_hooks[] = {
},
};
static struct printer_config printer_config;
static struct printer_chc_config printer_config;
void printer_hook_init(const struct printer_config *cfg, int rfid_port_no, HINSTANCE self) {
void printer_chc_hook_init(const struct printer_chc_config *cfg, int rfid_port_no, HINSTANCE self) {
HANDLE fwFile = NULL;
DWORD bytesRead = 0;
@ -1170,7 +1172,7 @@ void printer_hook_init(const struct printer_config *cfg, int rfid_port_no, HINST
rotate180 = cfg->rotate_180;
memcpy(&printer_config, cfg, sizeof(*cfg));
printer_hook_insert_hooks(NULL);
printer_chc_hook_insert_hooks(NULL);
/*
if (self != NULL) {
@ -1229,7 +1231,7 @@ void printer_hook_init(const struct printer_config *cfg, int rfid_port_no, HINST
dprintf("Printer: hook enabled.\n");
}
void printer_hook_insert_hooks(HMODULE target) {
void printer_chc_hook_insert_hooks(HMODULE target) {
hook_table_apply(target, "C310Ausb.dll", C3XXusb_hooks, _countof(C3XXusb_hooks));
hook_table_apply(target, "C310Busb.dll", C3XXusb_hooks, _countof(C3XXusb_hooks));
hook_table_apply(target, "C310FWDLusb.dll", C3XXFWDLusb_hooks, _countof(C3XXFWDLusb_hooks));
@ -3147,207 +3149,6 @@ int CHCUSB_writeLaminate(const void *handle, uint8_t *data, uint32_t offset, uin
return chcusb_writeLaminate(data, writeSize, rResult);
}
// copy pasted from https://dev.s-ul.net/domeori/c310emu
#define BITMAPHEADERSIZE 0x36
DWORD ConvertDataToBitmap(
DWORD dwBitCount,
DWORD dwWidth, DWORD dwHeight,
PBYTE pbInput, DWORD cbInput,
PBYTE pbOutput, DWORD cbOutput,
PDWORD pcbResult,
bool pFlip) {
if (!pbInput || !pbOutput || dwBitCount < 8) return -3;
if (cbInput < (dwWidth * dwHeight * dwBitCount / 8)) return -3;
PBYTE pBuffer = (PBYTE)malloc(cbInput);
if (!pBuffer) return -2;
BYTE dwColors = (BYTE)(dwBitCount / 8);
if (!dwColors) return -1;
UINT16 cbColors;
RGBQUAD pbColors[256];
switch (dwBitCount) {
case 1:
cbColors = 1;
break;
case 2:
cbColors = 4;
break;
case 4:
cbColors = 16;
break;
case 8:
cbColors = 256;
break;
default:
cbColors = 0;
break;
}
if (cbColors) {
BYTE dwStep = (BYTE)(256 / cbColors);
for (UINT16 i = 0; i < cbColors; ++i) {
pbColors[i].rgbRed = dwStep * i;
pbColors[i].rgbGreen = dwStep * i;
pbColors[i].rgbBlue = dwStep * i;
pbColors[i].rgbReserved = 0;
}
}
DWORD dwTable = cbColors * sizeof(RGBQUAD);
DWORD dwOffset = BITMAPHEADERSIZE + dwTable;
// calculate the padded row size, again
DWORD dwLineSize = (dwWidth * dwBitCount / 8 + 3) & ~3;
BITMAPFILEHEADER bFile = {0};
BITMAPINFOHEADER bInfo = {0};
bFile.bfType = 0x4D42; // MAGIC
bFile.bfSize = dwOffset + cbInput;
bFile.bfOffBits = dwOffset;
bInfo.biSize = sizeof(BITMAPINFOHEADER);
bInfo.biWidth = dwWidth;
bInfo.biHeight = dwHeight;
bInfo.biPlanes = 1;
bInfo.biBitCount = (WORD)dwBitCount;
bInfo.biCompression = BI_RGB;
bInfo.biSizeImage = cbInput;
if (cbOutput < bFile.bfSize) return -1;
// Flip the image (if necessary) and add padding to each row
if (pFlip) {
for (size_t i = 0; i < dwHeight; i++) {
for (size_t j = 0; j < dwWidth; j++) {
for (size_t k = 0; k < dwColors; k++) {
// Calculate the position in the padded buffer
// Make sure to also flip the colors from RGB to BRG
size_t x = (dwHeight - i - 1) * dwLineSize + (dwWidth - j - 1) * dwColors + (dwColors - k - 1);
size_t y = (dwHeight - i - 1) * dwWidth * dwColors + j * dwColors + k;
*(pBuffer + x) = *(pbInput + y);
}
}
}
} else {
for (size_t i = 0; i < dwHeight; i++) {
for (size_t j = 0; j < dwWidth; j++) {
for (size_t k = 0; k < dwColors; k++) {
// Calculate the position in the padded buffer
size_t x = i * dwLineSize + j * dwColors + (dwColors - k - 1);
size_t y = (dwHeight - i - 1) * dwWidth * dwColors + j * dwColors + k;
*(pBuffer + x) = *(pbInput + y);
}
}
}
}
memcpy(pbOutput, &bFile, sizeof(BITMAPFILEHEADER));
memcpy(pbOutput + sizeof(BITMAPFILEHEADER), &bInfo, sizeof(BITMAPINFOHEADER));
if (cbColors) memcpy(pbOutput + BITMAPHEADERSIZE, pbColors, dwTable);
memcpy(pbOutput + dwOffset, pBuffer, cbInput);
*pcbResult = bFile.bfSize;
free(pBuffer);
return 0;
}
DWORD WriteDataToBitmapFile(
LPCWSTR lpFilePath, DWORD dwBitCount,
DWORD dwWidth, DWORD dwHeight,
PBYTE pbInput, DWORD cbInput,
PBYTE pbMetadata, DWORD cbMetadata,
bool pFlip) {
if (!lpFilePath || !pbInput) return -3;
HANDLE hFile;
DWORD dwBytesWritten;
hFile = CreateFileW(
lpFilePath,
GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH,
NULL);
if (hFile == INVALID_HANDLE_VALUE) return -1;
// calculate the padded row size and padded image size
DWORD dwLineSize = (dwWidth * dwBitCount / 8 + 3) & ~3;
DWORD dwImageSize = dwLineSize * dwHeight;
DWORD cbResult;
DWORD cbBuffer = dwImageSize + 0x500;
PBYTE pbBuffer = (PBYTE)calloc(cbBuffer, 1);
if (!pbBuffer) return -2;
if (ConvertDataToBitmap(dwBitCount, dwWidth, dwHeight, pbInput, dwImageSize, pbBuffer, cbBuffer, &cbResult, pFlip) < 0) {
cbResult = -1;
goto WriteDataToBitmapFile_End;
}
WriteFile(hFile, pbBuffer, cbResult, &dwBytesWritten, NULL);
if (pbMetadata)
WriteFile(hFile, pbMetadata, cbMetadata, &dwBytesWritten, NULL);
CloseHandle(hFile);
cbResult = dwBytesWritten;
WriteDataToBitmapFile_End:
free(pbBuffer);
return cbResult;
}
DWORD WriteArrayToFile(LPCSTR lpOutputFilePath, LPVOID lpDataTemp, DWORD nDataSize, BOOL isAppend) {
#ifdef NDEBUG
return nDataSize;
#else
HANDLE hFile;
DWORD dwBytesWritten;
DWORD dwDesiredAccess;
DWORD dwCreationDisposition;
if (isAppend) {
dwDesiredAccess = FILE_APPEND_DATA;
dwCreationDisposition = OPEN_ALWAYS;
} else {
dwDesiredAccess = GENERIC_WRITE;
dwCreationDisposition = CREATE_ALWAYS;
}
hFile = CreateFileA(
lpOutputFilePath,
dwDesiredAccess,
FILE_SHARE_READ,
NULL,
dwCreationDisposition,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH,
NULL);
if (hFile == INVALID_HANDLE_VALUE) {
return FALSE;
}
WriteFile(hFile, lpDataTemp, nDataSize, &dwBytesWritten, NULL);
CloseHandle(hFile);
return dwBytesWritten;
#endif
}
void printer_set_dimensions(int width, int height){
WIDTH = width;
HEIGHT = height;

View File

@ -4,7 +4,7 @@
#include <stdbool.h>
#include <stdint.h>
struct printer_config {
struct printer_chc_config {
bool enable;
bool rotate_180;
char serial_no[8];
@ -15,8 +15,8 @@ struct printer_config {
uint32_t wait_time;
};
void printer_hook_init(const struct printer_config *cfg, int rfid_port_no, HINSTANCE self);
void printer_hook_insert_hooks(HMODULE target);
void printer_chc_hook_init(const struct printer_chc_config *cfg, int rfid_port_no, HINSTANCE self);
void printer_chc_hook_insert_hooks(HMODULE target);
void printer_set_dimensions(int width, int height);
int WINAPI fwdlusb_updateFirmware_main(uint8_t update, LPCSTR filename, uint16_t *rResult);

918
common/hooklib/printer_cx.c Normal file
View File

@ -0,0 +1,918 @@
// ReSharper disable CppParameterNeverUsed
// ReSharper disable CppParameterMayBeConstPtrOrRef
#include "printer_cx.h"
#include <assert.h>
#include <stdio.h>
#include <windows.h>
#include <wtypes.h>
#include "imageutil.h"
#include "hook/procaddr.h"
#include "hook/table.h"
#include "util/dprintf.h"
#pragma region prototypes
static int __stdcall hook_CXCMD_Retransfer();
static bool __stdcall hook_CXCMD_CheckIfConnected(int* pSlotId, int* pId);
static int __stdcall hook_CXCMD_xImageOut();
static int __stdcall hook_CXCMD_MoveCard(int slotId, int id, int dest, int flip, int filmInit, int immed);
static int __stdcall hook_CXCMD_xWriteMagData();
static int __stdcall hook_CXCMD_SecurityPrint(int slotId, int id, int color, int bufferIndex, int immed);
static int __stdcall hook_CXCMD_ScanPrinterNext();
static int __stdcall hook_CXCMD_Print(int slotId, int id, int color, int bufferIndex, int immed);
static int __stdcall hook_CXCMD_RezeroUnit(int slotId, int id, int action);
static int __stdcall hook_CXCMD_WriteMagData();
static int __stdcall hook_CXCMD_LogSense(int iSlot, int iID, int iPage, uint8_t* pbyBuffer);
static int __stdcall hook_CXCMD_StandardInquiry(int iSlot, int iID, uint8_t* pbyBuffer);
static int __stdcall hook_CXCMD_ModeSense(int iSlot, int iID, int iPC, int iPage, uint8_t* pbyBuffer);
static int __stdcall hook_CXCMD_UpdateFirmware(int iSlot, int iID, char* pFile, int iDataID);
static int __stdcall hook_CXCMD_ModeSelect(int iSlot, int iID, int iSp, int iPage, uint8_t* pbyData);
static int __stdcall hook_CXCMD_GetPrintingStatus();
static int __stdcall hook_CXCMD_SendDiagnostic(int iSlot, int iID, int iTestMode, int iTestPatten, int iTestCount);
static int __stdcall hook_CXCMD_RetransferAndTurn(int slotId, int id, int immed);
static int __stdcall hook_CXCMD_LogSelect(int iSlot, int iID, int iMod);
static int __stdcall hook_CXCMD_ReadPosition(int slotId, int id, uint8_t* buffer);
static int __stdcall hook_CXCMD_SecurityLock();
static int __stdcall hook_CXCMD_SetPrintingStatus();
static int __stdcall hook_CXCMD_xReadISOMagData();
static int __stdcall hook_CXCMD_WriteISO3TrackMagData();
static int __stdcall hook_CXCMD_PasswordSet();
static int __stdcall hook_CXCMD_GetPrinterStatus();
static int __stdcall hook_CXCMD_WriteProjectCode();
static int __stdcall hook_CXCMD_LoadCard(int slotId, int id, int dest, int flip, int filmInit, int immed);
static int __stdcall hook_CXCMD_ReadMagData();
static int __stdcall hook_CXCMD_ScanPrinter(int* pSlotId, int* pId);
static int __stdcall hook_CXCMD_xWriteISOMagData();
static int __stdcall hook_CXCMD_ICControl();
static int __stdcall hook_CXCMD_ImageOut(int slotId, int id, uint8_t* plane, int length, int color, int bufferIndex);
static int __stdcall hook_CXCMD_ReadBuffer(int iSlot, int iID, int iMode, int iBufferID, uint8_t* pbyData, int iOffset,
int iLength);
static int __stdcall hook_CXCMD_xReadMagData();
static int __stdcall hook_CXCMD_WriteBuffer(int iSlot, int iID, int iMode, int iBufferID, uint8_t* pbyData, int iOffset,
int iLength);
static int __stdcall hook_CXCMD_DefineLUT(int slotId, int id, int color, int length, uint8_t* buffer);
static int __stdcall hook_CXCMD_ReadISO3TrackMagData();
static int __stdcall hook_CXCMD_TestUnitReady(int slotId, int id);
static int __stdcall hook_CXCMD_RetransferAndEject(int slotId, int id, int immed);
static bool __stdcall hook_Lut24_Exchange(const wchar_t* pFile, uint8_t* y, uint8_t* m, uint8_t* c, int sizeY, int sizeM,
int sizeC);
static bool __stdcall hook_Wdata_create(uint8_t* pbyRdata, uint8_t* pbyGdata, uint8_t* pbyBdata, int iWidth,
int iHeight, bool bPortrait, int iAlgorithim, uint8_t* pbyWdata);
static int __cdecl hook_init_accesscodekey(BSTR fileName);
static int __cdecl hook_accesscodekeyoverwriteheader(void* context, BSTR header, int headerLen, BSTR accessheaderkey, int headerkeylen);
#pragma endregion
#pragma region hooktables
static const struct hook_symbol hook_pcp_syms[] = {
{
.name = "CXCMD_Retransfer",
.patch = hook_CXCMD_Retransfer,
.ordinal = 19,
},
{
.name = "CXCMD_CheckIfConnected",
.patch = hook_CXCMD_CheckIfConnected,
.ordinal = 1,
},
{
.name = "CXCMD_xImageOut",
.patch = hook_CXCMD_xImageOut,
.ordinal = 36,
},
{
.name = "CXCMD_MoveCard",
.patch = hook_CXCMD_MoveCard,
.ordinal = 12,
},
{
.name = "CXCMD_xWriteMagData",
.patch = hook_CXCMD_xWriteMagData,
.ordinal = 40,
},
{
.name = "CXCMD_SecurityPrint",
.patch = hook_CXCMD_SecurityPrint,
.ordinal = 26,
},
{
.name = "CXCMD_ScanPrinterNext",
.patch = hook_CXCMD_ScanPrinterNext,
.ordinal = 24,
},
{
.name = "CXCMD_Print",
.patch = hook_CXCMD_Print,
.ordinal = 14,
},
{
.name = "CXCMD_RezeroUnit",
.patch = hook_CXCMD_RezeroUnit,
.ordinal = 22,
},
{
.name = "CXCMD_WriteMagData",
.patch = hook_CXCMD_WriteMagData,
.ordinal = 34,
},
{
.name = "CXCMD_LogSense",
.patch = hook_CXCMD_LogSense,
.ordinal = 9,
},
{
.name = "CXCMD_StandardInquiry",
.patch = hook_CXCMD_StandardInquiry,
.ordinal = 29,
},
{
.name = "CXCMD_ModeSense",
.patch = hook_CXCMD_ModeSense,
.ordinal = 11,
},
{
.name = "CXCMD_UpdateFirmware",
.patch = hook_CXCMD_UpdateFirmware,
.ordinal = 31,
},
{
.name = "CXCMD_ModeSelect",
.patch = hook_CXCMD_ModeSelect,
.ordinal = 10,
},
{
.name = "CXCMD_GetPrintingStatus",
.patch = hook_CXCMD_GetPrintingStatus,
.ordinal = 4,
},
{
.name = "CXCMD_SendDiagnostic",
.patch = hook_CXCMD_SendDiagnostic,
.ordinal = 27,
},
{
.name = "CXCMD_RetransferAndTurn",
.patch = hook_CXCMD_RetransferAndTurn,
.ordinal = 21,
},
{
.name = "CXCMD_LogSelect",
.patch = hook_CXCMD_LogSelect,
.ordinal = 8,
},
{
.name = "CXCMD_ReadPosition",
.patch = hook_CXCMD_ReadPosition,
.ordinal = 18,
},
{
.name = "CXCMD_SecurityLock",
.patch = hook_CXCMD_SecurityLock,
.ordinal = 25,
},
{
.name = "CXCMD_SetPrintingStatus",
.patch = hook_CXCMD_SetPrintingStatus,
.ordinal = 28,
},
{
.name = "CXCMD_xReadISOMagData",
.patch = hook_CXCMD_xReadISOMagData,
.ordinal = 37,
},
{
.name = "CXCMD_WriteISO3TrackMagData",
.patch = hook_CXCMD_WriteISO3TrackMagData,
.ordinal = 33,
},
{
.name = "CXCMD_PasswordSet",
.patch = hook_CXCMD_PasswordSet,
.ordinal = 13,
},
{
.name = "CXCMD_GetPrinterStatus",
.patch = hook_CXCMD_GetPrinterStatus,
.ordinal = 3,
},
{
.name = "CXCMD_WriteProjectCode",
.patch = hook_CXCMD_WriteProjectCode,
.ordinal = 35,
},
{
.name = "CXCMD_LoadCard",
.patch = hook_CXCMD_LoadCard,
.ordinal = 7,
},
{
.name = "CXCMD_ReadMagData",
.patch = hook_CXCMD_ReadMagData,
.ordinal = 17,
},
{
.name = "CXCMD_ScanPrinter",
.patch = hook_CXCMD_ScanPrinter,
.ordinal = 23,
},
{
.name = "CXCMD_xWriteISOMagData",
.patch = hook_CXCMD_xWriteISOMagData,
.ordinal = 39,
},
{
.name = "CXCMD_ICControl",
.patch = hook_CXCMD_ICControl,
.ordinal = 5,
},
{
.name = "CXCMD_ImageOut",
.patch = hook_CXCMD_ImageOut,
.ordinal = 6,
},
{
.name = "CXCMD_ReadBuffer",
.patch = hook_CXCMD_ReadBuffer,
.ordinal = 15,
},
{
.name = "CXCMD_xReadMagData",
.patch = hook_CXCMD_xReadMagData,
.ordinal = 38,
},
{
.name = "CXCMD_WriteBuffer",
.patch = hook_CXCMD_WriteBuffer,
.ordinal = 32,
},
{
.name = "CXCMD_DefineLUT",
.patch = hook_CXCMD_DefineLUT,
.ordinal = 2,
},
{
.name = "CXCMD_ReadISO3TrackMagData",
.patch = hook_CXCMD_ReadISO3TrackMagData,
.ordinal = 16,
},
{
.name = "CXCMD_TestUnitReady",
.patch = hook_CXCMD_TestUnitReady,
.ordinal = 30,
},
{
.name = "CXCMD_RetransferAndEject",
.patch = hook_CXCMD_RetransferAndEject,
.ordinal = 20,
},
};
static const struct hook_symbol hook_lut_syms[] = {
{
.name = "Lut24_Exchange",
.patch = hook_Lut24_Exchange,
.ordinal = 1,
},
};
static const struct hook_symbol hook_wdata_syms[] = {
{
.name = "Wdata_create",
.patch = hook_Wdata_create,
.ordinal = 1,
},
};
static const struct hook_symbol hook_ac_syms[] = {
{
.name = "init_accesscodekey",
.patch = hook_init_accesscodekey,
},{
.name = "accesscodekeyoverwriteheader",
.patch = hook_accesscodekeyoverwriteheader,
},
};
#pragma endregion
static void write_int(uint8_t* data, int index, int value) {
data[index] = value >> 24;
data[index + 1] = value >> 16;
data[index + 2] = value >> 8;
data[index + 3] = value;
}
static void write_short(uint8_t* data, int index, short value) {
data[index] = value >> 8;
data[index + 1] = value;
}
static struct printer_cx_config printer_config;
static wchar_t printer_out_path[MAX_PATH];
static struct printer_cx_data printer_data;
#define HEIGHT 664
#define WIDTH 1036
#define IMAGE_BUFFER_SIZE WIDTH * HEIGHT
static uint8_t back_buffer[4][IMAGE_BUFFER_SIZE];
static uint8_t front_buffer[4][IMAGE_BUFFER_SIZE];
static uint64_t current_card_id;
DWORD load_printer_data() {
DWORD bytesRead = 0;
HANDLE hSave = CreateFileW(printer_config.printer_data_path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hSave != INVALID_HANDLE_VALUE) {
if (!ReadFile(hSave, &printer_data, sizeof(printer_data), &bytesRead, NULL)){
CloseHandle(hSave);
return GetLastError();
}
CloseHandle(hSave);
if (bytesRead != sizeof(printer_data)){
return -1;
}
if (printer_data.version != PRINTER_DATA_VERSION) {
return -2;
}
return 0;
} else {
return GetLastError();
}
}
DWORD save_printer_data() {
DWORD bytesWritten = 0;
HANDLE hSave = CreateFileW(printer_config.printer_data_path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hSave != NULL) {
if (!WriteFile(hSave, &printer_data, sizeof(printer_data), &bytesWritten, NULL)){
CloseHandle(hSave);
dprintf("CX7000: Failed writing data: %lx\n", GetLastError());
return GetLastError();
}
CloseHandle(hSave);
return 0;
} else {
dprintf("CX7000: Failed opening data file for writing: %lx\n", GetLastError());
return GetLastError();
}
}
void printer_cx_hook_init(const struct printer_cx_config* cfg, HINSTANCE self) {
assert(cfg != NULL);
if (!cfg->enable) {
return;
}
memcpy(&printer_config, cfg, sizeof(*cfg));
printer_cx_hook_insert_hooks(NULL);
CreateDirectoryW(cfg->printer_out_path, NULL);
memcpy(printer_out_path, cfg->printer_out_path, MAX_PATH);
if (load_printer_data() != 0) {
memset(&printer_data, 0, sizeof(printer_data));
printer_data.version = PRINTER_DATA_VERSION;
if (save_printer_data() == 0) {
dprintf("CX7000: Printer data initialized.\n");
}
}
dprintf("CX7000: hook enabled.\n");
}
void printer_cx_hook_insert_hooks(HMODULE target) {
hook_table_apply(target, "PCP21CT64.dll", hook_pcp_syms, _countof(hook_pcp_syms));
hook_table_apply(target, "LUT24EXG64.dll", hook_lut_syms, _countof(hook_lut_syms));
hook_table_apply(target, "WCREATE64.dll", hook_wdata_syms, _countof(hook_wdata_syms));
hook_table_apply(target, "accesscode_dll.dll", hook_ac_syms, _countof(hook_ac_syms));
/* Unity workaround */
proc_addr_table_push(target, "PCP21CT64.dll", hook_pcp_syms, _countof(hook_pcp_syms));
proc_addr_table_push(target, "LUT24EXG64.dll", hook_lut_syms, _countof(hook_lut_syms));
proc_addr_table_push(target, "WCREATE64.dll", hook_wdata_syms, _countof(hook_wdata_syms));
proc_addr_table_push(target, "accesscode_dll.dll", hook_ac_syms, _countof(hook_ac_syms));
}
static int __stdcall hook_CXCMD_Retransfer() {
dprintf("CX7000: %s\n", __func__);
dprintf("CX7000: Unimplemented\n"); // unused
return CX_ERROR_USB_COM_3201;
}
static bool __stdcall hook_CXCMD_CheckIfConnected(int* pSlotId, int* pId) {
dprintf("CX7000: %s\n", __func__);
return printer_config.enable;
}
static int __stdcall hook_CXCMD_xImageOut() {
dprintf("CX7000: %s\n", __func__);
dprintf("CX7000: Unimplemented\n"); // unused
return CX_ERROR_USB_COM_3201;
}
static int __stdcall hook_CXCMD_MoveCard(int slotId, int id, int dest, int flip, int filmInit, int immed) {
dprintf("CX7000: %s(%d, %d, %d, %d)\n", __func__, dest, flip, filmInit, immed);
return CX_OK;
}
static int __stdcall hook_CXCMD_xWriteMagData() {
dprintf("CX7000: %s\n", __func__);
dprintf("CX7000: Unimplemented\n"); // unused
return CX_ERROR_USB_COM_3201;
}
static int __stdcall hook_CXCMD_SecurityPrint(int slotId, int id, int color, int bufferIndex, int immed) {
dprintf("CX7000: %s\n", __func__);
dprintf("CX7000: Unimplemented\n"); // unused
return CX_ERROR_USB_COM_3201;
}
static int __stdcall hook_CXCMD_ScanPrinterNext() {
dprintf("CX7000: %s\n", __func__);
dprintf("CX7000: Unimplemented\n"); // unused
return CX_ERROR_USB_COM_3201;
}
static int __stdcall hook_CXCMD_ImageOut(int slotId, int id, uint8_t* plane, int length, int color, int bufferIndex) {
dprintf("CX7000: %s\n", __func__);
assert(color >= 0 && color <= 3);
assert(bufferIndex >= 0 && bufferIndex <= 1);
assert(length == IMAGE_BUFFER_SIZE);
// colorIndex: 0 = w, 1 = c, 2 = m, 3 = y
// bufferIndex: 0 = back, 1 = front
if (bufferIndex == 0) {
memcpy(back_buffer[color], plane, length);
} else {
memcpy(front_buffer[color], plane, length);
}
return CX_OK;
}
static int __stdcall hook_CXCMD_Print(int slotId, int id, int color, int bufferIndex, int immed) {
dprintf("CX7000: %s(%d, %d, %d)\n", __func__, color, bufferIndex, immed);
assert(bufferIndex >= 0 && bufferIndex <= 1);
SYSTEMTIME t;
GetLocalTime(&t);
// color: 1 = back, 3 = front
// bufferIndex: 0 = back, 1 = front
wchar_t dumpPath[MAX_PATH];
uint8_t metadata[5];
metadata[0] = current_card_id >> 32;
write_int(metadata, 1, (int32_t)current_card_id);
swprintf_s(
dumpPath, MAX_PATH,
L"%s\\CX7000_%04d%02d%02d_%02d%02d%02d_%s.bmp",
printer_out_path, t.wYear, t.wMonth, t.wDay, t.wHour, t.wMinute, t.wSecond, bufferIndex == 0 ? L"back" : L"front");
// convert image from seperate CMY arrays to one RGB array
int size = IMAGE_BUFFER_SIZE * 3;
uint8_t* raw_image = malloc(size);
for (int i = 0; i < IMAGE_BUFFER_SIZE; i++) {
// 0 is "white" and we don't really care about that
raw_image[i * 3] = 0xFF - (bufferIndex == 0 ? back_buffer : front_buffer)[1][i];
raw_image[i * 3 + 1] = 0xFF - (bufferIndex == 0 ? back_buffer : front_buffer)[2][i];
raw_image[i * 3 + 2] = 0xFF - (bufferIndex == 0 ? back_buffer : front_buffer)[3][i];
}
dprintf("CX7000: Saving %s image to %ls\n", bufferIndex == 0 ? "back" : "front", dumpPath);
int ret = WriteDataToBitmapFile(dumpPath, 24, WIDTH, HEIGHT, raw_image, size, metadata, 5, false);
free(raw_image);
if (ret < 0) {
dprintf("CX7000: WriteDataToBitmapFile returned %d\n", ret);
return CX_ERROR_FATAL_3301;
}
return CX_OK;
}
static int __stdcall hook_CXCMD_RezeroUnit(int slotId, int id, int action) {
dprintf("CX7000: %s\n", __func__);
return CX_OK;
}
static int __stdcall hook_CXCMD_WriteMagData() {
dprintf("CX7000: %s\n", __func__);
dprintf("CX7000: Unimplemented\n"); // unused
return CX_ERROR_USB_COM_3201;
}
static int __stdcall hook_CXCMD_LogSense(int iSlot, int iID, int iPage, uint8_t* pbyBuffer) {
dprintf("CX7000: %s\n", __func__);
const int size = 108;
memset(pbyBuffer, 0, size);
if (iPage == 56) {
dprintf("CX7000: MediumQuantity\n");
write_int(pbyBuffer, 8, (int)printer_data.print_counter); // total count
write_int(pbyBuffer, 16, 22); // free count
write_int(pbyBuffer, 24, 33); // head count
write_int(pbyBuffer, 32, (int)printer_data.print_counter_since_clean); // cleaning count
write_int(pbyBuffer, 40, 55); // error count
write_int(pbyBuffer, 48, 66); // cru cleaning count
return CX_OK;
} else if (iPage == 57) {
dprintf("CX7000: Miscellaneous\n");
write_int(pbyBuffer, 16, 234); // re transfer hr power on time
write_int(pbyBuffer, 24, 456); // remedy hr power on time
write_int(pbyBuffer, 40, 789); // unresettable re transfer hr power on time
write_int(pbyBuffer, 48, 1023); // unresettable remedy hr power on time
return CX_OK;
}
dprintf("CX7000: Unknown LogSense\n");
return CX_ERROR_USB_COM_3201;
}
static int __stdcall hook_CXCMD_StandardInquiry(int iSlot, int iID, uint8_t* pbyBuffer) {
const int size = 96;
dprintf("CX7000: %s\n", __func__);
memset(pbyBuffer, 0, size);
memcpy(pbyBuffer + 32, printer_config.printer_firm_version, 8);
memcpy(pbyBuffer + 50, printer_config.printer_camera_version, 8);
memcpy(pbyBuffer + 71, printer_config.printer_config_version, 8);
memcpy(pbyBuffer + 79, printer_config.printer_table_version, 8);
//memcpy(pbyBuffer + 58, printer_config.thermal_head_info, 13); // unused
return CX_OK;
}
static int __stdcall hook_CXCMD_ModeSense(int iSlot, int iID, int iPC, int iPage, uint8_t* pbyBuffer) {
dprintf("CX7000: %s(%d, %d)\n", __func__, iPC, iPage);
const int size = 104;
memset(pbyBuffer, 0, size);
if (iPC == 1 && iPage == 40) { // GetMediaInfo
pbyBuffer[51] = 10; // film count (10=100%)
pbyBuffer[52] = 50; // ink count (50=100%)
return CX_OK;
} else if (iPC == 1 && iPage == 35) { // ReadInkInfo
pbyBuffer[6] = 0; // "b"
write_short(pbyBuffer, 8, 50); // Remain
return CX_OK;
}
dprintf("CX7000: Unknown ModeSense\n");
return CX_ERROR_USB_COM_3201;
}
static int __stdcall hook_CXCMD_UpdateFirmware(int iSlot, int iID, char* pFile, int iDataID) {
dprintf("CX7000: %s\n", __func__);
dprintf("CX7000: Unimplemented\n"); // intentionally not implemented
return CX_ERROR_USB_COM_3201;
}
static int __stdcall hook_CXCMD_ModeSelect(int iSlot, int iID, int iSp, int iPage, uint8_t* pbyData) {
dprintf("CX7000: %s\n", __func__);
dprintf("CX7000: Unimplemented\n"); // unused
return CX_ERROR_USB_COM_3201;
}
static int __stdcall hook_CXCMD_GetPrintingStatus() {
dprintf("CX7000: %s\n", __func__);
dprintf("CX7000: Unimplemented\n"); // unused
return CX_ERROR_USB_COM_3201;
}
static int __stdcall hook_CXCMD_SendDiagnostic(int iSlot, int iID, int iTestMode, int iTestPatten, int iTestCount) {
dprintf("CX7000: %s(%d, %d, %d)\n", __func__, iTestMode, iTestPatten, iTestCount);
if (iTestMode == 19) {
dprintf("CX7000: Printer Front Buttons Enabled: %d\n", iTestPatten);
return CX_OK;
} else if (iTestMode == 17) {
dprintf("CX7000: Printer was cleaned (haha)\n");
printer_data.print_counter_since_clean = 0;
save_printer_data();
return CX_OK;
} else if (iTestMode == 18) {
dprintf("CX7000: Transport Mode enabled\n");
printer_data.is_transport = true;
save_printer_data();
return CX_OK;
} else if (iTestMode == 20) {
dprintf("CX7000: Transport Mode disabled\n");
printer_data.is_transport = false;
save_printer_data();
return CX_OK;
}
dprintf("CX7000: Unknown SendDiagnostic\n");
return CX_ERROR_USB_COM_3201;
}
static int __stdcall hook_CXCMD_RetransferAndTurn(int slotId, int id, int immed) {
dprintf("CX7000: %s\n", __func__);
return CX_OK;
}
static int __stdcall hook_CXCMD_LogSelect(int iSlot, int iID, int iMod) {
dprintf("CX7000: %s\n", __func__);
dprintf("CX7000: Unimplemented\n"); // unused
return CX_ERROR_USB_COM_3201;
}
static int __stdcall hook_CXCMD_ReadPosition(int slotId, int id, uint8_t* buffer) {
dprintf("CX7000: %s\n", __func__);
const int size = 8;
memset(buffer, 0, size);
buffer[0] = 1 << 2; // IsExist (0 means YES!)
buffer[7] = 0; // position (of card; 0 = printer, 1 = "IR")
return CX_OK;
}
static int __stdcall hook_CXCMD_SecurityLock() {
dprintf("CX7000: %s\n", __func__);
dprintf("CX7000: Unimplemented\n"); // unused
return CX_ERROR_USB_COM_3201;
}
static int __stdcall hook_CXCMD_SetPrintingStatus() {
dprintf("CX7000: %s\n", __func__);
dprintf("CX7000: Unimplemented\n"); // unused
return CX_ERROR_USB_COM_3201;
}
static int __stdcall hook_CXCMD_xReadISOMagData() {
dprintf("CX7000: %s\n", __func__);
dprintf("CX7000: Unimplemented\n"); // unused
return CX_ERROR_USB_COM_3201;
}
static int __stdcall hook_CXCMD_WriteISO3TrackMagData() {
dprintf("CX7000: %s\n", __func__);
dprintf("CX7000: Unimplemented\n"); // unused
return CX_ERROR_USB_COM_3201;
}
static int __stdcall hook_CXCMD_PasswordSet() {
dprintf("CX7000: %s\n", __func__);
dprintf("CX7000: Unimplemented\n"); // unused
return CX_ERROR_USB_COM_3201;
}
static int __stdcall hook_CXCMD_GetPrinterStatus() {
dprintf("CX7000: %s\n", __func__);
dprintf("CX7000: Unimplemented\n"); // unused
return CX_ERROR_USB_COM_3201;
}
static int __stdcall hook_CXCMD_WriteProjectCode() {
dprintf("CX7000: %s\n", __func__);
dprintf("CX7000: Unimplemented\n"); // unused
return CX_ERROR_USB_COM_3201;
}
static int __stdcall hook_CXCMD_LoadCard(int slotId, int id, int dest, int flip, int filmInit, int immed) {
dprintf("CX7000: %s(%d, %d, %d, %d)\n", __func__, dest, flip, filmInit, immed);
return CX_OK;
}
static int __stdcall hook_CXCMD_ReadMagData() {
dprintf("CX7000: %s\n", __func__);
dprintf("CX7000: Unimplemented\n"); // unused
return CX_ERROR_USB_COM_3201;
}
static int __stdcall hook_CXCMD_ScanPrinter(int* pSlotId, int* pId) {
dprintf("CX7000: %s\n", __func__);
if (!printer_config.enable) {
return CX_ERROR_NOT_CONNECTED_6804;
}
*pSlotId = 1;
*pId = 1;
return CX_OK;
}
static int __stdcall hook_CXCMD_xWriteISOMagData() {
dprintf("CX7000: %s\n", __func__);
dprintf("CX7000: Unimplemented\n"); // unused
return CX_ERROR_USB_COM_3201;
}
static int __stdcall hook_CXCMD_ICControl() {
dprintf("CX7000: %s\n", __func__);
dprintf("CX7000: Unimplemented\n"); // unused
return CX_ERROR_USB_COM_3201;
}
static int __stdcall hook_CXCMD_ReadBuffer(int iSlot, int iID, int iMode, int iBufferID, uint8_t* pbyData, int iOffset,
int iLength) {
dprintf("CX7000: %s(%d, %d, %d)\n", __func__, iMode, iBufferID, iLength);
memset(pbyData, 0, iLength);
if (iMode == 2 && iBufferID == 87 && iLength == 10) {
dprintf("CX7000: ReadCondition\n");
pbyData[0] = printer_data.is_transport; // transport mode
pbyData[1] = 0; // head white ink level, unused
pbyData[2] = 0; // main white ink level, unused
pbyData[3] = 0; // total white ink level, unused
return CX_OK;
} else if (iMode == 2 && iBufferID == 112 && iLength == 6) {
dprintf("CX7000: GetMacAddress\n");
pbyData[0] = 0x12; // displays in test menu, else ununused?
pbyData[1] = 0x34;
pbyData[2] = 0x56;
pbyData[3] = 0x78;
pbyData[4] = 0x9A;
pbyData[5] = 0xBC;
return CX_OK;
} else if (iMode == 2 && iBufferID == 82 && iLength == 4) {
dprintf("CX7000: GetCleaningWaitCount\n");
// seemingly unused
write_short(pbyData, 0, 0);
return CX_OK;
} else if (iMode == 2 && iBufferID == 85 && iLength == 10) {
dprintf("CX7000: GetSensorInfo\n");
pbyData[0] = 244; // retransfer heat roller thermistor; must be over 243
pbyData[1] = 0; // main pwb thermistor; unused
pbyData[2] = 0; // thermal head thermistor; unused
pbyData[3] = 0; // heater cover thermistor; unused
return CX_OK;
} else if (iMode == 2 && iBufferID == 88 && iLength == 16) {
dprintf("CX7000: ReadErrorStatus\n");
pbyData[1] = 0; // is door open?
//pbyData[2...] = // any of the error codes that fit in a byte (from CX_ERROR_FATAL_3301 to CX_ERROR_PRINT_INTERRUPT_6805_3)
return CX_OK;
} else if (iMode == 2 && iBufferID == 224 && iLength == 10) {
dprintf("CX7000: ReadCode\n");
printer_data.print_counter_since_clean++;
current_card_id = ++printer_data.print_counter;
dprintf("CX7000: Generated new card ID: %lld\n", current_card_id);
save_printer_data();
pbyData[0] = current_card_id >> 32; // MSB of card id
write_int(pbyData, 1, (int32_t)current_card_id); // lower 4 bytes of card id
pbyData[5] = 0x0; // Direction (1 = rotate image by 180 degrees)
pbyData[6] = 0x1; // CheckCode (0 = error)
return CX_OK;
} else if (iMode == 2 && iBufferID == 144 && iLength == 260) {
dprintf("CX7000: ReadErrorLog\n");
write_int(pbyData, 0, 0); // LogCount
/*for (int i = 0; false; i++) { // list of error ids
write_int(pbyData, i + 4, 0);
}*/
return CX_OK;
}
dprintf("CX7000: Unknown ReadBuffer\n");
return CX_ERROR_USB_COM_3201;
}
static int __stdcall hook_CXCMD_xReadMagData() {
dprintf("CX7000: %s\n", __func__);
dprintf("CX7000: Unimplemented\n"); // unused
return CX_ERROR_USB_COM_3201;
}
static int __stdcall hook_CXCMD_WriteBuffer(int iSlot, int iID, int iMode, int iBufferID, uint8_t* pbyData, int iOffset, // NOLINT(*-non-const-parameter)
int iLength) {
dprintf("CX7000: %s(%d, %d, %d, %d)\n", __func__, iMode, iBufferID, iOffset, iLength);
if (iMode == 2 && iBufferID == 82 && iLength == 4) {
int val = pbyData[0] << 8 | pbyData[1];
dprintf("CX7000: Set cleaning limit: %d\n", val);
return CX_OK;
}
dprintf("CX7000: Unknown WriteBuffer\n");
return CX_ERROR_USB_COM_3201;
}
static int __stdcall hook_CXCMD_DefineLUT(int slotId, int id, int color, int length, uint8_t* buffer) {
dprintf("CX7000: %s\n", __func__);
dprintf("CX7000: Unimplemented\n"); // unused
return CX_ERROR_USB_COM_3201;
}
static int __stdcall hook_CXCMD_ReadISO3TrackMagData() {
dprintf("CX7000: %s\n", __func__);
dprintf("CX7000: Unimplemented\n"); // unused
return CX_ERROR_USB_COM_3201;
}
static int __stdcall hook_CXCMD_TestUnitReady(int slotId, int id) {
dprintf("CX7000: %s\n", __func__);
if (!printer_config.enable) {
return CX_ERROR_NOT_CONNECTED_6804;
}
return CX_OK;
}
static int __stdcall hook_CXCMD_RetransferAndEject(int slotId, int id, int immed) {
dprintf("CX7000: %s\n", __func__);
return CX_OK;
}
static bool __stdcall hook_Lut24_Exchange(const wchar_t* pFile, uint8_t* y, uint8_t* m, uint8_t* c, int sizeY, int sizeM,
int sizeC) {
dprintf("CX7000: %s(%ls)\n", __func__, pFile);
// stub?
return true;
}
static bool __stdcall hook_Wdata_create(uint8_t* pbyRdata, uint8_t* pbyGdata, uint8_t* pbyBdata, int iWidth,
int iHeight, bool bPortrait, int iAlgorithim, uint8_t* pbyWdata) {
dprintf("CX7000: %s(%d, %d, %d)\n", __func__, iHeight, bPortrait, iAlgorithim);
// stub?
return true;
}
// TODO: these two only exist while we have no decrypted dump of accesscode_dll
static int __cdecl hook_init_accesscodekey(BSTR fileName) {
dprintf("AccesscodeKey: Init\n");
return 0;
}
static int __cdecl hook_accesscodekeyoverwriteheader(void* context, BSTR header, int headerLen, BSTR accessheaderkey, int headerkeylen) {
dprintf("AccesscodeKey: Overwrite Header\n");
return 0;
}

View File

@ -0,0 +1,73 @@
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include <windows.h>
#define PRINTER_DATA_VERSION 1
struct printer_cx_config {
bool enable;
wchar_t printer_out_path[MAX_PATH];
wchar_t printer_data_path[MAX_PATH];
char printer_firm_version[8];
char printer_camera_version[8];
char printer_config_version[8];
char printer_table_version[8];
};
struct printer_cx_data {
uint8_t version;
uint64_t print_counter;
uint64_t print_counter_since_clean;
bool is_transport;
};
enum {
CX_OK = 0,
CX_ERROR_FATAL_3301 = -1,
CX_ERROR_USB_COM_3201 = -2,
CX_ERROR_PRINT_INTERRUPT_6805_4 = -4,
CX_ERROR_CODE_UNREADABLE_3303 = -5,
CX_ERROR_INK_LOW_3202 = -6,
CX_ERROR_PRINT_INTERRUPT_6805_3 = -7,
CX_ERROR_NO_CARD_6801 = -16961536,
CX_ERROR_DOOR_OPEN_6808 = -16961792,
CX_ERROR_6831 = -16963328,
CX_ERROR_6810 = -16964864,
CX_ERROR_CLEAN_PRINTER_3999 = -16973056,
CX_ERROR_JAM_6805_1 = -17010688,
CX_ERROR_REVERSE_JAM_6805_2 = -17010944,
CX_ERROR_CAMERA_JAM_6805_3 = -17011200,
CX_ERROR_TRANSPORT_JAM_6805_4 = -17011456,
CX_ERROR_PAPER_SENSOR_JAM_6805_5 = -17011712,
CX_ERROR_RETRANSFER_JAM_6805_6 = -17011968,
CX_ERROR_PAPER_RIPPED_6813_3 = -17015040,
CX_ERROR_CODE_READ_6811 = -17018112,
CX_ERROR_UNAUTHORIZED_INK_6803_1 = -17018880,
CX_ERROR_INK_EMPTY_6813_1 = -17019136,
CX_ERROR_PRINT_TIMEOUT_6810_3 = -17056768,
CX_ERROR_CAMERA_HARDWARE_FAULT_6810_5 = -17083136,
CX_ERROR_CAMERA_COM_6810_6 = -17083392,
CX_ERROR_ROLLER_6810_15 = -17088768,
CX_ERROR_OVER_TEMPERATURE_6810_16 = -17089024,
CX_ERROR_POWER_INTERRUPT_6810_1 = -17089280,
CX_ERROR_INITIALIZATION_6810_2 = -17094656,
CX_ERROR_OVER_TEMPERATURE_6810_10 = -17100800,
CX_ERROR_RETRANSFER_ROLLER_6810_11 = -17101056,
CX_ERROR_THERMOSTAT_6810_12 = -17101312,
CX_ERROR_OVER_TEMPERATURE_6810_20 = -17101568,
CX_ERROR_STRAIGHTEN_ROLLER_6810_21 = -17101824,
CX_ERROR_THERMOSTAT_6810_22 = -17102080,
CX_ERROR_PRINTER_TOO_COLD_6833_1 = -16971264,
CX_ERROR_OVER_TEMPERATURE_6810_25 = -17102848,
CX_ERROR_CAMERA_NOT_FOUND_6810_7 = -17116672,
CX_ERROR_RETRANSFER_ROLL_EMPTY_6802_3 = -21144064,
CX_ERROR_INK_ROLL_EMPTY_6802_1 = -21148160,
CX_ERROR_NOT_CONNECTED_6804 = -33554432,
CX_ERROR_CAMERA_JAM_6805_7 = -17012224,
CX_ERROR_INVALID_CLEANING_CARD_6832_1 = -16965376,
CX_ERROR_TEMPERATURE_RESOLVED_6833_2 = -16971520,
};
void printer_cx_hook_init(const struct printer_cx_config *cfg, HINSTANCE self);
void printer_cx_hook_insert_hooks(HMODULE target);

View File

@ -11,7 +11,7 @@
#include "hooklib/dll.h"
#include "hooklib/path.h"
#include "hooklib/printer.h"
#include "hooklib/printer_chc.h"
#include "hooklib/reg.h"
#include "hooklib/touch.h"
#include "hooklib/serial.h"

View File

@ -18,6 +18,6 @@ y3io_lib = static_library(
'y3.c',
'y3.h',
'impl/dummy/y3io.c',
'impl/dummy/y3io.h',
'impl/y3io.h',
],
)

View File

@ -7,7 +7,7 @@
#include "hooklib/dvd.h"
#include "hooklib/touch.h"
#include "hooklib/printer.h"
#include "hooklib/printer_chc.h"
#include "gfxhook/config.h"

View File

@ -40,7 +40,7 @@ void cm_hook_config_load(
io4_config_load(&cfg->io4, filename);
vfd_config_load(&cfg->vfd, filename);
touch_screen_config_load(&cfg->touch, filename);
printer_config_load(&cfg->printer, filename);
printer_chc_config_load(&cfg->printer, filename);
cm_dll_config_load(&cfg->dll, filename);
unity_config_load(&cfg->unity, filename);
}

View File

@ -6,7 +6,7 @@
#include "hooklib/dvd.h"
#include "hooklib/touch.h"
#include "hooklib/printer.h"
#include "hooklib/printer_chc.h"
#include "cmhook/cm-dll.h"
@ -22,7 +22,7 @@ struct cm_hook_config {
struct vfd_config vfd;
struct cm_dll_config dll;
struct touch_screen_config touch;
struct printer_config printer;
struct printer_chc_config printer;
struct unity_config unity;
};

View File

@ -59,7 +59,7 @@ static DWORD CALLBACK cm_pre_startup(void)
/* Hook external DLL APIs */
printer_hook_init(&cm_hook_cfg.printer, 0, cm_hook_mod);
printer_chc_hook_init(&cm_hook_cfg.printer, 0, cm_hook_mod);
/* Initialize emulation hooks */

View File

@ -103,6 +103,7 @@ void ekt_hook_config_load(
dvd_config_load(&cfg->dvd, filename);
led15093_config_load(&cfg->led15093, filename);
y3_config_load(&cfg->y3, filename);
printer_cx_config_load(&cfg->printer, filename);
unity_config_load(&cfg->unity, filename);
ekt_dll_config_load(&cfg->dll, filename);
}

View File

@ -7,6 +7,7 @@
#include "board/led15093.h"
#include "hooklib/dvd.h"
#include "hooklib/printer_cx.h"
#include "platform/config.h"
@ -24,6 +25,7 @@ struct ekt_hook_config {
struct y3_config y3;
struct ekt_dll_config dll;
struct unity_config unity;
struct printer_cx_config printer;
};
void ekt_dll_config_load(

View File

@ -34,6 +34,7 @@
#include "ekthook/config.h"
#include "ekthook/io4.h"
#include "hooklib/printer_cx.h"
#include "platform/platform.h"
@ -72,6 +73,8 @@ static DWORD CALLBACK ekt_pre_startup(void)
goto fail;
}
printer_cx_hook_init(&ekt_hook_cfg.printer, ekt_hook_mod);
/* Initialize emulation hooks */
hr = platform_hook_init(

View File

@ -58,6 +58,14 @@ HRESULT ekt_io_poll(void) {
ekt_opbtn |= EKT_IO_OPBTN_SERVICE;
}
if (GetAsyncKeyState(ekt_io_cfg.vk_sw1) & 0x8000) {
ekt_opbtn |= EKT_IO_OPBTN_SW1;
}
if (GetAsyncKeyState(ekt_io_cfg.vk_sw2) & 0x8000) {
ekt_opbtn |= EKT_IO_OPBTN_SW2;
}
if (GetAsyncKeyState(ekt_io_cfg.vk_coin) & 0x8000) {
if (!ekt_io_coin) {
ekt_io_coin = true;

View File

@ -120,7 +120,7 @@ void fgo_hook_config_load(
io4_config_load(&cfg->io4, filename);
vfd_config_load(&cfg->vfd, filename);
touch_screen_config_load(&cfg->touch, filename);
printer_config_load(&cfg->printer, filename);
printer_chc_config_load(&cfg->printer, filename);
fgo_deck_config_load(&cfg->deck, filename);
ftdi_config_load(&cfg->ftdi, filename);
led15093_config_load(&cfg->led15093, filename);

View File

@ -7,7 +7,7 @@
#include "hooklib/dvd.h"
#include "hooklib/touch.h"
#include "hooklib/printer.h"
#include "hooklib/printer_chc.h"
#include "gfxhook/config.h"
@ -24,7 +24,7 @@ struct fgo_hook_config {
struct io4_config io4;
struct vfd_config vfd;
struct touch_screen_config touch;
struct printer_config printer;
struct printer_chc_config printer;
struct deck_config deck;
struct ftdi_config ftdi;
struct led15093_config led15093;

View File

@ -29,7 +29,7 @@
#include "hooklib/dll.h"
#include "hooklib/dvd.h"
#include "hooklib/touch.h"
#include "hooklib/printer.h"
#include "hooklib/printer_chc.h"
#include "hooklib/createprocess.h"
#include "hooklib/serial.h"
#include "hooklib/spike.h"
@ -81,7 +81,7 @@ static DWORD CALLBACK fgo_pre_startup(void)
/* Hook external DLL APIs */
printer_hook_init(&fgo_hook_cfg.printer, 4, fgo_hook_mod);
printer_chc_hook_init(&fgo_hook_cfg.printer, 4, fgo_hook_mod);
if (fgo_hook_cfg.printer.enable) {
dll_hook_push(fgo_hook_mod, L"C330Ausb.dll");
dll_hook_push(fgo_hook_mod, L"C330AFWDLusb.dll");

View File

@ -126,7 +126,7 @@ void kemono_hook_config_load(
vfd_config_load(&cfg->vfd, filename);
kemono_dll_config_load(&cfg->dll, filename);
unity_config_load(&cfg->unity, filename);
printer_config_load(&cfg->printer, filename);
printer_chc_config_load(&cfg->printer, filename);
amex_config_load(&cfg->amex, filename);
led15093_config_load(&cfg->led15093, filename);
}

View File

@ -22,7 +22,7 @@ struct kemono_hook_config {
struct vfd_config vfd;
struct kemono_dll_config dll;
struct unity_config unity;
struct printer_config printer;
struct printer_chc_config printer;
struct amex_config amex;
struct led15093_config led15093;
};

View File

@ -7,7 +7,7 @@
#include "hook/iohook.h"
#include "hook/process.h"
#include "hook/table.h"
#include "hooklib/printer.h"
#include "hooklib/printer_chc.h"
#include "hooklib/serial.h"
#include "hooklib/spike.h"
#include "kemonohook/config.h"
@ -65,7 +65,7 @@ static DWORD CALLBACK kemono_pre_startup(void) {
goto fail;
}
printer_hook_init(&kemono_hook_cfg.printer, 0, kemono_hook_mod);
printer_chc_hook_init(&kemono_hook_cfg.printer, 0, kemono_hook_mod);
printer_set_dimensions(720, 1028); // printer doesn't call setimageformat
/* Initialize emulation hooks */