/****************************************************************************
**                                                                          **
**  Template file for implementing Multidec API helpers                     **
**  Supports: MD 8.0, 8.1 and 8.2 (API 1.02)                                **
**  Base class implementation                                               **
**  Visual C++ 6                                                            **
**                                                                          **
**  (C) Vlinders, June 2002, V 1.00                                         **
**                                                                          **
 ****************************************************************************/

#include "stdafx.h"
#include "sc.h"
#include "API_Impl.h"
#include "imagehlp.h"
#pragma comment(lib,"imagehlp.lib")
unsigned char XorCWEven[8]	={0,0,0,0, 0,0,0,0};
unsigned char XorCWOdd[8]	={0,0,0,0, 0,0,0,0};
unsigned char XorCWEven_1[8]={0x55,0x55,0xAA,0xAA,0x99,0x99,0xBB,0xBB};
unsigned char XorCWOdd_1[8]	={0x55,0x55,0xAA,0xAA,0x99,0x99,0xBB,0xBB};

unsigned short DVBSetDescrCmd=0x0110;	// or 010A for Linux_9_4_01_04

HMODULE				hTT=NULL;					// Handle on TTDVBACC.dll module

char				CallerName[_MAX_PATH];
char				curPath[_MAX_PATH];
char				dlldirPath[_MAX_PATH];

HHOOK hhook;

BOOL CALLBACK EnumChildWndProc(HWND hwnd, LPARAM lparam)
{
	char classname[256]="";
	GetClassName(hwnd,classname,sizeof(classname));
	if(strstr(classname,"Afx:400000:b"))
	{
		g_API_Impl->m_subclass_hwnd=hwnd;
		return FALSE;
	}
	return TRUE;
}

CAPI_Impl::CAPI_Impl()
{
	m_hDLL=NULL;
	m_MultiDecInstance=NULL;
	m_MultiDecWindow=NULL;
	m_MultiDecLog=FALSE;
	m_MultiDec_DLL_ID=-1;
	m_MDAPIFlag=0;
	m_MDAPIVer=0x0000;
	m_WTVPAPIFlag=0;
	m_WTVPAPIVer=0;
	m_PROGAPIFlag=0;
	m_PROGAPIVer=0;
	m_DVBxAPIFlag=0;
	m_DVBxAPIVer=0;
	m_UseTT=false;
	m_OSD_KEY_EVENT=NULL;
	m_osdshown=false;
	strcpy(m_TTVersionAsString,"");
	m_TTVersionNumber=TT_UNKNOWN;
	m_original_wndproc=NULL;
	m_subclass_hwnd=NULL;
	m_progdvb_osd_window_nr=2;
	m_use_alternate_osd=false;
}

CAPI_Impl::~CAPI_Impl()
{
}
void CAPI_Impl::CopyFrom80(MyProgram_t *dest, TProgramm80*from)
{
	memcpy(dest,from,(DWORD)&(from->Filters)-(DWORD)from); // Common part
	if(dest->Filteranzahl>12) dest->Filteranzahl=12; // For safety
	memset(dest->Filters,0,sizeof(TPIDFilters)*MAX_PID_IDS);
	for(int x=0;x<dest->Filteranzahl;x++)
	{
		memcpy(&(dest->Filters[x]),&(from->Filters[x]),sizeof(TPIDFilters));
	}
	if(dest->CA_Anzahl>6) dest->CA_Anzahl=6; // for Safety
	memset(dest->CA_System,0,sizeof(TCA_System82)*MAX_CA_SYSTEMS);
	for(int x=0;x<dest->CA_Anzahl && x<6.;x++)
	{
		dest->CA_System[x].CA_Typ=from->CA_System[x].CA_Typ;
		dest->CA_System[x].ECM=from->CA_System[x].ECM;
		dest->CA_System[x].EMM=from->CA_System[x].EMM;
		dest->CA_System[x].Provider_Id=0xFFFFFFFF; // Not available
	}
	memcpy(dest->CA_Land,from->CA_Land,sizeof(from->CA_Land));
	dest->Merker=from->Merker;
	dest->Link_TP=from->Link_TP;
    dest->Link_SID=from->Link_SID;
    dest->Dynamisch=from->Dynamisch;
	memcpy(dest->Extern_Buffer,from->Extern_Buffer,sizeof(from->Extern_Buffer));
}


