优化bug
This commit is contained in:
+8
-16
@@ -1,4 +1,4 @@
|
||||
import { app, BrowserWindow, dialog, globalShortcut, screen } from 'electron'
|
||||
import { app, BrowserWindow, dialog, globalShortcut } from 'electron'
|
||||
import { join } from 'path'
|
||||
|
||||
app.commandLine.appendSwitch('disable-gpu-shader-disk-cache')
|
||||
@@ -14,10 +14,12 @@ if (!gotSingleInstanceLock) {
|
||||
app.quit()
|
||||
}
|
||||
|
||||
import { ensureConsoleUtf8 } from './utils/ensure-console-utf8'
|
||||
import { suppressKnownDllStderr } from './utils/suppress-dll-stderr'
|
||||
import { loadAppFileConfig, applyFileConfigToStore } from './services/app-config'
|
||||
import { migrateTraceConfig, setTraceWebContents } from './utils/trace-bridge'
|
||||
|
||||
ensureConsoleUtf8()
|
||||
suppressKnownDllStderr()
|
||||
|
||||
process.on('uncaughtException', (err) => {
|
||||
@@ -41,24 +43,12 @@ function focusMainWindow(): void {
|
||||
mainWindow.focus()
|
||||
}
|
||||
|
||||
function getDefaultWindowSize(): { width: number; height: number } {
|
||||
const { width: sw, height: sh } = screen.getPrimaryDisplay().workAreaSize
|
||||
let w = Math.max(1280, Math.min(Math.floor(sw * 0.85), 1600))
|
||||
let h = contentHeightForWidth(w)
|
||||
const maxH = Math.floor(sh * 0.85)
|
||||
if (h > maxH) {
|
||||
h = Math.max(contentHeightForWidth(MIN_CONTENT_WIDTH), maxH)
|
||||
w = Math.round((h * DESIGN_WIDTH) / DESIGN_HEIGHT)
|
||||
}
|
||||
return { width: w, height: h }
|
||||
}
|
||||
|
||||
function createWindow(): void {
|
||||
const { width, height } = getDefaultWindowSize()
|
||||
// 目标设备屏幕为 720x360,窗口默认 1:1 显示设计稿大小
|
||||
mainWindow = new BrowserWindow({
|
||||
useContentSize: true,
|
||||
width,
|
||||
height,
|
||||
width: DESIGN_WIDTH,
|
||||
height: DESIGN_HEIGHT,
|
||||
minWidth: MIN_CONTENT_WIDTH,
|
||||
minHeight: contentHeightForWidth(MIN_CONTENT_WIDTH),
|
||||
show: false,
|
||||
@@ -94,6 +84,8 @@ function createWindow(): void {
|
||||
|
||||
mainWindow.on('resize', () => {
|
||||
if (!mainWindow) return
|
||||
// 最大化时让窗口填满屏幕,不强制 2:1 内容比例
|
||||
if (mainWindow.isMaximized()) return
|
||||
const [cw, ch] = mainWindow.getContentSize()
|
||||
const wantH = contentHeightForWidth(cw)
|
||||
if (Math.abs(ch - wantH) > 2) {
|
||||
|
||||
@@ -107,7 +107,9 @@ export function registerIpcHandlers(): void {
|
||||
ribbonType: cached?.ribbonType ?? '—',
|
||||
ribbonAmount: cached?.ribbonAmount ?? '—',
|
||||
statusText: parsed.statusText,
|
||||
serialNo: cached?.serialNo ?? '—'
|
||||
serialNo: cached?.serialNo ?? '—',
|
||||
printerName: cached?.printerName ?? '—',
|
||||
isSingleSide: cached?.isSingleSide ?? false
|
||||
}
|
||||
configStore.set('lastPrinterStatus', snapshot)
|
||||
return ok({ statusText: parsed.statusText, statusCode: code })
|
||||
@@ -152,6 +154,32 @@ export function registerIpcHandlers(): void {
|
||||
}
|
||||
})
|
||||
|
||||
// 读卡:移动卡片到读取区(SAPI_PrinterMovetousbreader)
|
||||
tracedHandle('dll:printer-read-card', async () => {
|
||||
try {
|
||||
assertReady()
|
||||
const dll = await loadDllModule()
|
||||
if (!dll.isUsbReaderApiAvailable()) return fail(CS_FAIL, 'USB_READER_API_UNAVAILABLE')
|
||||
const code = dll.dllPrinterMoveToUsbReader()
|
||||
return code === CS_OK ? ok() : fail(code, '读卡失败')
|
||||
} catch (err) {
|
||||
return fail(CS_FAIL, String(err))
|
||||
}
|
||||
})
|
||||
|
||||
// 退卡:移动卡片到出卡区(SAPI_PrinterMovetohopper)
|
||||
tracedHandle('dll:printer-eject-card', async () => {
|
||||
try {
|
||||
assertReady()
|
||||
const dll = await loadDllModule()
|
||||
if (!dll.isHopperApiAvailable()) return fail(CS_FAIL, 'HOPPER_API_UNAVAILABLE')
|
||||
const code = dll.dllPrinterMoveToHopper()
|
||||
return code === CS_OK ? ok() : fail(code, '退卡失败')
|
||||
} catch (err) {
|
||||
return fail(CS_FAIL, String(err))
|
||||
}
|
||||
})
|
||||
|
||||
tracedHandle('dll:printer-error-str', async (_e, errorNo?: number) => {
|
||||
if (!mainAppState.initialized) return ok({ text: '' })
|
||||
try {
|
||||
|
||||
@@ -23,7 +23,9 @@ export async function openDesignApp(
|
||||
const target = path.resolve(exePath.trim())
|
||||
const err = await shell.openPath(target)
|
||||
if (err) {
|
||||
return { ok: false, message: err }
|
||||
// 用户在 UAC/系统弹窗中点击"否"或被系统拒绝时,shell.openPath 返回通用错误字符串
|
||||
// 不把原始 "Failed to Open Path" 直接抛给用户,给出可读说明
|
||||
return { ok: false, message: '打开设计软件失败,可能已被取消或需要管理员权限' }
|
||||
}
|
||||
return { ok: true }
|
||||
}
|
||||
|
||||
@@ -24,6 +24,8 @@ let SAPI_Init: any = null
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
let SAPI_GetPrinterInfo: any = null
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
let SAPI_FreePrinterInfo: any = null
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
let SAPI_GetPrinterErrorStr: any = null
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
let SAPI_RestJobEx: any = null
|
||||
@@ -77,6 +79,20 @@ function traceCall<T>(name: string, args: Record<string, unknown> | undefined, f
|
||||
}
|
||||
}
|
||||
|
||||
function freePrinterInfoPtr(ptr: number): void {
|
||||
if (!ptr) return
|
||||
// DLL 堆分配的缓冲区必须用 DLL 导出的释放函数;koffi.free 会触发 STATUS_HEAP_CORRUPTION
|
||||
if (SAPI_FreePrinterInfo) {
|
||||
try {
|
||||
SAPI_FreePrinterInfo(ptr)
|
||||
} catch (e) {
|
||||
log.warn('SAPI_FreePrinterInfo failed', e)
|
||||
}
|
||||
return
|
||||
}
|
||||
log.warn('SAPI_FreePrinterInfo unavailable; printer info buffer not freed')
|
||||
}
|
||||
|
||||
function readPrinterJsonFromOutPtr(len: number, outPtr: Buffer): { code: number; json?: Record<string, unknown> } {
|
||||
if (len <= 0) return { code: len }
|
||||
const ptr = koffi.decode(outPtr, 0, 'void *') as number
|
||||
@@ -90,7 +106,7 @@ function readPrinterJsonFromOutPtr(len: number, outPtr: Buffer): { code: number;
|
||||
return { code: len }
|
||||
}
|
||||
} finally {
|
||||
koffi.free(ptr)
|
||||
freePrinterInfoPtr(ptr)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,6 +126,13 @@ function loadLibrary(): void {
|
||||
SAPI_GetUsbCopyState = lib.func('int __stdcall SAPI_GetUsbCopyState(_Out_ int *, _Out_ int *)')
|
||||
SAPI_PrinterResetprinter = lib.func('int __stdcall SAPI_PrinterResetprinter()')
|
||||
|
||||
try {
|
||||
SAPI_FreePrinterInfo = lib.func('void __stdcall SAPI_FreePrinterInfo(void *)')
|
||||
} catch {
|
||||
SAPI_FreePrinterInfo = null
|
||||
log.warn('SAPI_FreePrinterInfo not in workDll')
|
||||
}
|
||||
|
||||
try {
|
||||
SAPI_UploadFile = lib.func('int __stdcall SAPI_UploadFile(str, str, str)')
|
||||
hasUploadApi = true
|
||||
@@ -151,6 +174,15 @@ function loadLibrary(): void {
|
||||
emitTrace('[dll] SAPI_PrinterMovetousbreader not in workDll (optional)')
|
||||
}
|
||||
|
||||
try {
|
||||
SAPI_PrinterMovetohopper = lib.func('int __stdcall SAPI_PrinterMovetohopper()')
|
||||
hasHopperApi = true
|
||||
} catch {
|
||||
SAPI_PrinterMovetohopper = null
|
||||
hasHopperApi = false
|
||||
emitTrace('[dll] SAPI_PrinterMovetohopper not in workDll (optional)')
|
||||
}
|
||||
|
||||
try {
|
||||
SAPI_GetPrinterCardPosition = lib.func('int __stdcall SAPI_GetPrinterCardPosition(_Out_ int *)')
|
||||
hasCardPositionApi = true
|
||||
@@ -354,6 +386,14 @@ export function dllPrinterMoveToUsbReader(): number {
|
||||
})
|
||||
}
|
||||
|
||||
export function dllPrinterMoveToHopper(): number {
|
||||
return traceCall('SAPI_PrinterMovetohopper', undefined, () => {
|
||||
loadLibrary()
|
||||
if (!SAPI_PrinterMovetohopper) throw new Error('HOPPER_API_UNAVAILABLE')
|
||||
return SAPI_PrinterMovetohopper() as number
|
||||
})
|
||||
}
|
||||
|
||||
export function dllPrinterReject(): number {
|
||||
return traceCall('SAPI_PrinterMovetoreject', undefined, () => {
|
||||
loadLibrary()
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
import koffi from 'koffi'
|
||||
|
||||
/** Windows 控制台默认多为 GBK,DLL 日志为 UTF-8,会导致中文乱码。 */
|
||||
export function ensureConsoleUtf8(): void {
|
||||
if (process.platform !== 'win32') return
|
||||
try {
|
||||
const kernel32 = koffi.load('kernel32.dll')
|
||||
const SetConsoleOutputCP = kernel32.func('bool __stdcall SetConsoleOutputCP(uint32)')
|
||||
const SetConsoleCP = kernel32.func('bool __stdcall SetConsoleCP(uint32)')
|
||||
SetConsoleOutputCP(65001)
|
||||
SetConsoleCP(65001)
|
||||
} catch {
|
||||
/* ignore: no console or API unavailable */
|
||||
}
|
||||
try {
|
||||
if (process.stdout.setDefaultEncoding) process.stdout.setDefaultEncoding('utf8')
|
||||
if (process.stderr.setDefaultEncoding) process.stderr.setDefaultEncoding('utf8')
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user