Source file: /~heha/mb-iwp/Antriebe/Schrittmotorkarte/Regal.zip/Regal.cpp

/* Hochregallager-Demo mit 3 Schrittmotoren sowie Schrittmotorsteuerung am Parallelport
 * Schaltplan siehe Eagle „Schrittmotorkarte.sch“
 * Zum Programmierstil siehe http://www.tu-chemnitz.de/~heha/hs_freeware/mein_msvc.htm
 * h#s 06/07
Zu tun:
 */

#define WIN32_LEAN_AND_MEAN
#define _WIN32_WINNT 0x0501	// WM_THEMECHANGED aktivieren
#include <windows.h>
#include <windowsx.h>	// Makros
#include <commdlg.h>	// Datei öffnen/speichern
#include <commctrl.h>	// Listenfenster für die Zeitschritte
#include <shlwapi.h>	// nützliche Funktionen
#include <mmsystem.h>

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

//Leider hat Win95 mit IE 3.0 ein reduziertes Angebot der
//shlwapi.dll, kein StrCatBuff, kein wnsprintf, kein wvnsprintf,
//daher Ersetzung durch „unsichere“ Funktionen aus kernel32.dll
//Weiterhin kennt Win95 die Schrift "MS Shell Dlg 2" nicht...
#ifdef WIN95
# undef  StrCatBuff
# define StrCatBuff(d,s,l) lstrcat(d,s)
# define wnsprintf1(d,l,t,a1)			wsprintf(d,t,a1)
# define wnsprintf2(d,l,t,a1,a2)		wsprintf(d,t,a1,a2)
# define wnsprintf3(d,l,t,a1,a2,a3)		wsprintf(d,t,a1,a2,a3)
# define wnsprintf6(d,l,t,a1,a2,a3,a4,a5,a6)	wsprintf(d,t,a1,a2,a3,a4,a5,a6)
# undef  wvnsprintf
# define wvnsprintf(d,l,t,a) wvsprintf(d,t,a)
#else
# define wnsprintf1 wnsprintf
# define wnsprintf2 wnsprintf
# define wnsprintf3 wnsprintf
# define wnsprintf6 wnsprintf
#endif

#ifdef DEBUG
# define _debug(x) DebugPrintf x
void _cdecl DebugPrintf(LPCTSTR s,...) {
 TCHAR buf[256];
 wvnsprintf(buf,elemof(buf),s,(va_list)(&s+1));
 OutputDebugString(buf);
}
#else
# define _debug(x)
#endif

#ifdef WIN32
# define Send_WM_Command(ToWnd,CtlId,NotifyCode,FromWnd)\
  SendMessage(ToWnd,WM_COMMAND,MAKELONG(CtlId,NotifyCode),(LPARAM)FromWnd);
#else	// Win16
# define Send_WM_Command(ToWnd,CtlId,NotifyCode,FromWnd)\
  SendMessage(ToWnd,WM_COMMAND,CtlId,MAKELONG((UINT)FromWnd,NotifyCode));
#endif

// Deklaration der zwei Einsprünge in (statisch gebundene) InpOut32.dll
EXTERN_C void _declspec(dllimport) WINAPI Out32(WORD,BYTE);
EXTERN_C BYTE _declspec(dllimport) WINAPI Inp32(WORD);

/*****************************************
 * Globale Variablen und Typdefinitionen *
 *****************************************/
WORD gLptBase=0x378;	// Voreinstellung
HINSTANCE ghInstance;
HWND ghMainWnd;
UINT gEditErrors;	// Bit pro Editfenster für Fehler (Hintergrund rot)
const TCHAR gHelpFileName[]=T("Regal.hlp");
static HWND gToolTip;

struct{
 HBRUSH hbrError;	// rot (Fehler im Editfenster)
}gGdiObj;

TCHAR StdMBoxTitle[64];

/****************
 * aus WUTILS.C *
 ****************/

//Win32-typische Strukturen mit DWORD-Ausrichtung initialisieren
void _fastcall InitStruct(LPVOID p, UINT len) {
 LPUINT q=(LPUINT)p;
 *q=len; len/=sizeof(UINT); len--;
 if (len) do *++q=0; while (--len);
}