// Should be overridden in derived class
void CAPI_Impl::to_log(char *x)
{
}
#include "sc.h"
// Called on loading of the DLL
BOOL CAPI_Impl::DllMain(HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved)
{
	char *p=NULL;
	switch (dwReason)
	{
    case DLL_PROCESS_ATTACH:
        m_hDLL=hDLL;
        GetModuleFileName (NULL, (LPTSTR) CallerName, 256);
		GetCurrentDirectory(sizeof(curPath),curPath);
		GetModuleFileName(hDLL,dlldirPath,sizeof(dlldirPath));
		p=strrchr(dlldirPath,'\\');
		if(p) *p='\0'; 
		break;
	case DLL_PROCESS_DETACH:
		break;
	}
	return TRUE;
}
// Called when the program initialize the plugin
// Detection of the MD API used, and if WTVP is present
// customization can be done by overriding and calling this base function
void CAPI_Impl::On_Start(HINSTANCE MDInstance, HWND MDWnd, BOOL Log_Set, int DLL_ID, char *My_Hot_Key,char *Api_Version, int *Keep_me_running )
{
	char buff[1024]="";
	m_MultiDecInstance=MDInstance;
	m_MultiDecWindow=MDWnd;
    m_MultiDecLog = Log_Set;
    m_MultiDec_DLL_ID=DLL_ID;


	*My_Hot_Key='G';   // oder 0x00 für Kein HotKey
	// Determine MD API version
	m_MDAPIFlag=0;
	m_MDAPIVer=0x0000;
	char VersionString[64]; 
	memset(VersionString,0,sizeof(VersionString));
	if(TRUE==SendMessage(m_MultiDecWindow,WM_USER,MDAPI_GET_VERSION,(LONG)VersionString) || !IsBadStringPtr(Api_Version,8) )
	{
		// MD-API Version MM.mm Root dddddd	(MD)
		// MD-API Version MM.mm - MM.mm		(PROGDVB)
		__try
		{
			int VerMaj, VerMin, RootSize;
			if(!_strnicmp(Api_Version,"MD-API",5))
			{
				char *pver=strstr(Api_Version,"Version ");
				if(pver)
				{
					pver+=8;
					int spos=-1;
					if(2==sscanf(pver,"%02X.%02X%n",&VerMaj, &VerMin,&spos))
					{
						m_MDAPIVer=VerMaj*256+VerMin;
						if(VerMaj!=0)
						{
							m_MDAPIFlag=1; // New interface
							if(Keep_me_running)
								*Keep_me_running=0; // Keep running
						}
					}
					if(2==sscanf(pver+spos," - %02d.%02d",&VerMaj,&VerMin)) // PROGDVB API
					{
						m_PROGAPIVer=VerMaj*256+VerMin;
						if(VerMaj!=0)
							m_PROGAPIFlag=1;
					}
				}
				char *proot=strstr(Api_Version,"Root ");
				if(proot)
				{
					proot+=5;
					if(1==sscanf(proot,"%d",&RootSize))
					{
						m_RootSize=RootSize;
						switch(RootSize)
						{
						case 254036: // Normal Linux_9_3
							break;
						case 254324:
							if( *(__int64*)&XorCWEven==0)
								memcpy(XorCWEven,XorCWEven_1,8);
							if( *(__int64*)&XorCWOdd==0)
								memcpy(XorCWOdd,XorCWOdd_1,8);
							break;
						case 254176:
							if( *(__int64*)&XorCWEven==0)
								memcpy(XorCWEven,XorCWEven_1,8);
							if( *(__int64*)&XorCWOdd==0)
								memcpy(XorCWOdd,XorCWOdd_1,8);
							DVBSetDescrCmd=0x010A;
							break;
						default:
							sprintf(buff,"Unsupported Root size: %d",RootSize);
							to_log(buff);
							break;
						}
					}
				}
			}
			if(!_strnicmp(VersionString,"WTVP-API",8))
			{
				char *pver=strstr(VersionString,"Version ");
				if(pver)
				{
					pver+=8;
					VerMaj=0; VerMin=0;
					if(2==sscanf(pver,"%d.%d",&VerMaj, &VerMin))
					{
						m_WTVPAPIVer=VerMaj*256+VerMin;
						if(VerMaj!=0)
						{
							m_WTVPAPIFlag=1; 
							if(hTT) m_UseTT=true;
							if(Keep_me_running)
								*Keep_me_running=0; // Keep running
						}
					}
					sprintf(buff,"%d %d",VerMaj,VerMin);
				}
			}
			else if(!_strnicmp(VersionString,"WTVP ",5)) // 1.4x+
			{
				char *pver=strstr(VersionString,"API-Version ");
				if(pver)
				{
					pver+=12;
					VerMaj=0; VerMin=0;
					if(2==sscanf(pver,"%d.%d",&VerMaj, &VerMin))
					{
						m_WTVPAPIVer=VerMaj*256+VerMin;
						if(VerMaj!=0)
						{
							m_WTVPAPIFlag=1; 
							if(hTT) m_UseTT=true;
							if(Keep_me_running)
								*Keep_me_running=0; // Keep running
						}
					}
					sprintf(buff,"WTVP-API:%d %d",VerMaj,VerMin);
				}
			}
			else if(!_strnicmp(VersionString,"DVBx-API",8))
			{
				m_MDAPIFlag=1;
				m_MDAPIVer=0x102; // Pretend it's MDAPI 1.02
				char *pver=strstr(VersionString,"Version ");
				if(pver)
				{
					pver+=8;
					VerMaj=0; VerMin=0;
					if(2==sscanf(pver,"%d.%d",&VerMaj, &VerMin))
					{
						m_DVBxAPIVer=VerMaj*256+VerMin;
						if(VerMaj!=0)
						{
							if(hTT) 
							{
								m_DVBxAPIFlag=1; 
								m_UseTT=true;
							}
							if(Keep_me_running)
								*Keep_me_running=0; // Keep running
						}
					}
					sprintf(buff,"DVBx-API:%d %d",VerMaj,VerMin);
					to_log(buff);
				}
			}

		}
		__except(1)
		{
			m_MDAPIFlag=0; // hope this assertion is good
		}
	}
	else 
		m_MDAPIFlag=0;

    if(m_MDAPIFlag)
		sprintf(buff,"MDAPI (>=8.2) %02hX.%02hX\nApi:%s Version:%s ",(m_MDAPIVer>>8)&0xFF,m_MDAPIVer&0xFF,Api_Version,VersionString);
	else
	sprintf(buff,"MDAPI (<=8.1)");
	to_log(buff);

	if(m_WTVPAPIFlag)
	{
		sprintf(buff,"WTVPAPI: %02hX.%02hX  ",(m_WTVPAPIVer>>8)&0xFF,m_WTVPAPIVer&0xFF);
		to_log(buff);
		m_UseTT=true; // For sending DVB commands
	}
	if(m_PROGAPIFlag)
	{
		sprintf(buff,"PROGAPI: %02hX.%02hX  ",(m_PROGAPIVer>>8)&0xFF,m_PROGAPIVer&0xFF);
		to_log(buff);
	}
	if(m_DVBxAPIFlag)
	{
		sprintf(buff,"DVBxAPI: %02hX.%02hX  ",(m_DVBxAPIVer>>8)&0xFF,m_DVBxAPIVer&0xFF);
		to_log(buff);
	}
	if(WTVPAPIFlag())
	{
		EnumChildWindows(m_MultiDecWindow,EnumChildWndProc,(LPARAM)this);
	}
	if(PROGAPIFlag())
		m_use_alternate_osd=true;
}
// Called by the program just before closing
void CAPI_Impl::On_Exit(HINSTANCE MDInstance, HWND MDWnd, BOOL Log_Set)
{
	APIUnSubclassWindow();
	if(m_OSD_KEY_EVENT) CloseHandle(m_OSD_KEY_EVENT);
	m_OSD_KEY_EVENT=NULL;
}

