#include <windows.h>
#include <windowsx.h>
#include "dmm.h"
#include <commdlg.h>
#include <commctrl.h>
#include <shlwapi.h>
#include <stdio.h>
#include <tchar.h>
#include <htmlhelp.h>
#ifdef _M_IX86
#undef Int32x32To64
// MSVC macht aus dieser (Nicht-Windows-)Funktion ein _allmul: unnötig!
__forceinline __int64 Int32x32To64(long x,long y) {
__int64 r;
_asm mov eax,x
_asm imul y
_asm mov dword ptr[r],eax
_asm mov dword ptr[r+4],edx
return r;
}
#endif
LOG gLog;
void SetEditFocus(HWND w) {
Edit_SetSel(w,0,-1);
SetFocus(w);
}
#ifdef UNICODE
# define CF_TXT CF_UNICODETEXT
#else
# define CF_TXT CF_TEXT
#endif
bool DDECH::Reconnect() {
if (hszItem) {DdeFreeStringHandle(gDdeInst,hszItem); hszItem=0;}
if (hConv) {DdeDisconnect(hConv); hConv=0;}
HSZ hszService=0,hszTopic=0;
PTSTR p1=StrChr(ServiceTopicItem,'|'); // service|topic!item
PTSTR p2=StrChr(p1?p1:ServiceTopicItem,'!');
if (p1) {
*p1=0;
hszService=DdeCreateStringHandle(gDdeInst,ServiceTopicItem,CP_WINNEUTRAL);
*p1='|';
}else hszService=DdeCreateStringHandle(gDdeInst,T("DMM"),CP_WINNEUTRAL);
if (p2) *p2=0;
hszTopic=DdeCreateStringHandle(gDdeInst,p1?p1+1:ServiceTopicItem,CP_WINNEUTRAL);
if (p2) *p2='!';
hszItem=DdeCreateStringHandle(gDdeInst,p2?p2+1:T("v"),CP_WINNEUTRAL);
hConv=DdeConnect(gDdeInst,hszService,hszTopic,NULL);
DdeFreeStringHandle(gDdeInst,hszTopic);
DdeFreeStringHandle(gDdeInst,hszService);
if (hConv) {
DdeClientTransaction(NULL,0,hConv,hszItem,CF_TXT,XTYP_REQUEST,TIMEOUT_ASYNC,NULL);
DdeClientTransaction(NULL,0,hConv,hszItem,CF_TXT,XTYP_ADVSTART|XTYPF_ACKREQ,TIMEOUT_ASYNC,NULL);
}
return hConv!=0;
}
int DDECH::QueryInfo(char*buf,int blen,UINT cp,UINT what) {
*buf=0;
return 0;
}
int DDECH::QueryValue(char*buf,int blen,UINT cp,UINT how) {
UINT fmt=CF_TEXT;
if (cp!=CP_ACP) fmt=CF_UNICODETEXT;
HDDEDATA d=DdeClientTransaction(NULL,0,hConv,hszItem,cp,XTYP_REQUEST,10,NULL);
int r=0;
if (d) {
BYTE*p=DdeAccessData(d,NULL);
switch (cp) {
case CP_ACP: lstrcpynA(buf,(char*)p,blen); r=lstrlenA(buf); break;
case 1200: lstrcpynW((PWSTR)buf,(PWSTR)p,blen>>1); r=lstrlenW((PWSTR)buf)<<1; break;
default: r=WideCharToMultiByte(cp,0,(PWSTR)p,-1,buf,blen,NULL,NULL)-1;
}
DdeUnaccessData(d);
DdeFreeDataHandle(d);
}
return r;
}
DDECH::~DDECH() {
if (hszItem) {DdeFreeStringHandle(gDdeInst,hszItem); hszItem=0;}
if (hConv) {DdeDisconnect(hConv); hConv=0;}
delete ServiceTopicItem;
}
void LOG::OnOff(HWND Wnd, int sw) {
if (f) {
if (sw&2) { // close it?
fclose(f);
f=NULL;
HMENU m=GetSystemMenu(Wnd,FALSE);
CheckMenuItem(m,0x60,MF_UNCHECKED);
}
}else{
if (sw&1) { // open it?
OPENFILENAME ofn;
ZeroMemory(&ofn,sizeof(ofn));
ofn.lStructSize=sizeof(ofn);
ofn.hInstance=ghInst; // muss sein!
ofn.lpstrFile=fname;
ofn.nMaxFile=elemof(fname);
ofn.hwndOwner=Wnd;
ofn.Flags=OFN_PATHMUSTEXIST|OFN_HIDEREADONLY|OFN_EXPLORER|OFN_ENABLESIZING|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE;
if (*HelpName) ofn.Flags|=OFN_SHOWHELP;
TCHAR filter[128];
filter[LoadString(0,15,filter,elemof(filter)-1)+1]=0;
ofn.lpstrFilter=filter;
ofn.lCustData=(LPARAM)this;
ofn.lpfnHook=OFNHookProc;
ofn.lpTemplateName=MAKEINTRESOURCE(0x60);
if (!GetSaveFileName(&ofn)) return;
f=_tfopen(fname,T("a+t"));
if (!f) return;
curcol=0;
HMENU m=GetSystemMenu(Wnd,FALSE);
CheckMenuItem(m,0x60,MF_CHECKED);
}
}
}
// difference of current time to start time, in seconds
double LOG::GetDiff() {
if (Interval) return T+=Interval;
__int64 ft;
GetSystemTimeAsFileTime((LPFILETIME)&ft);
return (ft-starttime)/1E7;
}
static char* toString(double v) {
static char s[32];
if (v!=v) s[0]=0;
else{
_snprintf(s,elemof(s),"%G",v);
ptc(s);
}
return s;
}
void LOG::Line(int col, const READOUT*ro, DWORD features, DWORD change) {
if (hDlg && col) {
SetDlgItemTextA(hDlg,123,toString(ro[0].value));
}
if (!f) return; // logging not enabled
double t=0;
int x;
if (curcol<col // first-time call, columns expand,
|| change&0x8888 // units change
|| (features^curfeatures)&(1<<F_AC)) { // AC/DC change?
fseek(f,0,SEEK_END);
if (ftell(f)) fprintf(f,"\n"); // produce empty line after some already recorded data
if (!(flags&1)) GetSystemTimeAsFileTime((LPFILETIME)&starttime); // get time for first-time value
T=0;
if (flags&2) { // TODO: save header information in Extended Attributes
__int64 timeLocal; // 1. to get local time, 2. to get time zone
FileTimeToLocalFileTime((LPFILETIME)&starttime,(LPFILETIME)&timeLocal);
SYSTEMTIME st;
FileTimeToSystemTime((LPFILETIME)&timeLocal,&st); // get info for the first header line
div_t tz=div(int((timeLocal-starttime)/60E7),60); // This quirks assumes there is no -00:30 timezone
fprintf(f,"%d-%02d-%02dT%02d:%02d:%02d%c%03d%+03d:%02d\n", // Output first header line
st.wYear,st.wMonth,st.wDay,
st.wHour,st.wMinute,st.wSecond,
comma(),st.wMilliseconds, tz.quot, abs(tz.rem));
if (flags&4) fprintf(f,"Time"); // emit a line with names (not very useful here)
for (x=0; x<col; x++) fprintf(f,"\tval%s%d",features&1<<F_AC?"~":"",x);
for (x=0; x<nExtra; x++) fprintf(f,"\t%s",Extra[x]->ServiceTopicItem);
fprintf(f,"\n");
if (flags&4) fprintf(f,"s"); // emit a line with units
for (x=0; x<col; x++) {
char s[8];
GenLogUnit(s,ro+x);
fprintf(f,"\t%s",s);
}
for (x=0; x<nExtra; x++) {
char s[8];
Extra[x]->QueryInfo(s,sizeof s,CP_UTF8,0);
fprintf(f,"\t%s",s);
}
fprintf(f,"\n");
}
// TODO: Lines with deviations should follow
if (col>curcol) curcol=col;
curfeatures=features;
}else t=GetDiff();
if (flags&4) fprintf(f,"%s",toString(t));
for (x=0; x<col; x++) fprintf(f,"\t%s",toString(ro[x].value));
for (x=0; x<nExtra; x++) {
char s[16];
Extra[x]->QueryValue(s,sizeof s,CP_UTF8,flags);
fprintf(f,"\t%s",s);
}
fprintf(f,"\n");
fflush(f);
}
static void SetDlgItemDouble(HWND Wnd, UINT id, double v, int nk) {
TCHAR s[32];
DoubleToString(v,nk,s,elemof(s));
SetDlgItemText(Wnd,id,s);
}
static double GetDlgItemDouble(HWND Wnd, UINT id) {
TCHAR s[32],*p;
GetDlgItemText(Wnd,id,s,elemof(s));
p=_tcschr(s,',');
if (p) *p='.';
double v;
_stscanf(s,T("%lg"),&v);
return v;
}
void LOG::ManageCombos(HWND Wnd, int was, int now) {
if (was==now) return;
nExtra=now;
if (now>was) {
RECT rc[2];
GetWindowRect(GetDlgItem(Wnd,23),rc+0);
GetWindowRect(GetDlgItem(Wnd,123),rc+1);
MapWindowPoints(0,Wnd,(LPPOINT)rc,4);
int gap=(rc[0].right-rc[0].left)>>1;
int width=rc[1].right-rc[1].left;
int height=rc[1].bottom-rc[1].top;
HWND w=GetDlgItem(Wnd,123);
DWORD sty=GetWindowStyle(w);
DWORD styx=GetWindowExStyle(w);
for (int i=was; i<now; i++) {
int x=rc[1].right+gap+i*(gap+width);
//DDECH*cur;
Extra[i]=new DDECH();
w=CreateWindowEx(styx,T("EDIT"),NULL,sty,
x,rc[1].top,width,height, Wnd,HMENU(124+i),0,NULL);
HFONT f=GetWindowFont(Wnd);
SetWindowFont(w,f,TRUE);
w=CreateWindowEx(styx,T("COMBOBOX"),NULL,WS_VISIBLE|WS_CHILD|WS_BORDER|WS_TABSTOP|CBS_AUTOHSCROLL|CBS_DROPDOWN,
x,rc[0].top,width,(rc[0].bottom-rc[0].top)<<3, Wnd,HMENU(24+i),0,NULL);
SetWindowFont(w,f,TRUE);
int j=0;
for (PCTSTR p=propose;*p;p+=lstrlen(p)+1,j++) {
ComboBox_AddString(w,p);
if (i==j) SetWindowText(w,p);
}
}
}else{
for (int i=was; --i>=now; ) {
DestroyWindow(GetDlgItem(Wnd,24+i));
DestroyWindow(GetDlgItem(Wnd,124+i));
delete Extra[i];
Extra[i]=NULL;
}
}
//Extra=(DDECH**)LocalReAlloc(Extra,nExtra*sizeof(void*),LMEM_MOVEABLE|LMEM_ZEROINIT);
}
HDDEDATA LOG::DdeCallback(UINT uType,UINT uFmt,HCONV hConv,HSZ hsz1,HSZ hsz2,HDDEDATA hData) {
HDDEDATA ret=DDE_FNOTPROCESSED;
for (int i=0; i<nExtra; i++) if (hConv==Extra[i]->hConv) {
if (hDlg) switch (uType) {
case XTYP_XACT_COMPLETE: // REQUEST (asynchronous, possibly Unicode)
case XTYP_ADVDATA: { // ADVISE (hot)
TCHAR s[32];
DdeGetData(hData,(BYTE*)s,sizeof s,0);
SetDlgItemText(hDlg,124+i,s);
ret=(HDDEDATA)DDE_FACK;
}break;
}else switch (uType) {
case XTYP_XACT_COMPLETE: { // REQUEST (asynchronous)
DdeGetData(hData,(BYTE*)Extra[i]->buf,sizeof Extra[i]->buf,0);
Waiters&=~(1<<i);
if (!Waiters) SetEvent(WaitEvt);
}break;
}
}
return ret;
}
/*
BOOL CALLBACK LOG::EnumWindowsProc(HWND w, LPARAM p) {
PTSTR s=*(PTSTR*)p;
PTSTR e;
for (e=s; *e; e+=lstrlen(e)+1); // points to terminating (second) zero
if (w!=ghMainWnd) { // only foreign windows
TCHAR buf[32];
GetClassName(w,buf,elemof(buf));
if (!lstrcmpi(buf,T("DMM"))) { // with own class name
DWORD pid;
GetWindowThreadProcessId(w,&pid);
HANDLE h=OpenProcess(PROCESS_VM_READ,FALSE,pid);
if (h) {
TCHAR ForeignConfName[CONFMAX];
ReadProcessMemory(h,ConfName,ForeignConfName,CONFMAX,NULL);
CloseHandle(h);
int l=e-s;
int n=lstrlen(ForeignConfName)+1;
s=(PTSTR)LocalReAlloc(s,(l+n+1)*sizeof TCHAR,LMEM_MOVEABLE|LMEM_ZEROINIT);
lstrcpyn(s+l,ForeignConfName,n);
*(PTSTR*)p=s;
}
}
}
return TRUE;
}
*/
UINT_PTR CALLBACK LOG::OFNHookProc(HWND Wnd, UINT msg, WPARAM wParam, LPARAM lParam) {
LOG*o=(LOG*)GetWindowLongPtr(Wnd,DWLP_USER);
switch (msg) {
case WM_INITDIALOG: {
HWND w;
OPENFILENAME*ofn=(OPENFILENAME*)lParam;
o=(LOG*)ofn->lCustData;
SetWindowLongPtr(Wnd,DWLP_USER,(LPARAM)o);
o->hDlg=Wnd;
HFONT f=GetWindowFont(GetParent(Wnd));
SetWindowFont(Wnd,f,FALSE);
for (w=GetWindow(Wnd,GW_CHILD);w;w=GetNextSibling(w)) SetWindowFont(w,f,FALSE);
GetSystemTimeAsFileTime((LPFILETIME)&o->starttime);
o->Interval=1;
o->flags=0x06;
w=GetDlgItem(Wnd,17); // DateTimePicker
DateTime_SetFormat(w,T("yyy'-'MM'-'dd' 'HH':'mm':'ss' —'dddd"));
DateTime_SetSystemtime(w,GDT_NONE,NULL);
CreateUpDownControl(
WS_CHILD|WS_VISIBLE|WS_BORDER|UDS_ALIGNRIGHT|UDS_NOTHOUSANDS|UDS_HOTTRACK|UDS_SETBUDDYINT|UDS_ARROWKEYS,
0,0,0,0,Wnd,19,ofn->hInstance,GetDlgItem(Wnd,18),3600,0,0);
SetDlgItemDouble(Wnd,18,o->Interval,0);
CheckDlgButton(Wnd,20,o->flags>>1&1);
CheckDlgButton(Wnd,21,o->flags>>2&1);
CreateUpDownControl(
WS_CHILD|WS_VISIBLE|WS_BORDER|UDS_ALIGNRIGHT|UDS_NOTHOUSANDS|UDS_HOTTRACK|UDS_SETBUDDYINT|UDS_ARROWKEYS,
0,0,0,0,Wnd,23,ofn->hInstance,GetDlgItem(Wnd,22),ECOLMAX,0,o->nExtra);
if (!o->propose) {
// o->propose=(PTSTR)LocalAlloc(LPTR,sizeof TCHAR);
// EnumWindows(EnumWindowsProc,(LPARAM)&o->propose);
HCONVLIST l=DdeConnectList(gDdeInst,NULL,NULL,NULL,NULL);
if (l) {
PTSTR a=(PTSTR)LocalAlloc(LPTR,16384*sizeof(TCHAR));
PTSTR p=a;
// for (p=a; *p; p+=lstrlen(p)+1); // advance to terminating (second) zero
PTSTR e=a+16383;
for (HCONV c=NULL; c=DdeQueryNextServer(l,c);) {
CONVINFO ci;
ci.cb=sizeof ci;
if (DdeQueryConvInfo(c,QID_SYNC,&ci)) {
p+=DdeQueryString(gDdeInst,ci.hszSvcPartner,p,DWORD(e-p),CP_WINNEUTRAL);
*p++='|';
p+=DdeQueryString(gDdeInst,ci.hszTopic,p,DWORD(e-p),CP_WINNEUTRAL)+1;
}
}
DdeDisconnectList(l);
*p++=0;
o->propose=(PCTSTR)LocalReAlloc(a,(p-a)*sizeof(TCHAR),LMEM_MOVEABLE|LMEM_ZEROINIT);
}
}
o->ManageCombos(Wnd,0,o->nExtra);
}return TRUE;
case WM_COMMAND: switch (LOWORD(wParam)) {
case 18: if (HIWORD(wParam)==EN_UPDATE) {
o->Interval=GetDlgItemDouble(Wnd,18);
EnableWindow(GetPrevSibling((HWND)lParam),o->flags&1 || o->Interval);
}break;
case 20: { // use header - and therefore date/time field?
o->flags^=0x02;
HWND w=GetDlgItem(Wnd,17);
ShowWindow(w,o->flags>>1&1);
ShowWindow(GetPrevSibling(w),o->flags>>1&1);
}break;
case 21: {
o->flags^=0x04;
}break;
case 22: if (HIWORD(wParam)==EN_UPDATE) { // add/remove column?
o->ManageCombos(Wnd,o->nExtra,GetDlgItemInt(Wnd,22,NULL,FALSE));
}break;
default: {
int x=LOWORD(wParam)-24; // Changes on editable comboboxes?
if ((unsigned)x<ECOLMAX && HIWORD(wParam)==CBN_EDITUPDATE) {
SetDlgItemText(Wnd,124+x,NULL); // remove string immediately (?)
SetTimer(Wnd,x,500,NULL); // Defer reaction to allow slow typing
}
}
}break;
case WM_TIMER: {
KillTimer(Wnd,wParam);
DDECH*ch=o->Extra[wParam];
delete ch->ServiceTopicItem;
HWND w=GetDlgItem(Wnd,24+(int)wParam);
int l=ComboBox_GetTextLength(w)+1;
ch->ServiceTopicItem = new TCHAR[l];
ComboBox_GetText(w,ch->ServiceTopicItem,l);
if (!ch->Reconnect()) {
TCHAR s[64];
LoadString(ghInst,25,s,elemof(s));
SetDlgItemText(Wnd,124+(int)wParam,s);
}
}break;
case WM_NOTIFY: switch (((NMHDR*)lParam)->code) {
case DTN_DATETIMECHANGE: {
NMDATETIMECHANGE*dtc=(NMDATETIMECHANGE*)lParam;
o->flags=o->flags&0xFE|(dtc->dwFlags&GDT_NONE?0:1);
FILETIME ft;
SystemTimeToFileTime(&dtc->st,&ft);
LocalFileTimeToFileTime(&ft,(FILETIME*)&o->starttime);
EnableWindow(GetPrevSibling(dtc->nmhdr.hwndFrom),o->flags&1);
EnableWindow(GetNextSibling(dtc->nmhdr.hwndFrom),o->flags&1 || o->Interval);
}break;
case CDN_HELP: {
HtmlHelp(Wnd,HelpName,HH_HELP_CONTEXT,0x60);
}break;
case CDN_FILEOK: {
if (o->flags&1 && !o->Interval) {
MBox(Wnd,24,MB_OK|MB_ICONEXCLAMATION);
SetEditFocus(GetDlgItem(Wnd,18));
SetWindowLong(Wnd,DWLP_MSGRESULT,TRUE);
return TRUE;
}
if (o->Interval<0) {
o->Interval=-o->Interval;
o->flags|=0x08;
}
}break;
}break;
case WM_DESTROY: o->hDlg=0; break;
}
return FALSE;
}
Detected encoding: ANSI (CP1252) | 4
|
|