Source file: /~heha/mb-iwp/Datenhandschuh/Demo/glovetest.zip/glovetest.cpp

#define WIN32_LEAN_AND_MEAN
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <windowsx.h>	// Makros
#include <shlwapi.h>	// nützliche Funktionen
#include <commctrl.h>
#include <ddeml.h>

#define elemof(x) (sizeof(x)/sizeof((x)[0]))
#define T(x) TEXT(x)
#define nobreak

HINSTANCE ghInstance;
HWND ghMainWnd;
TCHAR StdMBoxTitle[64];
unsigned gComNum;
HANDLE hCom;

void _fastcall InitStruct(LPVOID p, UINT len) {
 LPUINT p2=(LPUINT)p;
 *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));
}

BOOL OpenCom(void) {
 TCHAR ComName[12];
 wsprintf(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 FALSE;}
 DCB dcb;
 InitStruct(&dcb,sizeof(dcb));
 GetCommState(hCom,&dcb);
 dcb.BaudRate=9600;	// default setting for big Fakespace box
 dcb.ByteSize=8;
 dcb.StopBits=TWOSTOPBITS;
 SetCommState(hCom,&dcb);
 static const COMMTIMEOUTS to={MAXDWORD,0,0,0,0};
 return SetCommTimeouts(hCom,(LPCOMMTIMEOUTS)&to);
}

typedef struct {
 unsigned char N;
 unsigned short C[5];
}conn_t;

conn_t conn;
unsigned timeval;

static void SendString(const char*s) {
 DWORD bw;
 WriteFile(hCom,s,lstrlenA(s),&bw,NULL);
}

static void InvalHands(void) {
 InvalidateRect(GetDlgItem(ghMainWnd,11),NULL,FALSE);
}

static void CheckDataArrival(void) {
 DWORD br;
 static unsigned char buf[64],c;
 static unsigned idx;
 for(;;) {
  if (!ReadFile(hCom,&c,1,&br,NULL)) return;
  if (!br) break;
  if (idx==0) {
   if (c>=0x80 && c<=0x82) buf[idx++]=c;	// valid STX, otherwise discard the byte
  }else{
   if (idx<elemof(buf)) buf[idx++]=c;
   if (c==0x8F) {		// valid ETX, show message
    TCHAR s[100], *p=s;
    p+=wsprintf(p,T("%02X "),buf[0]);
    if (buf[0]==0x82) {
     p+=wsprintf(p,T("\""));
     for (unsigned k=1; k<idx-1; k++) {
      p+=wsprintf(p,T("%c"),buf[k]);
     }
     p+=wsprintf(p,T("\" "));
    }else{
     if (IsDlgButtonChecked(ghMainWnd,16)==2)
       CheckDlgButton(ghMainWnd,16,buf[0]-0x80);	// T state detected
     for (unsigned k=1; k<idx-1; k++) {
      p+=wsprintf(p,T("%02X "),buf[k]);
     }
     unsigned n=(idx-2)>>1;	// number of connections
     timeval=0;
     if (buf[0]==0x81) {
      n--;
      timeval=(buf[idx-2]<<7)|buf[idx-3];
      SetTimer(ghMainWnd,3,1000,NULL);	// display time for 1 second
     }
     conn.N=n;
     BYTE all_bits=0;
     for (unsigned i=0; i<n; i++) {
      BYTE lobyte=buf[(i<<1)+1];
      BYTE hibyte=buf[(i<<1)+2];
      conn.C[i]=MAKEWORD(lobyte,hibyte);
      all_bits|=lobyte|hibyte;
     }
     if (all_bits&0x20 && IsDlgButtonChecked(ghMainWnd,17)==2)
       CheckDlgButton(ghMainWnd,17,1);	// G1 state detected
     InvalHands();
    }
    p+=wsprintf(p,T("%02X\r\n"),buf[idx-1]);
    HWND w=GetDlgItem(ghMainWnd,12);
    DWORD Start,End,Len;
    Len=Edit_GetTextLength(w);
    SendMessage(w,EM_GETSEL,(WPARAM)&Start,(LPARAM)&End);
    Edit_SetSel(w,Len,Len);
    Edit_ReplaceSel(w,s);
    if (Len==Start && Start==End);	// update cursor
    else Edit_SetSel(w,Start,End);	// not update cursor
    idx=0;
   }
  }
 }
}

#define MAXCOMSEARCH	32