// Should be overridden
void CAPI_Impl::On_Send_Dll_ID_Name(char *Name)
{
}

// Should be overridden
void CAPI_Impl::On_Menu_Select(unsigned int MenuID )
{
}

// Should be overridden
void CAPI_Impl::On_Channel_Change( const struct TProgramm82 &CurrentProgramm )
{
	char buff[2048]="";
	char it[256]="";
	int i=0;
	if(MDAPIFlag()==0 || PROGAPIFlag()==1) // Convert back to old type
	{
		CopyFrom80(&CurProg,(TProgramm80*)&CurrentProgramm);
	}
	else
	{
		memcpy(&CurProg,&CurrentProgramm,sizeof(TProgramm82));
	}
}

// Should be overridden
void CAPI_Impl::On_Hot_Key( void )
{
}

// Should be overridden
void CAPI_Impl::On_Rec_Play(RECPLAY_t Mode)
{
	switch(Mode)
	{
	case RECPLAY_PLAY:
		break;
	case RECPLAY_RECORD:
		break;
	case RECPLAY_STOP:
		break;
	}
}

// Could be overridden
void CAPI_Impl::On_Osd_Key( unsigned char Key )
{
    m_OSD_Key_Value=Key;
	if (m_OSD_KEY_EVENT != NULL ) SetEvent(m_OSD_KEY_EVENT);
}

// Should be overridden
void CAPI_Impl::On_Filter_Close(unsigned int FilterOffset )
{
}


