CVS: seamlessrdp/ClientDLL Client.Reg,NONE,1.1 StdString.h,NONE,1.1 TSWindowClipper.vcproj,NONE,1.1 Tokenizer.cpp,NONE,1.1 Tokenizer.h,NONE,1.1 WindowData.cpp,NONE,1.1 WindowData.h,NONE,1.1 clipper.Def,NONE,1.1 clipper.cpp,NONE,1.1 clipper.h,NONE,1.1 hash.cpp,NONE,1.1 hash.h,NONE,1.1

Peter Åstrand <[email protected]>
Newsgroups gmane.network.rdesktop.cvs
Message-ID <[email protected]>
Update of /cvsroot/rdesktop/seamlessrdp/ClientDLL
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv1824/ClientDLL

Added Files:
	Client.Reg StdString.h TSWindowClipper.vcproj Tokenizer.cpp 
	Tokenizer.h WindowData.cpp WindowData.h clipper.Def 
	clipper.cpp clipper.h hash.cpp hash.h 
Log Message:
Imported CodeProject tswindowclipper source.

--- NEW FILE: Client.Reg ---
REGEDIT4



[HKEY_CURRENT_USER\Software\Microsoft\Terminal Server Client\Default\AddIns\TSWindowClipper]

"Name" = "TSWindowClipper.dll"




--- NEW FILE: StdString.h ---
(This appears to be a binary file; contents omitted.)

--- NEW FILE: TSWindowClipper.vcproj ---
(This appears to be a binary file; contents omitted.)

--- NEW FILE: Tokenizer.cpp ---
/////////////////////////////////////////////////////////////////////////////

// Tokenizer.cpp

//

// Date:        Thursday, November 18, 1999

// Autor:       Eduardo Velasquez

// Description: Tokenizer class for CStrings. Works like strtok().

///////////////



//#include "atlstr.h"







#include "Tokenizer.h"



#ifdef _DEBUG

#define new DEBUG_NEW

#undef THIS_FILE

static char THIS_FILE[] = __FILE__;

#endif



CTokenizer::CTokenizer(const CStdString& cs, const CStdString& csDelim):

	m_cs(cs),

	m_nCurPos(0)

{

	SetDelimiters(csDelim);

}



void CTokenizer::SetDelimiters(const CStdString& csDelim)

{

	for(int i = 0; i < csDelim.GetLength(); ++i)

		m_delim.set(static_cast<BYTE>(csDelim[i]));

}



bool CTokenizer::Next(CStdString& cs)

{

	cs.Empty();



	while(m_nCurPos < m_cs.GetLength() && m_delim[static_cast<BYTE>(m_cs[m_nCurPos])])

		++m_nCurPos;



	if(m_nCurPos >= m_cs.GetLength())

		return false;



	int nStartPos = m_nCurPos;

	while(m_nCurPos < m_cs.GetLength() && !m_delim[static_cast<BYTE>(m_cs[m_nCurPos])])

		++m_nCurPos;

	

	cs = m_cs.Mid(nStartPos, m_nCurPos - nStartPos);



	return true;

}



CStdString CTokenizer::Tail() const

{

	int nCurPos = m_nCurPos;



	while(nCurPos < m_cs.GetLength() && m_delim[static_cast<BYTE>(m_cs[nCurPos])])

		++nCurPos;



	CStdString csResult;



	if(nCurPos < m_cs.GetLength())

		csResult = m_cs.Mid(nCurPos);



	return csResult;

}


--- NEW FILE: Tokenizer.h ---
/////////////////////////////////////////////////////////////////////////////

// Tokenizer.h

//

// Date:        Monday, October 22, 2001

// Autor:       Eduardo Velasquez

// Description: Tokenizer class for CStrings. Works like strtok.

///////////////





#include "StdString.h"



#if !defined(__TOKENIZER_H__)

#define __TOKENIZER_H__



#if _MSC_VER >= 1000

#pragma once

#endif // _MSC_VER >= 1000



#if !defined(_BITSET_)

#	include <bitset>

#endif // !defined(_BITSET_)



class CTokenizer

{

public:

	CTokenizer(const CStdString& cs, const CStdString& csDelim);

	void SetDelimiters(const CStdString& csDelim);



	bool Next(CStdString& cs);

	CStdString	Tail() const;



private:

	CStdString m_cs;

	std::bitset<256> m_delim;

	int m_nCurPos;

};



#endif  // !defined(__TOKENIZER_H__)


--- NEW FILE: WindowData.cpp ---
//*********************************************************************************

//

//Title: Terminal Services Window Clipper

//

//Author: Martin Wickett

//

//Date: 2004

//

//*********************************************************************************



#include "WindowData.h"



CWindowData::CWindowData(const CStdString& csId) : m_csTitle(""),m_csId(""), m_iX1(0),m_iY1(0),m_iX2(0),m_iY2(0)

{

	

}



void CWindowData::SetId(const CStdString& csId)

{

	m_csId = csId;

}



void CWindowData::SetTitle(const CStdString& csTitle)

{

	m_csTitle = csTitle;

}



void CWindowData::SetX1(int iX1)

{

	m_iX1 = iX1;

}



void CWindowData::SetY1(int iY1)

{

	m_iY1 = iY1;

}



void CWindowData::SetX2(int iX2)

{

	m_iX2 = iX2;

}



void CWindowData::SetY2(int iY2)

{

	m_iY2 = iY2;

}



CStdString CWindowData::GetId()

{

	return this->m_csId;

}



CStdString CWindowData::GetTitle()

{

	return this->m_csTitle;

}



int CWindowData::GetX1()

