#include "vipsys3.h"
#include <windows.h>
#include <windowsx.h>
#include <shlwapi.h>
#include <commctrl.h>
#include <stdio.h>
#include <tchar.h>
#include <limits.h>
#include "analyzer.h"
#include <math.h>
#if _MSC_VER < 1400 // Visual C++ 6
__forceinline void __stosd(void*p, DWORD val, DWORD count) {
_asm mov edi,p
_asm mov eax,val
_asm mov ecx,count
_asm rep stosd
}
__forceinline void __movsw(void*d, const void*s, DWORD count) {
_asm mov edi,d
_asm mov esi,s
_asm mov ecx,count
_asm rep movsw
}
#else
# include <intrin.h>
#endif
/* Wunschliste:
* Funktionierend
* Log-Datei
* Reboot überstehen
*/
HINSTANCE ghInst;
HWND ghMainWnd,ghStatus;
HICON ghIcons[2];
HANDLE hCom;
int Instance;
TConfig Config;
/**********************************
* Zeichenobjekte und -funktionen *
**********************************/
#define FONTNAME T("Arial") // Name of standard font used
struct GDI{ // holds GDI resources needed for painting the client area
HFONT fntBig,fntSmall; // fonts
HPEN penGrid; // for table styling
HBITMAP bmDblBuf; // bitmap and DC, only used for double buffering
HDC dcDblBuf;
void Make(int,int); // (Re)Creates fonts and doublebuffer bitmap for given client pixel size
void Make(); // Same but fetches the client size beforehand
void Delete(); // Releases all GDI resources, for minimized display
static void ClientRect(RECT&);
int xx; // Spaltenbreite (Pixel)
int yy; // Zeilenhöhe (Pixel)
private:
static HFONT MakeFont(int,int,int,LPCTSTR);
static void DeleteObj(HGDIOBJ&);
}gGdi;
void GDI::DeleteObj(HGDIOBJ&obj) {
if (obj && DeleteObject(obj)) obj=0;
}
void GDI::Delete() {
if (dcDblBuf && DeleteDC(dcDblBuf)) dcDblBuf=0; // kicks out selected pen, font, and bitmap
HGDIOBJ *obj=(HGDIOBJ*)this;
for (int i=0; i<4; i++) DeleteObj(obj[i]);
}
HFONT GDI::MakeFont(int x, int y, int weight, LPCTSTR name) {
HFONT ret=CreateFont(y,x,0,0,weight,0,0,0,DEFAULT_CHARSET,0,0,0,0,name);
return ret;
}
// Font re-initialization, called when
// * window size changes
// * measurement unit or prefix changes
// * appearance changes between scope and multimeter mode
void GDI::Make(int x, int y) {
Delete();
if (Config.doubleBuf) {
HDC dc=GetDC(0);
bmDblBuf=CreateCompatibleBitmap(dc,x,y);
dcDblBuf=CreateCompatibleDC(dc);
ReleaseDC(0,dc);
SelectBitmap(dcDblBuf,bmDblBuf);
}
fntBig=MakeFont(x/30,MulDiv(y,2,8),0,FONTNAME);
xx=x/5;
yy=30;
fntSmall=MakeFont(MulDiv(xx,10,256),yy,0,FONTNAME);
}
void GDI::ClientRect(RECT&r) {
static const int Info[]={1,1,2,1,0};
GetEffectiveClientRect(ghMainWnd,&r,(int*)Info);
}
void GDI::Make() {
RECT r;
ClientRect(r);
Make(r.right-r.left,r.bottom-r.top);
}
TCHAR StdMBoxTitle[64];
// Assumption: The decimal character is never an MBCS character! Is this true?
WCHAR cDecimalW; // The decimal delimiter
char cDecimalA; // ANSI version
DWORD gDdeInst;
UINT CF_XlTable; // Clipboard-Format
#ifdef UNICODE
#define MyLoadStringW(id,buf,len) LoadString(ghInst,id,buf,len)
#else
int MyLoadStringW(UINT id, LPWSTR buf, int len) {
HRSRC r=FindResource(ghInst,MAKEINTRESOURCE((id>>4)+1),RT_STRING);
PCWSTR p=(PCWSTR)LoadResource(ghInst,r);
if (!p) return 0;
for (id&=15; id; id--) {
p+=*p+1;
}
len--;
if (len<0) return *p+1; // Allokationsgröße in Zeichen
if (len>*p) len=*p;
p++;
__movsw((WORD*)buf,(WORD*)p,len); // inklusive etwaiger Nullen!
buf[len]=0;
return len;
}
#endif
static const int _NaN = _I32_MAX; // "signaling NaN"
#define NaN (*(float*)&_NaN)
/*******************
* Hilfsfunktionen *
*******************/
void _fastcall InitStruct(LPVOID p, DWORD len) {
__stosd((DWORD*)p,0,len>>2);
*(DWORD*)p=len;
}
UINT GetCheckboxGroup(HWND Wnd, UINT u, UINT o) {
UINT v,m;
for (v=0,m=1; u<=o; u++,m+=m) if (IsDlgButtonChecked(Wnd,u)==1) v|=m;
return v;
}
void SetCheckboxGroup(HWND Wnd, UINT u, UINT o, UINT v) {
for (; u<=o; u++,v>>=1) CheckDlgButton(Wnd,u,v&1);
}
// Wandelt eine (Hex-)Ziffer [0-9A-Z] in eine Zahl 0..35, sonst >=36
static char OneDigit(char c) {
if (c>=0x60) c-=0x20; // Großbuchstaben machen
c-='0';
if ((unsigned char)c<10) return c; // Ziffern
c-='A'-'0';
if (c<0) return c; // ungültig
c+=10;
return c; // Buchstaben oder ungültig
}
// Zahl aus String konvertieren, aber maximal <maxlen> Zeichen schlucken
// Doppelzeiger zeigt nachher auf nächstes, nicht mehr verarbeitetes Zeichen
int mystrtoul(const char*&s, int base, int maxlen) {
int r=0;
for(;maxlen;maxlen--) {
char d=OneDigit(*s);
if ((unsigned char)d>=base) break;
r*=base;
r+=d;
s++;
}
return r;
}
// Erzeugt (C-mäßigen) String aus Byte-Kette
// Puffer dürfen sich nicht überlappen
static void escape(char *d, const char *s, int len) {
char c;
for (; len; len--, s++) {
c=*s;
switch (c) {
case '\r': c='r'; break;
case '\n': c='n'; break;
case '\a': c='a'; break;
case '\b': c='b'; break;
case '\t': c='t'; break;
case 27: c='e'; break;
}
if (c!=*s || c=='\\' || c=='^') d+=wsprintfA(d,"\\%c",c);
else if ((unsigned char)c<' ') d+=wsprintfA(d,"\\x%02X",(unsigned char)c);
else *d++=c;
}
*d=0;
}
// Erzeugt Byte-Kette aus nullterminiertem String
// Verarbeitet Backslash-Kodes (C), ^-Kodes (Terminal)
// Puffer dürfen sich überlappen, max. 256 Bytes
static int unescape (char*d, const char *s) {
char c;
int n=0; // Bytezähler
for(;;){
switch (c=*s++) {
case 0: return n;
case '\\': {
switch (c=*s++) { // nächstes Zeichen interpretieren
case 0: return n;
case 'r': c='\r'; break;
case 'n': c='\n'; break;
case 'a': c='\a'; break;
case 'b': c='\b'; break;
case 't': c='\t'; break;
case 'e': c=27; break; // Escape
case 'x': c=(char)mystrtoul(s,16,2); break;
default: if ('0'<=c && c<='7') {
s--; c=(char)mystrtoul(s,8,3);
} break;
// Alle anderen Folgezeichen unverändert durchlassen
}
}break;
case '^': c=*s++-'@'; // nächstes Zeichen - 0x40 (auch 0 erlaubt!)
}
*d++=c; n++;
}
return n;
}
static void hexlisting(char*d, const char*s, int l) {
for (; l>0; l--) {
d+=wsprintfA(d,"%02X ",(unsigned char)(*s++));
}
}
static void numberdecode(char *d, const char*s, char exp=-128) {
WORD m=MAKEWORD(s[0],s[1]);
if (exp==-128) exp=s[2]; // Komma-Position
char format[8];
if (exp<=0) {
wsprintfA(format,"%%0%du",-exp+1);
int l=wsprintfA(d,format,m);
if (exp) {
RtlMoveMemory(d+l+exp+1,d+l+exp,-exp+1);
d[l+exp]=','; // Komma einpflanzen
}
}else{
wsprintfA(format,"%%u%%0%dd",exp);
wsprintfA(d,format,m,0); // Nullen anhängen lassen
}
}
int _cdecl MBox(HWND Wnd, UINT id, UINT Type, ...) {
TCHAR buf[256],fmt[256];
LoadString(ghInst,id,fmt,elemof(fmt));
_sntprintf(buf,elemof(buf),fmt,(va_list)(&Type+1));
return MessageBox(Wnd,buf,StdMBoxTitle,Type);
}
#ifdef _M_IX86
EXTERN_C void _declspec(naked) _cdecl _fltused(void) {}
#endif
static bool LoadConfig() {
bool found=false;
HKEY k;
if (RegOpenKey(HKEY_CURRENT_USER,T("Software\\h#s\\VipSys3"),&k)) return found; // nothing saved ever
DWORD len=sizeof(Config);
TCHAR ConfName[16];
_sntprintf(ConfName,elemof(ConfName),T("Config%d"),Instance);
if (!RegQueryValueEx(k,ConfName,NULL,NULL,(LPBYTE)&Config,&len)) found=true;
RegCloseKey(k);
if (found) {
// Reposition window as saved
WINDOWPLACEMENT wp;
wp.length=sizeof(wp);
GetWindowPlacement(ghMainWnd,&wp);
Config.winpos>>wp.rcNormalPosition;
wp.showCmd=SW_HIDE;
SetWindowPlacement(ghMainWnd,&wp);
}
return found;
}
static void SaveConfig() {
RegSetValue(HKEY_CURRENT_USER,T("Software\\h#s"),REG_SZ,T("haftmann#software"),17*sizeof(TCHAR));
HKEY k;
if (RegCreateKey(HKEY_CURRENT_USER,T("Software\\h#s\\VipSys3"),&k)) return;
TCHAR s[64];
int l=LoadString(ghInst,1,s,elemof(s));
RegSetValue(k,NULL,REG_SZ,s,l*sizeof(TCHAR));
TCHAR ConfName[16];
_sntprintf(ConfName,elemof(ConfName),T("Config%d"),Instance);
// Retrieve Window placement info
WINDOWPLACEMENT wp;
wp.length=sizeof(wp);
GetWindowPlacement(ghMainWnd,&wp);
Config.winpos=wp.rcNormalPosition;
Config.showCmd=(char)wp.showCmd;
// Store configuration information
RegSetValueEx(k,ConfName,0,REG_BINARY,(LPBYTE)&Config,sizeof(Config));
RegCloseKey(k);
}
static const DCB DefDcb={
sizeof(DefDcb),9600,
1,0,1,0,1,0,1,0,0,0,0,2,1,0,
0,65535,65535,7,2,0,0x11,0x13,0,0,'\n',0};
static TCHAR stCom[]=T("COM%u");
OVERLAPPED gOvl;
void RestartEmpfang() {
if (hCom) CloseHandle(hCom);
TCHAR ComName[12];
_sntprintf(ComName,elemof(ComName),T("\\\\.\\COM%u"),Config.serialNo+1);
hCom=CreateFile(ComName,GENERIC_READ|GENERIC_WRITE,
0,NULL,OPEN_EXISTING,FILE_FLAG_OVERLAPPED,0);
if (hCom==INVALID_HANDLE_VALUE) hCom=0;
if (hCom) {
DCB dcb;
DLGCONFIG::SetDCB(dcb,Config.serialCfg);
SetCommState(hCom,&dcb);
static const COMMTIMEOUTS to={MAXDWORD,0,0,10,100};
SetCommTimeouts(hCom,(COMMTIMEOUTS*)&to);
SetCommMask(hCom,EV_RXFLAG);
}
gOvl.hEvent=CreateEvent(NULL,FALSE,FALSE,NULL);
}
int Send(const char *s, int l) {
DWORD bw;
WriteFile(hCom,s,l,&bw,&gOvl);
GetOverlappedResult(hCom,&gOvl,&bw,TRUE);
return bw;
}
int Recv(char *s, int l) {
DWORD br,ev;
WaitCommEvent(hCom,&ev,&gOvl);
if (WaitForSingleObject(gOvl.hEvent,500)) {
CancelIo(hCom);
}
ReadFile(hCom,s,l,&br,&gOvl);
GetOverlappedResult(hCom,&gOvl,&br,TRUE);
return br;
}
// Senden und Horchen mit Wiederholfunktion bei ESC K CR LF
int SendRecv(const char *s, int sl, char *r, int rl) {
int l;
DWORD tic=GetTickCount();
do{
if (Send(s,sl)!=sl) return -10;
l=Recv(r,rl);
if (l!=4) return l;
if (*(DWORD*)r!=0x0A0D4B1B) return l;
}while (GetTickCount()-tic<3000); // wiederholen
return -11;
}
// Senden, Horchen und Vergleichen des Empfangsstrings mit Sendestring
int SendRecv(const char *s, int sl) {
if ((unsigned)sl>=8) return -12;
char r[8];
int l=SendRecv(s,sl,r,sizeof(r));
if (l<0) return l;
if (l!=sl) return -13; // no match
if (memcmp(s,r,l)) return -13; // no match
return l;
}
#if 0
// blockierende Datenabfrage bis "EOF" (Seite 136)
// liefert "Anzahl Bytes", oder negative Zahl für Fehlerkode
int Query(char*d, int dlen) {
int expectblock=0;
int len=0;
static const char s[4]={0x1B,'O','\r','\n'};
for(;;){
char r[42]; // maximal 1+6+16*2+1+2 = 42 Bytes
int l=SendRecv(s,4,r,sizeof(r));
if (l<0) return l;
int a;
int e=string_decode(r,l,&a,d,dlen);
if (e<0) return e; // mit Fehler aussteigen
if (!e && a==0x1000) return len; // EOF-Block: alles fertig zusammengesetzt
if (a!=expectblock) return -7; // Fehler bei "Adresse"
d+=e; len+=e;
dlen-=e; // verbleibender Platz
expectblock++;
if (dlen<0) {
static const char s[4]={0x1B,'A','\r','\n'}; // vorzeitig abbrechen!
SendRecv(s,4);
return len;
}
}
}
LONG_PTR CALLBACK UnusedProc(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam) {
switch (Msg) {
case WM_INITDIALOG: {
SetDlgItemTextA(Wnd,10,"\\eA\\r\\n");
}return TRUE;
case WM_COMMAND: switch (LOWORD(wParam)) {
case 1: {
char t[20];
GetDlgItemTextA(Wnd,10,t,elemof(t));
char u[20];
int l=unescape(u,t);
char r[44];
l=SendRecv(u,l,r,sizeof(r));
char j[280];
escape(j,r,l);
SetDlgItemTextA(Wnd,11,j);
// l=stringdecode(j,r,l);
if (l>=0) {
if (j[0] != (l-3)<<1) {l=-6; goto fehler;}
hexlisting(r,j+1,l-1);
SetDlgItemTextA(Wnd,12,r);
// Für ESC m 1 CR LF : (Seite 170)
if (j[2]!=0x10) {
char z[160];
numberdecode(z,j+3);
lstrcatA(z," V");
SetDlgItemTextA(Wnd,15,z);
numberdecode(z,j+6);
lstrcatA(z," A");
SetDlgItemTextA(Wnd,16,z);
numberdecode(z,j+9);
lstrcatA(z," kW");
SetDlgItemTextA(Wnd,17,z);
numberdecode(z,j+12,-3);
lstrcatA(z," °");
SetDlgItemTextA(Wnd,18,z);
}
}else fehler: SetDlgItemTextA(Wnd,12,NULL);
SetDlgItemInt(Wnd,14,l,TRUE);
}break;
case 2: EndDialog(Wnd,wParam); break;
case 5: {
char b[800];
HCURSOR oc=SetCursor(LoadCursor(0,IDC_WAIT));
DWORD tic=GetTickCount();
char t[20];
GetDlgItemTextA(Wnd,10,t,elemof(t));
char u[20];
int l=unescape(u,t);
char r[44];
l=SendRecv(u,l,r,sizeof(r));
char j[280];
escape(j,r,l);
SetDlgItemTextA(Wnd,11,j);
l=Query(b,sizeof(b));
tic=GetTickCount()-tic;
SetCursor(oc);
SetDlgItemInt(Wnd,14,l,TRUE);
wsprintfA(t,"%u ms",tic);
SetDlgItemTextA(Wnd,11,t);
if (l>=0) {
if (l>256) l=256;
char r[1000];
hexlisting(r,b,l);
SetDlgItemTextA(Wnd,12,r);
}
}break;
}
}
return FALSE;
}
#endif
double VAL3::toFloat() const{
return w*pow(10.0F,e);
}
double VAL2::toFloat(char e) const{
return w*pow(10.0F,e);
}
int toStringW(double f, PWSTR s, int l) {
return _snwprintf(s,l,L"%G",f);
}
STRING_ESCM escm_data;
DWORD time_used;
static void FillBack(HDC dc, int x1, int y1, int x2, int y2) {
TRIVERTEX vert[]={
{x1,y1,0xe000,0xe000,0xe000},
{x1,y2,0xf000,0xf000,0xf000},
{x2,y2,0xff00,0xff00,0xff00},
{x2,y1,0xf000,0xf000,0xf000}};
GRADIENT_TRIANGLE Tri[]={
{0,1,2},
{0,2,3}};
GradientFill(dc,vert,elemof(vert),Tri,elemof(Tri),GRADIENT_FILL_TRIANGLE);
}
struct TH{ // table header cell item
UINT sid; // string resource index for text display
LONG_PTR par; // one free parameter for sprintf()
char dde2[4]; // second part of DDE name (e.g. "-1")
};
struct TD{ // table body cell item
double val,min,max; // data for DDE
char str[10]; // text for display, not localized (contains "." decimal point)
char unitprefix; // 0-based exponent of 10
char colspan; // colspan, 0 = unused column!
};
union COL{
TH th; // first row
TD td; // non-first rows
};
#pragma warning(disable:4200)
struct TR{
UINT sid; // string resource index for descriptive text display
LONG_PTR par; // one free parameter for sprintf()
UINT nid; // string resource index for name display
char name[7]; // alternative name, as UTF-8 (unused)
char ndeco; // name decoration flags: average, peak
char dde1[8]; // first part of DDE name (e.g. "Up" for U-peak), 7-bit ASCII only
BYTE ncol; // number of columns following, 0 = sub-divider ("Tariff Band")
char unitcode; // the unit code for common units, appended to each(?) <td> item
char unit[8]; // the unit for uncommon units, as UTF-8 (unused)
COL col[];
};
struct SPAN{ // handles COLSPAN
unsigned ncol; // number of columns of the table
unsigned*w; // triangular widths array
static unsigned BF(unsigned x) {return x*(x+1)/2;};
SPAN() {};
SPAN(unsigned col) {w=new unsigned[BF(ncol=col)];};
~SPAN() {delete[]w;};
unsigned&PW(unsigned x, unsigned spanx) const{
// possible bugs:
if (x>=ncol) x=ncol-1;
if (x+spanx>ncol) spanx=ncol-x;
if (!spanx) spanx=1;
// calculate index
return w[(BF(ncol+1-spanx)-1)+x];
};
void setmax(unsigned x, unsigned spanx, unsigned w) const{
unsigned&pw=PW(x,spanx);
if (pw<w) pw=w;
};
unsigned get(unsigned x, unsigned spanx) const{return PW(x,spanx);};
};
static PWSTR GenUnitW(PWSTR d, char unitprefix, char unitcode, char f) {
return d;
}
// obige Tabellenstruktur ausgeben
static void OutTable(HDC dc, TR*tr, int n){
// 0. Check whether table is valid
if (!tr || n<2) return;
int xx=tr[0].ncol; // the header dictates the number of possible columns
if (!xx) return; // no data column
// 1. Check for needed column widths
SPAN w(xx+2);
for (int y=0; y<n; y++) {
TR*tr=tr+y; // TODO: Not so easy!
WCHAR t[32],s[32];
MyLoadStringW(tr->sid,t,elemof(t));
int l=_snwprintf(s,elemof(s),t,tr->par);
SIZE size;
GetTextExtentPoint32W(dc,s,l,&size);
w.setmax(0,1,size.cx); // build maximum
l=MyLoadStringW(tr->sid,t,elemof(t));
GetTextExtentPoint32W(dc,t,l,&size);
w.setmax(1,1,size.cx); // build maximum
for (int x=0; x<tr->ncol; x++) {
if (x==xx) break; // it's a bug in given table structure
COL*col=tr->col+x;
if (y) {
MyLoadStringW(col->th.sid,t,elemof(t));
l=_snwprintf(s,elemof(s),t,col->th.par);
}else{
l=_snwprintf(s,elemof(s),L"%S",col->td.str);
l=int(GenUnitW(s+l,col->td.unitprefix,tr->unitcode,1)-s);
}
GetTextExtentPoint32W(dc,s,l,&size);
w.setmax(2+x,col->td.colspan,size.cx); // build maximum
}
}
// 2. Emit the table
}
static void OutLine(HDC dc, UINT id, double f[], int n) {
POINT p; // origin
MoveToEx(dc,0,0,&p);
WCHAR s[128];
FillBack(dc,p.x,p.y,p.x+gGdi.xx,p.y+gGdi.yy);
int l=MyLoadStringW(id,s,elemof(s));
TextOutW(dc,p.x+1,p.y,s,l);
if (n==12) {
for (int i=0,k=0; i<4; i++) {
l=toStringW(f[k++],s,elemof(s));
StrCpyNW(s+l,L" / ",elemof(s)-l); l+=3;
l+=toStringW(f[k++],s+l,elemof(s)-l);
StrCpyNW(s+l,L" / ",elemof(s)-l); l+=3;
l+=toStringW(f[k++],s+l,elemof(s)-l);
FillBack(dc,p.x+gGdi.xx*(i+1),p.y,p.x+gGdi.xx*(i+2),p.y+gGdi.yy);
TextOutW(dc,p.x+gGdi.xx*(i+1)+1,p.y,s,l);
}
}else{
for (int i=0; i<4; i++) {
l=toStringW(f[i],s,elemof(s));
FillBack(dc,p.x+gGdi.xx*(i+1),p.y,p.x+gGdi.xx*(i+2),p.y+gGdi.yy);
TextOutW(dc,p.x+gGdi.xx*(i+1)+1,p.y,s,l);
}
}
MoveToEx(dc,p.x,p.y+gGdi.yy,NULL); // next line
}
static void OutLine(HDC dc, UINT id, VAL3 v[4]) {
double f[4];
for (int i=0; i<4; i++) f[i]=v[i].toFloat();
OutLine(dc,id,f,4);
}
static void OutLine(HDC dc, UINT id, VAL3 v[4], VAL3 a[4], VAL3 p[4]) {
double f[12];
for (int i=0,k=0; i<4; i++) {
f[k++]=v[i].toFloat();
f[k++]=a[i].toFloat();
f[k++]=p[i].toFloat();
}
OutLine(dc,id,f,12);
}
static void OutLine(HDC dc, UINT id, VAL2 v[4], char e) {
double f[4];
for (int i=0; i<4; i++) f[i]=v[i].toFloat(e);
OutLine(dc,id,f,4);
}
void HandlePaint(HDC dc,LPARAM options) {
RECT r;
GDI::ClientRect(r);
if (options&PRF_ERASEBKGND) {
HBRUSH brBack=GetSysColorBrush(COLOR_WINDOW);
SelectBrush(dc,brBack);
PatBlt(dc,0,0,r.right,r.bottom,PATCOPY);
}
// if (w.hMutex && WaitForSingleObject(w.hMutex,200)) return; // timeout - should never occur, SetData() is fast
// Value (with unit) sent by multimeter
// int slen;
// SIZE size;
// WCHAR buf[32];
HFONT ofont=SelectFont(dc,gGdi.fntSmall);
SetBkMode(dc,TRANSPARENT);
OutLine(dc,19,escm_data.u);
OutLine(dc,18,escm_data.i);
OutLine(dc,20,escm_data.p,escm_data.pa,escm_data.pp);
OutLine(dc,21,escm_data.s,escm_data.sa,escm_data.sp);
OutLine(dc,22,escm_data.q,escm_data.qa,escm_data.qp);
OutLine(dc,24,escm_data.c,-3);
// if (w.hMutex) ReleaseMutex(w.hMutex);
SelectFont(dc,ofont);
}
/*************************
* Main window procedure *
*************************/
static LONG_PTR CALLBACK MainWndProc(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam) {
switch (Msg) {
case WM_CREATE: {
ghMainWnd=Wnd;
Config.serialCfg=0x58;
TCHAR s[64];
LoadString(ghInst,1,s,elemof(s));
SetWindowText(Wnd,s);
ghStatus=CreateStatusWindow(WS_VISIBLE|WS_CHILD,NULL,Wnd,2);
SendMessage(Wnd,WM_WININICHANGE,0,0);
Instance=_ttoi(PathGetArgs(GetCommandLine()));
// Kommandozeilen-Argument: Nummer der Konfiguration, 0-basiert
LoadConfig();
PostMessage(Wnd,WM_USER+100,0,0);
}break;
case WM_USER+100: {
RestartEmpfang();
// SetInitScreen();
// if (w.conf.Make()) w.Start();
// else PostMessage(Wnd,WM_COMMAND,0x40,0);
}break;
case WM_USER+22: { // lParam = bits indicating what portion of information has changed
if (lParam) {
if (IsIconic(Wnd)) {
// if (lParam&0x2000F) SetWindowTitle(); // check Readout[0] change, not else
}else{
if (lParam&0xA8888) gGdi.Make();
if (gGdi.dcDblBuf) HandlePaint(gGdi.dcDblBuf,PRF_ERASEBKGND);
InvalidateRect(Wnd,NULL,TRUE);
}
}
// if (lParam&(1<<24) && Config.flashIcon) {
// SendMessage(Wnd,WM_SETICON,ICON_SMALL,(LPARAM)ghIcons[1]);
// SetTimer(Wnd,2,100,NULL);
// }
}break;
case WM_TIMER: switch (wParam) {
case 2: {
KillTimer(Wnd,wParam);
SendMessage(Wnd,WM_SETICON,ICON_SMALL,(LPARAM)ghIcons[0]);
}break;
}break;
case WM_WININICHANGE: {
TCHAR sDecimal[2];
GetProfileString(T("intl"),T("sDecimal"),T("."),sDecimal,elemof(sDecimal));
#ifdef UNICODE
cDecimalW=*sDecimal;
WideCharToMultiByte(CP_ACP,0,sDecimal,1,&cDecimalA,1,".",NULL);
#else
cDecimalA=*sDecimal;
MultiByteToWideChar(CP_ACP,0,sDecimal,1,&cDecimalW,1);
#endif
}return 0;
case WM_SIZE: {
if (ghStatus) SendMessage(ghStatus,Msg,wParam,lParam);
if (wParam==SIZE_MINIMIZED) {
// SetWindowTitle();
gGdi.Delete(); // no GDI resources are needed, so free all!
}else{
gGdi.Make(GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam));
if (gGdi.dcDblBuf) HandlePaint(gGdi.dcDblBuf,PRF_ERASEBKGND);
}
}break;
case WM_PAINT: {
PAINTSTRUCT ps;
BeginPaint(Wnd,&ps);
SendMessage(Wnd,WM_PRINTCLIENT,(WPARAM)ps.hdc,PRF_ERASEBKGND);
EndPaint(Wnd,&ps);
}return 0;
case WM_PRINTCLIENT: {
if (gGdi.dcDblBuf) {
RECT r;
GDI::ClientRect(r);
BitBlt((HDC)wParam,0,0,r.right,r.bottom,gGdi.dcDblBuf,0,0,SRCCOPY);
}else HandlePaint((HDC)wParam,lParam);
}break;
case WM_COMMAND: switch (LOWORD(wParam)) { // from TranslateAccelerator
case 9: SendMessage(Wnd,WM_CLOSE,0,0); break;
case 99: MBox(Wnd,2,MB_OK); break;
case 0x10: {
HCURSOR oc=SetCursor(LoadCursor(0,IDC_WAIT));
DWORD tic=GetTickCount();
static const char esca[]={0x1b,'A','\r','\n'};
int l=SendRecv(esca,4);
if (l!=4) MessageBeep(0);
static const char escm[]={0x1b,'M','\r','\n'};
l=SendRecv(escm,4);
if (l!=4) {
MessageBeep(0);
break;
}
string_recv(&escm_data,sizeof(escm_data),SendRecv,(BYTE*)RecordList0);
tic=GetTickCount()-tic;
SetCursor(oc);
TCHAR t[64];
_sntprintf(t,elemof(t),T("%u ms"),tic);
SetWindowText(Wnd,t);
InvalidateRect(Wnd,NULL,TRUE);
}break;
case 0x40: {
DLGCONFIG Dlg={0,Config.serialNo,Config.serialCfg,Config.checkBits};
if (DialogBoxParam(ghInst,MAKEINTRESOURCE(0x40),Wnd,(DLGPROC)Dlg.DlgProc,(LPARAM)&Dlg)==IDOK) {
if (Config.serialNo!=Dlg.serialNo || Config.serialCfg!=Dlg.serialCfg) {
Config.serialNo=Dlg.serialNo;
Config.serialCfg=Dlg.serialCfg;
RestartEmpfang();
}
Config.checkBits=Dlg.checkBits;
// w.Stop();
// SetInitScreen();
// w.Start();
SaveConfig();
}
}break;
// case 0x50: CreateDialog(Wnd,WM_COPY,0,0); break;
case 0x60: {
DLGDATASEL Dlg={Config.sel.u};
if (DialogBoxParam(ghInst,MAKEINTRESOURCE(0x60),Wnd,(DLGPROC)Dlg.DlgProc,(LPARAM)&Dlg)==IDOK) {
Config.sel=Dlg.sel;
}
}break;
}break;
case WM_CLOSE: {
// w.Stop();
SaveConfig();
}break;
case WM_ENDSESSION: if (wParam) {
SaveConfig(); // don't halt thread, instead, ensure fast Windows shutdown
}break;
case WM_DESTROY: {
gGdi.Delete();
PostQuitMessage(IDOK);
}break;
}
return DefWindowProc(Wnd,Msg,wParam,lParam);
}
void CALLBACK WinMainCRTStartup() {
ghInst=GetModuleHandle(NULL);
InitCommonControls();
ghIcons[0]=(HICON)LoadImage(ghInst,MAKEINTRESOURCE(1),IMAGE_ICON,16,16,0);
ghIcons[1]=(HICON)LoadImage(ghInst,MAKEINTRESOURCE(2),IMAGE_ICON,16,16,0);
WNDCLASSEX wc={
sizeof(wc),
CS_BYTEALIGNWINDOW|CS_DBLCLKS|CS_HREDRAW|CS_VREDRAW,
MainWndProc,
0,
0,
ghInst,
LoadIcon(ghInst,MAKEINTRESOURCE(1)),
LoadCursor(0,IDC_ARROW),
0,
MAKEINTRESOURCE(1),
T("VIPSYS3"),
ghIcons[0]};
RegisterClassEx(&wc);
CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,T("VIPSYS3"),NULL,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,0,400,400,
0,0,ghInst,NULL);
ShowWindow(ghMainWnd,SW_SHOWDEFAULT);
// ShowWindow(ghMainWnd,Config.showCmd);
MSG Msg;
HACCEL hAccel=LoadAccelerators(ghInst,MAKEINTRESOURCE(1));
while (GetMessage(&Msg,0,0,0)) {
if (TranslateAccelerator(ghMainWnd,hAccel,&Msg)) continue;
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
// gHszList.Delete();
// DdeUninitialize(gDdeInst);
ExitProcess((UINT)Msg.wParam);
}
Detected encoding: ANSI (CP1252) | 4
|
|