int CAPI_Impl::On_Key_Down(UINT nChar, UINT nRepCnt, UINT nFlags)
{
	unsigned char Key=nChar;
	if(nChar>=VK_NUMPAD0&&nChar<=VK_NUMPAD9)
		Key=nChar-VK_NUMPAD0+'0';
	else switch(nChar)
	{
		case VK_MULTIPLY: Key='*'; break;
		case VK_DIVIDE: Key='/'; break;
		case VK_ADD: Key='+'; break;
		case VK_SUBTRACT: Key='-'; break;
		case VK_DECIMAL: Key='.'; break;
	}
	On_Osd_Key(Key);
	char msg[256]="";
	sprintf(msg,"KeyDown:%02X",Key);
	to_log(msg);
	if(m_osdshown) return 3; else return 0;
}
// Helpers Plugin calling MD

int CAPI_Impl::Get_MDAPI_Version(char *version)
{
	return 0!=SendMessage(m_MultiDecWindow,WM_USER,MDAPI_GET_VERSION,(LONG)version);
}
int CAPI_Impl::Set_Current_Transponder(struct TTransponder *Transponder)
{
	int ret=0;
	ret=SendMessage(m_MultiDecWindow,WM_USER,MDAPI_SET_TRANSPONDER,(LONG)Transponder );
	return ret;
}
int CAPI_Impl::Get_Current_Transponder(struct TTransponder *Transponder)
{
	int ret=0;
	ret=SendMessage(m_MultiDecWindow,WM_USER,MDAPI_GET_TRANSPONDER,(LONG)Transponder );
	return ret;
}

int CAPI_Impl::Get_Current_Programm( struct TProgrammNummer *TPNr )
{
	int ret=0;
	ret=SendMessage(m_MultiDecWindow,WM_USER,MDAPI_GET_PROGRAMM_NUMMER,(LONG)TPNr);
	return ret;
}

int CAPI_Impl::Set_Current_Programm( int Nummer )
{
	int ret=0;
	if(WTVPAPIFlag())
		ret=SendMessage(m_MultiDecWindow,WM_USER,MDAPI_GET_PROGRAMM_NUMMER,(LONG)&Nummer);
	else
		ret=SendMessage(m_MultiDecWindow,WM_USER,MDAPI_SET_PROGRAMM_NUMMER,Nummer);
	return ret;
}
// For MDAPI before MD8.2
int CAPI_Impl::Get_Programm_Detail80( struct TProgramm80 *TPtg)
{
	int ret=0;
    ret=SendMessage(m_MultiDecWindow,WM_USER,MDAPI_GET_PROGRAMM,(LONG)TPtg);
	return ret;
}

int CAPI_Impl::Set_Programm_Detail80( struct TProgramm80 *TPtg)
{
	int ret=0;
    ret=SendMessage(m_MultiDecWindow,WM_USER,MDAPI_SET_PROGRAMM,(LONG)TPtg );
	return ret;
}
// MDAPI 1.02+
int CAPI_Impl::Get_Programm_Detail( struct TProgramm82 *TPtg)
{
	int ret=0;
    ret=SendMessage(m_MultiDecWindow,WM_USER,MDAPI_GET_PROGRAMM,(LONG)TPtg);
	return ret;
}

int CAPI_Impl::Set_Programm_Detail( struct TProgramm82 *TPtg)
{
	int ret=0;
    ret=SendMessage(m_MultiDecWindow,WM_USER,MDAPI_SET_PROGRAMM,(LONG)TPtg );
	return ret;
}

int CAPI_Impl::Save_Programm_Liste( void )
{
	int ret=0;
    ret=SendMessage(m_MultiDecWindow,WM_USER,MDAPI_SAVE_PROGRAMM,0 );
	return ret;
}

int CAPI_Impl::Rescan_Programm( struct TProgramm82 *TPtg)
{
	int ret=0;
    SendMessage(m_MultiDecWindow,WM_USER,MDAPI_GET_PROGRAMM,(LONG)TPtg);
    ret=SendMessage(m_MultiDecWindow,WM_USER,MDAPI_RESCAN_PROGRAMM,(LONG)TPtg );
	return ret;
}

void f_Filter_Data_Arrival(int MyFilter, int DataLen, unsigned char *_Data)
{
	g_API_Impl->On_Filter_Data_Arrival(MyFilter, DataLen, _Data);
}
void CAPI_Impl::On_Filter_Data_Arrival(int MyFilter, int DataLen, unsigned char *_Data)
{
}
int CAPI_Impl::Start_Filter(struct TSTART_FILTER *sf)
{
	int ret=0;
	if(sf->Irq_Call_Adresse==0)
	{
		sf->Irq_Call_Adresse=(DWORD)f_Filter_Data_Arrival;
	}
	ret=SendMessage(m_MultiDecWindow,WM_USER,MDAPI_START_FILTER,(LONG)sf);
	if(WTVPAPIFlag())
		return sf->Running_ID>=0;
	else return ret;
}

