#define WIN32_LEAN_AND_MEAN
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <windowsx.h> // Makros
#include <setupapi.h>
#include <devguid.h>
#include <shlwapi.h> // ohne msvcrt.dll
#include <commctrl.h>
#include <ddeml.h>
#define elemof(x) (sizeof(x)/sizeof((x)[0]))
#define T(x) TEXT(x)
#define nobreak
#ifdef DEBUG
# define _debug(x) DebugPrintf x
void _cdecl DebugPrintf(LPCTSTR s,...) {
TCHAR buf[256];
wvnsprintf(buf,elemof(buf),s,(va_list)(&s+1));
OutputDebugString(buf);
}
#else
# define _debug(x)
#endif
#ifdef WIN32
# define Send_WM_Command(ToWnd,CtlId,NotifyCode,FromWnd)\
SendMessage(ToWnd,WM_COMMAND,MAKELONG(CtlId,NotifyCode),(LPARAM)FromWnd);
#else // Win16
# define Send_WM_Command(ToWnd,CtlId,NotifyCode,FromWnd)\
SendMessage(ToWnd,WM_COMMAND,CtlId,MAKELONG((UINT)FromWnd,NotifyCode));
#endif
#ifdef UNICODE
# define CF_TXT CF_UNICODETEXT
#else
# define CF_TXT CF_TEXT
#endif
#define WM_CONTINUEINIT (WM_USER+0x100)
HINSTANCE ghInstance;
HWND ghMainWnd;
HFONT gBigFont;
TCHAR StdMBoxTitle[64];
DWORD gComNum;
BOOL gShowSign;
TCHAR sDecimal[2]; // je nach Windows-Einstellung
DWORD gDdeInst;
HSZ hszService;
UINT CF_XlTable; // Clipboard-Format
EXTERN_C int _fltused; // Linker ruhig stellen
int _fltused;
/****************
* aus WUTILS.C *
****************/
//Win32-typische Strukturen mit DWORD-Ausrichtung initialisieren
void _fastcall InitStruct(LPVOID p, UINT len) {
LPUINT p2=(LPUINT)p; // sonst hat C++ Verdauungsstörungen
*p2=len; len/=sizeof(UINT); len--;
if (len) do *++p2=0; while (--len);
}
int vMBox(HWND Wnd, LPCTSTR Text, UINT Type, va_list va) {
TCHAR buf[256],buf2[256];
if (!((DWORD_PTR)Text>>16)) {
LoadString(ghInstance,(UINT)(DWORD_PTR)Text,buf2,elemof(buf2));
Text=buf2;
}
wvnsprintf(buf,elemof(buf),Text,va);
return MessageBox(Wnd,buf,StdMBoxTitle,Type);
}
int _cdecl MBox(HWND Wnd, LPCTSTR Text, UINT Type, ...) {
return vMBox(Wnd,Text,Type,(va_list)(&Type+1));
}
/*************
* Dialog(e) *
*************/
INT_PTR CALLBACK HardwareDlgProc(HWND Wnd,UINT Msg,WPARAM wParam,LPARAM lParam) {
switch (Msg) {
case WM_INITDIALOG: {
SetTimer(Wnd,1,1,NULL);
CheckDlgButton(Wnd,12,gShowSign);
}return TRUE;
case WM_DEVICECHANGE: SetTimer(Wnd,1,1500,NULL); break;
case WM_TIMER: {
KillTimer(Wnd,wParam);
// serielle Schnittstellen (neu) listen (bei jedem WM_DEVICECHANGE bspw. für USB)
HWND hCombo=GetDlgItem(Wnd,13);
ComboBox_ResetContent(hCombo);
HANDLE devs=SetupDiGetClassDevs(&GUID_DEVCLASS_PORTS,NULL,0,DIGCF_PRESENT);
if (devs!=INVALID_HANDLE_VALUE) {
SP_DEVINFO_DATA devInfo;
devInfo.cbSize=sizeof devInfo;
for (DWORD i=0; SetupDiEnumDeviceInfo(devs,i,&devInfo); i++) {
HKEY hKey;
TCHAR s[16];
DWORD slen=sizeof s;
DWORD num;
if ((hKey=SetupDiOpenDevRegKey(devs,&devInfo,DICS_FLAG_GLOBAL,0,DIREG_DEV,KEY_READ))
==INVALID_HANDLE_VALUE) continue;
if (!RegQueryValueEx(hKey,T("PortName"),NULL,NULL,(LPBYTE)s,&slen)
&& s[0]=='C' // LPTx ausfiltern
&& (num=StrToInt(s+3))) { // muss !=0 sein
int idx=ComboBox_AddString(hCombo,s);
ComboBox_SetItemData(hCombo,idx,num);
if (num==gComNum) ComboBox_SetCurSel(hCombo,idx);
}
RegCloseKey(hKey);
}
SetupDiDestroyDeviceInfoList(devs);
}
}break;
case WM_COMMAND: switch (LOWORD(wParam)) {
case IDOK: {
HWND hCombo=GetDlgItem(Wnd,13);
int i=ComboBox_GetCurSel(hCombo);
if (i<0) {
MBox(Wnd,(LPCTSTR)2,MB_OK);
SetFocus(hCombo);
break;
}
gComNum=(DWORD)ComboBox_GetItemData(hCombo,i);
gShowSign=IsDlgButtonChecked(Wnd,12);
}nobreak;
case IDCANCEL: EndDialog(Wnd,wParam); break;
}break;
}
return FALSE;
}
/*********************
* Temperaturabfrage *
*********************/
TCHAR gAnzeige[12];
double gValue;
HANDLE hCom;
void OpenCom(void) {
TCHAR ComName[12]; // ohne Backslashes geht's nur bis COM9!
wnsprintf(ComName,elemof(ComName),T("\\\\.\\COM%u"),gComNum);
hCom=CreateFile(ComName,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,0);
if (hCom==INVALID_HANDLE_VALUE) hCom=0;
}
static const union{
__int64 i;
double d;
}_NaN={-1}; // alle Bits 1
#define NaN _NaN.d
void QueryTemp(void) {
TCHAR Anzeige[12];
LoadString(ghInstance,3/*Fehler*/,Anzeige,elemof(Anzeige));
gValue=NaN; // ungültige Zahl zuweisen
if (hCom) {
DCB dcb;
InitStruct(&dcb,sizeof(dcb));
dcb.BaudRate=9600;
dcb.ByteSize=7;
dcb.Parity=ODDPARITY;
dcb.StopBits=TWOSTOPBITS;
dcb.fBinary=TRUE;
dcb.fParity=TRUE;
SetCommState(hCom,&dcb);
static const COMMTIMEOUTS to={0,0,100,0,0};
SetCommTimeouts(hCom,(LPCOMMTIMEOUTS)&to);
PurgeComm(hCom,PURGE_TXCLEAR|PURGE_RXCLEAR);
// Hin müssen 9 Bytes folgenden Inhaltes:
static const char WriteMsg[]={0x02,"00 1A05 "};
// Zurück kommt {0x06 "*xxxxcc"}
// mit xxxx = vzb. Temperatur in Hundertstel als Hexzahl
// und cc = Prüfcode (unbekannt, auch nach längerer Suche ungeknackt)
char ReadMsg[8];
DWORD bytes;
if (WriteFile(hCom,WriteMsg,9,&bytes,NULL)
&& bytes==9
&& ReadFile(hCom,ReadMsg,8,&bytes,NULL)
&& bytes==8
&& ReadMsg[0]==0x06
&& ReadMsg[1]=='*') {
ReadMsg[0]='0';
ReadMsg[1]='x';
ReadMsg[6]=0;
int t; // Temperatur in Hundertstel
if (StrToIntExA(ReadMsg,STIF_SUPPORT_HEX,&t)) {
t=(short)t; // Vorzeichen aufblasen
gValue=(double)t/100; // gültige Zahl zuweisen
if (-10000<=t && t<=20000) {
TCHAR sign=' ';
if (gShowSign && t>0) sign='+'; // falls gewünscht
if (t<0) {
sign='-';
t=-t;
}
wnsprintf(Anzeige,elemof(Anzeige),T("%c%u%c%02u °C"),sign,t/100,sDecimal[0],t%100);
}
}
}
}
if (lstrcmp(gAnzeige,Anzeige)) {
lstrcpy(gAnzeige,Anzeige);
if (IsIconic(ghMainWnd)) SetWindowText(ghMainWnd,gAnzeige);
else InvalidateRect(ghMainWnd,NULL,FALSE);
DdePostAdvise(gDdeInst,0,0);
}
}
HDDEDATA CALLBACK DdeCallback(UINT uType,UINT uFmt,HCONV,HSZ,HSZ hsz2,
HDDEDATA,ULONG_PTR,ULONG_PTR) {
HDDEDATA ret=DDE_FNOTPROCESSED;
switch (uType) {
case XTYP_CONNECT: ret=(HDDEDATA)TRUE; break;
case XTYP_WILDCONNECT: { // Automatische Enumeration durch Logger
HSZ pairs[3]={hszService,hszService};
ret=DdeCreateDataHandle(gDdeInst,(LPBYTE)pairs,sizeof pairs,0,0,0,0);
}break;
case XTYP_ADVSTART: if (uFmt==CF_TEXT || uFmt==CF_UNICODETEXT || uFmt==CF_XlTable) ret=(HDDEDATA)TRUE; break;
case XTYP_ADVREQ:
case XTYP_REQUEST: {
if (uFmt==CF_TEXT) {
#ifdef UNICODE
CHAR buf[elemof(gAnzeige)];
int len=WideCharToMultiByte(CP_ACP,0,gAnzeige,-1,buf,elemof(buf),NULL,NULL)+1;
ret=DdeCreateDataHandle(gDdeInst,(LPBYTE)buf,len,0,hsz2,uFmt,0);
#else
ret=DdeCreateDataHandle(gDdeInst,(LPBYTE)gAnzeige,lstrlen(gAnzeige)+1,0,hsz2,uFmt,0);
#endif
}else if (uFmt==CF_UNICODETEXT) {
#ifdef UNICODE
ret=DdeCreateDataHandle(gDdeInst,(LPBYTE)gAnzeige,(lstrlen(gAnzeige)+1)<<1,0,hsz2,uFmt,0);
#else
WCHAR buf[elemof(gAnzeige)];
int len=MultiByteToWideChar(CP_ACP,0,gAnzeige,-1,buf,elemof(buf))+1;
ret=DdeCreateDataHandle(gDdeInst,(LPBYTE)buf,len<<1,0,hsz2,uFmt,0);
#endif
}else if (uFmt==CF_XlTable) {
#pragma pack(2)
struct{
short tdtTable,dimensions,rows,cols;
short tdtType,tdtSize;
union{
double tdtDouble;
short tdtShort;
};
}XlTable={
0x0010, // Header
4, // 4 Bytes folgen
1, // 1 Spalte
1, // 1 Zeile
1, // DOUBLE
sizeof(double),
gValue};
#pragma pack()
unsigned size=sizeof(XlTable);
if (gValue!=gValue) { // INF, NaN und ähnliches
XlTable.tdtType=4; // Error
XlTable.tdtSize=sizeof(short);
XlTable.tdtShort=42; // "#NV" (nicht verfügbar)
size-=6;
}
ret=DdeCreateDataHandle(gDdeInst,(LPBYTE)&XlTable,size,0,hsz2,uFmt,0);
}
}
}
return ret;
}
/****************
* Hauptfenster *
****************/
void LoadConfig(void) {
HKEY key;
if (RegOpenKey(HKEY_CURRENT_USER,T("Software\\h#s\\TempReqNT"),&key)) return;
WINDOWPLACEMENT wp;
InitStruct(&wp,sizeof(wp));
GetWindowPlacement(ghMainWnd,&wp);
DWORD size=sizeof(wp.rcNormalPosition);
RegQueryValueEx(key,T("WindowPos"),NULL,NULL,(LPBYTE)&wp.rcNormalPosition,&size);
SetWindowPlacement(ghMainWnd,&wp);
size=sizeof(gComNum);
RegQueryValueEx(key,T("ComNum"),NULL,NULL,(LPBYTE)&gComNum,&size);
size=sizeof(gShowSign);
RegQueryValueEx(key,T("ShowSign"),NULL,NULL,(LPBYTE)&gShowSign,&size);
RegCloseKey(key);
}
void SaveConfig(void) {
HKEY key;
if (RegCreateKey(HKEY_CURRENT_USER,T("Software\\h#s\\TempReqNT"),&key)) return;
RegSetValueEx(key,NULL,0,REG_SZ,(PBYTE)StdMBoxTitle,(lstrlen(StdMBoxTitle)+1)*sizeof(TCHAR));
WINDOWPLACEMENT wp;
InitStruct(&wp,sizeof(wp));
GetWindowPlacement(ghMainWnd,&wp);
RegSetValueEx(key,T("WindowPos"),0,REG_BINARY,(LPBYTE)&wp.rcNormalPosition,sizeof(wp.rcNormalPosition));
RegSetValueEx(key,T("ComNum"),0,REG_DWORD,(LPBYTE)&gComNum,sizeof(DWORD));
RegSetValueEx(key,T("ShowSign"),0,REG_DWORD,(LPBYTE)&gShowSign,sizeof(DWORD));
RegCloseKey(key);
}
LRESULT CALLBACK MainWndProc(HWND Wnd,UINT Msg,WPARAM wParam,LPARAM lParam) {
switch (Msg) {
case WM_CREATE: {
ghMainWnd=Wnd;
HMENU SysMenu=GetSystemMenu(Wnd,FALSE);
TCHAR s[64];
LoadString(ghInstance,4,s,elemof(s)); // Menüpunkte ergänzen
InsertMenu(SysMenu,SC_CLOSE,0,0x40,s);
LoadString(ghInstance,5,s,elemof(s));
InsertMenu(SysMenu,SC_CLOSE,0,0x50,s);
SendMessage(Wnd,WM_WININICHANGE,0,0);
SendMessage(Wnd,WM_QUERYOPEN,0,0); // Titel setzen
LoadConfig();
PostMessage(Wnd,WM_CONTINUEINIT,0,0);
}break;
case WM_CONTINUEINIT: {
if (gComNum) {
OpenCom();
QueryTemp();
if (!hCom && MBox(Wnd,(LPCTSTR)6,MB_OKCANCEL,gComNum)==IDOK) Send_WM_Command(Wnd,0x40,0,0);
}else Send_WM_Command(Wnd,0x40,0,0); // beim ersten Start sofort zur Konfiguration
SetTimer(Wnd,100,1000,NULL);
}break;
case WM_WININICHANGE: {
GetProfileString(T("intl"),T("sDecimal"),T("."),sDecimal,elemof(sDecimal));
}return 0;
case WM_SIZE: {
if (wParam==SIZE_MINIMIZED) {
SetWindowText(Wnd,gAnzeige);
}else{
if (gBigFont) DeleteFont(gBigFont);
gBigFont=CreateFont(-GET_Y_LPARAM(lParam),GET_X_LPARAM(lParam)/12,0,0,0,0,0,0,0,0,0,0,0,T("Arial"));
}
}break;
case WM_PAINT: {
PAINTSTRUCT ps;
BeginPaint(Wnd,&ps);
SendMessage(Wnd,WM_PRINTCLIENT,(WPARAM)ps.hdc,0);
EndPaint(Wnd,&ps);
}return 0;
case WM_PRINTCLIENT: {
RECT r;
GetClientRect(Wnd,&r);
SelectFont((HDC)wParam,gBigFont);
SetTextAlign((HDC)wParam,TA_BOTTOM|TA_CENTER);
ExtTextOut((HDC)wParam,r.right/2,r.bottom,ETO_OPAQUE,&r,gAnzeige,lstrlen(gAnzeige),NULL);
}break;
case WM_QUERYOPEN: {
TCHAR s[64];
LoadString(ghInstance,1,s,elemof(s));
SetWindowText(Wnd,s);
}break;
case WM_COPY: {
HGLOBAL hMem=GlobalAlloc(GMEM_MOVEABLE,(lstrlen(gAnzeige)+1)*sizeof(TCHAR));
if (!hMem) break;
if (OpenClipboard(Wnd) && EmptyClipboard()) {
lstrcpy((LPTSTR)GlobalLock(hMem),gAnzeige);
GlobalUnlock(hMem);
SetClipboardData(CF_TXT,hMem);
CloseClipboard();
}else GlobalFree(hMem);
}break;
case WM_COMMAND: // von TranslateAccelerator
case WM_SYSCOMMAND: switch (wParam&0xFFF0) {
case 0x40: if (DialogBox(ghInstance,MAKEINTRESOURCE(100),Wnd,HardwareDlgProc)==IDOK) {
if (hCom) CloseHandle(hCom);
OpenCom();
QueryTemp();
}break;
case 0x50: SendMessage(Wnd,WM_COPY,0,0);
}break;
case WM_TIMER: QueryTemp(); break; // Temperaturabfrage
case WM_CLOSE: SendMessage(Wnd,WM_ENDSESSION,1,0); break; // speichern auslösen!
case WM_ENDSESSION: if (wParam) SaveConfig(); break;
case WM_DESTROY: {
if (hCom) CloseHandle(hCom);
if (gBigFont) DeleteFont(gBigFont);
PostQuitMessage(0);
}break;
}
return DefWindowProc(Wnd,Msg,wParam,lParam);
}
/******************************
* Hauptprogramm (lächerlich) *
******************************/
int _stdcall WinMainCRTStartup(void) {
ghInstance=GetModuleHandle(NULL);
WNDCLASSEX wc;
InitStruct(&wc,sizeof(wc));
wc.style=CS_HREDRAW|CS_VREDRAW;
wc.lpfnWndProc=MainWndProc;
wc.hInstance=ghInstance;
wc.hCursor=LoadCursor(0,IDC_ARROW);
wc.hIcon=LoadIcon(ghInstance,MAKEINTRESOURCE(100));
wc.lpszMenuName=MAKEINTRESOURCE(100);
wc.lpszClassName=T("TempReqNT");
RegisterClassEx(&wc);
InitCommonControls(); // wichtig für Teletubbieoptik!
LoadString(ghInstance,1,StdMBoxTitle,elemof(StdMBoxTitle));
ghMainWnd=CreateWindowEx(WS_EX_ACCEPTFILES|WS_EX_OVERLAPPEDWINDOW,
T("TempReqNT"),NULL,WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,0,
CW_USEDEFAULT,0,
0,0,ghInstance,GetCommandLine());
ShowWindow(ghMainWnd,SW_SHOWDEFAULT);
CF_XlTable=RegisterClipboardFormat(T("XlTable")); // Excel-Tabellenformat
DdeInitialize(&gDdeInst,DdeCallback,APPCLASS_STANDARD
|CBF_FAIL_POKES|CBF_FAIL_EXECUTES
|CBF_SKIP_CONNECT_CONFIRMS|CBF_SKIP_REGISTRATIONS
|CBF_SKIP_DISCONNECTS|CBF_SKIP_UNREGISTRATIONS,0);
hszService=DdeCreateStringHandle(gDdeInst,T("TempReqNT"),CP_WINNEUTRAL);
DdeNameService(gDdeInst,hszService,0,DNS_REGISTER|DNS_FILTERON);
MSG Msg;
HACCEL hAccel=LoadAccelerators(ghInstance,MAKEINTRESOURCE(100));
while (GetMessage(&Msg,0,0,0)) {
if (TranslateAccelerator(ghMainWnd,hAccel,&Msg)) continue;
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
DdeFreeStringHandle(gDdeInst,hszService);
DdeUninitialize(gDdeInst);
ExitProcess((UINT)Msg.wParam);
}
| Detected encoding: ANSI (CP1252) | 4
|
|
|