{

	return this->m_iX1;

}



int CWindowData::GetY1()

{

	return this->m_iY1;

}



int CWindowData::GetX2()

{

	return this->m_iX2;

}



int CWindowData::GetY2()

{

	return this->m_iY2;

}
--- NEW FILE: WindowData.h ---
//*********************************************************************************

//

//Title: Terminal Services Window Clipper

//

//Author: Martin Wickett

//

//Date: 2004

//

//*********************************************************************************



#include "StdString.h"



#if !defined(__WINDOWDATA_H__)

#define __WINDOWDATA_H__



class CWindowData

{

public:

	CWindowData(const CStdString& csId);



	void CWindowData::SetId(const CStdString& csId);

	void CWindowData::SetTitle(const CStdString& csTitle);

	void CWindowData::SetX1(int iX1);

	void CWindowData::SetY1(int iY1);

	void CWindowData::SetX2(int iX2);

	void CWindowData::SetY2(int iY2);

	HWND CWindowData::TaskbarWindowHandle;



    CStdString CWindowData::GetId();

	CStdString CWindowData::GetTitle();

	int CWindowData::GetX1();

	int CWindowData::GetY1();

	int CWindowData::GetX2();

	int CWindowData::GetY2();



private:

	CStdString m_csTitle;

	CStdString m_csId;

	int m_iX1,m_iY1,m_iX2,m_iY2;

};



#endif  // !defined(__WINDOWDATA_H__)
--- NEW FILE: clipper.Def ---
LIBRARY TSWindowClipper



EXPORTS

        VirtualChannelEntry @1




--- NEW FILE: clipper.cpp ---
//*********************************************************************************

//

//Title: Terminal Services Window Clipper

//

//Author: Martin Wickett

//

//Date: 2004

//

//*********************************************************************************



#define TSDLL



#include "clipper.h"



BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)

{

	UNREFERENCED_PARAMETER(lpvReserved);

	UNREFERENCED_PARAMETER(hinstDLL);



    switch(fdwReason)

    {

        case DLL_PROCESS_ATTACH:

            break;



        case DLL_THREAD_ATTACH:

            break;



        case DLL_THREAD_DETACH:

            break;



        case DLL_PROCESS_DETACH:

            break;



        default:

            break;

    }

    return TRUE;

}



void WINAPI VirtualChannelOpenEvent(DWORD openHandle, UINT event, LPVOID pdata, 

									UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags)