static BOOL CALLBACK ComSelDlgProc(HWND Wnd,UINT Msg,WPARAM wParam,LPARAM lParam) {
 switch (Msg) {
  case WM_INITDIALOG: {
   SetTimer(Wnd,1,100,NULL);
  }return TRUE;

  case WM_DEVICECHANGE: SetTimer(Wnd,1,1500,NULL);

  case WM_TIMER: {
   KillTimer(Wnd,wParam);
   HWND hCombo=GetDlgItem(Wnd,13);
   ComboBox_ResetContent(hCombo);
   HMODULE hLib=LoadLibraryA("cfgmgr32.dll");
   for (UINT i=1; i<=MAXCOMSEARCH; i++) {
    DWORD cclen;
    TCHAR ComName[8];
    COMMCONFIG cc;
    InitStruct(&cc,cclen=sizeof(cc));
    wnsprintf(ComName,elemof(ComName),T("COM%u"),i);
    if (GetDefaultCommConfig(ComName,&cc,&cclen)) {
     int idx=ComboBox_AddString(hCombo,ComName);
     ComboBox_SetItemData(hCombo,idx,i);
     if (i==gComNum) ComboBox_SetCurSel(hCombo,idx);
    }
   }
   if (hLib) FreeLibrary(hLib);
  }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|MB_ICONEXCLAMATION);
     SetFocus(hCombo);
     break;
    }
    gComNum=(unsigned)ComboBox_GetItemData(hCombo,i);
   }nobreak;
   case IDCANCEL: EndDialog(Wnd,wParam); break;
  }break;
  
 }
 return FALSE;
}

static void DrawCircle(HDC dc, POINT p) {
 Ellipse(dc,p.x-5,p.y-10,p.x+5,p.y+10);
}

static const COLORREF colors[]={	// colors for connections
 0x30F090,
 0xF03030,
 0x307090,
 0x903070,
 0x709030};

struct {
 HFONT hFont;
 HBRUSH hbrCircles[elemof(colors)];
 HPEN hThickPen;
}gGdiObj;

static void DrawConn(HDC dc, BYTE bits, unsigned i) {
 static const POINT pos[]={	// fingertip positions
  {97,140},
  {77,175},
  {57,180},
  {37,160},
  {15,75},
  {15,180}};
  
 HPEN open=SelectPen(dc,GetStockPen(NULL_PEN));
 SelectBrush(dc,
   i<elemof(colors) ? gGdiObj.hbrCircles[i] : GetStockBrush(LTGRAY_BRUSH));
 for (unsigned k=0; k<elemof(pos); k++) {
  if (bits&(1<<k)) DrawCircle(dc,pos[k]);
 }
 SelectPen(dc,open);
}

static void DrawHand(HDC dc,BOOL right) {
 static const POINT BezierPoints[]={
  {10,0},{5,30},{5,30},{5,70},
  {5,110},{25,110},{25,70},
  {25,0},{30,0},{30,160},
  {30,185},{45,185},{45,160},
  {45,60},{50,60},{50,180},
  {50,205},{65,205},{65,180},
  {65,60},{70,60},{70,175},
  {70,200},{85,200},{85,175},
  {85,60},{90,60},{90,140},
  {90,160},{105,160},{105,140},
  {105,130},{105,20},{100,0}
 };
 PolyBezier(dc,BezierPoints,elemof(BezierPoints));
 BYTE mask=0;
 for (unsigned i=0; i<conn.N; i++) {
  BYTE bits=right?HIBYTE(conn.C[i]):LOBYTE(conn.C[i]);
  DrawConn(dc,bits,i);	// set circles
  mask|=bits;
 }
 DrawConn(dc,~mask,(unsigned)-1);	// remove circles, don't flicker
}

static void DrawHands(LPDRAWITEMSTRUCT dis) {
 SetMapMode(dis->hDC,MM_ANISOTROPIC);
 SetViewportExtEx(dis->hDC,(dis->rcItem.right-dis->rcItem.left)>>1,
			   dis->rcItem.top-dis->rcItem.bottom,NULL);
 SetViewportOrgEx(dis->hDC,(dis->rcItem.right+dis->rcItem.left)>>1,
			   dis->rcItem.bottom,NULL);
 SelectPen(dis->hDC,gGdiObj.hThickPen);
 SetWindowExtEx(dis->hDC,110,200,NULL);
 DrawHand(dis->hDC,TRUE);		// right hand
 SetWindowExtEx(dis->hDC,-110,200,NULL);
 DrawHand(dis->hDC,FALSE);		// left hand
 RECT r;
 SetRect(&r,-25,120,25,140);
 TCHAR s[32];
 SelectFont(dis->hDC,GetStockFont(ANSI_VAR_FONT));
 SetTextAlign(dis->hDC,TA_BOTTOM|TA_CENTER);
 ExtTextOut(dis->hDC,0,120,ETO_OPAQUE|ETO_CLIPPED,&r,s,
   wsprintf(s,timeval?T("%u ms"):T(""),timeval),NULL);
 ExtTextOut(dis->hDC,0,170,0,NULL,T("GND"),3,NULL);
}

static void EnableControls(void) {
 for (HWND w=GetDlgItem(ghMainWnd,13); w; w=GetNextSibling(w))
   EnableWindow(w,hCom!=0);
}

void MakeGdiObj(void) {
 gGdiObj.hFont=CreateFont(12,0,0,0,0,0,0,0,0,0,0,0,0,T("Lucidia Console"));
 for (int i=0; i<elemof(colors); i++) {
  gGdiObj.hbrCircles[i]=CreateSolidBrush(colors[i]);
 }
 gGdiObj.hThickPen=CreatePen(PS_SOLID,2,0);
}