int CAPI_Impl::Stop_Filter(int filterid)
{
	int ret=0;
	ret=SendMessage(m_MultiDecWindow,WM_USER,MDAPI_STOP_FILTER,(LONG)filterid);
	return ret;
}
int CAPI_Impl::Scan_Current_CAT(struct TTPCatio82  *CurrentCat)
{
	int ret=0;
	CurrentCat->TPCatAnzahl=0;
    ret=SendMessage(m_MultiDecWindow,WM_USER,MDAPI_SCAN_CURRENT_CAT,(LONG)CurrentCat);
    if (( CurrentCat->TPCatAnzahl < 0 ) || ( CurrentCat->TPCatAnzahl > 31 )) CurrentCat->TPCatAnzahl=0;
	return ret;
}


int CAPI_Impl::Scan_Current_TP80(TProgramm80 *newprograms)
{
	int ret=0;
	ret=SendMessage(m_MultiDecWindow,WM_USER,MDAPI_SCAN_CURRENT_TP,(LONG)newprograms);
	return ret;
}
int CAPI_Impl::Scan_Current_TP(TProgramm82 *newprograms)
{
	int ret=0;
	ret=SendMessage(m_MultiDecWindow,WM_USER,MDAPI_SCAN_CURRENT_TP,(LONG)newprograms);
	return ret;
}
/**************** Useful Helpers  ****************/

typedef struct
{
	void *thisptr;
	CAPI_Impl::THREADSTARTProc f;
} ThreadLauncherArgs_t;
ThreadLauncherArgs_t ThreadLauncherArgs;


DWORD WINAPI ThreadLauncher(LPVOID arg)
{
	ThreadLauncherArgs_t *tt=(ThreadLauncherArgs_t*)arg;
	CAPI_Impl*	nthis=(CAPI_Impl*)tt->thisptr;
	CAPI_Impl::THREADSTARTProc f=tt->f;
	nthis->m_osdshown=true;
	nthis->to_log("OSD launching...");
//	nthis->APISubclassWindow();
	(nthis->*f)();
//	nthis->APIUnSubclassWindow();
	nthis->m_osdshown=false;
	nthis->to_log("OSD finished");
	return 0;
}
void CAPI_Impl::Create_Osd_Thread(LPVOID obj,THREADSTARTProc f)
{
	if(m_osdshown==true) return;

	DWORD LinkThreadID;
	if ( m_OSD_KEY_EVENT == NULL ) m_OSD_KEY_EVENT=CreateEvent(NULL,FALSE,FALSE,NULL);
    m_OSD_Key_Value=' ';
	ResetEvent(m_OSD_KEY_EVENT);
   
	ThreadLauncherArgs.thisptr=obj;
	ThreadLauncherArgs.f=f;
	CloseHandle(CreateThread ((LPSECURITY_ATTRIBUTES)NULL,       // No security.
                         			  (DWORD)0,                          // Same stack size.
                         			  ThreadLauncher,// Thread procedure.
                         			  (LPVOID)&ThreadLauncherArgs,                         // Parameter.
                         			  (DWORD)0,                          // Start immediatly.
                         			  (LPDWORD)&LinkThreadID));  
}

