////////////////////////////////////////////////////////
//  pcidebug.dll
//                        Aug 20 1999 kashiwano masahiro
//
////////////////////////////////////////////////////////

#include "stdafx.h"
#include <stdio.h>
#include <windows.h>
#include <winioctl.h>
#include <stddef.h>
#include <assert.h>
#include <malloc.h>

#include "Pcidebug.h"
#include "driverload.h"

#define _DBG 0

int GetFileInternalName(const char *file,char *name);

//#include "resource.h"

void InitializeDll();
void DeinitializeDll();

int initialize(HMODULE ghInst);
int initialize_vxd(HMODULE ghInst);
void close(void);

extern void init_isr(void);

char DRIVERID[MAX_PATH];		//"CrystalSysInfo"
char DRIVERFILENAME[MAX_PATH];	//"SysInfo.sys" or SysInfoX64.sys
char DRIVERNAME[MAX_PATH];		//"CrystalSysInfo"

HINSTANCE g_hModule = NULL;
HANDLE handle = NULL;
int drivertype = 0;

// DLL
static DLLSTATUS status = DLLSTATUS_OTHERERROR;
//char DRIVERID[MAX_PATH];

//
// OS
//
// 
//1: windows 3.1
//2: windows 95
// 3: windows NT
// 4: windows NT x64
// -1: 
typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE hProcess,PBOOL Wow64Process);

BOOL IsWow64(VOID)
{
	BOOL bIsWow64 = FALSE;
	LPFN_ISWOW64PROCESS fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandleA("kernel32"),"IsWow64Process");
	if (NULL != fnIsWow64Process)
	{
		if (!fnIsWow64Process(GetCurrentProcess(),&bIsWow64))
		{
			// handle error
			bIsWow64 = FALSE;
		}
	}
	return bIsWow64;
}


//--------------------------

int oscheck()
{
	OSVERSIONINFO os;
	os.dwOSVersionInfoSize = sizeof(os);
	if(GetVersionEx(&os) == 0){
		assert(0);
		return 0;
	}
	switch(os.dwPlatformId){
	case VER_PLATFORM_WIN32s:
		return 1;
	case VER_PLATFORM_WIN32_WINDOWS:
		return 2;
	case VER_PLATFORM_WIN32_NT:
#ifdef _X86_64
		return 4;
#else
		return IsWow64() ? 4 : 3;	//Windowx XP 64Bit Edition or Windows NT
#endif
	default:
		return -1;
	}
}

void InitializeDll()
{
	char str[MAX_PATH];
	char name[64];
	int ostype, res;
	//int i;
	OSVERSIONINFO os;

	drivertype = 0;
	ostype = oscheck();
	if(!(ostype >= 2 && ostype <= 4)) return ;
	GetModuleFileNameA(NULL,str,MAX_PATH);
	GetFileInternalName(str,name);

	os.dwOSVersionInfoSize = sizeof(os);
	if(GetVersionEx(&os) == 0){
		assert(0);
		return ;
	}

	switch(ostype)
	{
	case 4:// NT x64
	case 3:// NT
		strcpy(DRIVERID,"CrystalSysInfo");
		if(ostype==4){
			strcpy(DRIVERFILENAME, "SysInfoX64.sys");
#if _DBG
			printf("InitializeDll : SysInfoX64.sys\n");
#endif
		}else{
			if(os.dwMajorVersion==4){
				strcpy(DRIVERFILENAME, "SysInfoNT4.sys");
#if _DBG
				printf("InitializeDll : SysInfoNT4.sys\n");
#endif
			}else{
				strcpy(DRIVERFILENAME, "SysInfo.sys");
#if _DBG
				printf("InitializeDll : SysInfo.sys\n");
#endif
			}
		}

		/* Initialize the DRIVERNME to "CrystalSysInfo" */
		strcpy(DRIVERNAME,"\\\\.\\CrystalSysInfo");
		drivertype |= SYS_DRIVER_USE;
		status = DLLSTATUS_NOERROR;

		break;
	
	default:// NT 95/98
		status = DLLSTATUS_NOTSUPPORTEDPLATFORM;
#if _DBG
		printf("InitializeDll : DLLSTATUS_NOTSUPPORTEDPLATFORM\n");
#endif
		break;
	}
	if(status == DLLSTATUS_NOTSUPPORTEDPLATFORM) return ;

	/* Initialize driver */
	res = initialize(g_hModule);
			
	switch ( res ){
	case 0:
		status = DLLSTATUS_NOERROR;
#if _DBG
		printf("InitializeDll : DLLSTATUS_NOERROR\n");
#endif
		break;
	case 2:
		handle = NULL;
		status = DLLSTATUS_DRIVERNOTLOADED;
#if _DBG
		printf("InitializeDll : DLLSTATUS_DRIVERNOTLOADED\n");
#endif
		break;
	default:
		handle = NULL;
		status = DLLSTATUS_OTHERERROR;
#if _DBG
		printf("InitializeDll : DLLSTATUS_OTHERERROR\n");
#endif
		break;
	}
}

void DeinitializeDll()
{
	close();
	status = DLLSTATUS_OTHERERROR;
}