int _cdecl MBox(HWND Wnd, LPCTSTR Text, UINT Type, ...) {
 TCHAR buf[256],buf2[256];
 if (!HIWORD(Text)) {
  LoadString(ghInstance,(UINT)(DWORD_PTR)Text,buf2,elemof(buf2));
  Text=buf2;
 }
 wvnsprintf(buf,elemof(buf),Text,(va_list)(&Type+1));
 return MessageBox(Wnd,buf,StdMBoxTitle,Type);
}

/************************************************
 * LED-Darstellung (etwa wie LptChk, WinDriver) *
 ************************************************/

void MakeGdiObj(void) {
 gGdiObj.hbrError=CreateSolidBrush(RGB(255,128,128));
}

void KillGdiObj(void) {
 DeleteBrush(gGdiObj.hbrError);
}

/**************************
 * Schrittmotoren steuern *
 **************************/
 
struct TMotor{
 int Ist,Soll;
 int Anfang,Ende;	// nur für Scrollbar
 int Offset;		// Nullpunktverschiebung (nur für Anzeige)
 char InSync;
 char InMove;		// svw. Geschwindigkeit (vzb.)
 bool synced;
 BYTE mask;		// 1 << Motornummer
 void DoneStep();
 void Stop();
 void Move(int Pos);
 void Sync(char Dir);
 static void ReadStatusport();
 static void CALLBACK Step3(UINT,UINT,DWORD_PTR,DWORD_PTR,DWORD_PTR);
 static void Init();
 static void Done();
};

TMotor Motor[3];
static UINT gTimerId;
static volatile BYTE dataport=0x18,statusport,dir_reg=0x18;
// Bitbelegung <dataport>
// 0 - Enable Motor 0 (X) - Richtung Motor 0 (X)
// 1 - Enable Motor 1 (Y) - Richtung Motor 1 (Y)
// 2 - Enable Motor 2 (Z) - Richtung Motor 2 (Z)
// 3 - Schritt (alle freigeschaltenen Motoren)
// 4 - globales Enable
// 5 - Strobe für Richtungsregister (L-H-Flanke)
// Bitbelegung <statusport>
// 7 - Motor 0 (X) durch passenden Endschalter freigegeben (BSY)
// 5 - Motor 1 (Y) durch passenden Endschalter freigegeben (PE)
// 4 - Motor 2 (Z) durch passenden Endschalter freigegeben (SEL)
// In der Software "passend" auf Bit 0..2 umgesetzt

// Achtung! Ausführung im Multimedia-Thread!
void TMotor::DoneStep() {
 if (dataport&mask) {
  if (InSync) {
   if (synced) Ist+=InSync;
   if (!(statusport&mask)) {
    InSync=0;
    if (!synced) Soll=Ist=0;
    synced=true;
   }
  }else{
   Ist+=InMove;
   if (Ist==Soll) {
    dataport&=~mask;
    InMove=0;
   }
  }
 }
}

void TMotor::ReadStatusport() {
 BYTE b=Inp32(gLptBase+1)&0xB0;
 if (!(b&0x80)) b|=1;
 if (b&0x20) b|=2;
 if (b&0x10) b|=4;
 statusport=b;
}

// Achtung! Ausführung im Multimedia-Thread!
void CALLBACK TMotor::Step3(UINT TimerID, UINT Msg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2) {
 static BYTE saved_dir_reg;
 if (!(dataport&7)) return;		// nichts zu tun
 ReadStatusport();
 if (saved_dir_reg!=dir_reg) {
  saved_dir_reg=dir_reg;
  Out32(gLptBase+0,dir_reg);		// schaltet ENABLE kurzfristig aus
  Out32(gLptBase+0,dir_reg|0x20);	// Richtungsbit einschreiben
  Out32(gLptBase+0,dir_reg);
  Out32(gLptBase+0,dataport);
 }
 Out32(gLptBase+0,dataport&~8);
 Sleep(1);
 Out32(gLptBase+0,dataport);		// L-H-Flanke macht Schritt(e)
 Motor[0].DoneStep();
 Motor[1].DoneStep();
 Motor[2].DoneStep();
}