int CAPI_Impl::OSD_CreateWindow(unsigned char Bits, unsigned short x1,unsigned short y1,unsigned short x2,unsigned short y2,BOOL Has_KeyBoard_Input)
{
	int ret=0;
	struct TOSD_START Osd_Start;


	// Bits 0 = 2 Farbige Fenstern ( können größ sein )
	// Bits 1 = 4 Farbige Fenster ( sollten klein sein ( Speicher auf DVB´s Karte zu klein )

	OSD_Close();	
	if(m_use_alternate_osd)
	{
		TDVB_COMMAND dvb;
		int wnr=m_progdvb_osd_window_nr;
		dvb.Cmd_Buffer[0]=0x0300; // WCreate
		dvb.Cmd_Buffer[1]=0x04;
		dvb.Cmd_Buffer[2]=wnr; // Window nr
		dvb.Cmd_Buffer[3]=Bits;
		dvb.Cmd_Buffer[4]=x2-x1;
		dvb.Cmd_Buffer[5]=y2-y1;
		dvb.Cmd_laenge=6;
		SendMDCommand(dvb);

		dvb.Cmd_Buffer[0]=0x0303; // MoveA
		dvb.Cmd_Buffer[1]=0x03;
		dvb.Cmd_Buffer[2]=wnr; // Window nr
		dvb.Cmd_Buffer[3]=x1;
		dvb.Cmd_Buffer[4]=y1;
		dvb.Cmd_laenge=5;
		SendMDCommand(dvb);
/*
		dvb.Cmd_Buffer[0]=0x0306; // DrawBlock
		dvb.Cmd_Buffer[1]=0x06;
		dvb.Cmd_Buffer[2]=wnr;  // Window nr
		dvb.Cmd_Buffer[3]=10;  // x
		dvb.Cmd_Buffer[4]=10;  // y
		dvb.Cmd_Buffer[5]=60;  // sizex
		dvb.Cmd_Buffer[6]=30;  // sizey
		dvb.Cmd_Buffer[7]=1;   // Color
		dvb.Cmd_laenge=8;
		SendMDCommand(dvb);
*/
		return 1;
	}
    if(!WTVPAPIFlag())
	{
		Osd_Start.BitTiefe = Bits ;     
		Osd_Start.DLL_Id=m_MultiDec_DLL_ID;
		Osd_Start.x1=x1;
		Osd_Start.y1=y1;
		Osd_Start.x2=x2;
		Osd_Start.y2=y2;
		Osd_Start.Input=Has_KeyBoard_Input;        
		ret=SendMessage(m_MultiDecWindow,WM_USER,MDAPI_START_OSD,(LONG)&Osd_Start);
	}
	else
	{
		Osd_Start.BitTiefe = Bits;     
		Osd_Start.DLL_Id=0;
		Osd_Start.x1=0;
		Osd_Start.y1=0;
		Osd_Start.x2=x2-x1;
		Osd_Start.y2=y2-y1;
		Osd_Start.Input=0;        
		ret=SendMessage(m_MultiDecWindow,WM_USER,MDAPI_START_OSD,(LONG)&Osd_Start);
		WTVP_OSD_MOVE Osd_Move;
		Osd_Move.x=x1;
		Osd_Move.y=y1;
		SendMessage(m_MultiDecWindow,WM_USER,WTVP_MOVE_OSD,(LONG)&Osd_Move);
	}
	return ret;
};

int CAPI_Impl::OSD_Draw_Block( unsigned short x,unsigned short y,unsigned short SizeX,unsigned short SizeY,unsigned short Color)
{
	int ret=0;
	if(m_use_alternate_osd)
	{
		TDVB_COMMAND dvb;
		dvb.Cmd_Buffer[0]=0x0306; // DBox
		dvb.Cmd_Buffer[1]=0x06;
		dvb.Cmd_Buffer[2]=m_progdvb_osd_window_nr;  // Window nr
		dvb.Cmd_Buffer[3]=x;  // x
		dvb.Cmd_Buffer[4]=y;  // y
		dvb.Cmd_Buffer[5]=SizeX;  // sizex
		dvb.Cmd_Buffer[6]=SizeY;  // sizey
		dvb.Cmd_Buffer[7]=Color;   // Color
		dvb.Cmd_laenge=8;
		SendMDCommand(dvb);
		return 1;
	}
	struct TOSD_DRAW  Osd_Draw;
	Osd_Draw.x=x;
	Osd_Draw.y=y;
	Osd_Draw.Sizex=SizeX;    
	Osd_Draw.Sizey=SizeY;    
	Osd_Draw.Color=Color;
	ret=SendMessage(m_MultiDecWindow,WM_USER,MDAPI_OSD_DRAWBLOCK,(LONG)&Osd_Draw);
	return ret;
};


int CAPI_Impl::OSD_Set_Font( unsigned short Typ,unsigned short Fg_Color,unsigned short Bg_Color)
{
	int ret=0;
	if(m_use_alternate_osd)
	{
		TDVB_COMMAND dvb;
		dvb.Cmd_Buffer[0]=0x0309; // Set_Font
		dvb.Cmd_Buffer[1]=0x04;
		dvb.Cmd_Buffer[2]=m_progdvb_osd_window_nr;  // Window nr
		dvb.Cmd_Buffer[3]=Typ;		 // x
		dvb.Cmd_Buffer[4]=Fg_Color;  // y
		dvb.Cmd_Buffer[5]=Bg_Color;  // sizex
		dvb.Cmd_laenge=6;
		SendMDCommand(dvb);
		return 1;
	}
	struct TOSD_SETFONT  Osd_Set_Font;
	Osd_Set_Font.Typ=Typ;
	Osd_Set_Font.Fg_Color=Fg_Color;
	Osd_Set_Font.Bg_Color=Bg_Color;
	ret=SendMessage(m_MultiDecWindow,WM_USER,MDAPI_OSD_SETFONT,(LONG)&Osd_Set_Font);
	return ret;
};

