將 POS 機廠商提供的 Police.dll(無標頭檔、僅百字說明)封裝進 ATL ActiveX 控制項,供 IE 網頁呼叫操作硬體。
無標頭檔時,以 LoadLibrary + GetProcAddress 取得函數位址,轉型為正確呼叫慣例(__stdcall)的函數指標。
IPosCtrl)| 方法 | 功能 |
|---|---|
Init(short nCom) | 載入 DLL、開啟 COM 埠 |
Quit() | 關閉 COM 埠、卸載 DLL |
ModifyPosDT(BSTR bstrDT) | 設定 POS 機時間 |
EmptyPos() | 清空 POS 機資料 |
CPosCtrl)#pragma data_seg("mydata")
static HINSTANCE DLLInst = NULL;
#pragma data_seg()
HANDLE (__stdcall *Init_comm)(LPSTR);
BYTE (__stdcall *Exit)(HANDLE);
BYTE (__stdcall *Protocol)(HANDLE, BYTE, BYTE, BYTE*, BYTE*, BYTE*);
BYTE (__stdcall *Pipe_control)(HANDLE, BYTE);
BYTE (__stdcall *Dev_escape)(HANDLE);
#pragma data_seg("mydata") 讓 DLLInst 處於共享區段,多進程載入同一 ActiveX 時共用 DLL 句柄(視需求決定是否需要)。
void CPosCtrl::InitDll() {
DLLInst = LoadLibrary("police.dll");
if (DLLInst) {
Init_comm = (HANDLE(__stdcall*)(LPSTR))GetProcAddress(DLLInst, "Init_comm");
Exit = (BYTE(__stdcall*)(HANDLE))GetProcAddress(DLLInst, "Exit");
Protocol = (BYTE(__stdcall*)(HANDLE,BYTE,BYTE,BYTE*,BYTE*,BYTE*))GetProcAddress(DLLInst, "Protocol");
Pipe_control = (BYTE(__stdcall*)(HANDLE,BYTE))GetProcAddress(DLLInst, "Pipe_control");
Dev_escape = (BYTE(__stdcall*)(HANDLE))GetProcAddress(DLLInst, "Dev_escape");
}
else {
MessageBox(NULL, "載入 DLL 失敗!", "錯誤", MB_OK|MB_ICONERROR);
exit(0);
}
}
void CPosCtrl::ExitDll() {
if (DLLInst) FreeLibrary(DLLInst);
}
STDMETHODIMP CPosCtrl::Init(short nComNo) {
InitDll();
char str[20]; sprintf(str, "COM%d", nComNo);
hCom = (*Init_comm)(str);
MessageBox(NULL, "開啟 COM 埠成功", "提示", MB_OK);
return S_OK;
}
STDMETHODIMP CPosCtrl::Quit() {
(*Exit)(hCom);
ExitDll();
MessageBox(NULL, "關閉 COM 埠成功", "提示", MB_OK);
return S_OK;
}
STDMETHODIMP CPosCtrl::ModifyPosDT(BSTR bstrDT) {
return SetPosDateTime((char*)bstrDT) ? S_OK : S_FALSE;
}
STDMETHODIMP CPosCtrl::EmptyPos() {
ClearPos();
return S_OK;
}
void CPosCtrl::ASCII_TO_BCD(char* cSource, char* cResult, int iSourceLen, int iResultLen) {
int iBegin = (iSourceLen % 2) ? 1 : 0;
if (iBegin) cResult[0] = cSource[0] - '0';
for (int i = iBegin; i < iResultLen; i++)
cResult[i] = (cSource[2*i-iBegin]-'0')*16 + (cSource[2*i-iBegin+1]-'0');
cResult[iResultLen] = '\0';
}
BOOL CPosCtrl::SetPosDateTime(char* pchDateTime) {
unsigned char cInput[257], cOutput[256];
BYTE byOutput, retVal;
for (int n=1, i=0; i<8; i++, n<<=1) { // 8 路裝置
(*Pipe_control)(hCom, n);
if (MessageBox(NULL, "確定修改時間?", "確認", MB_YESNO) == IDNO) return FALSE;
ASCII_TO_BCD(pchDateTime, (char*)cInput, 10, 5);
retVal = (*Protocol)(hCom, 0x85, 5, cInput, &byOutput, cOutput); // Com_DownDateTime
MessageBox(NULL, retVal ? "修改成功" : "修改失敗", "結果", MB_OK);
}
(*Protocol)(hCom, 0x86, 5, cInput, &byOutput, cOutput); // Com_Exit
(*Dev_escape)(hCom);
(*Pipe_control)(hCom, 0);
return TRUE;
}
PosActiveX.dll。regsvr32 C:\Path\PosActiveX.dll。Police.dll 必須置於系統目錄:
Windows\SystemWINNT\System32 (或 System32)LoadLibrary 找不到 DLL。<object id="posCtrl" classid="clsid:YOUR-CLSID" width=0 height=0></object>
<script>
posCtrl.Init(1); // 開啟 COM1
posCtrl.ModifyPosDT("202401011200"); // 設定時間
posCtrl.EmptyPos(); // 清空資料
posCtrl.Quit(); // 關閉
</script>
GetProcAddress 應檢查 NULL,避免呼叫空指標崩潰。BSTR 為 Unicode,傳給 ANSI DLL 需 WideCharToMultiByte 或 _bstr_t 轉換,範例直接轉型有風險。hCom 需關鍵區保護。Quit 必須確保被呼叫(頁面卸載 onbeforeunload 呼叫),否則 COM 埠、DLL 句柄洩漏。Safe for Scripting/Initialization 才能在 IE 低安全性區域執行。