{

	LPDWORD pdwControlCode = (LPDWORD)pdata;

	CHAR ourData[1600];

	UINT  ui = 0;



    UNREFERENCED_PARAMETER(openHandle);

    UNREFERENCED_PARAMETER(dataFlags);

    

    ZeroMemory(ourData, sizeof(ourData));



    //copy the send string (with the same lenth of the data)

	strncpy(ourData,(LPSTR)pdata,dataLength/sizeof(char));



	if (OUTPUT_DEBUG_INFO == 1 )

	{

		OutputDebugString("TS WINDOW CLIPPER :: CLIENT DLL :: Info --> Virtual channel data received");

		OutputDebugString(ourData);

	}

    

    if (dataLength == totalLength)

	{

        switch(event)

        {

            case CHANNEL_EVENT_DATA_RECEIVED:

            {             

				CTokenizer tok(_T((LPSTR)ourData), _T(";"));

				CStdString cs;



				CWindowData* wid=new CWindowData("");

				CStdString messageType;

				int mixMaxType = 0;



				while(tok.Next(cs))

				{

					CStdString msg;

					CTokenizer msgTok(cs, _T("="));	

					

					msgTok.Next(msg);



					if (strcmp(msg,"MSG")==0)

					{

						msgTok.Next(msg);

						messageType = msg;

					}



					if (strcmp(msg,"ID")==0)

					{

						msgTok.Next(msg);

						wid->SetId(msg);

					}

					else if (strcmp(msg,"TITLE")==0)

					{

						msgTok.Next(msg);

						wid->SetTitle(msg);

					}

					else if (strcmp(msg,"POS")==0)

					{

						msgTok.Next(msg);



						CStdString pos;

						CTokenizer posTok(msg, _T("~"));

						

						posTok.Next(pos);

						

						

						// check bounds, coords can be negative if window top left point is moved off the screen.

						// we don't care about that since the window can't be see so just use zero.



						if (strchr(pos, '-')==NULL)

						{

							wid->SetX1(atoi(pos));

						}

						else

						{

							wid->SetX1(0);

						}



						posTok.Next(pos);



						if (strchr(pos, '-')==NULL)

						{

							wid->SetY1(atoi(pos));

						}

						else

						{

							wid->SetY1(0);

						}



						posTok.Next(pos);



						if (strchr(pos, '-')==NULL)

						{

							wid->SetX2(atoi(pos));

						}

						else

						{

							wid->SetX2(0);

						}



						posTok.Next(pos);



						if (strchr(pos, '-')==NULL)

						{

							wid->SetY2(atoi(pos));

						}

						else

						{

							wid->SetY2(0);

						}

					}

					else if (strcmp(msg,"TYPE")==0)

					{

						msgTok.Next(msg);

						mixMaxType = atoi(msg);

					}

				}

 

				if (strcmp(messageType,"HSHELL_WINDOWCREATED")==0)

				{

					if (OUTPUT_DEBUG_INFO == 1 )

					{

						OutputDebugString("TS WINDOW CLIPPER :: CLIENT DLL :: Info --> Message was of type HSHELL_WINDOWCREATED window title is:");

						OutputDebugString(wid->GetTitle());

					}



					CStdString s = wid->GetId();

					char *ptr;

					int length = s.GetLength();

					ptr = s.GetBufferSetLength(length);



					hash_insert(ptr,wid,&m_ht);

				

					CreateAndShowWindow(wid);



					DoClipping(1);

				}

				else if(strcmp(messageType,"HSHELL_WINDOWDESTROYED")==0)

				{

					if (OUTPUT_DEBUG_INFO == 1 )

					{

						OutputDebugString("TS WINDOW CLIPPER :: CLIENT DLL :: Info --> Message was of type HSHELL_WINDOWDISTROYED window title is:");

						OutputDebugString(wid->GetTitle());

					}



					CStdString s = wid->GetId();

					char *ptr;

					int length = s.GetLength();

					ptr = s.GetBufferSetLength(length);

					

					CWindowData* oldWinData = (CWindowData*) hash_del(ptr,&m_ht);



					DestroyTaskbarWindow(oldWinData);



					delete oldWinData;



					DoClipping(1);

				}

				else if(strcmp(messageType,"HCBT_MINMAX")==0)

				{

					if (OUTPUT_DEBUG_INFO == 1 )

					{

						OutputDebugString("TS WINDOW CLIPPER :: CLIENT DLL :: Info --> Message was of type HCBT_MINMAX");

					}





					//TODO



				}

				else if(strcmp(messageType,"HCBT_MOVESIZE")==0)

				{

					if (OUTPUT_DEBUG_INFO == 1 )

					{

						OutputDebugString("TS WINDOW CLIPPER :: CLIENT DLL :: Info --> Message was of type HCBT_MOVESIZE window title is:");

						OutputDebugString(wid->GetTitle());

					}



					CStdString s = wid->GetId();

					char *ptr;

					int length = s.GetLength();

					ptr = s.GetBufferSetLength(length);

					

					CWindowData* movedWinData = (CWindowData*) hash_lookup(ptr,&m_ht);

					

					if(movedWinData!=NULL)

					{

						movedWinData->SetX1(wid->GetX1());

						movedWinData->SetX2(wid->GetX2());

						movedWinData->SetY1(wid->GetY1());

						movedWinData->SetY2(wid->GetY2());



						DoClipping(1);

					}



					delete wid;

				}			

				else if(strcmp(messageType,"CALLWNDPROC_WM_MOVING")==0)

				{

					if (OUTPUT_DEBUG_INFO == 1 )

					{

						OutputDebugString("TS WINDOW CLIPPER :: CLIENT DLL :: Info --> Message was of type CALLWNDPROC_WM_MOVING window title is:");

						OutputDebugString(wid->GetTitle());

					}



					CStdString s = wid->GetId();

					char *ptr;

					int length = s.GetLength();

					ptr = s.GetBufferSetLength(length);

					

					CWindowData* movedWinData = (CWindowData*) hash_lookup(ptr,&m_ht);

					

					if(movedWinData!=NULL)

					{

						movedWinData->SetX1(wid->GetX1());

						movedWinData->SetX2(wid->GetX2());

						movedWinData->SetY1(wid->GetY1());

						movedWinData->SetY2(wid->GetY2());

						

						////might be too much of an overhead forcing the redraw here. Might be better to do 'DoClipping(0)' instead?

						DoClipping(1);

					}



					delete wid;

				}			

            }

            break;



            case CHANNEL_EVENT_WRITE_COMPLETE:

            {

            }

            break;



            case CHANNEL_EVENT_WRITE_CANCELLED:

			{

            }

            break;



            default:

            {

            }

            break;

        }

    }

    else

	{

	}

}





VOID VCAPITYPE VirtualChannelInitEventProc(LPVOID pInitHandle, UINT event, LPVOID pData, UINT dataLength)

{

    UINT  ui;



    UNREFERENCED_PARAMETER(pInitHandle);

    UNREFERENCED_PARAMETER(dataLength);



    switch(event)

    {

        case CHANNEL_EVENT_INITIALIZED:

        {

        }

        break;



        case CHANNEL_EVENT_CONNECTED:

        { 

            //

            // open channel

            //

            ui = gpEntryPoints->pVirtualChannelOpen(gphChannel,&gdwOpenChannel,CHANNELNAME,(PCHANNEL_OPEN_EVENT_FN)VirtualChannelOpenEvent);



		    if (ui == CHANNEL_RC_OK)

			{

			

			}

			else

			{

				MessageBox(NULL,TEXT("Open of RDP virtual channel failed"),TEXT("TS Window Clipper"),MB_OK);

			}



            if (ui != CHANNEL_RC_OK)

			{

                return;

            }        

        }

        break;



        case CHANNEL_EVENT_V1_CONNECTED:

        {

            MessageBox(NULL,TEXT("Connecting to a non Windows 2000 Terminal Server"),TEXT("TS Window Clipper"),MB_OK);

        }

        break;



        case CHANNEL_EVENT_DISCONNECTED:

        {



        }

        break;



        case CHANNEL_EVENT_TERMINATED:

        {

            //

            // free the entry points table

            //

            LocalFree((HLOCAL)gpEntryPoints);

        }

        break;



        default:

        {



        }

        break;

    }

}



BOOL VCAPITYPE VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints)