void TMotor::Init() {
// RtlZeroMemory(Motor,sizeof(Motor));
// Kennwerte der Hochregallager-Demo (mech. Aufbau)
 Motor[0].mask=1; Motor[0].Ende=22050;
 Motor[1].mask=2; Motor[1].Ende=12590;
 Motor[2].mask=4; Motor[2].Ende=3330;
 timeBeginPeriod(1);
 gTimerId=timeSetEvent(2,1,Step3,0,TIME_PERIODIC);	// 500 Hz
}

void TMotor::Done() {
 timeKillEvent(gTimerId);
 timeEndPeriod(1);
}

void TMotor::Stop() {
 if (!InMove) return;
 dataport&=~mask;		// Motor deaktivieren
 InMove=0;
}

void TMotor::Move(int Pos) {
 if (Soll==Pos) return;
 Stop();
 Soll=Pos;
 int i=this-Motor;
 SendDlgItemMessage(ghMainWnd,10+i*10,TBM_SETTIC,0,i==1?-Pos:Pos);
 if (Pos>Ist) {
  InMove=1;
  dir_reg&=~mask;
 }else if (Pos<Ist){
  InMove=-1;
  dir_reg|=mask;
 }
 dataport|=mask;	// Motor und global aktivieren
}

void TMotor::Sync(char Dir) {
 InSync=Dir;
 if (Dir>0) {
  dir_reg&=~mask;
  dataport|=mask;
 }else if (Dir<0) {
  dir_reg|=mask;
  dataport|=mask;
 }else dataport&=~mask;	// anhalten mit Dir=0
}

/***********************
 * Laden und Speichern *
 ***********************/

void GetDefaultsFileName(PTSTR Name, UINT len) {
 PTSTR p;
 GetModuleFileName(0,Name,len);
 p=PathFindFileName(Name);
 len-=(UINT)(p-Name);
 lstrcpyn(p,T("Regal.ini"),len);
}

// alles mögliche per WritePrivateProfileString() schreiben
// Sonderfall Format == NULL: Value = String (svw. LPCTSTR)
// Sonderfall Format == Value == NULL: Eintrag löschen
// Achtung: Format == "%s": Value = Zeiger auf LPCTSTR!
BOOL vWriteProfile(LPCTSTR FileName, LPCTSTR Section, LPCTSTR Key, LPCTSTR Format, va_list Value) {
 TCHAR buf[MAX_PATH];
 if (Format) {
  wvnsprintf(buf,elemof(buf),Format,Value);
  Value=(va_list)buf;
 }
 return WritePrivateProfileString(Section,Key,(LPCTSTR)Value,FileName);
}

BOOL _cdecl WriteProfile(LPCTSTR FileName, LPCTSTR Section, LPCTSTR Key, LPCTSTR Format, ...) {
 return vWriteProfile(FileName,Section,Key,Format,(va_list)(&Format+1));
}

void SaveDefaults(void) {
 TCHAR FileName[MAX_PATH];
 WINDOWPLACEMENT wp;

 GetDefaultsFileName(FileName,elemof(FileName));
 InitStruct(&wp,sizeof(wp));
 GetWindowPlacement(ghMainWnd,&wp);
 vWriteProfile(FileName,T("MainWnd"),T("WinPos"),T("%i,%i"),(va_list)&wp.rcNormalPosition);
 WriteProfile(FileName,T("MainWnd"),T("LptBase"),T("0x%X"),gLptBase);
 if (false) MBox(ghMainWnd,MAKEINTRESOURCE(37)/*Fehler*/,MB_OK,FileName);
}

// Kommaseparierte Integer-Liste in Array wandeln
int ScanInts(LPCTSTR s, int ints[], int elems) {
 int i=0;
 if (elems) do{
  *ints++=StrToInt(s);
  i++;
  s=StrChr(s,',');
  if (!s) break;
  s++;	// hinter Komma
 }while (--elems);
 return i;	// Anzahl gewandelter Elemente
}

void LoadDefaults(void) {
 TCHAR FileName[MAX_PATH];
 TCHAR buf[MAX_PATH];
 int val;
 POINT p;

 GetDefaultsFileName(FileName,elemof(FileName));
// Fensterposition und -größe lesen
 if (GetPrivateProfileString(T("MainWnd"),T("WinPos"),
   T(""),buf,elemof(buf),FileName)
 && ScanInts(buf,(int*)&p.x,2)==2) {
  SetWindowPos(ghMainWnd,0,
    p.x,p.y,0,0,SWP_NOSIZE|SWP_NOZORDER);
// Fenster in Bildschirm ziehen...
  SendMessage(ghMainWnd,DM_REPOSITION,0,0);
 }
 if (GetPrivateProfileString(T("MainWnd"),T("LptBase"),
   T(""),buf,elemof(buf),FileName)
 && StrToIntEx(buf,STIF_SUPPORT_HEX,&val)
 && val>0x100
 && val<=0xFFFF) gLptBase=(WORD)val;
}