int CAPI_Impl::OSD_Write_Text( unsigned short x,unsigned short y,const char *Text)
{
	int ret=0;
	if(m_use_alternate_osd)
	{
		return 0;
	}
	struct TOSD_SETEXT  Osd_Set_Text;
	Osd_Set_Text.x=x;
	Osd_Set_Text.y=y;
	strncpy(Osd_Set_Text.Zeile,Text,128);
	ret=SendMessage(m_MultiDecWindow,WM_USER,MDAPI_OSD_TEXT,(LONG)&Osd_Set_Text);
	return ret;
};


int CAPI_Impl::OSD_Close(  void )
{
	int ret=0;
	if(m_use_alternate_osd)
	{
		TDVB_COMMAND dvb;
		dvb.Cmd_Buffer[0]=0x0301; // WDestroy
		dvb.Cmd_Buffer[1]=0x01;
		dvb.Cmd_Buffer[2]=m_progdvb_osd_window_nr;  // Window nr
		dvb.Cmd_laenge=3;
		SendMDCommand(dvb);
		return 1;
	}
	ret=SendMessage(m_MultiDecWindow,WM_USER,MDAPI_STOP_OSD,0);
	return ret;
};



int CAPI_Impl::OSD_Send_Key(unsigned char Key)
{
	int ret=0;
	ret=SendMessage(m_MultiDecWindow,WM_USER,MDAPI_SEND_OSD_KEY, (LPARAM)Key);
	return ret;
}

// WTVP & ProgDVB (not Multidec)
int CAPI_Impl::WTVP_Send_Diseqc( const WTVP_DiseqcStruc& ds)
{
	return(SendMessage(m_MultiDecWindow, WM_USER, WTVP_SEND_DISEQC, (LPARAM)&ds));
}

// Only iTimerNumber is needed for the Get: WTVP fills the rest
int CAPI_Impl::WTVP_GetTimerRecord( WTVP_TimerRecord *timrec)
{
	return SendMessage(m_MultiDecWindow, WM_USER, WTVP_GET_TIMERRECORD, (LPARAM)timrec);
}
int CAPI_Impl::WTVP_SetTimerRecord( WTVP_TimerRecord *timrec)
{
	return SendMessage(m_MultiDecWindow, WM_USER, WTVP_SET_TIMERRECORD, (LPARAM)timrec);
}

BYTE CAPI_Impl::WTVP_ReadVolume()
{
	BYTE bVol=0;
	SendMessage(m_MultiDecWindow, WM_USER,WTVP_GET_VOLUME,(LONG)&bVol);
	return bVol;
}
int CAPI_Impl::WTVP_SetVolume(BYTE bVol)
{
	return SendMessage(m_MultiDecWindow, WM_USER,WTVP_SET_VOLUME,(LONG)&bVol);
}
int CAPI_Impl::WTVP_GetChannelCount()
{
	int iChan=-1;
	SendMessage(m_MultiDecWindow, WM_USER,WTVP_CHANNELS_COUNT,(LONG)&iChan);
	return iChan;
}
// Not working right now
int CAPI_Impl::PROG_Send_Diseqc( TProgAPIDiSEqCmd& ds)
{
	return(SendMessage(m_MultiDecWindow, WM_USER, WTVP_SEND_DISEQC, (LPARAM)&ds));
}

// ProgDVB only
int CAPI_Impl::PROG_Get_Signal_Level( TProgAPISignalState *sig)
{
	sig->dwLength=sizeof(TProgAPISignalState);
	return SendMessage(m_MultiDecWindow, WM_USER, PROGAPI_GET_SIGNAL_LEVEL, (LPARAM) sig);
}

// Send a DVB command using TT functions
// Not working with Multidec, only TTDVBACC applications
void CAPI_Impl::SendTTCommand(TDVB_COMMAND dvb)
{
}
// Send a DVB command using regular MD API
void CAPI_Impl::SendMDCommand(TDVB_COMMAND dvb)
{
	to_log("MDCommand");
	SendMessage(m_MultiDecWindow,WM_USER,MDAPI_DVB_COMMAND,(LONG)&dvb);
}

BOOL CAPI_Impl::WritePrivateProfileInt(LPCTSTR section, LPCTSTR keyname, int value, LPCTSTR ini)
{
	char temp[32];
	sprintf(temp,"%d",value);
	return WritePrivateProfileString(section,keyname,temp,ini);
}