{

    CHANNEL_DEF cd;

    UINT        uRet;



	size_t s = 10;

	hash_construct_table(&m_ht, s);



    //

    // allocate memory

    //

    gpEntryPoints = (PCHANNEL_ENTRY_POINTS) LocalAlloc(LPTR, pEntryPoints->cbSize);



    memcpy(gpEntryPoints, pEntryPoints, pEntryPoints->cbSize);



    //

    // initialize CHANNEL_DEF structure

    //

    ZeroMemory(&cd, sizeof(CHANNEL_DEF));

    strcpy(cd.name, CHANNELNAME); // ANSI ONLY



    //

    // register channel

    //

    uRet = gpEntryPoints->pVirtualChannelInit((LPVOID *)&gphChannel,(PCHANNEL_DEF)&cd, 1,VIRTUAL_CHANNEL_VERSION_WIN2000,(PCHANNEL_INIT_EVENT_FN)VirtualChannelInitEventProc);

   

	if (uRet == CHANNEL_RC_OK)

    {

		if (ALWAYS__CLIP)

		{

			DoClipping(1);

		}

    }

   else

    {

	    MessageBox(NULL,TEXT("RDP Virtual channel Init Failed"),TEXT("TS Window Clipper"),MB_OK);

    }



    if (uRet != CHANNEL_RC_OK)

	{

        return FALSE;

	}



    //

    // make sure channel was initialized

    //

    if (cd.options != CHANNEL_OPTION_INITIALIZED)

	{

        return FALSE;

	}



    return TRUE;

}





// data structure to transfer informations

typedef struct _WindowFromProcessOrThreadID

{

   union

   {

       DWORD  procId;

       DWORD  threadId;

   };

   HWND   hWnd;     

}Wnd4PTID;



// Callback procedure

BOOL CALLBACK PrivateEnumWindowsProc(HWND hwnd,LPARAM lParam)

{

     DWORD procId;

     DWORD threadId;

     Wnd4PTID* tmp = (Wnd4PTID*)lParam;

     // get the process/thread id of current window

     threadId = GetWindowThreadProcessId(hwnd, &procId);

     // check if the process/thread id equal to the one passed by lParam?

     if(threadId == tmp->threadId || procId == tmp->procId)

     {

           // check if the window is a main window

           // because there lots of windows belong to the same process/thread

           LONG dwStyle = GetWindowLong(hwnd, GWL_STYLE);

           if(dwStyle & WS_SYSMENU)

           {

                  tmp->hWnd = hwnd;

                  return FALSE;  // break the enumeration

           }

     }

     return TRUE;  // continue the enumeration

}



// Enumarate all the MainWindow of the system

HWND FindProcessMainWindow(DWORD procId)

{

     Wnd4PTID  tempWnd4ID;

     tempWnd4ID.procId = procId;

     if(!EnumWindows((WNDENUMPROC)PrivateEnumWindowsProc, (LPARAM)&tempWnd4ID))

	 {

         

		if (OUTPUT_DEBUG_INFO == 1 )

		{

			OutputDebugString("TS WINDOW CLIPPER :: CLIENT DLL :: Info --> Found main process window");

		}



		 return tempWnd4ID.hWnd;

	 }



	 

	if (OUTPUT_DEBUG_INFO == 1 )

	{

		OutputDebugString("TS WINDOW CLIPPER :: CLIENT DLL :: Info --> Could not find main process window"); 

	}



     return NULL;

}





void DoClipping(int forceRedraw)

{

	//if main window handle is null, try to get it

	if (m_mainWindowHandle==NULL)

	{

		m_mainWindowHandle = FindProcessMainWindow(GetCurrentProcessId());

		

		//hide the window from taskbar and put at the back of the z order

		if ( HIDE_TSAC_WINDOW ==1 )

		{

			ShowWindow(m_mainWindowHandle, SW_HIDE);

			SetWindowLongPtr(m_mainWindowHandle, GWL_EXSTYLE,GetWindowLong(m_mainWindowHandle, GWL_EXSTYLE) | WS_EX_TOOLWINDOW);

			ShowWindow(m_mainWindowHandle, SW_SHOW);

		}



		SetWindowPos(m_mainWindowHandle, HWND_NOTOPMOST, 0, 0, 0, 0,SWP_NOMOVE | SWP_NOSIZE);

	}

	

	//if we have the handle, lets use it for the clipping

	if (m_mainWindowHandle!=NULL)

	{

		RECT wRect;

		GetWindowRect(m_mainWindowHandle,&wRect);

	

		if (OUTPUT_DEBUG_INFO == 1 )

		{

			OutputDebugString("TS WINDOW CLIPPER :: CLIENT DLL :: Info --> Restarting clipping..."); 

		}



		m_regionResult = NULL;

		

		if (OUTPUT_WINDOW_TABLE_DEBUG_INFO == 1 )

		{

			OutputDebugString("-----------------------------------------------------------------------------");

			OutputDebugString("TS WINDOW CLIPPER :: CLIENT DLL :: Info --> starting printing of window table");

		}



		//enumerate though hashtable

		if (&m_ht!=NULL)

		{

			hash_enumerate( &m_ht, CreateRegionFromWindowData);

		}



		if (OUTPUT_WINDOW_TABLE_DEBUG_INFO == 1 )

		{

			OutputDebugString("TS WINDOW CLIPPER :: CLIENT DLL :: Info --> finished printing of window table"); 

			OutputDebugString("-----------------------------------------------------------------------------");

		}



		if (m_regionResult==NULL)

		{

			if (ALWAYS__CLIP)

			{

				m_regionResult=CreateRectRgn(0,0,0,0);

			}

			else

			{

				m_regionResult = CreateRectRgn(0,0,wRect.right,wRect.bottom);

			}

		}



		SetWindowRgn(m_mainWindowHandle,(HRGN__*)m_regionResult, TRUE);	



		if (forceRedraw==1)

		{

			// invalidate the window and force it to redraw

			RedrawWindow(m_mainWindowHandle,NULL,NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN);

		}

	}

	else

	{

		if (OUTPUT_DEBUG_INFO == 1 )

		{

			OutputDebugString("TS WINDOW CLIPPER :: CLIENT DLL :: Info --> Coulf not find window to clip"); 

		}

	}

}