/***********************
 * 2 Dialog-Prozeduren *
 ***********************/
 
BOOL CALLBACK SetupDlgProc(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam) {
 switch (Msg) {
  case WM_INITDIALOG: {
   const static WORD DefLpt[3]={0x378,0x278,0x3BC};
   HWND hCombo=GetDlgItem(Wnd,101);
   TCHAR buf[16];
   int i;
   wsprintf(buf,T("%Xh"),gLptBase);
   SetWindowText(hCombo,buf);	// Eingabezeile belegen
   for (i=0; i<3; i++) {
    wsprintf(buf,T("%Xh (LPT%u)"),DefLpt[i],i+1);
    ComboBox_AddString(hCombo,buf);
    if (DefLpt[i]==gLptBase) ComboBox_SetCurSel(hCombo,i);
   }	// Auswahl einer Voreinstellung, überschreibt Eingabezeile
  }return TRUE;
  
  case WM_COMMAND: switch (LOWORD(wParam)) {
   case IDOK: {
    TCHAR buf[8];
    int value;
    buf[0]='0'; buf[1]='x';
    GetDlgItemText(Wnd,101,buf+2,elemof(buf)-2);
    if (!StrToIntEx(buf,STIF_SUPPORT_HEX,&value) || value<0x100) {
     Wnd=GetDlgItem(Wnd,101);
     SetFocus(Wnd);
     ComboBox_SetEditSel(Wnd,0,-1);	// bei Fehler
     break;
    }
    gLptBase=(WORD)value;
   }nobreak;
   case IDCANCEL: {
    EndDialog(Wnd,wParam);
   }break;
  }break;

  case WM_HELP: {
   LPHELPINFO hi=(LPHELPINFO)lParam;
   DWORD ids[4];
   ids[0]=hi->iCtrlId;
   ids[1]=MAKELONG(hi->iCtrlId,1101);	// High-Teil = Ressourcen-ID des Dialogs
   ids[2]=ids[3]=0;
   WinHelp((HWND)hi->hItemHandle,gHelpFileName,HELP_WM_HELP,(DWORD_PTR)ids);
  }break;
  
 }
 return FALSE;
}

struct TRegal{
 static const int X0=1300;
 static const int Y0=0;
 static const int DX=3500;	// Regalzellenabstand
 static const int DY=3518;
 static const int HY=200;	// Hubweg
 static const int ZE=3300;	// Ende Gabelweg
 int Ziel;
 int Hub;
 void MoveTo(int nr);
 void beladen(bool state);
 void PeriodicAction();
private:
 int x,y,z;
}Regal;

void TRegal::MoveTo(int nr) {
 if (Ziel==nr) return;
 Ziel=nr;
 if (Ziel<0) return;
 if (Ziel==0) {
  x=X0;
  y=Y0;
 }else{
  x=X0+((Ziel-1)%5+1)*DX;
  y=Y0+((20-Ziel)/5)*DY;
 }
 y+=Hub;
}

void TRegal::beladen(bool state) {
 int h=state?HY:0;
 if (Hub!=h) {
  Motor[1].Move(h-Hub+Motor[1].Soll);
  y+=h-Hub;
  Hub=h;
 }
}

void TRegal::PeriodicAction() {
 if (Ziel<0) return;
 if (Motor[0].InMove) return;
 if (Motor[1].InMove) return;
 if (Motor[2].InMove) return;
// Prüfen ob Zielgebiet erreicht
 if (Motor[0].Ist==x && Motor[1].Ist==y) {
  if (Motor[2].Soll!=ZE) {
   Motor[2].Move(ZE);
   SetDlgItemInt(ghMainWnd,31,ZE,TRUE);
  }
  return;
 }
// Zielgebiet nicht erreicht, Gabel ziehen?
 if (Motor[2].Soll!=0) {
  Motor[2].Move(0);
  SetDlgItemInt(ghMainWnd,31,0,TRUE);
  return;
 }
 Motor[0].Move(x);
 SetDlgItemInt(ghMainWnd,11,x,TRUE);
 Motor[1].Move(y);
 SetDlgItemInt(ghMainWnd,21,y,TRUE);
}

