Source file: /~heha/hsn/dlo/DLO_Parallel.zip/src/DLO_Parallel.c

/* Discolitez plugin, for controlling eight channels via
 * an old-style parallel port (8 bit)
 *
 * This plugin takes the port address from library name!
 * The address must be (hexa)decimal encoded after a blank.
 */

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <windowsx.h>
#include <mmsystem.h>
#include <shlwapi.h>
typedef enum {false,true} bool;
#define nobreak

WORD CurAddr;
BYTE PortState;
HINSTANCE hInst;
UINT TimerId;
HINSTANCE hInpOutDll;
void (_stdcall*Out32)(WORD a, BYTE b);

static const WORD DefAddrs[]={0x378,0x278,0x3BC};

// Fills combo box with 3 typical parallel port addresses
static void FillComboAddrs(HWND Wnd) {
 int i;
 bool set=false;
 char buf[20];
 for (i=0; i<3; i++) {
  wnsprintf(buf,sizeof(buf),"%Xh (%u, LPT%u)",DefAddrs[i],DefAddrs[i],i+1);
  ComboBox_AddString(Wnd,buf);
  if (CurAddr==DefAddrs[i]) {
   ComboBox_SetCurSel(Wnd,i);
   set=true;
  }
 }
 if (!set) {
  wnsprintf(buf,sizeof(buf),"%03Xh",CurAddr);
  SetWindowText(Wnd,buf);
 }
}

// Retrieves the DLL file name into buffer and returns a pointer
// to the first ' ' or the ".dll" portion of the file name.
// Returns NULL when failing.
static PSTR GetNumberPointer(PSTR p, size_t cch) {
 PSTR q;
 if (!GetModuleFileName(hInst,p,cch)) return NULL;
 p=PathFindFileName(p);
 if (!p) return p;
 q=StrChr(p,' ');
 if (!q) q=PathFindExtension(p);
 return q;
}

static bool SaveAddr(HWND Wnd) {
 char buf[16], DllName[MAX_PATH], NewName[MAX_PATH], *p;
 int a;
 buf[0]='0';
 buf[1]='x';
 GetWindowText(Wnd,buf+2,sizeof(buf)-2);
 if (!StrToIntEx(buf,STIF_SUPPORT_HEX,&a)) return false;
 if (HIWORD(a)) return false;	// >FFFFh
 if (!HIBYTE(a)) return false;	// <100h
 if (CurAddr==(WORD)a) return true;	// no change
 CurAddr=(WORD)a;	// assign
 p=GetNumberPointer(NewName,sizeof(NewName));
 if (!p) return true;
 lstrcpy(DllName,NewName);
 wnsprintf(p,NewName+MAX_PATH-p," 0x%X.dll",a);
 MoveFileEx(DllName,NewName,MOVEFILE_REPLACE_EXISTING);
 return true;
}

BOOL CALLBACK ConfigDlgProc(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam) {
 switch (Msg) {
  case WM_INITDIALOG: {
   FillComboAddrs(GetDlgItem(Wnd,10));
  }return TRUE;

  case WM_COMMAND: switch (LOWORD(wParam)) {
   case 1: {
    HWND w=GetDlgItem(Wnd,10);
    if (!SaveAddr(w)) {
     char s[256];
     LoadString(hInst,1,s,sizeof(s));
     MessageBox(Wnd,s,NULL,MB_OK);
     SetFocus(w);
     break;
    }
   }nobreak;
   case 2: EndDialog(Wnd,wParam); break;
  }break;
 }
 return FALSE;
}

// Let a timer procedure actualize the output,
// reduce load due to too many kernel<->user mode transitions
static void CALLBACK TimerProc(UINT TimerId, UINT uMsg, DWORD dwUser,
  DWORD dw1, DWORD dw2) {
 static BYTE NewState;
 if (NewState!=PortState) Out32(CurAddr,NewState=PortState);
}

/**********************
 * exported functions *
 **********************/
BYTE _declspec(dllexport) _cdecl DLO_getnch(void) {
 return 8;
}

// Brain-dead construcion of DiscoLitez requires bad programming style here
LPSTR _declspec(dllexport) _cdecl DLO_getname(void) {
 static char buf[32];
 wnsprintf(buf,sizeof(buf),"Parallel port at %Xh",CurAddr);
 return buf;
}

void _declspec(dllexport) _cdecl DLO_datain(BYTE ch, BYTE val) {
 BYTE mask = 1<<(ch-1);
 if (val) {
  if (PortState&mask) return;
 }else{
  if (~PortState&mask) return;
 }
 PortState ^= mask;	// The timer procedure will output this value
}

void _declspec(dllexport) _cdecl DLO_init(void) {
// cannot link statically to inpout32.dll because this DLL should not be in PATH
// and therefore cannot be found if not in current directory of calling process
 char LibPath[MAX_PATH],*p;
 if (!GetModuleFileName(hInst,LibPath,sizeof(LibPath))) return;
 p=PathFindFileName(LibPath);
 if (!p) return;
 lstrcpyn(p,"inpout32.dll",LibPath+sizeof(LibPath)-p);
 hInpOutDll=LoadLibraryEx(LibPath,0,LOAD_WITH_ALTERED_SEARCH_PATH);
 if (!hInpOutDll) return;
 (FARPROC)Out32=GetProcAddress(hInpOutDll,MAKEINTRESOURCE(2));
 if (!Out32) return;
 timeBeginPeriod(10);
 TimerId=timeSetEvent(10,10,TimerProc,0,TIME_PERIODIC);
}

void _declspec(dllexport) _cdecl DLO_done(void) {
 timeKillEvent(TimerId);
 timeEndPeriod(10);
 FreeLibrary(hInpOutDll);
}

void _declspec(dllexport) _cdecl DLO_about(void) {
 DialogBox(hInst,MAKEINTRESOURCE(100),0,ConfigDlgProc);
}

/********************
 * main entry point *
 ********************/
BOOL CALLBACK _DllMainCRTStartup(HINSTANCE hInstDll,DWORD fdwReason,LPVOID lpReserved) {
 if (fdwReason==DLL_PROCESS_ATTACH) {
  char DllName[MAX_PATH], *p;
  int a;
  hInst = hInstDll;	// Where the (dialog) resource comes from - and the file name
  DisableThreadLibraryCalls(hInstDll);
  p=GetNumberPointer(DllName,sizeof(DllName));
  CurAddr = p
	 && StrToIntEx(p+1,STIF_SUPPORT_HEX,&a)
	 && !HIWORD(a)
	 && HIBYTE(a) ? (WORD)a : 0x378;
 }
 return TRUE;
}
Detected encoding: ASCII (7 bit)2