/*
 *	contact_ctpci
 *
 *	Copyright (c) c't 2010 Andreas Stiller 
 *
 *	Can be freely distributed and used under the terms of the GNU GPL.
 *
 * Installs or contacts ctpci64.sys or ctpci32.sys, depending on OS
 * drvexec ()   : opcode and three parameters with type long 
 * drvexec64 () : opcode and three parameters with type long long 
 *               (not used for ctpci.sys)
*/


#include "contact_ctpci.h" 

HANDLE		hDriver;
#define use_ctpci
#ifdef use_ctpci 
#define DRVFILENAME32 "ctpci32.sys" 
#define DRVFILENAME64 "ctpci64.sys"
#define DRVNAME "ctpci" 
#define DEVNAME "\\\\.\\Dev_ctpci" 
#else 
#define DRVFILENAME32 "directNT1.20.sys" 
#define DRVFILENAME64 "directNT64.sys"
#define DRVNAME "directNT" 
#define DEVNAME "\\\\.\\Dev_directNT" 
#endif 



// Wow64DisableWow64FsRedirection() and Wow64EnableWow64FsRedirection() a

typedef struct { 
	 DWORD magic; 
	 DWORD versionhigh;
	 DWORD versionlow;
} DRVINFO;   


DWORD DRVerror;
DRVINFO DRVinfo;
BOOL DRV_already_installed;

typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
LPFN_ISWOW64PROCESS fnIsWow64Process;

BOOL IsWow64()
{
    BOOL bIsWow64 = FALSE;

    fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(
        GetModuleHandle(TEXT("kernel32")),"IsWow64Process");
  
    if (NULL != fnIsWow64Process)
    {
        if (!fnIsWow64Process(GetCurrentProcess(),&bIsWow64))
        {
            // handle error
        }
    }
    return bIsWow64;
}


DWORD drvexec(DWORD op,DWORD par1,DWORD par2,DWORD par3, 
			  void* outbuf, int outsize, int* BytesRet){   
 DWORD inbuf[4];
 SetLastError(0);
 inbuf[0]=op; inbuf[1]=par1; inbuf[2]=par2; inbuf[3]=par3;
 if (!DeviceIoControl( hDriver, IOCTL_DIRECTNT_CONTROL, &inbuf, 
	 sizeof (inbuf), outbuf, sizeof (outbuf),BytesRet, NULL)) {
 DRVerror=GetLastError();
 return DRVerror; 
 }
DRVerror=0;
return DRVerror;
}

DWORD drvexec64(ULONGLONG op,ULONGLONG par1,ULONGLONG par2,ULONGLONG par3,void* outbuf, int outsize, int* BytesReturned)
{   
    ULONGLONG inbuf[4];
	SetLastError(0);
	inbuf[0]=op; inbuf[1]=par1; inbuf[2]=par2; inbuf[3]=par3;
	if (!DeviceIoControl( hDriver, IOCTL_DIRECTNT_CONTROL64, &inbuf, sizeof (inbuf), outbuf, sizeof (outbuf), BytesReturned, NULL)) {
		DRVerror=GetLastError();
#ifdef _DEBUG 
  printf (" Error 0x%x with DeviceIOControl \n", DRVerror);
#endif
            return DRVerror; 
		}
 
 DRVerror=0;
 return DRVerror;
 }


BOOL init_directnt() 
{    
	BOOL ok; 
	LPSTR pbuf = NULL;
    int BytesReturned; 
	hDriver=CreateFile (
		DEVNAME,
		GENERIC_READ, // | GENERIC_WRITE,
		0, // 0 für Exclusive  File
		NULL,
		OPEN_EXISTING,
		FILE_FLAG_DELETE_ON_CLOSE,
		0);
	DRV_already_installed=(hDriver != INVALID_HANDLE_VALUE );
#ifdef _DEBUG
	if (DRV_already_installed) printf ("Driver was already installed\n"); 
	else  printf ("try to install Driver\n");
#endif
	if (!DRV_already_installed) {   
#ifdef _AMD64_
		ok=InstallandStartDriver (ExePath,DRVFILENAME64,DRVNAME);
		printf ("Windows 64 Bit Application With 64 Bit Driver\n"); 
#else 

		if (IsWow64()) {  
			ok=InstallandStartDriver (ExePath,DRVFILENAME64,DRVNAME);
			printf ("Windows 32 Bit Application under Wow64 with 64 Bit Driver\n");
		}
		else 
		{
			ok=InstallandStartDriver (ExePath,DRVFILENAME32,DRVNAME);
			printf ("Windows 32 Bit Application with 32 Bit Driver\n");
		}

#endif 

		if (!ok) {
			DWORD err=GetLastError();
			printf ("Error installing Driver : %d 0x%x \n",err,err);
			FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_ALLOCATE_BUFFER,
				NULL,
				err,
				MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
				(LPSTR) &pbuf,0,NULL
				);
			CharToOemA(pbuf,pbuf);
			printf("- %s\n",pbuf);
			return 0;
		} 
		
		hDriver=CreateFile (
			DEVNAME,
			GENERIC_READ, // | GENERIC_WRITE,
			0, // 0 für Exclusive  File
			NULL,
			OPEN_EXISTING,
			FILE_FLAG_DELETE_ON_CLOSE,
			0);
		if (hDriver != INVALID_HANDLE_VALUE ) {
#ifdef _DEBUG 
		printf ("yupp, contact to Driver\n");
#endif
		}
		else {printf ("no contact to driver\n");UninstallDriver(DRVNAME);return 0;
		}       
	} 		
     if (drvexec (OP_Check,0,0,0,&DRVinfo,12,&BytesReturned)!=0) return 0; // Fehler 
	 if (DRVinfo.magic!=0x12345678){ printf ("Error in Driverfunction DeviceIO\n"); return 0; }
#ifdef _DEBUG 
 printf ("Version %d.%d ok\n",DRVinfo.versionhigh,DRVinfo.versionlow);
#endif 
	return 1;
}

BOOL cleanup_directnt() {
#ifdef NDEBUG 
   if (DRV_already_installed) return 0; // was installed before? don't uninstall!
#endif 
    if (!UninstallDriver(DRVNAME)){ 
#ifdef _DEBUG 
		printf (" Can't UnInstall Driver \n");
#endif 
		return 0; 
	}
	else { 
#ifdef _DEBUG
		printf ("Driver uninstalled\n");
#endif
	return 1;
	}
}