BOOL CALLBACK MainDlgProc(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam) {
 static bool updating,dragging;
 switch (Msg) {
  case WM_INITDIALOG: {
   int nr;
   ghMainWnd=Wnd;
   GetWindowText(Wnd,StdMBoxTitle,elemof(StdMBoxTitle));
   gToolTip=CreateWindowEx(WS_EX_TOPMOST,TOOLTIPS_CLASS,NULL,
     WS_POPUP|TTS_NOPREFIX|TTS_ALWAYSTIP|TTS_BALLOON,0,0,0,0,Wnd,0,ghInstance,NULL);
   MakeGdiObj();
   LoadDefaults();	// ruft InitLptState auf - nach dem Einlesen der Portadresse
   TMotor::Init();

   for (nr=0; nr<3; nr++) {
    HWND w;
    w=GetDlgItem(Wnd,nr*10+10);
    if (nr==1) {
     SendMessage(w,TBM_SETRANGEMIN,FALSE,-Motor[nr].Ende);
     SendMessage(w,TBM_SETRANGEMAX,FALSE,0);
    }else SendMessage(w,TBM_SETRANGEMAX,FALSE,Motor[nr].Ende);
    SendMessage(w,TBM_SETPOS,TRUE,Motor[nr].Ist);
    SendMessage(w,TBM_SETPAGESIZE,0,10);
   }
   Regal.MoveTo(-1);	// ungültig machen
   SetTimer(Wnd,1,100,NULL);
  }return TRUE;
  
  case WM_COMMAND: switch (LOWORD(wParam)) {
//Menü:
   case 1005: {	// Vorgabe speichern
    SaveDefaults();
   }break;
   
   case 1009: {	// Beenden
    SendMessage(Wnd,WM_CLOSE,0,0);
   }break;

   case 1101: {	// Einstellungen
    DialogBox(ghInstance,MAKEINTRESOURCE(1101),Wnd,SetupDlgProc);
   }break;
   
   case 1901: {	// Hilfe
    WinHelp(Wnd,gHelpFileName,HELP_CONTENTS,0);
   }break;
   
   case 1909: {	// Über
    MBox(Wnd,MAKEINTRESOURCE(26),MB_OK);
   }break;

//Dialogelemente:
   case 12: Regal.MoveTo(-1); Motor[0].Sync(-1); break;
   case 22: Regal.MoveTo(-1); Motor[1].Sync(-1); break;
   case 32: Regal.MoveTo(-1); Motor[2].Sync(-1); break;
   
   case 99:  Regal.beladen(IsDlgButtonChecked(Wnd,wParam)!=0); break;
   case 100:
   case 101:
   case 102:
   case 103:
   case 104:
   case 105:
   case 106:
   case 107:
   case 108:
   case 109:
   case 110:
   case 111:
   case 112:
   case 113:
   case 114:
   case 115:
   case 116:
   case 117:
   case 118:
   case 119:
   case 120: Regal.MoveTo(wParam-100); break;
  }break;
  
  case WM_HSCROLL:
  case WM_VSCROLL: if (!updating){
   int nr=GetDlgCtrlID((HWND)lParam)/10-1;
   int pos=SendMessage((HWND)lParam,TBM_GETPOS,0,0);
   if (nr==1) pos=-pos;
   switch (LOWORD(wParam)) {
    case TB_THUMBTRACK:
    case TB_TOP:
    case TB_BOTTOM:
    case TB_LINEUP:
    case TB_LINEDOWN:
    case TB_PAGEUP:
    case TB_PAGEDOWN: {
     SetDlgItemInt(Wnd,nr*10+11,pos,TRUE);	// Sollwert anzeigen
     dragging=true;
    }break;
    
    case TB_THUMBPOSITION:
    case TB_ENDTRACK: {
     Regal.MoveTo(-1);
     Motor[nr].Move(pos);
     if (nr==1) pos=-pos;
//     SendMessage((HWND)lParam,TBM_SETTIC,0,pos);	// Sollwert als Strich anzeigen
     dragging=false;
    }break;
   }
  }break;
  
  case WM_TIMER: switch (wParam) {
// Istpositions-Anzeige (10 Hz, periodisch)
   case 1: {
    updating=true;
    if (!dragging) {
     SendDlgItemMessage(Wnd,10,TBM_SETPOS,TRUE,Motor[0].Ist);
     SendDlgItemMessage(Wnd,20,TBM_SETPOS,TRUE,-Motor[1].Ist);
     SendDlgItemMessage(Wnd,30,TBM_SETPOS,TRUE,Motor[2].Ist);
     if (!Motor[0].InMove) SendDlgItemMessage(Wnd,10,TBM_CLEARTICS,TRUE,0);
     if (!Motor[1].InMove) SendDlgItemMessage(Wnd,20,TBM_CLEARTICS,TRUE,0);
     if (!Motor[2].InMove) SendDlgItemMessage(Wnd,30,TBM_CLEARTICS,TRUE,0);
    }
    SetDlgItemInt(Wnd,13,Motor[0].Ist,TRUE);
    SetDlgItemInt(Wnd,23,Motor[1].Ist,TRUE);
    SetDlgItemInt(Wnd,33,Motor[2].Ist,TRUE);
    CheckDlgButton(Wnd,14,statusport&1?1:0);
    CheckDlgButton(Wnd,24,statusport&2?1:0);
    CheckDlgButton(Wnd,34,statusport&4?1:0);
    updating=false;
    Regal.PeriodicAction();
   }break;
// Editfenster-Validierung und Übernahme in die Liste
   case 11:
   case 13: {
    int i;
    BOOL b;
    KillTimer(Wnd,wParam);	// nicht-zyklisch!
    i=GetDlgItemInt(Wnd,wParam,&b,TRUE);
   }break;
  }break;
  
  case WM_CTLCOLOREDIT: {
   int id=GetDlgCtrlID((HWND)lParam)-54;
   if ((unsigned)id>=sizeof(gEditErrors)*8) break;
   if (!(gEditErrors&(1<<id))) break;
   SetBkMode((HDC)wParam,TRANSPARENT);
   SetBkColor((HDC)wParam,RGB(255,128,128));
  }return (BOOL)gGdiObj.hbrError;
  
  case WM_HELP: {
   LPHELPINFO hi=(LPHELPINFO)lParam;
   DWORD ids[4];
   ids[0]=hi->iCtrlId;
   ids[1]=MAKELONG(hi->iCtrlId,100);	// High-Teil = Ressourcen-ID des Dialogs
   ids[2]=ids[3]=0;
   WinHelp((HWND)hi->hItemHandle,gHelpFileName,HELP_WM_HELP,(DWORD)ids);
	// HELP_WM_HELP positioniert besser als HELP_CONTEXTPOPUP
  }break;
  
  case WM_ENDSESSION: {
   TMotor::Done();
   SaveDefaults();
  }break;
  
  case WM_CLOSE: {
   SendMessage(Wnd,WM_ENDSESSION,1,0);
   WinHelp(Wnd,gHelpFileName,HELP_QUIT,0);
   EndDialog(Wnd,0);
  }break;
  
  case WM_DESTROY: {
   KillGdiObj();
  }break;
 }
 return FALSE;
}

/******************************
 * Hauptprogramm (lächerlich) *
 ******************************/
 
int _stdcall WinMainCRTStartup(void) {
 WNDCLASS wc={
  CS_HREDRAW|CS_VREDRAW,
  DefDlgProc,
  0,	// ClsExtra
  DLGWINDOWEXTRA,
  ghInstance=GetModuleHandle(NULL),	// hInstance
  LoadIcon(ghInstance,MAKEINTRESOURCE(100)),	// hIcon
  LoadCursor(0,IDC_ARROW),	// hCursor
  (HBRUSH)(COLOR_WINDOW+1),
  NULL,
  T("Regal")};	// Klassenname (in Übereinstimmung mit Dialog-Ressource 100)

 RegisterClass(&wc);
 InitCommonControls();
 ExitProcess(DialogBoxParam(0,MAKEINTRESOURCE(100),0,MainDlgProc,(LPARAM)GetCommandLine()));
}
Detected encoding: ASCII (7 bit)8