void CreateRegionFromWindowData(char * key,void * value)

{

	CWindowData* wd;

	wd = (CWindowData*)value;

	int x1=0,x2=0,y1=0,y2=0;

	

	char strB[5];

	char strT[5];

	char strL[5];

    char strR[5];



	if (m_regionResult==NULL)

	{

		m_regionResult=CreateRectRgn(0,0,0,0);

	}

	

	if (OUTPUT_DEBUG_INFO == 1 && OUTPUT_WINDOW_TABLE_DEBUG_INFO != 1)

	{

		OutputDebugString("TS WINDOW CLIPPER :: CLIENT DLL :: Info --> Adding this window to cliping region");

		OutputDebugString(wd->GetTitle());

	}

	if (OUTPUT_WINDOW_TABLE_DEBUG_INFO == 1 )

	{

		ltoa(wd->GetY2(),strB,10);

		ltoa(wd->GetY1(),strT,10);

		ltoa(wd->GetX2(),strR,10);

		ltoa(wd->GetX1(),strL,10);



		OutputDebugString("This window is in the table:");

		OutputDebugString(wd->GetTitle());

		OutputDebugString(wd->GetId());

		OutputDebugString(strL);

		OutputDebugString(strT);

		OutputDebugString(strR);

		OutputDebugString(strB);

		OutputDebugString("*******************");

	}



	HRGN newRegion = CreateRectRgn(wd->GetX1(),wd->GetY1(),wd->GetX2(),wd->GetY2());

	

	CombineRgn(m_regionResult, newRegion, m_regionResult, RGN_OR);

}



/*

   Dummy procedure to catch when window is being maximised.



   Need to tell the window on the server to do the same.

 */

LRESULT CALLBACK DummyWindowCallbackProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)

{

	//TODO



	return DefWindowProc(hwnd, uMsg, wParam, lParam);

}



void CreateAndShowWindow(CWindowData* wd)

{

	if (classAlreadyRegistered==0)

	{

		static const char *szWndName = "WTSWinClipperDummy";

		WNDCLASS wc;

		

		wc.style			= 0;

		wc.lpfnWndProc		= DummyWindowCallbackProc;

		wc.cbClsExtra		= 0;

		wc.cbWndExtra		= 0;

		wc.hInstance		= 0;

		wc.hIcon			= 0;

		wc.hCursor			= 0;

		wc.hbrBackground	= 0;

		wc.lpszMenuName		= 0;

		wc.lpszClassName	= szWndName;



		if (RegisterClass(&wc))

		{

			classAlreadyRegistered=1;

		}

	}



    if (classAlreadyRegistered=1)

	{

		HWND hWnd = CreateWindow(TEXT("WTSWinClipperDummy"), wd->GetTitle(), WS_POPUP, 0, 0, 0, 0, 0, 0, 0, 0);

		ShowWindow( hWnd, 3 );

		SetWindowPos(hWnd,0,0,0,0,0,SWP_NOREDRAW);

		wd->TaskbarWindowHandle = hWnd;

		SetFocus(m_mainWindowHandle);

	}

}



void DestroyTaskbarWindow(CWindowData* wd)

{

	if (wd->TaskbarWindowHandle != NULL)

	{

		DestroyWindow(wd->TaskbarWindowHandle);

	}

}
--- NEW FILE: clipper.h ---
//*********************************************************************************

//

//Title: Terminal Services Window Clipper

//

//Author: Martin Wickett

//

//Date: 2004

//

//*********************************************************************************



#define VER_FILETYPE                VFT_DLL

#define VER_FILESUBTYPE             VFT2_UNKNOWN

#define VER_FILEDESCRIPTION_STR     "Virtual Channel sample DLL"

#define VER_INTERNALNAME_STR        "sysinf_c.dll"

#define VER_ORIGINALFILENAME_STR    "sysinf_c.dll"



#define STRICT

#define _



#include <windows.h>

#include <ntverp.h>

#include "common.ver"



#include <windows.h>

#include <stdio.h>

#include <wtsapi32.h>

#include <tchar.h>

#include <lmcons.h>



#ifdef TSDLL



#include <pchannel.h>

#include <cchannel.h>



#include <windows.h>

#include <winuser.h>



#endif



#include "hash.h"

#include "tokenizer.h"

#include "WindowData.h"



//

// definitions

//

#define CHANNELNAME "CLIPPER"



//

// GLOBAL variables

//



LPHANDLE              gphChannel;

DWORD                 gdwOpenChannel;

PCHANNEL_ENTRY_POINTS gpEntryPoints;



hash_table m_ht;

HRGN m_regionResult;

HWND m_mainWindowHandle = NULL;

int classAlreadyRegistered=0;



int const ALWAYS__CLIP = 0;//set this to 0 to turn off clipping when there are no windows

int const HIDE_TSAC_WINDOW = 1;

int const OUTPUT_DEBUG_INFO = 0;

int const OUTPUT_WINDOW_TABLE_DEBUG_INFO = 0;



//

// declarations

//

void WINAPI VirtualChannelOpenEvent(DWORD openHandle, UINT event, LPVOID pdata, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags);

VOID VCAPITYPE VirtualChannelInitEventProc(LPVOID pInitHandle, UINT event, LPVOID pData, UINT dataLength);

BOOL VCAPITYPE VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints);



void DoClipping(int forceRedraw);

