#define WIN32_LEAN_AND_MEAN
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <windowsx.h> // Makros
#include <setupapi.h>
#include <devguid.h>
#include <commctrl.h>
#include <ddeml.h>
#include <stdio.h>
#include <stdlib.h>
#include <tchar.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];
_sntprintf(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
# define FMT_STR L"%S"
#else
# define CF_TXT CF_TEXT
# define FMT_STR "s"
#endif
#define WM_CONTINUEINIT (WM_USER+0x100)
HINSTANCE ghInstance;
HWND ghMainWnd;
HFONT gBigFont,gExFont;
TCHAR StdMBoxTitle[64];
DWORD gComNum;
int gNK; // angezeigte Nachkommastellen (1 oder 2)
TCHAR sDecimal[2]; // je nach Windows-Einstellung
TCHAR sNegativeSign[2];
TCHAR sPositiveSign[2];
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;
}
_vsntprintf(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));
}
/**********************************
* Gleitkommazahlen-Konvertierung *
**********************************/
#if _MSC_VER >= 1400 && defined(_M_IX86)
EXTERN_C long _declspec(naked) _cdecl _ftol2_sse(double v) {
_asm { push eax
fistp dword ptr [esp] // die Zahl wurde auf ST0 übergeben
pop eax
ret
}
}
#endif
// Hier: als Festkommawert ausgeben
int DoubleToString(double v, int nk, LPTSTR buf, UINT buflen) {
// if (!_finite(v)) return _sntprintf(buf,buflen,T("NaN"));
int i=_sntprintf(buf,buflen,T("%.*f"),nk,v);
LPTSTR p=_tcschr(buf,'.');
if (p) *p=*sDecimal;
return i;
}
bool StringToDoubleA(LPCSTR s, double*v) {
if (!s || !*s) return false;
char buf[32];
lstrcpynA(buf,s,elemof(buf));
char *p=strchr((char*)s,',');
if (p) *p='.'; // Komma durch Punkt ersetzen (unabhängig von sDecimal)
double t=strtod(buf,(char**)&s);
if (v) *v=t;
return !*s; // OK nur wenn String-Ende erreicht
}
#ifdef UNICODE
bool StringToDouble(LPCWSTR s, double*v) {
if (!s) return false;
CHAR buf[32];
WideCharToMultiByte(CP_ACP,0,s,-1,buf,elemof(buf),0,0);
return StringToDoubleA(buf,v);
}
#else
# define StringToDouble StringToDoubleA
#endif
/*********************
* Temperaturabfrage *
*********************/
HSZ hszSoll; // DDE-String-Handles
double gSoll,gIst; // DDE-Variablen (in °C)
HANDLE hCom;
void SetWindowTitle(void) {
TCHAR s[64];
if (IsIconic(ghMainWnd)) {
if (gIst==gIst) {
int l=DoubleToString(gIst,2,s,elemof(s)-3);
lstrcpyn(s+l,T(" °C"),elemof(s)-l);
}else{
LoadString(ghInstance,3,s,elemof(s)); // "Fehler"
}
}else{
LoadString(ghInstance,1,s,elemof(s));
}
SetWindowText(ghMainWnd,s);
}
void OpenCom(void) {
TCHAR ComName[12];
_sntprintf(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; return;}
DCB dcb;
InitStruct(&dcb,sizeof(dcb));
dcb.BaudRate=9600;
dcb.ByteSize=8;
dcb.fBinary=TRUE;
SetCommState(hCom,&dcb);
static const COMMTIMEOUTS to={0,0,100,0,0};
SetCommTimeouts(hCom,(LPCOMMTIMEOUTS)&to);
}
// Der dumme Kalibrator will zwischen jedem gesendeten Zeichen eine kleine
// Pause (> 2 Stoppbits) haben! Bei 9600 Baud braucht 1 Zeichen ca. 1 ms
void SendSlowly(const char*s) {
for(;*s;s++) {
DWORD dwBytes;
WriteFile(hCom,s,1,&dwBytes,NULL);
Sleep(10);
}
}
bool SendPassword(void) {
if (!hCom) return false;
PurgeComm(hCom,PURGE_TXCLEAR|PURGE_RXCLEAR);
SendSlowly("O");
char ReadMsg[3];
DWORD dwBytes;
if (ReadFile(hCom,ReadMsg,3,&dwBytes,NULL)
&& dwBytes==3
&& ReadMsg[0]=='O'
&& ReadMsg[1]=='\r'
&& ReadMsg[2]=='\n') {
SendSlowly("^<%+@/*{");
return true;
}
return false;
}
bool QueryDevice(LPTSTR buf, UINT buflen) {
if (!hCom) return false;
SendSlowly("D");
char ReadMsg[32];
DWORD dwBytes;
if (ReadFile(hCom,ReadMsg,sizeof ReadMsg-1,&dwBytes,NULL)
&& ReadMsg[0]=='D'
&& ReadMsg[1]=='\r'
&& ReadMsg[2]=='\n') {
ReadMsg[dwBytes]=0;
char*p=strchr(ReadMsg+3,'\r');
if (!p) return false;
*p=0;
buf[_sntprintf(buf,buflen-1,FMT_STR,ReadMsg+3)]=0;
return true;
}
return false;
}
bool QueryVersion(LPTSTR buf, UINT buflen) {
if (!hCom) return false;
SendSlowly("V");
char ReadMsg[256];
DWORD dwBytes;
if (ReadFile(hCom,ReadMsg,sizeof ReadMsg-1,&dwBytes,NULL)
&& ReadMsg[0]=='V'
&& ReadMsg[1]=='\n' // wirklich andersherum hier!!
&& ReadMsg[2]=='\r') {
ReadMsg[dwBytes]=0;
buf[_sntprintf(buf,buflen,FMT_STR,ReadMsg+3)]=0;
return true;
}
return false;
}
static const union{
__int64 i;
double d;
}_NaN={-1}; // alle Bits 1
#define NaN _NaN.d
bool SetIst(double Ist) {
if (gIst!=Ist && (gIst==gIst || Ist==Ist)) { // NaN != NaN
gIst=Ist;
if (IsIconic(ghMainWnd)) SetWindowTitle();
else{
RECT r;
GetClientRect(ghMainWnd,&r);
r.top=r.bottom>>1;
InvalidateRect(ghMainWnd,&r,TRUE); // untere Hälfte neu zeichnen
}
DdePostAdvise(gDdeInst,0,0);
}
return true;
}
bool QueryIst(void) {
if (hCom) {
PurgeComm(hCom,PURGE_TXCLEAR|PURGE_RXCLEAR);
SendSlowly("T");
// Zurück kommt {"TB±0xxx.xx\r\n"}
// mit xxx.xx = Temperatur in Hundertstel, in °C
char ReadMsg[13];
DWORD dwBytes;
double Ist;
if (ReadFile(hCom,ReadMsg,12,&dwBytes,NULL)
&& dwBytes==12
&& sscanf(ReadMsg,"TB%lf\r\n",&Ist)==1) return SetIst(Ist);
}
SetIst(NaN);
return false;
}
bool CalcSoll(WORD hexval, double*val) {
static const WORD hexvals[]={
// -40 -30 -20 -10 0 10 20 30 40 50 60 70 80 90 100 110 120 130 140 °C
0x36A5,0x38FD,0x3B55,0x3DAD,0x4005,0x425D,0x44B5,0x470D,0x4965,0x4BBD,0x4E15,0x506D,0x52C5,0x551D,0x5775,0x59CD,0x5C25,0x5E7D,0x60D5+1};
int i;
for (i=0; i<elemof(hexvals); i++) if (hexval<hexvals[i]) break;
if (i==0) return false;
if (i==elemof(hexvals)) return false;
// stückweise Geraden-Approximation
if (val) *val=((double)(hexval-hexvals[i-1])/(hexvals[i]-hexvals[i-1])+i)*10-50;
return true;
}
void InternalSetSoll(double Soll) {
if (gSoll!=Soll && (gSoll==gSoll || Soll==Soll)) {
gSoll=Soll;
RECT r;
GetClientRect(ghMainWnd,&r);
r.bottom>>=1;
InvalidateRect(ghMainWnd,&r,TRUE); // obere Hälfte neu zeichnen
DdePostAdvise(gDdeInst,0,hszSoll);
}
}
bool QuerySoll(void) {
if (hCom) {
PurgeComm(hCom,PURGE_TXCLEAR|PURGE_RXCLEAR);
SendSlowly("s");
// Zurück kommt {"s\r\nxxxx00\r\n"}
char ReadMsg[12];
DWORD dwBytes;
long hexval;
double Soll;
if (ReadFile(hCom,ReadMsg,11,&dwBytes,NULL)
&& dwBytes==11
&& sscanf(ReadMsg,"s\r\n%lx\r\n",&hexval)==1
&& !(hexval&0xFF)
&& CalcSoll(WORD(hexval>>8),&Soll)) {
InternalSetSoll(Soll);
return true;
}
}
InternalSetSoll(NaN);
return false;
}
bool SendSoll(double Soll) {
if (!hCom) return false;
PurgeComm(hCom,PURGE_TXCLEAR|PURGE_RXCLEAR);
Soll*=100;
long val=(long)Soll; // ruft _ftol2_sse
char vz='+'; // Vorzeichen
if (val<0) val=-val, vz='-';
char WriteMsg[12],ReadMsg[12];
_snprintf(WriteMsg,elemof(WriteMsg),"S%c%04d.%02d\r\n",vz,val/100,val%100);
SendSlowly(WriteMsg);
DWORD dwBytes;
ReadMsg[11]=0;
if (ReadFile(hCom,ReadMsg,11,&dwBytes,NULL)
&& dwBytes==11
&& !lstrcmpA(WriteMsg,ReadMsg)) return true;
return false;
}
bool SetSoll(double Soll) {
if (Soll<-40.0) return false;
if (Soll>140.0) return false;
if (gSoll!=Soll) {
if (!SendSoll(Soll)) return false;
InternalSetSoll(Soll);
}
return true;
}
void InitCom(void) {
OpenCom();
if (hCom) {
SendPassword();
QuerySoll();
QueryIst();
}else{
MBox(ghMainWnd,(LPCTSTR)8,MB_OK|MB_ICONEXCLAMATION,gComNum);
Send_WM_Command(ghMainWnd,0x40,0,0); // sofort zur Konfiguration
}
}
/*******
* DDE *
*******/
#pragma pack(2)
typedef struct{
short tdtTable,dimensions,rows,cols; // 0x0010,4,1,1
short tdtType,tdtSize; // 1,sizeof(double)=8
double tdtData;
}TXlTableDouble;
typedef struct{
short tdtTable,dimensions,rows,cols; // 0x0010,4,1,1
short tdtType,tdtSize; // 4,sizeof(XlError)=2
short tdtErrorCode; // 36 = #NUM! (0=#NULL!,7=#DIV/0!,15=#VALUE!,23=#REF!,29=#NAME?,42=#N/A)
}TXlTableError;
#pragma pack()
HDDEDATA CALLBACK DdeCallback(UINT uType,UINT uFmt,HCONV,HSZ,HSZ hsz2,
HDDEDATA hData,ULONG_PTR,ULONG_PTR) {
HDDEDATA ret=DDE_FNOTPROCESSED;
switch (uType) {
case XTYP_ADVSTART: switch (uFmt) {
#ifdef UNICODE
case CF_TEXT:
#endif
case CF_TXT: break;
default: if (uFmt==CF_XlTable) break;
return ret;
}
case XTYP_CONNECT: ret=(HDDEDATA)TRUE; break;
case XTYP_WILDCONNECT: { // Automatische Enumeration durch Logger ("Item" fehlt noch!)
HSZ pairs[3]={hszService,hszService};
ret=DdeCreateDataHandle(gDdeInst,(LPBYTE)pairs,sizeof pairs,0,0,0,0);
}break;
case XTYP_POKE: if (!DdeCmpStringHandles(hsz2,hszSoll)) {
switch (uFmt) {
#ifdef UNICODE
case CF_TEXT: {
LPCSTR s=(LPCSTR)DdeAccessData(hData,NULL);
double v;
if (StringToDoubleA(s,&v) && SetSoll(v)) ret=(HDDEDATA)DDE_FACK;
DdeUnaccessData(hData);
}break;
#endif
case CF_TXT: {
LPCTSTR s=(LPCTSTR)DdeAccessData(hData,NULL);
double v;
if (StringToDouble(s,&v) && SetSoll(v)) ret=(HDDEDATA)DDE_FACK;
DdeUnaccessData(hData);
}break;
default: if (uFmt==CF_XlTable) {
DWORD len;
const TXlTableDouble*pXlTable=(const TXlTableDouble*)DdeAccessData(hData,&len);
if (len>=sizeof(TXlTableDouble) // Mindest-Datenmenge
&& pXlTable->tdtTable==0x0010 // richtiger Kopf
&& pXlTable->tdtType==1 // richtiger Typ-Kode
&& SetSoll(pXlTable->tdtData)) ret=(HDDEDATA)DDE_FACK;
DdeUnaccessData(hData);
}
}
}break;
case XTYP_ADVREQ:
case XTYP_REQUEST: {
double report;
if (!DdeCmpStringHandles(hsz2,hszSoll)) report=gSoll;
else report=gIst; // alles andere ist Istwert
switch (uFmt) {
#ifdef UNICODE
case CF_TEXT: {
TCHAR buf[32];
CHAR bufc[32];
DoubleToString(report,2,buf,elemof(buf));
int len=_snprintf(bufc,elemof(bufc),"%S",buf)+1;
ret=DdeCreateDataHandle(gDdeInst,(LPBYTE)bufc,len,0,hsz2,uFmt,0);
}break;
#endif
default: if (uFmt==CF_XlTable) {
TXlTableDouble XlTable={
0x0010, // Header
4, // 4 Bytes folgen
1, // 1 Spalte
1, // 1 Zeile
1, // DOUBLE
sizeof(double),
report};
if (report!=report) { // NaN
XlTable.tdtType=4;
XlTable.tdtSize=2;
((TXlTableError*)&XlTable)->tdtErrorCode=36;
}
ret=DdeCreateDataHandle(gDdeInst,(LPBYTE)&XlTable,sizeof(XlTable),0,hsz2,uFmt,0);
}else{ // Typ CF_TEXT oder CF_UNICODETEXT liefern
TCHAR buf[32];
ret=DdeCreateDataHandle(gDdeInst,(LPBYTE)buf,
(DoubleToString(report,2,buf,elemof(buf))+1)*sizeof(TCHAR),0,hsz2,CF_TXT,0);
}
}
}break;
}
return ret;
}
/*************
* 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,10+gNK-1,TRUE);
TCHAR s[32];
DoubleToString(gSoll,gNK,s,elemof(s));
SetDlgItemText(Wnd,16,s);
SendDlgItemMessage(Wnd,16,EM_SETMODIFY,0,0);
}return TRUE;
case WM_DEVICECHANGE: SetTimer(Wnd,1,1500,NULL);
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)
&& _stscanf(s,T("COM%u"),&num)==1) { // LPTx ausfiltern
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 10: switch (HIWORD(wParam)) {
case EN_CHANGE: SetTimer(Wnd,10,200,NULL); break;
}break;
case 17: { // Taste „Setzen“
TCHAR s[32];
HWND w=GetDlgItem(Wnd,16);
GetWindowText(w,s,elemof(s));
double v;
LPCTSTR error=(LPCTSTR)9;
if (StringToDouble(s,&v)) {
error=(LPCTSTR)10;
if (SetSoll(v)) break;
}
MBox(Wnd,error,MB_OK|MB_ICONEXCLAMATION); // Fehler (je nach Kode)
SetFocus(w);
Edit_SetSel(w,0,-1);
Edit_SetModify(w,FALSE);
}break;
case IDOK: {
HWND hCombo=GetDlgItem(Wnd,13);
int i=ComboBox_GetCurSel(hCombo);
if (i<0) {
MBox(Wnd,(LPCTSTR)2,MB_OK|MB_ICONEXCLAMATION);
SetFocus(hCombo);
break;
}
gComNum=(DWORD)ComboBox_GetItemData(hCombo,i);
gNK=IsDlgButtonChecked(Wnd,10)?1:2;
if (SendDlgItemMessage(Wnd,16,EM_GETMODIFY,0,0)) Send_WM_Command(Wnd,17,BN_CLICKED,Wnd);
}nobreak;
case IDCANCEL: EndDialog(Wnd,wParam); break;
}break;
}
return FALSE;
}
/****************
* Hauptfenster *
****************/
void LoadConfig(void) {
HKEY key;
gNK=2; // nicht auf 0 stehen lassen
if (RegOpenKeyEx(HKEY_CURRENT_USER,T("Software\\h#s\\TecalNT"),
0,KEY_QUERY_VALUE,&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(gNK);
RegQueryValueEx(key,T("Decimals"),NULL,NULL,(LPBYTE)&gNK,&size);
RegCloseKey(key);
}
void SaveConfig(void) {
HKEY key;
if (RegCreateKeyEx(HKEY_CURRENT_USER,T("Software\\h#s\\TecalNT"),
0,NULL,REG_OPTION_NON_VOLATILE,KEY_SET_VALUE,NULL,&key,NULL)) return;
RegSetValue(key,NULL,REG_SZ,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("Decimals"),0,REG_DWORD,(LPBYTE)&gNK,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];
for (int i=4; i<8; i++) {
LoadString(ghInstance,i,s,elemof(s)); // Menüpunkte ergänzen
InsertMenu(SysMenu,SC_CLOSE,0,i*0x10,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) InitCom();
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));
GetProfileString(T("intl"),T("sNegativeSign"),T("-"),sNegativeSign,elemof(sNegativeSign));
GetProfileString(T("intl"),T("sPositiveSign"),T(""),sPositiveSign,elemof(sPositiveSign));
}return 0;
case WM_SIZE: {
if (wParam==SIZE_MINIMIZED) SetWindowTitle();
else{
if (gBigFont) DeleteFont(gBigFont);
if (gExFont) DeleteFont(gExFont);
gBigFont=CreateFont(-GET_Y_LPARAM(lParam)/2,GET_X_LPARAM(lParam)/12,0,0,0,0,0,0,0,0,0,0,0,T("Arial"));
gExFont=CreateFont(-GET_Y_LPARAM(lParam)/8,GET_X_LPARAM(lParam)/48,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;
TCHAR s[32];
GetClientRect(Wnd,&r);
int l;
// Istwert
SelectFont((HDC)wParam,gBigFont);
SetTextAlign((HDC)wParam,TA_BOTTOM|TA_RIGHT);
if (gIst==gIst) {
l=DoubleToString(gIst,gNK,s,elemof(s));
lstrcpyn(s+l,T(" °C"),elemof(s)-l);
l+=3;
}else l=LoadString(ghInstance,3,s,elemof(s)); // "Fehler"
TextOut((HDC)wParam,r.right,r.bottom,s,l);
// Ist-Beschreibung
SelectFont((HDC)wParam,gExFont);
SetTextAlign((HDC)wParam,TA_TOP|TA_LEFT);
TextOut((HDC)wParam,0,r.bottom/2,s,LoadString(ghInstance,15/*Istwert*/,s,elemof(s)));
// Sollwert
SetTextColor((HDC)wParam,RGB(192,192,192));
SelectFont((HDC)wParam,gBigFont);
SetTextAlign((HDC)wParam,TA_BOTTOM|TA_RIGHT);
if (gSoll==gSoll) {
l=DoubleToString(gSoll,gNK,s,elemof(s));
lstrcpyn(s+l,T(" °C"),elemof(s)-l);
l+=3;
}else l=LoadString(ghInstance,3,s,elemof(s)); // "Fehler"
TextOut((HDC)wParam,r.right,r.bottom/2,s,l);
// Soll-Beschreibung
SelectFont((HDC)wParam,gExFont);
SetTextAlign((HDC)wParam,TA_TOP|TA_LEFT);
TextOut((HDC)wParam,0,0,s,LoadString(ghInstance,14/*Sollwert*/,s,elemof(s)));
}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,32*sizeof(TCHAR));
if (!hMem) break;
if (OpenClipboard(Wnd) && EmptyClipboard()) {
DoubleToString(gSoll,gNK,(LPTSTR)GlobalLock(hMem),32);
GlobalUnlock(hMem);
SetClipboardData(CF_TXT,hMem);
CloseClipboard();
}else GlobalFree(hMem);
}break;
case WM_PASTE: if (OpenClipboard(Wnd)) {
HANDLE h=GetClipboardData(CF_TXT);
if (h) {
double Soll;
StringToDouble((LPCTSTR)GlobalLock(h),&Soll);
GlobalUnlock(h);
SetSoll(Soll);
}
CloseClipboard();
}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);
InitCom();
}break;
case 0x50: SendMessage(Wnd,WM_COPY,0,0); break;
case 0x60: SendMessage(Wnd,WM_PASTE,0,0); break;
case 0x70: {
TCHAR s1[32],s2[256];
lstrcpyn(s1,T("--"),elemof(s1));
lstrcpyn(s2,T("--"),elemof(s2));
QueryDevice(s1,elemof(s1));
QueryVersion(s2,elemof(s2));
MBox(Wnd,(LPCTSTR)11,MB_OK|MB_ICONINFORMATION,s1,s2);
}break;
}break;
case WM_TIMER: if (!QuerySoll()) SendPassword(); QueryIst(); 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);
if (gExFont) DeleteFont(gExFont);
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.hbrBackground=(HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName=MAKEINTRESOURCE(100);
wc.lpszClassName=T("TecalNT");
RegisterClassEx(&wc);
InitCommonControls(); // wichtig für Teletubbieoptik!
LoadString(ghInstance,1,StdMBoxTitle,elemof(StdMBoxTitle));
ghMainWnd=CreateWindowEx(WS_EX_ACCEPTFILES|WS_EX_OVERLAPPEDWINDOW,
T("TecalNT"),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_EXECUTES
|CBF_SKIP_CONNECT_CONFIRMS|CBF_SKIP_REGISTRATIONS
|CBF_SKIP_DISCONNECTS|CBF_SKIP_UNREGISTRATIONS,0);
hszService=DdeCreateStringHandle(gDdeInst,T("TecalNT"),CP_WINNEUTRAL);
hszSoll=DdeCreateStringHandle(gDdeInst,T("Soll"),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,hszSoll);
DdeFreeStringHandle(gDdeInst,hszService);
DdeUninitialize(gDdeInst);
ExitProcess((UINT)Msg.wParam);
}
Detected encoding: ANSI (CP1252) | 4
|
|