void LoadConfig(void) {
 HKEY key;
 if (RegCreateKeyEx(HKEY_LOCAL_MACHINE,T("Software\\h#s\\glovetest"),
   0,NULL,REG_OPTION_NON_VOLATILE,KEY_QUERY_VALUE,NULL,&key,NULL)) return;
 DWORD size=sizeof(gComNum);
 RegQueryValueEx(key,T("Com"),NULL,NULL,(LPBYTE)&gComNum,&size);
 RegCloseKey(key);
}
 
void SaveConfig(void) {
 HKEY key;
 if (RegCreateKeyEx(HKEY_LOCAL_MACHINE,T("Software\\h#s\\glovetest"),
   0,NULL,REG_OPTION_NON_VOLATILE,KEY_SET_VALUE,NULL,&key,NULL)) return;
 TCHAR s[64];
 RegSetValue(key,NULL,REG_SZ,s,LoadString(ghInstance,1,s,elemof(s))*sizeof(TCHAR));
 RegSetValueEx(key,T("Com"),0,REG_DWORD,(LPBYTE)&gComNum,sizeof(gComNum));
 RegCloseKey(key);
}

static BOOL CALLBACK MainDlgProc(HWND Wnd,UINT Msg,WPARAM wParam,LPARAM lParam) {
 switch (Msg) {
  case WM_INITDIALOG: {
   ghMainWnd=Wnd;
   LoadConfig();
   MakeGdiObj();
   SetClassLong(Wnd,GCL_HICON,(LONG)(ULONG_PTR)
     LoadImage(ghInstance,MAKEINTRESOURCE(100),IMAGE_ICON,32,32,LR_SHARED));
   SetClassLong(Wnd,GCL_HICONSM,(LONG)(ULONG_PTR)
     LoadImage(ghInstance,MAKEINTRESOURCE(100),IMAGE_ICON,16,16,LR_SHARED));
   SendDlgItemMessage(Wnd,12,WM_SETFONT,(WPARAM)gGdiObj.hFont,FALSE);
   SetTimer(Wnd,1,100,NULL);
  }return TRUE;
  
  case WM_TIMER: switch (wParam) {
   case 1: {	// initialization timer
    KillTimer(Wnd,wParam);
    HMENU SysMenu=GetSystemMenu(Wnd,FALSE);
    TCHAR s[64];
    LoadString(ghInstance,4,s,elemof(s));	// insert a menu item
    InsertMenu(SysMenu,SC_CLOSE,0,0x40,s);
    do{
     if (gComNum && OpenCom()) { SendString("CP"); break; }
    }while (DialogBox(0,MAKEINTRESOURCE(101),Wnd,ComSelDlgProc)==IDOK);
    EnableControls();
    CheckDlgButton(Wnd,16,2);
    CheckDlgButton(Wnd,17,2);
    if (hCom) SetTimer(Wnd,2,100,NULL);
   }break;
   case 2: {	// cyclic timer that queries the serial port
// (not best - for maximum responsiveness use a thread or overlapped operation)
    CheckDataArrival();
   }break;
   case 3: {	// remove timestamp from hands display
    KillTimer(Wnd,wParam);
    timeval=0;
    InvalHands();
   }break;
  }break;
  
  case WM_DRAWITEM: DrawHands((LPDRAWITEMSTRUCT)lParam); break;

  case WM_COMMAND: switch (LOWORD(wParam)) {
   case 13: SendString("CL"); break;
   case 14: SendString("CR"); break;
   case 15: SendString("CP"); break;
   case 16:
   case 17: {
    char s[3];
    s[0]=LOWORD(wParam)==17 ? 'G' : 'T';
    s[1]=IsDlgButtonChecked(Wnd,LOWORD(wParam))?'0':'1';
    s[2]=0;
    SendString(s);
    CheckDlgButton(Wnd,LOWORD(wParam),s[1]-'0');
   }break; 
   case 18: {
    SetDlgItemText(Wnd,12,T(""));
   }break;
  }break;
  
  case WM_SYSCOMMAND: switch (wParam&0xFFF0) {
   case 0x40: {
    if (DialogBox(0,MAKEINTRESOURCE(101),Wnd,ComSelDlgProc)==IDOK) {
     CloseHandle(hCom); hCom=0;
     OpenCom();
     SendString("CP");
    }
   }break;
     
  }break;
  
  case WM_CLOSE: {
   SaveConfig();
   EndDialog(Wnd,2); 
  }break;
  
  case WM_ENDSESSION: if (wParam) SaveConfig(); break;
  
 }
 return FALSE;
}

int _stdcall WinMainCRTStartup(void) {
 ghInstance=GetModuleHandle(NULL);
 InitCommonControls();
 ExitProcess((UINT)DialogBox(0,MAKEINTRESOURCE(100),0,MainDlgProc));
}
Detected encoding: ANSI (CP1252)4
Wrong umlauts? - Assume file is ANSI (CP1252) encoded