void CreateRegionFromWindowData(char *,void *);



void CreateAndShowWindow(CWindowData* wd);

void DestroyTaskbarWindow(CWindowData* wd);
--- NEW FILE: hash.cpp ---
#include <string.h>

#include <stdlib.h>

/* #define NDEBUG */

#include <assert.h>



#include "hash.h"





/*

** public domain code by Jerry Coffin.

**

** Tested with Visual C 1.0 and Borland C 3.1.

** Compiles without warnings, and seems like it should be pretty

** portable.

*/



/* HW: HenkJan Wolthuis, 1997, public domain



      changed functionnames, all public functions now have a 'hash_' prefix

      minor editing, marked 'm all(?) with a description

      removed a bug in hash_del and one in hash_enumerate

      added some assertions

      added a 'count' member to hold the number of elements

      added hash_sorted_enum, sometimes useful

      changed the testmain

*/


/*
** RBS: Bob Stout, 2003, public domain
**
**  1. Fixed some problems in hash() static function.
**  2. Use unsigned shorts for hash values. This was implicit in the original
**     which was written for PC's using early Microsoft and Borland compilers.
*/

/* HW: #define to allow duplicate keys, they're added before the existing

      key so hash_lookup finds the last one inserted first (LIFO)

      when not defined, hash_insert swaps the datapointers, returning a

      pointer to the old data

*/

/* #define DUPLICATE_KEYS */



/*

** These are used in freeing a table.  Perhaps I should code up

** something a little less grungy, but it works, so what the heck.

 */

static void (*function)(void *) = NULL;

static hash_table *the_table = NULL;





/* Initialize the hash_table to the size asked for.  Allocates space

** for the correct number of pointers and sets them to NULL.  If it

** can't allocate sufficient memory, signals error by setting the size

** of the table to 0.

*/

/*HW: changed, now returns NULL on malloc-failure */

hash_table *hash_construct_table( hash_table *table, size_t size )

{

      size_t i;

      bucket **temp;



      table->size  = size;

      table->count = 0;

      table->table = (bucket **)malloc(sizeof(bucket *) * size);

      temp = table->table;



      if( NULL == temp )

      {

            table->size = 0;

            return NULL;      /*HW: was 'table' */

      }



      for( i=0; i<size; i++ )

            temp[i] = NULL;



      return table;

}





/*

** Hashes a string to produce an unsigned short, which should be

** sufficient for most purposes.

** RBS: fixed per user feedback from Steve Greenland

*/



static unsigned short hash(char *string)

{

      unsigned short ret_val = 0;

      int i;



      while (*string)

      {

            /*

            ** RBS: Added conditional to account for strings in which the

            ** length is less than an integral multiple of sizeof(int).
            **
            ** Note: This fixes the problem of hasing trailing garbage, but
            ** doesn't fix the problem with some CPU's which can't align on
            ** byte boundries. Any decent C compiler *should* fix this, but
            ** it still might extract a performance hit. Also unaddressed is
            ** what happens when using a CPU which addresses data only on
            ** 4-byte boundries when it tries to work with a pointer to a
            ** 2-byte unsigned short.
            */


            if (strlen(string) >= sizeof(unsigned short))

                  i = *(unsigned short *)string;

            else  i = (unsigned short)(*string);

            ret_val ^= i;

            ret_val <<= 1;

            string ++;

      }

      return ret_val;

}



/*

** Insert 'key' into hash table.

** Returns pointer to old data associated with the key, if any, or

** NULL if the key wasn't in the table previously.

*/

/* HW: returns NULL if malloc failed */

void *hash_insert( char *key, void *data, hash_table *table )

{

      unsigned short val = hash(key) % table->size;

      bucket *ptr;



      assert( NULL != key );



      /*

      ** NULL means this bucket hasn't been used yet.  We'll simply

      ** allocate space for our new bucket and put our data there, with

      ** the table pointing at it.

      */



      if( NULL == (table->table)[val] )

      {

            (table->table)[val] = (bucket *)malloc(sizeof(bucket));

            if( NULL == (table->table)[val] )

                  return NULL;



            if( NULL ==  ((table->table)[val]->key = (char*) malloc(strlen(key)+1)) )

            {

                  free( (table->table)[val] );

                  (table->table)[val] = NULL;

                  return NULL;

            }

            strcpy( (table->table)[val]->key, key);

            (table->table)[val] -> next = NULL;

            (table->table)[val] -> data = data;

            table->count++; /* HW */

            return (table->table)[val] -> data;

      }



/* HW: added a #define so the hashtable can accept duplicate keys */

#ifndef DUPLICATE_KEYS

        /*

        ** This spot in the table is already in use.  See if the current string

        ** has already been inserted, and if so, increment its count.

        */                                             /* HW: ^^^^^^^^ ?? */

      for( ptr = (table->table)[val]; NULL != ptr; ptr = ptr->next )

            if( 0 == strcmp(key, ptr->key) )

            {

                  void *old_data;



                  old_data = ptr->data;

                  ptr->data = data;

                  return old_data;

            }

#endif

      /*

      ** This key must not be in the table yet.  We'll add it to the head of

      ** the list at this spot in the hash table.  Speed would be

      ** slightly improved if the list was kept sorted instead.  In this case,

      ** this code would be moved into the loop above, and the insertion would

      ** take place as soon as it was determined that the present key in the

      ** list was larger than this one.

      */



      ptr = (bucket *)malloc(sizeof(bucket));

      if( NULL == ptr )

            return NULL;      /*HW: was 0 */



      if( NULL == (ptr -> key = (char*) malloc(strlen(key)+1)) )

            {

            free(ptr);

            return NULL;

            }

      strcpy( ptr->key, key );

      ptr -> data = data;

      ptr -> next = (table->table)[val];

      (table->table)[val] = ptr;

      table->count++; /* HW */



      return data;

}