///////////////////////////////////////////////////////////
//
// DLL LOAD 
// DLL UNLOAD 
//
///////////////////////////////////////////////////////////

BOOL APIENTRY DllMain(HMODULE hModule,
					  DWORD ul_reason_for_call, 
					  LPVOID lpReserved)
{
	switch( ul_reason_for_call ) {
	case DLL_PROCESS_ATTACH:
		g_hModule = hModule;
		break;
	case DLL_THREAD_ATTACH:
		break;
	case DLL_THREAD_DETACH:
		break;
	case DLL_PROCESS_DETACH:
		break;
	}
	return TRUE;
}

BOOL Opendriver(void)
{
	DWORD	dwStatus;

	handle = CreateFileA(
		DRIVERNAME,
        GENERIC_READ | GENERIC_WRITE,
        FILE_SHARE_READ | FILE_SHARE_WRITE,
        NULL,
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL,
        NULL
        );

	dwStatus = GetLastError();

    if (handle == INVALID_HANDLE_VALUE)
	{
		// 
        return FALSE;
    }
#if _DBG
	printf("Opendriver : handle = 0x%x\n", handle);
#endif
	return TRUE;
}


DWORD GetRefCount(HANDLE hHandle)
{
	DWORD dwRefCount;
	ULONG ReturnedLength, IoctlResult;


	dwRefCount = (DWORD)-1;

	if(hHandle)
	{
		IoctlResult = DeviceIoControl(
                            hHandle,
                            IOCTL_GET_REFCONT,
                            NULL,
                            0,
                            &dwRefCount,
                            sizeof(dwRefCount),
                            &ReturnedLength,
                            NULL
                            );
	}
	if(!IoctlResult) dwRefCount = (DWORD)-1;

	return dwRefCount;
}

void close()
{
	DWORD dwRefCount;
	
	dwRefCount = GetRefCount(handle);

	if(handle) CloseHandle(handle);
	if(drivertype & SYS_DRIVER_USE)
	{
		if(dwRefCount==1)
			UnloadDriver(DRIVERID);
	}
	handle = NULL;
}


/*
	NT Open

	 
	ghInst	 handle

	 
	0		  
	1		 
	2		  
	3		 
*/
int initialize(HMODULE ghInst)
{

	BOOL	ret;
	char tmp[MAX_PATH];
	char path[MAX_PATH];
	char *ptrEnd;

	//
	/*if(Opendriver()) {
		status = DLLSTATUS_NOERROR;
		printf("initialize : Opendriver --> DLLSTATUS_NOERROR\n");
		return 0;
	}
	else
	{
		printf("initialize : Opendriver --> fail\n");
	}*/

   /* Get current driver path */	
	GetModuleFileNameA(NULL,tmp, MAX_PATH); //GetCurrentDirectory(MAX_PATH, tmp);
	if ( (ptrEnd = strrchr(tmp, '\\')) != NULL ) {*ptrEnd = '\0';}
	sprintf(path,"%s\\%s",tmp,DRIVERFILENAME);

	/* Load driver */
	ret = LoadDriver(path, DRIVERID);
	if(ret == FALSE)
	{
		printf("LoadDriver 2 == false\n");
		
		GetWindowsDirectoryA(tmp, MAX_PATH);
		sprintf(tmp, "\\system32\\drivers\\", DRIVERFILENAME);
		ret = LoadDriver(tmp, DRIVERID);
		if(ret == FALSE)
		{
			return 2;
		}
		
		return 2;
	}
	else
	{
#if _DBG
		printf("LoadDriver 2 == success\n");
#endif
	}

	/* Open driver */  
	if(Opendriver()) {
		status = DLLSTATUS_NOERROR;
#if _DBG
		printf("initialize : Opendriver --> DLLSTATUS_NOERROR ");
#endif

		return 0; // Normal return
	}
	
	return 3; //Error return
}



/*
DLLSTATUS getdllstatus(void)

*/

DLLSTATUS WINAPI getdllstatus(void)
{
	return status;
}


int GetFileInternalName(const char *file,char *name)
{
	VS_FIXEDFILEINFO vffi;
	ULONG reserved = 0;	
	UINT size;
	char *buf = NULL, *vbuf;
	char str[256];
	int  Locale = 0;

	size = GetFileVersionInfoSizeA((char*)file,&reserved);
	str[0] = '\0';
	vbuf = (char*)malloc(size);

	if (GetFileVersionInfoA((char*)file, 0, size, vbuf))
	{
		VerQueryValueA(vbuf,("\\"),(void**)&buf,&size);
		CopyMemory( &vffi, buf, sizeof(VS_FIXEDFILEINFO));

		VerQueryValueA(vbuf, "\\VarFileInfo\\Translation", (void**)&buf, &size);
		CopyMemory(&Locale, buf, sizeof(int));
		wsprintfA(str,
					"\\StringFileInfo\\%04X%04X\\%s", 
					LOWORD(Locale), HIWORD(Locale),
					"InternalName"
				);
		VerQueryValueA(vbuf,str,(void**)&buf,&size);

		strcpy(str,buf);
		if(name != NULL){
			strcpy(name,buf);
		}
	}
	if(vbuf) free(vbuf);

	return 0;
}



