#include "smc1.h"
#include "wheelcap.h"
#include <stdlib.h>
#include <tchar.h>
HINSTANCE ghInstance; // "zeigt" zur Nur-Ressource-DLL oder enthält 0x400000
NOTIFYICONDATA nid;
char sDecimal[2];
#define WM_TrayNotify (WM_USER+200)
#define WM_ShowPropWnd (WM_USER+202)
CONFIG Config; // Persistente Daten
GDI Gdi; // GDI-Objekte
//HWND PropWnd; // Eigenschaftsfenster (<>0 wenn vorhanden)
/************************************************
* Das Hauptfenster ist eine Sprechblase *
************************************************/
static RECT TextRect, IlluRect;
static HICON TitleIcon, KnobIcon;
#define ROUNDNESS 16 // Abrundung
#define INITIALW 200 // Breite in Pixel
#define INITIALH 50 // Höhe in Pixel
// Erstellt alle global verwendeten GDI-Objekte,
// ggf. abhängig von Systemfarben!
void GDI::Create() {
TitleIcon=LoadIcon(ghInstance,MAKEINTRESOURCE(1));
KnobIcon=(HICON)LoadImage(ghInstance,MAKEINTRESOURCE(2),IMAGE_ICON,16,16,LR_SHARED);
SmallFont=CreateFont(-12,0,0,0,FW_NORMAL,0,0,0,
DEFAULT_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,DEFAULT_PITCH,
T("Arial Narrow"));
NormalFont=CreateFont(-12,0,0,0,FW_NORMAL,0,0,0,
DEFAULT_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,DEFAULT_PITCH,
T("Arial"));
BoldFont=CreateFont(-12,0,0,0,FW_BOLD,0,0,0,
DEFAULT_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,DEFAULT_PITCH,
T("Arial"));
FramePen=CreatePen(PS_INSIDEFRAME,1,GetSysColor(COLOR_INFOTEXT));
/*
LOGFONT lf;
GdiObj.brKurz=CreateSolidBrush(FARBE_KURZ);
GdiObj.brLang=CreateSolidBrush(FARBE_LANG);
GdiObj.brFehl=CreateSolidBrush(FARBE_FEHL);
GdiObj.peDivi=CreatePen(PS_DOT,0,FARBE_DIVI);
GdiObj.peXor =CreatePen(PS_SOLID,0,
GetSysColor(COLOR_3DFACE)^GetSysColor(COLOR_WINDOWTEXT));
GdiObj.fnQuer=CreateFont(20,0,0,0,FW_BOLD,0,0,0,0,0,0,0,0,T("Arial"));
GetObject(GetStockFont(DEFAULT_GUI_FONT),sizeof(lf),&lf);
lf.lfItalic=TRUE;
GdiObj.fnKursiv=CreateFontIndirect(&lf);
GdiObj.peZgr[0]=CreatePen(PS_SOLID,2,FARBE_ZGR2); // dicker Stift (Zeiger)
GdiObj.peZgr[1]=CreatePen(PS_SOLID,2,FARBE_ZGR);
GdiObj.peBlau[0]=CreatePen(PS_SOLID,0,FARBE_ZGR2); // dünner Stift (Bögen)
GdiObj.peBlau[1]=CreatePen(PS_SOLID,0,FARBE_ZGR);
GdiObj.brBlau[0]=CreateSolidBrush(FARBE_ZGR2); // Pinsel (Dreieck)
GdiObj.brBlau[1]=CreateSolidBrush(FARBE_ZGR);
*/
}
// Löscht alle global verwendeten GDI-Objekte
void GDI::Delete() {
int i;
for (i=0; i<sizeof(*this)/sizeof(HGDIOBJ); i++) {
DeleteObject(((HGDIOBJ*)this)[i]);
}
}
// Lädt Konfigurationsdaten aus Registrierung
bool CONFIG::Load() {
HKEY key;
bool ret=false;
if (!RegOpenKeyEx(HKEY_CURRENT_USER,T("Software\\h#s\\SMC"),0,KEY_QUERY_VALUE,&key)) {
DWORD size=sizeof(*this);
if (!RegQueryValueEx(key,T("Config"),NULL,NULL,(LPBYTE)this,&size)
&& size==sizeof(*this)) ret=true;
RegCloseKey(key);
}
return ret;
}
// Speichert Konfigurationsdaten in Registrierung
void CONFIG::Save() const {
HKEY key;
if (RegCreateKeyEx(HKEY_CURRENT_USER,T("Software\\h#s\\SMC"),
0,NULL,REG_OPTION_NON_VOLATILE,KEY_SET_VALUE,NULL,&key,NULL)) return;
RegSetValueEx(key,T("Config"),0,REG_BINARY,(LPBYTE)this,sizeof(*this));
RegCloseKey(key);
}
static void HideTrayIcon() {
Shell_NotifyIcon(NIM_DELETE,&nid);
}
static void ShowTrayIcon() {
nid.uFlags=NIF_ICON|NIF_MESSAGE|NIF_TIP;
nid.uVersion=NOTIFYICON_VERSION; // Features (W2K, WXP) aktivieren
Shell_NotifyIcon(NIM_ADD,&nid);
}
static void UpdateTrayIcon() {
// if (nid.uFlags&NIF_INFO) Sprechblase();
if (Shell_NotifyIcon(NIM_MODIFY,&nid)) return;
ShowTrayIcon();
}
void SetTrayTip() {
LoadString(ghInstance,1,nid.szTip,elemof(nid.szTip));
UpdateTrayIcon();
}
#define ACHSN 23 // Anzahl Achsen
#define GREIFN 20 // Anzahl Greifer
static const LPTSTR sAchse[ACHSN]={
T("OWIS-Lineartisch: Greiferverschiebung X"),
T("OWIS-Drehtisch: Revolver C"),
T("Eigenbau-Lineartisch (unbenutzt)"),
T("Greiferplattform Z-Achse (Hubbewegung)"),
T("Greiferplattform links/rechts neigen B"),
T("Greiferplattform vorn/hinten nicken A"),
T("Greiferplattform Einzelmotor vorn links"),
T("Greiferplattform Einzelmotor vorn rechts"),
T("Greiferplattform Einzelmotor hinten"),
T("STANDA-Schiebetisch 045507: Greiferverschiebung Y"),
T("STANDA-Drehtisch: Greiferdrehung"),
T("STANDA-Schiebetisch 048635: Greiferhöhe Z"),
T("frei"),
T("frei"),
T("frei"),
T("Fokusmotor 0"),
T("Fokusmotor 1"),
T("SMARACT-Kinematik links/rechts X"),
T("SMARACT-Kinematik vorn/hinten Y"),
T("SMARACT-Kinematik Drehung C"),
T("SMARACT-Einzelmotor oben"),
T("SMARACT-Einzelmotor Mitte"),
T("SMARACT-Einzelmotor unten")};
// Achsspezifische konstante Daten, die der Firmware nicht bekannt sind
struct ACHSINFO{
float ups; // Einheiten pro Ganzschritt, 0 beim Fokusmotor (weil unbekannt)
float len; // Gesamtstellweg in Einheiten (umlaufend rotatorisch: 360)
BYTE nk; // Nachkommastellen (bei ganzen mm)
BYTE nSteuer; // Steuerungs-Nummer
BYTE nAchse; // Achs-Nummer der Steuerung
BYTE flags; // Besonderheiten:
// Bit 0 = umlaufend
// Bit 1 = Einheit °, sonst mm
// Bit 2 = überspringen bei Durchwahl
DWORD depend; // Lineare Abhängigkeiten (bei virtueller Achse), triple-weise (6 Tripel)
// Bit 2:0 = vzb. Anteil Motor 0
// Bit 5:3 = vzb. Anteil Motor 1
// Bit 8:6 = vzb. Anteil Motor 2
// Bit 11:9 = vzb. Anteil Motor 3
// Bit 14:12 = vzb. Anteil Motor 4
// Bit 17:15 = vzb. Anteil Motor 5
// Bit 18 = Steuerung ohne echte Mikroschritte
float GetPos(BYTE f) const;
int GetPosStr(char*,int,BYTE f) const; // liefert Position (f=4) oder Geschwindigkeit (f=2) oder Info-Bits
};
// noch unimplementierte Koordinatentrafo für Parallelkinematik
static float GetPPosX(const ACHSINFO&pai, BYTE f) {
return 0;
}
static float GetPPosY(const ACHSINFO&pai, BYTE f) {
return 0;
}
static float GetPPosC(const ACHSINFO&pai, BYTE f) {
return 0;
}
static const ACHSINFO ai[ACHSN]={
{1.0F/200, 70.0F,4,0,0,0,01001000},
{1.0F/100,360.0F,3,0,1,3,01010000},
{1.0F/672, 24.0F,4,0,2,4,01100000},
{0.5F/24/3,15.0F,3,0,3,4,01000111}, // 3 Achsen addiert
{0.5F/24, 10.0F,3,0,4,6,01000071}, // Achse[1] subtrahiert, Achse[0] addiert
{0.5F/24/2,10.0F,3,0,5,6,01000611}, // Achse[2] 2x subtrahiert von Achse[1] + Achse[0]
{0.5F/24, 15.0F,3,0,6,4,01000001},
{0.5F/24, 15.0F,3,0,7,4,01000010},
{0.5F/24, 15.0F,3,0,8,4,01000100},
{1.0F/600, 25.0F,4,1,0,0,01001000},
{1.0F/100,360.0F,3,1,1,3,01010000},
{1.0F/600, 25.0F,4,1,2,0,01100000},
{0, 25, 4,1,3,4,01000001},
{0, 25, 4,1,4,4,01000010},
{0, 25, 4,1,5,4,01000100},
{0, 25, 0,1,6,0,0},
{0, 25, 0,1,7,4,0},
{0.5F/1000,10.0F,3,2,3,0,(DWORD)GetPPosX},
{0.5F/1000,10.0F,3,2,4,0,(DWORD)GetPPosY},
{0.5F/1000,10.0F,3,2,5,2,(DWORD)GetPPosC},
{0.5F/1000,15.0F,3,2,0,0,01000001},
{0.5F/1000,15.0F,3,2,1,0,01000010},
{0.5F/1000,15.0F,3,2,2,0,01000100}};
float ACHSINFO::GetPos(BYTE f) const{
union{
int i; // Integer-Zwischengröße
BYTE b[4]; // Returnwert für f=0
float f; // Returnwert für f=1,2,4
}r={0};
if (depend) {
if (depend<0x400000) { // reguläre Anhängigkeits-Info
r.i=0;
if (!f) r.b[0]--;
DWORD dep=depend&0777777; // 6 motorweise Abhängigkeiten
MOTOR *pmd=md+6*nSteuer; // Zeiger auf Motordaten
for (; dep; dep>>=3,pmd++) {
char fak=(char)((char)dep<<5)>>5; // jeweiligen Faktor mit Vorzeichen erweitern
if (fak) switch (f) {
case 0:
r.b[0]&=pmd->phase; // Bits UND-verknüpfen
r.b[1]|=pmd->phase; // ODER-verknüpfen
r.b[2]^=pmd->phase; // XOR-verknüpfen (wozu?)
r.b[3]++; break; // Anzahl der Verknüpfungen (um Unsinn aufzudecken)
case 1: r.i+=pmd->accel*fak; break;// sonst mit Faktor addieren
case 2: r.i+=pmd->speed*fak; break;
case 4: r.i+=pmd->ist*fak; break;
}
}
if (f) {
if (f==4 && depend&1<<18) r.i&=~255;// Bei Positionsangaben Mikroschritte entfernen
r.f=ups*r.i/512; // Physikalische Größe
switch (f) {
case 1: r.f/=1E-3F; nobreak; // Beschleunigung, Einheit pro s²
case 2: r.f/=256E-6F; break; // Geschwindigkeit, Einheit pro Sekunde
}
}
}else r.f=((float(*)(const ACHSINFO&,BYTE))depend)(*this,f); // Funktionszeiger aufrufen
}
return r.f;
}
int ACHSINFO::GetPosStr(char*s, int l, BYTE f) const{
int ret=0;
if (f) {
const char *suffix[]={NULL,"/s²","/s",NULL,""};
ret=_snprintf(s,l,"% .*f %s%s",nk,GetPos(f&7),flags&2?"°":"mm",suffix[f]);
char*p=StrChrA(s,'.');
if (p) *p=*sDecimal;
}else if (l>6) {
BYTE b[4];
*(float*)&b=GetPos(0);
static const char flagchar[]="brlhf"; // Zeichen für BRAKE, REF, LEFT, HOLD, FULL (Bits in Phase)
const char *fl=flagchar;
for (BYTE m=1; m<32; m<<=1, fl++) {
if (b[1]&m) *s++ = b[3]>1 && b[0]&m ? _toupper(*fl) : *fl, ret++;
} // Großbuchstaben für kombinierte Achsen, wenn Flag auf ALLE Achsen zutrifft
b[1]>>=5; b[0]>>=5; // Phase (3 Bits)
*s++ = (b[1]==b[0]) ? b[0]+'0' : '?', ret++;
*s=0; // terminieren (nur zum Debuggen nötig)
}
return ret;
}
static const LPTSTR sSteuer[]={
T("SM1 @ COM%d"),
T("SM2 @ COM%d"),
T("HCU-3D @ USB"),
NULL};
int Achse;
int Greifer;
BYTE GreiferState;
BYTE KeyState; // zum Hervorheben von Textteilen
static int GetGreifStr(char*s, int l, BYTE f=0) {
return _snprintf(s,l,"%s",GreiferState?"EIN":"AUS");
}
// Einen symbolisierten Drehknopf ausgeben
static void OutKnob(HDC dc, bool yes) {
if (yes) {
POINT p;
GetCurrentPositionEx(dc,&p);
DrawIconEx(dc,p.x,p.y,KnobIcon,0,0,0,0,DI_NORMAL);
MoveToEx(dc,p.x+20,p.y,NULL);
}
}
// Text ausgeben
static void OutText(HDC dc) {
SetTextAlign(dc,TA_UPDATECP);
TCHAR buf[128];
const ACHSINFO&rai=ai[Achse];
// 1. Zeile: welche Achse
bool focus=(KeyState&0x0E)==8; // Fokus für Drehknopf und Mausrad: linke (blaue) Taste gedrückt
int l=_sntprintf(buf,elemof(buf),T("Achse %d: %s"),Achse,sAchse[Achse]);
MoveToEx(dc,TextRect.left,TextRect.top,NULL);
SelectFont(dc,focus?Gdi.BoldFont:Gdi.NormalFont);
OutKnob(dc,focus);
TextOut(dc,0,0,buf,l);
// 2. Zeile: Achsposition
SelectFont(dc,Gdi.NormalFont);
MoveToEx(dc,TextRect.left,(TextRect.top*2+TextRect.bottom)/3,NULL);
focus=(KeyState&0x0E)==0; // Fokus wenn keine Taste gedrückt
OutKnob(dc,focus);
TextOut(dc,0,0,T("Position: "),10);
l=rai.GetPosStr(buf,elemof(buf),4);
SelectFont(dc,focus?Gdi.BoldFont:Gdi.NormalFont);
TextOut(dc,0,0,buf,l);
// Achsgeschwindigkeit
TextOut(dc,0,0,T(" "),3);
focus=(KeyState&0x0E)==2; // Fokus wenn Shift-Taste (Drehknopf) gedrückt
OutKnob(dc,focus);
SelectFont(dc,Gdi.NormalFont);
TextOut(dc,0,0,T("Geschw.: "),9);
l=rai.GetPosStr(buf,elemof(buf),2);
SelectFont(dc,focus?Gdi.BoldFont:Gdi.NormalFont);
TextOut(dc,0,0,buf,l);
// 3. Zeile: welcher Greifer und Greiferzustand
focus=(KeyState&0x0E)==4; // Fokus wenn zweite (grüne) Taste gedrückt
MoveToEx(dc,TextRect.left,(TextRect.top+TextRect.bottom*2)/3,NULL);
l=_sntprintf(buf,elemof(buf),T("Greifer %d: "),Greifer);
SelectFont(dc,focus?Gdi.BoldFont:Gdi.NormalFont);
OutKnob(dc,focus);
TextOut(dc,0,0,buf,l);
l=GetGreifStr(buf,elemof(buf));
SelectFont(dc,KeyState&1?Gdi.BoldFont:Gdi.NormalFont);
TextOut(dc,0,0,buf,l);
// Info
MoveToEx(dc,(TextRect.left+TextRect.right)/2,(TextRect.top+TextRect.bottom*2)/3,NULL);
SelectFont(dc,Gdi.SmallFont);
TextOut(dc,0,0,T("Info: "),6);
l=rai.GetPosStr(buf,elemof(buf),0);
TextOut(dc,0,0,buf,l);
// 2. Zeile rechts: Steuereinheit für aktuelle Achse
SelectFont(dc,Gdi.NormalFont);
SetTextAlign(dc,TA_RIGHT);
SetTextColor(dc,0xC0C0C0);
l=_sntprintf(buf,elemof(buf),sSteuer[rai.nSteuer],Config.SerialNo[rai.nSteuer]+1);
TextOut(dc,TextRect.right,(TextRect.top*2+TextRect.bottom)/3,buf,l);
// 3. Zeile rechts: Steuereinheit für aktuellen Greifer (zurzeit immer SM1)
l=_sntprintf(buf,elemof(buf),sSteuer[0],Config.SerialNo[0]+1);
TextOut(dc,TextRect.right,(TextRect.top+TextRect.bottom*2)/3,buf,l);
}
// Status aus Motorsteuerung lesen
static void ReadCurState() {
BYTE s[1], r[4];
s[0]='@';
if (w[0].SendRecv(s,sizeof(s),r,sizeof(r))==sizeof(r)) {
Achse=r[0];
Greifer=r[1];
GreiferState=r[2];
}
}
static LRESULT CALLBACK MainWndProc(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam) {
static UINT RegMsg_TaskbarCreated;
switch (Msg) {
case WM_CREATE: {
RegMsg_TaskbarCreated=RegisterWindowMessage(T("TaskbarCreated"));
Gdi.Create();
InitStruct(&nid,sizeof(nid));
nid.hWnd=Wnd;
nid.uID=1;
nid.uFlags=NIF_ICON|NIF_MESSAGE|NIF_TIP;
nid.uCallbackMessage=WM_TrayNotify;
nid.hIcon=(HICON)LoadImage(ghInstance,MAKEINTRESOURCE(1),IMAGE_ICON,16,16,LR_SHARED);
// SetStrings();
SetTrayTip();
InfoWindow(Wnd);
StartWorker();
SendMessage(Wnd,WM_WININICHANGE,0,0);
ReadCurState();
}break;
case WM_WININICHANGE: {
GetProfileStringA("intl","sDecimal",".",sDecimal,elemof(sDecimal));
InvalidateRect(Wnd,NULL,TRUE);
}break;
case WM_NCHITTEST: { // Maus über Fenster
SetTimer(Wnd,1,nid.uTimeout*1000,NULL); // Timer neu starten
POINT pt={GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam)};
RECT r;
GetWindowRect(Wnd,&r);
BYTE hitcode=0;
if (r.left<=pt.x && pt.x<r.left+ROUNDNESS/2) hitcode|=1; // linker Rand
if (r.right-ROUNDNESS/2<=pt.x && pt.x<r.right) hitcode|=2; // rechter Rand
if (r.top<=pt.y && pt.y<r.top+ROUNDNESS/2) hitcode|=4; // oberer Rand
if (r.bottom-ROUNDNESS/2<=pt.y && pt.y<r.bottom) hitcode|=8; // unterer Rand
static const BYTE htcode[16]={
HTCAPTION, HTLEFT, HTRIGHT, HTRIGHT,
HTTOP, HTTOPLEFT, HTTOPRIGHT, HTTOP,
HTBOTTOM, HTBOTTOMLEFT, HTBOTTOMRIGHT, HTBOTTOM,
HTBOTTOM, HTBOTTOMLEFT, HTBOTTOMRIGHT, HTBOTTOM};
return htcode[hitcode];
}
case WM_SIZE: {
int w=GET_X_LPARAM(lParam);
int h=GET_Y_LPARAM(lParam);
SetRect(&TextRect,6+32+6,6,w-6,6+3*16); // rechts neben dem Icon
SetRect(&IlluRect,6,6+3*16+6,w-6,h-6-6-3*16-6);
if (Gdi.rgn) DeleteRgn(Gdi.rgn);
Gdi.rgn=CreateRoundRectRgn(0,0,w,h,ROUNDNESS,ROUNDNESS);
SetWindowRgn(Wnd,Gdi.rgn,FALSE);
}nobreak;
case WM_MOVE: {
RECT r;
GetWindowRect(Wnd,&r);
Config.WinPos.set(r); // Fensterkoordinaten nachführen (zum späteren Speichern)
}break;
case WM_PAINT: {
PAINTSTRUCT ps;
// HFONT of;
BeginPaint(Wnd,&ps);
RECT r;
GetClientRect(Wnd,&r);
// Blase mit Rahmen zeichnen (ohne "Mundstück")
SelectBrush(ps.hdc,GetSysColorBrush(COLOR_INFOBK));
SelectPen(ps.hdc,Gdi.FramePen);
RoundRect(ps.hdc,0,0,r.right-1,r.bottom-1,ROUNDNESS,ROUNDNESS);
// Icon und Überschrift ausgeben
DrawIcon(ps.hdc,8,8,TitleIcon);
SetBkMode(ps.hdc,TRANSPARENT);
SetTextColor(ps.hdc,GetSysColor(COLOR_INFOTEXT));
// of=SelectFont(ps.hdc,Gdi.TitleFont);
// DrawText(ps.hdc,nid.szInfoTitle,-1,&TitleRect,DT_NOPREFIX|DT_SINGLELINE);
// Textkörper ausgeben
// SelectFont(ps.hdc,GetStockFont(DEFAULT_GUI_FONT));
// DrawText(ps.hdc,nid.szInfo,-1,&TextRect,DT_NOPREFIX|DT_WORDBREAK);
OutText(ps.hdc);
EndPaint(Wnd,&ps);
}return 0;
case WM_SHOWWINDOW: if (wParam) {
SetTimer(Wnd,1,nid.uTimeout*1000,NULL); // Fenster verschwindet automatisch
}break;
case WM_TIMER: switch (wParam) {
case 1: {
KillTimer(Wnd,wParam);
ShowWindow(Wnd,SW_HIDE);
}break;
}break;
case WM_ShowPropWnd: { // Zweiter Programmstart
// ShowProperties(); // PropSheet öffnen - und Tray-Icon zeigen
}break;
case WM_LokalInput: {
LOKALINPUT k;
k.lp=lParam;
KeyState=k.ks;
const ACHSINFO*pai=ai+Achse;
if (k.kp&1) { // Greifer schalten
GreiferState^=true;
w[0].Send(GreiferState?'g':'h');
}
if (k.kr&2) { // Motor stoppen
w[pai->nSteuer].Send('c');
}
if (k.delta) switch (k.ks&0x0F) {
case 0:
case 1: { // Schritte machen
if (k.delta<0) for (;k.delta; k.delta++) w[pai->nSteuer].Send('-');
else for (;k.delta; k.delta--) w[pai->nSteuer].Send('+');
}break;
case 2:
case 3: {
// debug(("Delta=%d, Steuerung=%d",k.delta,pai->nSteuer));
if (k.delta<0) for (;k.delta; k.delta++) w[pai->nSteuer].Send('b');
else for (;k.delta; k.delta--) w[pai->nSteuer].Send('a');
}break; // fahren
case 4: { // Greifer weiterschalten
Greifer+=k.delta;
if (Greifer<0) Greifer+=GREIFN;
if (Greifer>=GREIFN) Greifer-=GREIFN;
BYTE s[2],r[4];
s[0]='G'+Greifer;
s[1]='@';
if (w[0].SendRecv(s,sizeof(s),r,sizeof(r))==sizeof(r)) GreiferState=r[2];
else MessageBeep(MB_ICONEXCLAMATION);
}break;
case 8: { // Achse weiterschalten
Achse+=k.delta;
if (Achse<0) Achse+=ACHSN;
if (Achse>=ACHSN) Achse-=ACHSN;
pai=ai+Achse;
switch (pai->nSteuer) {
case 0:
case 1: {
w[pai->nSteuer].Send('0'+pai->nAchse);
}break;
}
}break;
default: Beep(500,20); // ungültiges KeyState
}
InvalidateRect(Wnd,NULL,TRUE);
ShowWindow(Wnd,SW_SHOWNA);
}break;
case WM_MotorChange: { // wenn sich etwas tut ...
div_t d=div(wParam,6); // d.quot=Steuer-Nummer, d.rem=Motor-Nummer (nicht Achs-Nummer!)
const ACHSINFO*pai=ai+Achse;
if (d.quot==pai->nSteuer && ai[Achse].depend&(7<<(d.rem*3))) {
InvalidateRect(Wnd,NULL,TRUE);
ShowWindow(Wnd,SW_SHOWNA);
}
}break;
case WM_WHEELCAP: {
ShowWindow(MainWnd,SW_SHOWNA);
Beep(1000+(short)HIWORD(lParam),30);
}break;
case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN:
ShowWindow(Wnd,SW_HIDE);
break;
case WM_TrayNotify: switch (lParam) {
case WM_LBUTTONDOWN: {
ShowWindow(Wnd,SW_SHOWNA);
}break;
case NIN_SELECT:
case NIN_KEYSELECT: {
// ShowProperties();
}break;
case WM_RBUTTONDOWN:
case WM_CONTEXTMENU: {
HMENU m=LoadMenu(ghInstance,MAKEINTRESOURCE(100));
GetLastError();
MENUITEMINFO mii;
InitStruct(&mii,sizeof(mii));
mii.fMask=MIIM_STATE;
mii.fState=MFS_DEFAULT;
if (IsWindowVisible(MainWnd)) mii.fState|=MFS_CHECKED;
SetMenuItemInfo(m,101,FALSE,&mii);
POINT p;
GetCursorPos(&p);
SetForegroundWindow(Wnd); // soll so sein
TrackPopupMenu(GetSubMenu(m,0),TPM_RIGHTALIGN|TPM_RIGHTBUTTON,
p.x,p.y,0,Wnd,NULL);
PostMessage(Wnd,WM_NULL,0,0); // soll so sein
Shell_NotifyIcon(NIM_SETFOCUS,&nid); // soll so sein
DestroyMenu(m);
}break;
// Diese Messages scheinen nicht unter W2k aufzutauchen! Ersatz??
case NIN_BALLOONTIMEOUT: // Signalausfall-Meldung weg?
case NIN_BALLOONUSERCLICK: { // (oder "fehlende Rechte")
nid.uFlags&=~NIF_INFO;
}break;
}break;
case WM_COMMAND: switch (LOWORD(wParam)) {
case 101: {
ShowWindow(Wnd,IsWindowVisible(Wnd)?SW_HIDE:SW_SHOWNA);
}break;
case 102: { // Eigenschaften....
// ShowProperties();
}break;
case 2: { // Beenden
SendMessage(Wnd,WM_CLOSE,0,0);
}break;
}break;
case WM_ENDSESSION: if (wParam) {
Config.Save();
}break;
case WM_DESTROY: {
Config.Save();
// nid.uFlags&=~NIF_INFO; Sprechblase();// Sprechblase entfernen
StopWorker();
InfoWindow(0);
HideTrayIcon();
Gdi.Delete();
PostQuitMessage(0);
}break;
default:
if (Msg==RegMsg_TaskbarCreated) ShowTrayIcon(); // Explorer-Absturz-Behandlung
}
return DefWindowProc(Wnd,Msg,wParam,lParam);
}
void CALLBACK WinMainCRTStartup() {
HWND Wnd=FindWindow(T("SMC"),NULL);
if (Wnd) { // Nachricht hinschicken
PostMessage(Wnd,WM_ShowPropWnd,0,0);
}else{
ghInstance=GetModuleHandle(NULL);
WNDCLASSEX wc;
InitStruct(&wc,sizeof(wc));
wc.style=CS_BYTEALIGNWINDOW|CS_SAVEBITS|CS_HREDRAW|CS_VREDRAW;
wc.lpfnWndProc=MainWndProc;
wc.hInstance=(HINSTANCE)0x400000;
wc.hCursor=LoadCursor(0,IDC_ARROW);
wc.lpszClassName=T("SMC");
RegisterClassEx(&wc);
InitCommonControls();
LoadString(ghInstance,1,MBoxTitle,elemof(MBoxTitle));
if (!Config.Load()) {
Config.WinPos.left=(Config.WinPos.right=(short)GetSystemMetrics(SM_CXFULLSCREEN)-16)-INITIALW;
Config.WinPos.top=(Config.WinPos.bottom=(short)GetSystemMetrics(SM_CYFULLSCREEN)-16)-INITIALH;
Config.SerialNo[0]=3;
Config.SerialNo[1]=4;
}
CreateWindowEx(WS_EX_TOPMOST|WS_EX_TOOLWINDOW|WS_EX_NOPARENTNOTIFY,
T("SMC"),NULL,WS_POPUP,
Config.WinPos.left,Config.WinPos.top,Config.WinPos.width(),Config.WinPos.height(),0,0,(HINSTANCE)0x400000,NULL);
MSG Msg;
while (GetMessage(&Msg,0,0,0)) {
// if (PropWnd) { // notwendig für nicht-modale Eigenschaftsfenster
// HWND PageWnd=PropSheet_GetCurrentPageHwnd(PropWnd);
// if (PageWnd) {
// Config.ActivePropSheet=PropSheet_HwndToIndex(PropWnd,PageWnd);
// if (PropSheet_IsDialogMessage(PropWnd,&Msg)) continue;
// }else{
// RetrievePropWndPos();
// DestroyWindow(PropWnd);
// PropWnd=0;
// Config.Save();
// }
// }
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
ExitProcess(Msg.wParam);
}
}
Detected encoding: UTF-8 | 0
|