/*

** Look up a key and return the associated data.  Returns NULL if

** the key is not in the table.

*/

void *hash_lookup( char *key, hash_table *table )

{

      unsigned short val = hash(key) % table->size;

      bucket *ptr;



      assert( NULL != key );



      if(NULL == (table->table)[val])

            return NULL;



      for( ptr = (table->table)[val]; NULL != ptr; ptr = ptr->next )

      {

            if(0 == strcmp( key, ptr -> key ) )

                  return ptr->data;

      }



      return NULL;

}



/*

** Delete a key from the hash table and return associated

** data, or NULL if not present.

*/



void *hash_del(char *key, hash_table *table)

{

      unsigned short val = hash(key) % table->size;

      void *data;

      bucket *ptr, *last = NULL;



      assert( NULL != key );



      if( NULL == (table->table)[val] )

            return NULL;      /* HW: was 'return 0' */



      /*

      ** Traverse the list, keeping track of the previous node in the list.

      ** When we find the node to delete, we set the previous node's next

      ** pointer to point to the node after ourself instead.      We then delete

      ** the key from the present node, and return a pointer to the data it

      ** contains.

      */

      for( last = NULL, ptr = (table->table)[val];

                  NULL != ptr;

                  last = ptr, ptr = ptr->next )

      {

            if( 0 == strcmp( key, ptr -> key) )

            {

                  if( last != NULL )

                  {

                        data = ptr -> data;

                        last -> next = ptr -> next;

                        free( ptr->key );

                        free( ptr );

                        table->count--; /* HW */

                        return data;

                  }



                  /* If 'last' still equals NULL, it means that we need to

                  ** delete the first node in the list. This simply consists

                  ** of putting our own 'next' pointer in the array holding

                  ** the head of the list. We then dispose of the current

                  ** node as above.

                  */

                  else

                  {

                        /* HW: changed this bit to match the comments above */

                        data = ptr->data;

                        (table->table)[val] = ptr->next;

                        free( ptr->key );

                        free( ptr );

                        table->count--; /* HW */

                        return data;

                  }

            }

      }



      /*

      ** If we get here, it means we didn't find the item in the table.

      ** Signal this by returning NULL.

      */



      return NULL;

}



/*

** free_table iterates the table, calling this repeatedly to free

** each individual node.  This, in turn, calls one or two other

** functions - one to free the storage used for the key, the other

** passes a pointer to the data back to a function defined by the user,

** process the data as needed.

*/



static void free_node( char *key, void *data )

{

      (void) data;



      assert( NULL != key );



      if( NULL != function )

      {

            function( hash_del( key, the_table ) );

      }

      else

            hash_del( key, the_table );

}



/*

** Frees a complete table by iterating over it and freeing each node.

** the second parameter is the address of a function it will call with a

** pointer to the data associated with each node.  This function is

** responsible for freeing the data, or doing whatever is needed with

** it.

*/



void hash_free_table( hash_table *table, void (*func)(void *) )

{

      function = func;

      the_table = table;



      hash_enumerate( table, free_node );

      free( table->table );

      table->table = NULL;

      table->size = 0;

      table->count = 0; /* HW */



      the_table = NULL;

      function = NULL;

}



/*

** Simply invokes the function given as the second parameter for each

** node in the table, passing it the key and the associated data.

*/



void hash_enumerate( hash_table *table, void (*func)(char *, void *) )

{

      unsigned i;

      bucket *temp;

      bucket *swap;



      for( i=0; i<table->size; i++ )

      {

            if( NULL != (table->table)[i] )

            {

                  /* HW: changed this loop */

                  temp = (table->table)[i];

                  while( NULL != temp )

                  {

                        /* HW: swap trick, in case temp is freed by 'func' */

                        swap = temp->next;

                        func( temp -> key, temp->data );

                        temp = swap;

                  }

            }

      }

}



/*      HW: added hash_sorted_enum()



      hash_sorted_enum is like hash_enumerate but gives

      sorted output. This is much slower than hash_enumerate, but

      sometimes nice for printing to a file...

*/



typedef struct sort_struct

      {

      char *key;

      void *data;

      } sort_struct;

static sort_struct *sortmap = NULL;



static int counter = 0;



/* HW: used as 'func' for hash_enumerate */

static void key_get( char *key, void *data )

{

      sortmap[ counter ].key = key;

      sortmap[ counter ].data = data;

      counter++;

}



/* HW: used for comparing the keys in qsort */

static int key_comp( const void* a, const void *b )

{

      return strcmp( (*(sort_struct*)a).key, (*(sort_struct*)b).key );

}



/*    HW: it's a compromise between speed and space. this one needs

      table->count * sizeof( sort_struct) memory.

      Another approach only takes count*sizeof(char*), but needs

      to hash_lookup the data of every key after sorting the key.

      returns 0 on malloc failure, 1 on success

*/

int hash_sorted_enum( hash_table *table, void (*func)( char *, void *) )

{

      int i;



      /* nothing to do ! */

      if( NULL == table || 0 == table->count || NULL == func )

            return 0;



      /* malloc an pointerarray for all hashkey's and datapointers */

      if( NULL == ( sortmap = (sort_struct*) malloc( sizeof( sort_struct ) * table->count)) )

            return 0;



      /* copy the pointers to the hashkey's */

      counter = 0;

      hash_enumerate( table, key_get );



      /* sort the pointers to the keys */

      qsort( sortmap, table->count, sizeof(sort_struct), key_comp );



      /* call the function for each node */

      for( i=0; i <abs( (table->count)); i++ )

      {

            func( sortmap[i].key, sortmap[i].data );

      } 



      /* free the pointerarray */

      free( sortmap );

      sortmap = NULL;



      return 1;

}



