Source file: /~heha/hs/UNI-T/dmm.zip/src/log.cpp

#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
Wrong umlauts? - Assume file is ANSI (CP1252) encoded