LRESULT CALLBACK f_MyAPIWndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
	char txt[256];
	sprintf(txt,"Wnd: %4X Msg:%08X W:%08X L:%08X",hwnd,msg,wparam,lparam);
	to_log(txt);

	if(hwnd==g_API_Impl->m_subclass_hwnd)
	{
		return g_API_Impl->APIWndProc(msg,wparam,lparam);
	}

	return DefWindowProc(hwnd, msg,wparam,lparam);

}
WNDPROC orig_mdproc;
LRESULT CALLBACK f_MyMDWndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
	char txt[256];
	if(msg>=WM_KEYFIRST&&msg<=WM_KEYLAST)
	{
		sprintf(txt,"%8d MDWnd: %4X Msg:%08X W:%08X L:%08X",clock(),hwnd,msg,wparam,lparam);
		to_log(txt);
	}
	return CallWindowProc(orig_mdproc,hwnd,msg,wparam,lparam);
}
LRESULT CALLBACK myhookproc(int code, WPARAM wparam, LPARAM lparam)
{
	char txt[256];
	CWPSTRUCT *cwp=(CWPSTRUCT*)lparam;
	sprintf(txt,"Hook Code: %d Wnd: %4X Msg:%08X W:%08X L:%08X",code,cwp->hwnd,cwp->message,cwp->wParam,cwp->lParam);
	to_log(txt);
	return CallNextHookEx(hhook,code,wparam,lparam);
}
LRESULT CALLBACK mymsghookproc(int nCode, WPARAM wParam, LPARAM lParam)
{
	char txt[256];
	
	LPMSG lpMsg = (LPMSG) lParam;
	if(lpMsg->message>=WM_KEYFIRST&&lpMsg->message<=WM_KEYLAST)
	{
		sprintf(txt,"%8d MsgHook Code: %d Wnd: %4X Msg:%08X W:%08X L:%08X W:%d",clock(),nCode,lpMsg->hwnd,lpMsg->message,lpMsg->wParam,lpMsg->lParam,wParam);
		to_log(txt);
	}
	if( (nCode >= 0) &&  PM_REMOVE == wParam &&  (lpMsg->message >= WM_KEYFIRST && lpMsg->message <= WM_KEYLAST) )
	 {
	 // The value returned from this hookproc is ignored, and it cannot
	 // be used to tell Windows the message has been handled. To avoid
	 // further processing, convert the message to WM_NULL before
	 // returning.
	 if(lpMsg->message==WM_KEYDOWN)
	 {
		 TranslateMessage(lpMsg);
//		 DispatchMessage(lpMsg);
	 }
	 if(lpMsg->message=WM_CHAR)
	 {
		 g_API_Impl->On_Osd_Key(lpMsg->wParam);
	 }
//	 if(lpMsg->message==WM_KEYDOWN)
	 {
		 lpMsg->message = WM_NULL;
		 lpMsg->lParam = 0L;
		lpMsg->wParam = 0;
	 }
	}
	// Passes the hook information to the next hook procedure in
	// the current hook chain.
	return ::CallNextHookEx(hhook, nCode, wParam, lParam);
}

LRESULT CAPI_Impl::APIWndProc(UINT msg, WPARAM wparam, LPARAM lparam)
{
	return CallWindowProc(m_original_wndproc,m_subclass_hwnd, msg,wparam,lparam);
}


int	CAPI_Impl::APISubclassWindow()
{
	char txt[256]="";
	hhook=SetWindowsHookEx(WH_GETMESSAGE,mymsghookproc,NULL,GetWindowThreadProcessId(m_MultiDecWindow,NULL));
//	orig_mdproc=(WNDPROC)SetWindowLong(m_MultiDecWindow,GWL_WNDPROC,(LPARAM)(WNDPROC)f_MyMDWndProc);
	if(WTVPAPIFlag())
	{
		// Find read WTVP window

		if(m_subclass_hwnd)
		{
			m_original_wndproc=(WNDPROC)SetWindowLong(m_subclass_hwnd, GWL_WNDPROC, (LPARAM)(WNDPROC)f_MyAPIWndProc);
			sprintf(txt,"Subclass: Wnd:%x old=%08x New:%08x MDHwnd:%08x",m_subclass_hwnd,m_original_wndproc,f_MyAPIWndProc,m_MultiDecWindow);
			to_log(txt);
			return (int)m_original_wndproc;
		}

	}
	return NULL;
}
int	CAPI_Impl::APIUnSubclassWindow()
{	
	if(hhook)
		UnhookWindowsHookEx(hhook);
	hhook=NULL;
	if(m_original_wndproc!=NULL && m_subclass_hwnd!=NULL)
		return SetWindowLong(m_subclass_hwnd, GWL_WNDPROC, (LPARAM)(WNDPROC)m_original_wndproc);
	else return NULL;
}