/* HW: changed testmain */

#define TEST

#ifdef TEST



#include <stdio.h>

//#include "snip_str.h" /* for strdup() */



FILE *o;



void fprinter(char *string, void *data)

{

      fprintf(o,"%s:    %s\n", string, (char *)data);

}



void printer(char *string, void *data)

{

      printf("%s:    %s\n", string, (char *)data);

}



/* function to pass to hash_free_table */

void strfree( void *d )

{

      /* any additional processing goes here (if you use structures as data) */

      /* free the datapointer */

      free(d);

}





int main(void)

{

      hash_table table;



      char *strings[] = {

            "The first string",

            "The second string",

            "The third string",

            "The fourth string",

            "A much longer string than the rest in this example.",

            "The last string",

            NULL

            };



      char *junk[] = {

            "The first data",

            "The second data",

            "The third data",

            "The fourth data",

            "The fifth datum",

            "The sixth piece of data"

            };



      int i;

      void *j;



      hash_construct_table(&table,211);



      /* I know, no checking on strdup ;-)), but using strdup

            to demonstrate hash_table_free with a functionpointer */

      for (i = 0; NULL != strings[i]; i++ )

            hash_insert( strings[i], strdup(junk[i]), &table );



      /* enumerating to a file */

      if( NULL != (o = fopen("HASH.HSH","wb")) )

      {

            fprintf( o, "%d strings in the table:\n\n", table.count );

            hash_enumerate( &table, fprinter );

            fprintf( o, "\nsorted by key:\n");

            hash_sorted_enum( &table, fprinter );

            fclose( o );

      }



      /* enumerating to screen */

      hash_sorted_enum( &table, printer );

      printf("\n");



      /* delete 3 strings, should be 3 left */

      for( i=0; i<3; i++ )

      {

            /* hash_del returns a pointer to the data */

            strfree( hash_del( strings[i], &table) );

      }

      hash_enumerate( &table, printer);



      for (i=0;NULL != strings[i];i++)

      {

            j = hash_lookup(strings[i], &table);

            if (NULL == j)

                  printf("\n'%s' is not in the table", strings[i]);

            else

                  printf("\n%s is still in the table.", strings[i]);

      }



      hash_free_table( &table, strfree );



      return 0;

}

#endif /* TEST */


--- NEW FILE: hash.h ---
/* HW: HenkJan Wolthuis, 1997 */

#ifndef HASH__H

#define HASH__H



#include <stddef.h>             /* For size_t   */

/*

** A hash table consists of an array of these buckets.      Each bucket

** holds a copy of the key, a pointer to the data associated with the

** key, and a pointer to the next bucket that collided with this one,

** if there was one.

*/



typedef struct bucket {

      char *key;

      void *data;

      struct bucket *next;

} bucket;



/*

** This is what you actually declare an instance of to create a table.

** You then call 'construct_table' with the address of this structure,

** and a guess at the size of the table.  Note that more nodes than this

** can be inserted in the table, but performance degrades as this

** happens.  Performance should still be quite adequate until 2 or 3

** times as many nodes have been inserted as the table was created with.

*/



typedef struct hash_table {

      size_t size;

      size_t count;     /* HW */

      bucket **table;

} hash_table;



/*

** This is used to construct the table.  If it doesn't succeed, it sets

** the table's size to 0, and the pointer to the table to NULL.

*/

/* HW: returns NULL if it fails */

hash_table *hash_construct_table(hash_table *table,size_t size);



/*

** Inserts a pointer to 'data' in the table, with a copy of 'key' as its

** key.  Note that this makes a copy of the key, but NOT of the

** associated data.

*/



void *hash_insert(char *key,void *data,struct hash_table *table);



/*

** Returns a pointer to the data associated with a key.  If the key has

** not been inserted in the table, returns NULL.

*/



void *hash_lookup(char *key,struct hash_table *table);



/*

** Deletes an entry from the table.  Returns a pointer to the data that

** was associated with the key so the calling code can dispose of it

** properly.

*/



void *hash_del(char *key,struct hash_table *table);



/*

** Goes through a hash table and calls the function passed to it

** for each node that has been inserted.  The function is passed

** a pointer to the key, and a pointer to the data associated

** with it.

*/



void hash_enumerate( hash_table *table,void (*func)(char *,void *));



/* HW: same as above, but sorted output ( sorted on 'key') */

int hash_sorted_enum( hash_table *table, void(*func)(char *, void*));



/*

** Frees a hash table.  For each node that was inserted in the table,

** it calls the function whose address it was passed, with a pointer

** to the data that was in the table.  The function is expected to

** free the data.  Typical usage would be:

** free_table(&table, free);

** if the data placed in the table was dynamically allocated, or:

** free_table(&table, NULL);

** if not.  ( If the parameter passed is NULL, it knows not to call

** any function with the data. )

*/



void hash_free_table(hash_table *table, void (*func)(void *));



#endif /* HASH__H */




-------------------------------------------------------
SF.Net email is sponsored by: Discover Easy Linux Migration Strategies
from IBM. Find simple to follow Roadmaps, straightforward articles,
informative Webcasts and more! Get everything you need to get up to
speed, fast. http://ads.osdn.com/?ad_id=7477&alloc_id=16492&op=click
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.