Initial commit: Complete open-source Decal rebuild

All 5 phases of the open-source Decal rebuild:

Phase 1: 14 decompiled .NET projects (Interop.*, Adapter, FileService, DecalUtil)
Phase 2: 10 native DLLs rewritten as C# COM servers with matching GUIDs
  - DecalDat, DHS, SpellFilter, DecalInput, DecalNet, DecalFilters
  - Decal.Core, DecalControls, DecalRender, D3DService
Phase 3: C++ shims for Inject.DLL (D3D9 hooking) and LauncherHook.DLL
Phase 4: DenAgent WinForms tray application
Phase 5: WiX installer and build script

25 C# projects building with 0 errors.
Native C++ projects require VS 2022 + Windows SDK (x86).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
erik 2026-02-08 18:27:56 +01:00
commit d1442e3747
1382 changed files with 170725 additions and 0 deletions

View file

@ -0,0 +1,16 @@
#pragma once
class ACMessage
{
public:
virtual BYTE *getData () = 0;
virtual DWORD getSize () = 0;
virtual DWORD getType () = 0;
};
class ACMessageSink
{
public:
virtual void onMessage( ACMessage& ) = 0;
virtual void onMessageOut( ACMessage& ) = 0;
};

View file

@ -0,0 +1,74 @@
// DecalNet.cpp : Implementation of DLL Exports.
// Note: Proxy/Stub Information
// To build a separate proxy/stub DLL,
// run nmake -f DecalNetps.mk in the project directory.
#include "stdafx.h"
#include "resource.h"
#include <initguid.h>
#include "DecalNet.h"
#include "DecalNet_i.c"
#include "NetService.h"
#include "WebRequest.h"
CComModule _Module;
BEGIN_OBJECT_MAP(ObjectMap)
OBJECT_ENTRY(CLSID_NetService, cNetService)
OBJECT_ENTRY(CLSID_WebRequest, cWebRequest)
END_OBJECT_MAP()
/////////////////////////////////////////////////////////////////////////////
// DLL Entry Point
extern "C"
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/)
{
if (dwReason == DLL_PROCESS_ATTACH)
{
_Module.Init(ObjectMap, hInstance, &LIBID_DecalNet);
DisableThreadLibraryCalls(hInstance);
}
else if (dwReason == DLL_PROCESS_DETACH)
_Module.Term();
return TRUE; // ok
}
/////////////////////////////////////////////////////////////////////////////
// Used to determine whether the DLL can be unloaded by OLE
STDAPI DllCanUnloadNow(void)
{
return (_Module.GetLockCount()==0) ? S_OK : S_FALSE;
}
/////////////////////////////////////////////////////////////////////////////
// Returns a class factory to create an object of the requested type
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
{
return _Module.GetClassObject(rclsid, riid, ppv);
}
/////////////////////////////////////////////////////////////////////////////
// DllRegisterServer - Adds entries to the system registry
STDAPI DllRegisterServer(void)
{
// registers object, typelib and all interfaces in typelib
return _Module.RegisterServer(TRUE);
}
/////////////////////////////////////////////////////////////////////////////
// DllUnregisterServer - Removes entries from the system registry
STDAPI DllUnregisterServer(void)
{
return _Module.UnregisterServer(TRUE);
}

View file

@ -0,0 +1,9 @@
; DecalNet.def : Declares the module parameters.
LIBRARY "DecalNet.DLL"
EXPORTS
DllCanUnloadNow PRIVATE
DllGetClassObject PRIVATE
DllRegisterServer PRIVATE
DllUnregisterServer PRIVATE

View file

@ -0,0 +1,341 @@
# Microsoft Developer Studio Project File - Name="DecalNet" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
CFG=DecalNet - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "DecalNet.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "DecalNet.mak" CFG="DecalNet - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "DecalNet - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE "DecalNet - Win32 Unicode Debug" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE "DecalNet - Win32 Release MinSize" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE "DecalNet - Win32 Unicode Release MinSize" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
MTL=midl.exe
RSC=rc.exe
!IF "$(CFG)" == "DecalNet - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "..\Debug"
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 1
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MTd /W3 /Gm /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /Yu"stdafx.h" /FD /GZ /c
# ADD CPP /nologo /MDd /W3 /Gm /Gi /GX /ZI /Od /Ob0 /I "..\Include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /Yu"stdafx.h" /FD /GZ /c
# ADD MTL /nologo /I "..\Include" /Oicf
# ADD BASE RSC /l 0x1009 /d "_DEBUG"
# ADD RSC /l 0x1009 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib urlmon.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept
# Begin Custom Build - Performing registration
OutDir=.\..\Debug
TargetPath=\Projects\decaldev2\source\Debug\DecalNet.dll
InputPath=\Projects\decaldev2\source\Debug\DecalNet.dll
SOURCE="$(InputPath)"
"$(OutDir)\regsvr32.trg" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
regsvr32 /s /c "$(TargetPath)"
echo regsvr32 exec. time > "$(OutDir)\regsvr32.trg"
# End Custom Build
!ELSEIF "$(CFG)" == "DecalNet - Win32 Unicode Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "DebugU"
# PROP BASE Intermediate_Dir "DebugU"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "DebugU"
# PROP Intermediate_Dir "DebugU"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MTd /W3 /Gm /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_USRDLL" /D "_UNICODE" /Yu"stdafx.h" /FD /GZ /c
# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "..\Include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_USRDLL" /D "_UNICODE" /Yu"stdafx.h" /FD /GZ /c
# ADD MTL /nologo /I "..\Include" /Oicf
# ADD BASE RSC /l 0x1009 /d "_DEBUG"
# ADD RSC /l 0x1009 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib urlmon.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept
# Begin Custom Build - Performing registration
OutDir=.\DebugU
TargetPath=.\DebugU\DecalNet.dll
InputPath=.\DebugU\DecalNet.dll
SOURCE="$(InputPath)"
"$(OutDir)\regsvr32.trg" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
if "%OS%"=="" goto NOTNT
if not "%OS%"=="Windows_NT" goto NOTNT
regsvr32 /s /c "$(TargetPath)"
echo regsvr32 exec. time > "$(OutDir)\regsvr32.trg"
goto end
:NOTNT
echo Warning : Cannot register Unicode DLL on Windows 95
:end
# End Custom Build
!ELSEIF "$(CFG)" == "DecalNet - Win32 Release MinSize"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "ReleaseMinSize"
# PROP BASE Intermediate_Dir "ReleaseMinSize"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "..\Release"
# PROP Intermediate_Dir "ReleaseMinSize"
# PROP Ignore_Export_Lib 1
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MT /W3 /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "_ATL_DLL" /D "_ATL_MIN_CRT" /Yu"stdafx.h" /FD /c
# ADD CPP /nologo /MD /W3 /GX- /Zi /Oa /Og /Oi /Os /Oy /Ob1 /Gf /Gy /I "..\Include" /D "_MBCS" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_USRDLL" /Yu"stdafx.h" /FD /c
# ADD MTL /nologo /I "..\Include" /Oicf
# ADD BASE RSC /l 0x1009 /d "NDEBUG"
# ADD RSC /l 0x1009 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib urlmon.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept /libpath:"..\Release"
# Begin Custom Build - Performing registration
OutDir=.\..\Release
TargetPath=\Projects\decaldev2\source\Release\DecalNet.dll
InputPath=\Projects\decaldev2\source\Release\DecalNet.dll
SOURCE="$(InputPath)"
"$(OutDir)\regsvr32.trg" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
regsvr32 /s /c "$(TargetPath)"
echo regsvr32 exec. time > "$(OutDir)\regsvr32.trg"
# End Custom Build
!ELSEIF "$(CFG)" == "DecalNet - Win32 Unicode Release MinSize"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "ReleaseUMinSize"
# PROP BASE Intermediate_Dir "ReleaseUMinSize"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "ReleaseUMinSize"
# PROP Intermediate_Dir "ReleaseUMinSize"
# PROP Ignore_Export_Lib 1
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MT /W3 /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_USRDLL" /D "_UNICODE" /D "_ATL_DLL" /D "_ATL_MIN_CRT" /Yu"stdafx.h" /FD /c
# ADD CPP /nologo /MT /W3 /GX /Zi /O1 /I "..\Include" /D "_UNICODE" /D "_ATL_DLL" /D "_ATL_MIN_CRT" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_USRDLL" /Yu"stdafx.h" /FD /c
# ADD MTL /nologo /I "..\Include" /Oicf
# ADD BASE RSC /l 0x1009 /d "NDEBUG"
# ADD RSC /l 0x1009 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib urlmon.lib libctiny.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept /libpath:"..\Release"
# Begin Custom Build - Performing registration
OutDir=.\ReleaseUMinSize
TargetPath=.\ReleaseUMinSize\DecalNet.dll
InputPath=.\ReleaseUMinSize\DecalNet.dll
SOURCE="$(InputPath)"
"$(OutDir)\regsvr32.trg" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
if "%OS%"=="" goto NOTNT
if not "%OS%"=="Windows_NT" goto NOTNT
regsvr32 /s /c "$(TargetPath)"
echo regsvr32 exec. time > "$(OutDir)\regsvr32.trg"
goto end
:NOTNT
echo Warning : Cannot register Unicode DLL on Windows 95
:end
# End Custom Build
!ENDIF
# Begin Target
# Name "DecalNet - Win32 Debug"
# Name "DecalNet - Win32 Unicode Debug"
# Name "DecalNet - Win32 Release MinSize"
# Name "DecalNet - Win32 Unicode Release MinSize"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\DecalNet.cpp
# End Source File
# Begin Source File
SOURCE=.\DecalNet.def
# End Source File
# Begin Source File
SOURCE=..\Include\DecalNet.idl
# ADD MTL /tlb "DecalNet.tlb" /h "..\Include\DecalNet.h" /iid "..\Include\DecalNet_i.c"
# End Source File
# Begin Source File
SOURCE=.\DecalNet.rc
# End Source File
# Begin Source File
SOURCE=.\FilterAdapterV1.cpp
# End Source File
# Begin Source File
SOURCE=.\Message.cpp
# End Source File
# Begin Source File
SOURCE=.\MessageLoaders.cpp
# End Source File
# Begin Source File
SOURCE=.\MessageParsers.cpp
# End Source File
# Begin Source File
SOURCE=.\MessageRoot.cpp
# End Source File
# Begin Source File
SOURCE=.\MessageStruct.cpp
# End Source File
# Begin Source File
SOURCE=.\MessageVector.cpp
# End Source File
# Begin Source File
SOURCE=.\NetService.cpp
# End Source File
# Begin Source File
SOURCE=.\ProtocolStack.cpp
# End Source File
# Begin Source File
SOURCE=.\StdAfx.cpp
# ADD CPP /Yc"stdafx.h"
# End Source File
# Begin Source File
SOURCE=.\WebRequest.cpp
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=.\DecalNetCP.h
# End Source File
# Begin Source File
SOURCE=..\Include\DecalNetImpl.h
# End Source File
# Begin Source File
SOURCE=.\FilterAdapterV1.h
# End Source File
# Begin Source File
SOURCE=.\Message.h
# End Source File
# Begin Source File
SOURCE=.\MessageImpl.h
# End Source File
# Begin Source File
SOURCE=.\MessageLoaders.h
# End Source File
# Begin Source File
SOURCE=.\MessageParsers.h
# End Source File
# Begin Source File
SOURCE=.\MessageRoot.h
# End Source File
# Begin Source File
SOURCE=.\MessageStruct.h
# End Source File
# Begin Source File
SOURCE=.\MessageVector.h
# End Source File
# Begin Source File
SOURCE=.\NetService.h
# End Source File
# Begin Source File
SOURCE=.\ProtocolStack.h
# End Source File
# Begin Source File
SOURCE=.\Resource.h
# End Source File
# Begin Source File
SOURCE=.\StdAfx.h
# End Source File
# Begin Source File
SOURCE=.\WebRequest.h
# End Source File
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
# Begin Source File
SOURCE=.\NetService.rgs
# End Source File
# Begin Source File
SOURCE=.\WebRequest.rgs
# End Source File
# End Group
# End Target
# End Project

134
Native/DecalNet/DecalNet.rc Normal file
View file

@ -0,0 +1,134 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#include "..\Include\DecalVersion.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""winres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"1 TYPELIB ""DecalNet.tlb""\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION DECAL_MAJOR, DECAL_MINOR, DECAL_BUGFIX, DECAL_RELEASE
PRODUCTVERSION DECAL_MAJOR, DECAL_MINOR, DECAL_BUGFIX, DECAL_RELEASE
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x4L
FILETYPE 0x2L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "Comments", "DecalNet is the core module that processes the network messages between the client and the server"
VALUE "FileDescription", "DecalNet Module"
VALUE "FileVersion", DECAL_VERSION_STRING
VALUE "InternalName", "DecalNet"
VALUE "LegalCopyright", "Copyright 2001"
VALUE "OriginalFilename", "DecalNet.DLL"
VALUE "ProductName", "DecalNet Module"
VALUE "ProductVersion", DECAL_VERSION_STRING
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
/////////////////////////////////////////////////////////////////////////////
//
// String Table
//
STRINGTABLE
BEGIN
IDS_PROJNAME "DecalNet"
END
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// English (Canada) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENC)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_CAN
#pragma code_page(1252)
#endif //_WIN32
/////////////////////////////////////////////////////////////////////////////
//
// REGISTRY
//
IDR_NETSERVICE REGISTRY "NetService.rgs"
IDR_WEBREQUEST REGISTRY "WebRequest.rgs"
#endif // English (Canada) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
1 TYPELIB "DecalNet.tlb"
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,60 @@
#ifndef _DECALNETCP_H_
#define _DECALNETCP_H_
template <class T>
class CProxyIWebRequestEvents : public IConnectionPointImpl<T, &DIID_IWebRequestEvents, CComDynamicUnkArray>
{
//Warning this class may be recreated by the wizard.
public:
HRESULT Fire_Begin()
{
CComVariant varResult;
T* pT = static_cast<T*>(this);
int nConnectionIndex;
int nConnections = m_vec.GetSize();
for (nConnectionIndex = 0; nConnectionIndex < nConnections; nConnectionIndex++)
{
pT->Lock();
CComPtr<IUnknown> sp = m_vec.GetAt(nConnectionIndex);
pT->Unlock();
IDispatch* pDispatch = reinterpret_cast<IDispatch*>(sp.p);
if (pDispatch != NULL)
{
VariantClear(&varResult);
DISPPARAMS disp = { NULL, NULL, 0, 0 };
pDispatch->Invoke(0x1, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &disp, &varResult, NULL, NULL);
}
}
return varResult.scode;
}
HRESULT Fire_End(LONG nResultCode, BSTR strText)
{
CComVariant varResult;
T* pT = static_cast<T*>(this);
int nConnectionIndex;
CComVariant* pvars = new CComVariant[2];
int nConnections = m_vec.GetSize();
for (nConnectionIndex = 0; nConnectionIndex < nConnections; nConnectionIndex++)
{
pT->Lock();
CComPtr<IUnknown> sp = m_vec.GetAt(nConnectionIndex);
pT->Unlock();
IDispatch* pDispatch = reinterpret_cast<IDispatch*>(sp.p);
if (pDispatch != NULL)
{
VariantClear(&varResult);
pvars[1] = nResultCode;
pvars[0] = strText;
DISPPARAMS disp = { pvars, NULL, 2, 0 };
pDispatch->Invoke(0x2, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &disp, &varResult, NULL, NULL);
}
}
delete[] pvars;
return varResult.scode;
}
};
#endif

View file

@ -0,0 +1,11 @@
LIBRARY "DecalNetPS"
DESCRIPTION 'Proxy/Stub DLL'
EXPORTS
DllGetClassObject @1 PRIVATE
DllCanUnloadNow @2 PRIVATE
GetProxyDllInfo @3 PRIVATE
DllRegisterServer @4 PRIVATE
DllUnregisterServer @5 PRIVATE

View file

@ -0,0 +1,16 @@
DecalNetps.dll: dlldata.obj DecalNet_p.obj DecalNet_i.obj
link /dll /out:DecalNetps.dll /def:DecalNetps.def /entry:DllMain dlldata.obj DecalNet_p.obj DecalNet_i.obj \
kernel32.lib rpcndr.lib rpcns4.lib rpcrt4.lib oleaut32.lib uuid.lib \
.c.obj:
cl /c /Ox /DWIN32 /D_WIN32_WINNT=0x0400 /DREGISTER_PROXY_DLL \
$<
clean:
@del DecalNetps.dll
@del DecalNetps.lib
@del DecalNetps.exp
@del dlldata.obj
@del DecalNet_p.obj
@del DecalNet_i.obj

View file

@ -0,0 +1,21 @@
// FilterAdapterV1.cpp
// Implementation of class cFilterAdapterV1
#include "Stdafx.h"
#include "FilterAdapterV1.h"
HRESULT cFilterAdapterV1::init ( REFCLSID clsid )
{
HRESULT hRes = ::CoCreateInstance ( clsid, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown,
reinterpret_cast< LPVOID * > ( &m_pV1 ) );
_ASSERTE( SUCCEEDED ( hRes ) );
return hRes;
}
STDMETHODIMP cFilterAdapterV1::DispatchServer ( IMessage2 *pMessage )
{
CComPtr<INetworkFilter> pNF;
HRESULT hRes = m_pV1->QueryInterface ( &pNF );
_ASSERTE( SUCCEEDED ( hRes ) );
return pNF->Dispatch ( pMessage );
}

View file

@ -0,0 +1,28 @@
// FilterAdapterV1.h
// Declaration of the filter adapter for V1 filters
#ifndef __FILTERADAPTER_H
#define __FILTERADAPTER_H
#include <DecalNetImpl.h>
class cFilterAdapterV1
: public CComObjectRootEx< CComMultiThreadModel >,
public ISoloNetworkFilterImpl< cFilterAdapterV1 >
{
CComPtr<IUnknown> m_pV1;
public:
HRESULT init ( REFCLSID clsid );
BEGIN_COM_MAP(cFilterAdapterV1)
COM_INTERFACE_ENTRY(INetworkFilter2)
COM_INTERFACE_ENTRY_AGGREGATE_BLIND(m_pV1.p)
END_COM_MAP()
public:
// INetworkFilter2
STDMETHOD(DispatchServer)(IMessage2 *pMessage);
};
#endif

393
Native/DecalNet/Message.cpp Normal file
View file

@ -0,0 +1,393 @@
// Message.cpp : Implementation of cMessage
#include "stdafx.h"
#include "DecalNet.h"
#include "NetService.h"
#include "Message.h"
#include "MessageLoaders.h"
#include "MessageParsers.h"
#include "MessageRoot.h"
cMessage::cFieldList::iterator cMessage::cLoadContext::lookupField( cMessage::cMessageElement *pElement )
{
for( cLoadContext *pContext = this; pContext != NULL; pContext = pContext->m_pParent )
{
for( cFieldList::iterator i = pContext->m_pMessage->m_fields.begin() + pContext->m_dwOffset; i != pContext->m_pMessage->m_fields.end(); i += i->m_nOwns )
{
if( i->m_pSchema == pElement )
return i;
}
}
return m_pMessage->m_fields.end();
}
void cMessage::cMessageSchema::loadSchema( MSXML::IXMLDOMDocumentPtr &pDoc, DWORD dwSchema )
{
TCHAR szQuery[ 255 ];
::_stprintf( szQuery, _T( "/schema/messages/message[@type='%04X']" ), dwSchema );
MSXML::IXMLDOMElementPtr pMessage = pDoc->selectSingleNode( szQuery );
if( pMessage.GetInterfacePtr() == NULL )
// Nothing here, so we create a valid but empty message
return;
cElementParser::cContext c( &m_members );
c.parseChildren( pMessage );
}
void cMessage::init()
{
// Load the schema
CComBSTR strTemplate( _T( "%decal%\\messages.xml" ) ),
strPath;
m_pService->m_pDecal->MapPath( strTemplate, &strPath );
g_pXML.CreateInstance( __uuidof( MSXML::DOMDocument ) );
BOOL bSuccess = g_pXML->load( strPath.m_str );
if( ! bSuccess )
{
USES_CONVERSION;
std::string szXML;
DecryptXML( OLE2A( strPath.m_str ), szXML );
if( szXML != "" )
bSuccess = g_pXML->loadXML( _bstr_t( szXML.c_str() ) );
}
// Initialize our schema helper objects
cFieldLoader::init();
cElementParser::init();
}
void cMessage::DecryptXML( const char *szPath, std::string &szXML )
{
if( szPath == NULL )
{
szXML = "";
return;
}
FILE *f = fopen( szPath, "rb" );
if( f == NULL )
{
szXML = "";
return;
}
szXML.clear();
unsigned char szBuffer[1025];
try
{
CCryptProv crypt;
if( crypt.Initialize( PROV_RSA_FULL, "Decal_Memlocs", MS_DEF_PROV ) == NTE_BAD_KEYSET )
crypt.Initialize( PROV_RSA_FULL, "Decal_Memlocs", MS_DEF_PROV, CRYPT_NEWKEYSET );
CCryptMD5Hash hash;
hash.Initialize( crypt );
hash.AddString( DECAL_KEY );
CCryptDerivedKey key;
key.Initialize( crypt, hash );
DWORD dwDecLen = 0;
while( ! feof(f) )
{
memset( szBuffer, 0, sizeof( szBuffer ) );
dwDecLen = fread( szBuffer, 1, 1024, f );
key.Decrypt( feof(f), (BYTE *) szBuffer, &dwDecLen );
szXML += (char *)szBuffer;
}
key.Destroy();
hash.Destroy();
crypt.Release();
}
catch( ... )
{
// crap...
szXML = "";
}
fclose( f );
}
void cMessage::term()
{
g_schema.clear();
cElementParser::term();
cFieldLoader::term();
if( g_pXML.GetInterfacePtr() != NULL )
g_pXML.Release();
}
/////////////////////////////////////////////////////////////////////////////
// cMessage
cMessage::cMessage()
: m_nType( 0 ),
m_pStartCrack( NULL ),
m_pEndCrack( NULL ),
m_pEndData( NULL ),
m_pSchema( NULL ),
m_pRoot( NULL )
{
}
cMessage::cFieldList::iterator cMessage::getFieldFromElement( cMessageElement *pElement )
{
for( cFieldList::iterator i = m_fields.begin(); i != m_fields.end(); i += i->m_nOwns )
{
cMessageElement *pSchema = i->m_pSchema;
if( pSchema == pElement )
break;
}
return i;
}
void cMessage::crackMessage( BYTE *pBody, DWORD dwSize )
{
m_pStartCrack = pBody;
m_pEndData = pBody + dwSize + sizeof( DWORD );
m_nType = *reinterpret_cast< long * >( pBody );
m_fields.clear();
m_pEndCrack = m_pStartCrack + sizeof( long );
m_pSchema = NULL;
}
bool cMessage::loadNextElement()
{
if( m_iLoaded == m_pSchema->m_members.end() )
return false;
// Attempt to load what we've got
cLoadContext context( this );
if( !m_iLoaded->get()->load( context ) )
{
m_iLoaded = m_pSchema->m_members.end();
return false;
}
++ m_iLoaded;
return true;
}
void cMessage::loadAllElements()
{
if( m_pSchema == NULL )
{
// First look up the message to see if it's already decoded
cMessageSchemaMap::iterator i_schema = g_schema.find( m_nType );
if( i_schema == g_schema.end() )
{
// Make a new one
m_pSchema = new cMessageSchema;
m_pSchema->loadSchema( g_pXML, m_nType );
g_schema.insert( cMessageSchemaMap::value_type( m_nType, VSBridge::auto_ptr< cMessageSchema >( m_pSchema ) ) );
}
else
m_pSchema = i_schema->second.get();
// At this point we have "a" schema of some quality
// set up the cursors
m_iLoaded = m_pSchema->m_members.begin();
}
if( m_iLoaded == m_pSchema->m_members.end() )
return;
cLoadContext context( this );
while ( m_iLoaded != m_pSchema->m_members.end () )
{
if ( m_iLoaded->get()->load ( context ) )
++ m_iLoaded;
else
m_iLoaded = m_pSchema->m_members.end();
}
}
STDMETHODIMP cMessage::get_Type(long *pVal)
{
_ASSERTE( pVal != NULL );
*pVal = *reinterpret_cast< long * >( m_pStartCrack );
return S_OK;
}
STDMETHODIMP cMessage::get_Data(VARIANT *pVal)
{
long nSize = m_pEndData - m_pStartCrack - sizeof( DWORD );
if( nSize == 0 )
{
// Special case, this message is entirely cracked - return NULL
pVal->vt = VT_NULL;
pVal->intVal = 0;
return S_OK;
}
// We've got some data to share
SAFEARRAYBOUND sab = { nSize, 0 };
SAFEARRAY *pArray = ::SafeArrayCreate( VT_UI1, 1, &sab );
::SafeArrayAllocData( pArray );
LPVOID pvData;
::SafeArrayAccessData( pArray, &pvData );
::memcpy( pvData, m_pStartCrack, nSize );
::SafeArrayUnaccessData( pArray );
pVal->vt = VT_ARRAY | VT_UI1;
pVal->parray = pArray;
return S_OK;
}
STDMETHODIMP cMessage::get_Begin(IMessageIterator **pVal)
{
if( m_pRoot == NULL )
{
// Create a new message root object
CComObject< cMessageRoot > *pRoot;
CComObject< cMessageRoot >::CreateInstance( &pRoot );
// Do an extra addref so this object sticks around after the client is done with it
pRoot->AddRef();
pRoot->init( this );
m_pRoot = pRoot;
}
m_pRoot->Reset();
if( m_pSchema == NULL )
{
// First look up the message to see if it's already decoded
cMessageSchemaMap::iterator i_schema = g_schema.find( m_nType );
if( i_schema == g_schema.end() )
{
// Make a new one
m_pSchema = new cMessageSchema;
m_pSchema->loadSchema( g_pXML, m_nType );
g_schema.insert( cMessageSchemaMap::value_type( m_nType, VSBridge::auto_ptr< cMessageSchema >( m_pSchema ) ) );
}
else
m_pSchema = i_schema->second.get();
// At this point we have "a" schema of some quality
// set up the cursors
m_iLoaded = m_pSchema->m_members.begin();
}
return m_pRoot->QueryInterface( IID_IMessageIterator, reinterpret_cast< void ** >( pVal ) );
}
STDMETHODIMP cMessage::get_Member(VARIANT vName, VARIANT *pVal)
{
loadAllElements ();
::VariantInit (pVal);
if( vName.vt == VT_BSTR )
{
_bstr_t bstrName = vName;
// Iterate over the fields and return our match - in this loop we'll do incremental
// cracking, so it's a little messy. When we hit the end, we look to see if there are
// more uncracked fields
int nFieldCount = m_fields.size();
for( int nField = 0; nField != nFieldCount; nField += m_fields[ nField ].m_nOwns )
{
if( m_fields[ nField ].m_pSchema->m_strName == bstrName )
{
m_fields[ nField ].m_pSchema->getValue( this, m_fields.begin() + nField, pVal );
return S_OK;
}
}
pVal->vt = VT_EMPTY;
return S_OK;
}
// Attempt to convert it into an index
HRESULT hRes = ::VariantChangeType( &vName, &vName, 0, VT_I4 );
if( FAILED( hRes ) )
{
_ASSERTE( FALSE );
return hRes;
}
// Check if the value is in range
long nIndex = vName.lVal;
if( nIndex < 0 )
{
_ASSERTE( nIndex >= 0 );
return E_INVALIDARG;
}
// Now, one problem is we aren't exactly sure how big the array is, so we have to walk
// through the fields, skipping appropriately
for( cFieldList::iterator i = m_fields.begin(); i != m_fields.end(); i += i->m_nOwns, -- nIndex )
{
if( nIndex == 0 )
{
// We've found the index - extract the value
i->m_pSchema->getValue( this, i, pVal );
return S_OK;
}
}
// The index was too high
_ASSERTE( FALSE );
return E_INVALIDARG;
}
STDMETHODIMP cMessage::get_MemberName(long nIndex, BSTR *pVal)
{
loadAllElements ();
_ASSERTE( nIndex >= 0 );
_ASSERTE( pVal != NULL );
USES_CONVERSION;
for( cFieldList::iterator i = m_fields.begin(); i != m_fields.end(); i += i->m_nOwns, -- nIndex )
{
if( nIndex == 0 )
{
// We've found the index - extract the value
*pVal = OLE2BSTR( i->m_pSchema->m_strName );
return S_OK;
}
}
// The index was too high
return E_INVALIDARG;
}
STDMETHODIMP cMessage::get_Count(long *pVal)
{
loadAllElements ();
_ASSERTE( pVal != NULL );
*pVal = 0;
for( cFieldList::iterator i = m_fields.begin(); i != m_fields.end(); i += i->m_nOwns, ++ ( *pVal ) );
return S_OK;
}

161
Native/DecalNet/Message.h Normal file
View file

@ -0,0 +1,161 @@
// Message.h : Declaration of the cMessage
#ifndef __MESSAGE_H_
#define __MESSAGE_H_
#include "resource.h" // main symbols
class cNetService;
class cMessageRoot;
// the public key to unencrypt xmls
#include "..\include\DecalKey.h"
/////////////////////////////////////////////////////////////////////////////
// cMessage
class ATL_NO_VTABLE cMessage :
public CComObjectRootEx<CComMultiThreadModel>,
public IDispatchImpl< IMessage2, &IID_IMessage2, &LIBID_DecalNet >
{
public:
void DecryptXML( const char *szFilename, std::string &szXML );
class cMessageElement;
class cField
{
public:
cMessageElement *m_pSchema;
void *m_pvData;
int m_nOwns;
CComPtr< IMessageIterator > m_pDisp;
};
typedef std::vector< cField > cFieldList;
class cLoadContext
{
cMessage *m_pMessage;
DWORD m_dwOffset;
cLoadContext *m_pParent;
public:
cLoadContext( cMessage *pMessage )
: m_pMessage( pMessage ),
m_dwOffset( 0 ),
m_pParent( NULL )
{
}
cLoadContext( cLoadContext *pParent )
: m_pMessage( pParent->m_pMessage ),
m_dwOffset( m_pMessage->m_fields.size() ),
m_pParent( pParent )
{
}
cFieldList::iterator lookupField( cMessageElement *pElement );
DWORD addField( cMessageElement *pElement, void *pvData )
{
cField f;
f.m_pSchema = pElement;
f.m_pvData = pvData;
f.m_nOwns = 1;
m_pMessage->m_fields.push_back( f );
return m_pMessage->m_fields.size();
}
void groupField( DWORD dwIndex )
{
m_pMessage->m_fields[ dwIndex - 1 ].m_nOwns += m_pMessage->m_fields.size() - dwIndex;
}
cMessage *getMessage()
{
return m_pMessage;
}
};
class cMessageElement
{
public:
_bstr_t m_strName;
virtual ~cMessageElement()
{
}
// Decodes from the current point and returns
// the pointer advanced by a certain number of offsets
virtual bool load( cLoadContext &context ) = 0;
virtual void getValue( cMessage *pMsg, cFieldList::iterator i, LPVARIANT pDest ) = 0;
virtual long getNumber( cFieldList::iterator i )
{
// Default implementation fails
_ASSERTE( FALSE );
return 0;
}
};
typedef std::vector< VSBridge::auto_ptr< cMessageElement > > cElementList;
class cMessageSchema
{
public:
cElementList m_members;
void loadSchema( MSXML::IXMLDOMDocumentPtr &pDoc, DWORD dwSchema );
bool parseChildren( cElementList &list, MSXML::IXMLDOMElementPtr &pElement );
};
cNetService *m_pService;
typedef std::map< DWORD, VSBridge::auto_ptr< cMessageSchema > > cMessageSchemaMap;
MSXML::IXMLDOMDocumentPtr g_pXML;
cMessageSchemaMap g_schema;
void init();
void term();
cMessage();
cFieldList m_fields;
long m_nType;
cMessageSchema *m_pSchema;
cFieldList::iterator getFieldFromElement( cMessageElement *pElement );
BYTE *m_pStartCrack,
*m_pEndCrack,
*m_pEndData;
void crackMessage( BYTE *pBody, DWORD dwSize );
cElementList::iterator m_iLoaded;
cMessageRoot *m_pRoot;
bool loadNextElement();
void loadAllElements();
BEGIN_COM_MAP(cMessage)
COM_INTERFACE_ENTRY(IMessage2)
COM_INTERFACE_ENTRY(IMessage)
COM_INTERFACE_ENTRY(IDispatch)
END_COM_MAP()
// IMessage
public:
STDMETHOD(get_Count)(/*[out, retval]*/ long *pVal);
STDMETHOD(get_MemberName)(long nIndex, /*[out, retval]*/ BSTR *pVal);
STDMETHOD(get_Member)(VARIANT vIndex, /*[out, retval]*/ VARIANT *pVal);
STDMETHOD(get_Begin)(/*[out, retval]*/ IMessageIterator * *pVal);
STDMETHOD(get_Data)(/*[out, retval]*/ VARIANT *pVal);
STDMETHOD(get_Type)(/*[out, retval]*/ long *pVal);
};
#endif //__MESSAGE_H_

View file

@ -0,0 +1,363 @@
// MessageImpl.h
// Declaration of helper classes for implementing the IMessageMembers interface
#ifndef __MESSAGEIMPL_H
#define __MESSAGEIMPL_H
#include "Message.h"
template< class ImplT >
class ATL_NO_VTABLE IMessageIteratorImpl
: public IDispatchImpl< IMessageIterator, &__uuidof( IMessageIterator ), &LIBID_DecalNet >
{
public:
enum { eEndIndex = 0xFFFFFFFF };
cMessage *getSource();
DWORD getStartIndex();
DWORD getEndIndex();
DWORD m_dwIterator;
long m_nIndex;
void init()
{
m_nIndex = -1;
}
DWORD getNextIndex( DWORD dwIndex )
{
DWORD dwNextIndex = dwIndex + ( static_cast< ImplT * >( this )->getSource()->m_fields.begin() + dwIndex )->m_nOwns;
if( dwNextIndex == static_cast< ImplT * >( this )->getEndIndex() )
return eEndIndex;
return dwNextIndex;
}
DWORD getNextIndex()
{
if( m_nIndex == -1 )
{
DWORD dwIndex = static_cast< ImplT * >( this )->getStartIndex();
if ( dwIndex == static_cast< ImplT * >( this )->getEndIndex () )
// This was 0 size
return eEndIndex;
return dwIndex;
}
return static_cast< ImplT * >( this )->getNextIndex( m_dwIterator );
}
HRESULT advanceToIndex( long nIndex )
{
if( nIndex <= m_nIndex )
{
_ASSERT( FALSE );
return E_INVALIDARG;
}
int nCurIndex = m_nIndex;
for( DWORD dwIterator = static_cast< ImplT * >( this )->getNextIndex(); dwIterator != eEndIndex; dwIterator = static_cast< ImplT * >( this )->getNextIndex( dwIterator ) )
{
// Reset the counter
++ nCurIndex;
if( nCurIndex == nIndex )
{
m_dwIterator = dwIterator;
m_nIndex = nCurIndex;
return S_OK;
}
}
// The advance went off the edge
m_dwIterator = eEndIndex;
return S_FALSE;
}
HRESULT advanceToName( BSTR strName )
{
int nIndex = m_nIndex;
for( DWORD dwIterator = static_cast< ImplT * >( this )->getNextIndex(); dwIterator != eEndIndex; dwIterator = static_cast< ImplT * >( this )->getNextIndex( dwIterator ) )
{
++ nIndex;
if( ::VarBstrCmp( strName, ( static_cast< ImplT * >( this )->getSource()->m_fields.begin() + dwIterator )->m_pSchema->m_strName, LOCALE_USER_DEFAULT, 0 ) == VARCMP_EQ )
{
// We've found the field
m_nIndex = nIndex;
m_dwIterator = dwIterator;
return S_OK;
}
}
return S_FALSE;
}
HRESULT advanceNext()
{
m_dwIterator = static_cast< ImplT * >( this )->getNextIndex();
if( m_dwIterator == eEndIndex )
return S_FALSE;
++ m_nIndex;
return S_OK;
}
STDMETHOD(get_Current)(VARIANT *pData)
{
if( pData == NULL )
{
_ASSERT( FALSE );
return E_POINTER;
}
if( m_dwIterator == eEndIndex )
{
pData->vt = VT_NULL;
return E_FAIL;
}
cMessage::cFieldList::iterator i = static_cast< ImplT * >( this )->getSource()->m_fields.begin() + m_dwIterator;
i->m_pSchema->getValue( static_cast< ImplT * >( this )->getSource(), i, pData );
return S_OK;
}
STDMETHOD(get_MemberName)( BSTR *pstrName )
{
if( pstrName == NULL )
{
_ASSERT( FALSE );
return E_POINTER;
}
if( m_dwIterator == eEndIndex )
return E_FAIL;
cMessage::cFieldList::iterator i = static_cast< ImplT * >( this )->getSource()->m_fields.begin() + m_dwIterator;
*pstrName = SysAllocString( i->m_pSchema->m_strName );
return S_OK;
}
STDMETHOD(get_Index)( long *pnIndex )
{
if( pnIndex == NULL )
{
_ASSERT( FALSE );
return E_POINTER;
}
if( m_dwIterator == eEndIndex )
return E_FAIL;
*pnIndex = m_nIndex;
return S_OK;
}
STDMETHOD(get_Next)( VARIANT vIndex, LPVARIANT pvValue )
{
if( pvValue == NULL )
{
_ASSERT( FALSE );
return E_POINTER;
}
HRESULT hRes;
if( vIndex.vt == VT_ERROR )
// Error value indicates the optional value was not filled
hRes = advanceNext();
else if( vIndex.vt == VT_BSTR )
hRes = advanceToName( vIndex.bstrVal );
else
{
// Try and convert it to a long
HRESULT hResConv = ::VariantChangeType( &vIndex, &vIndex, 0, VT_I4 );
if( FAILED( hResConv ) )
{
_ASSERT( FALSE );
return E_INVALIDARG;
}
hRes = advanceToIndex( vIndex.lVal );
}
if( hRes == S_FALSE )
{
pvValue->vt = VT_NULL;
return hRes;
}
cMessage::cFieldList::iterator i = static_cast< ImplT * >( this )->getSource()->m_fields.begin() + m_dwIterator;
i->m_pSchema->getValue( static_cast< ImplT * >( this )->getSource(), i, pvValue );
return S_OK;
}
STDMETHOD(get_NextString)(BSTR Name, BSTR *pValue)
{
VARIANT v;
v.vt = VT_BSTR;
v.bstrVal = Name;
VARIANT vOut;
HRESULT hRes = get_Next( v, &vOut );
if( hRes == S_FALSE )
return E_FAIL;
if( vOut.vt != VT_BSTR )
{
_ASSERT( FALSE );
return E_FAIL;
}
*pValue = vOut.bstrVal;
return S_OK;
}
STDMETHOD(get_NextInt)(BSTR Name, long *pValue)
{
VARIANT v;
v.vt = VT_BSTR;
v.bstrVal = Name;
VARIANT vOut;
HRESULT hRes = get_Next( v, &vOut );
if( hRes == S_FALSE )
return E_FAIL;
if( vOut.vt == VT_I4 )
*pValue = vOut.lVal;
else if( vOut.vt == VT_I2 )
*pValue = vOut.iVal;
else if ( vOut.vt == VT_UI1 )
*pValue = vOut.bVal;
else
{
_ASSERT( FALSE );
return E_FAIL;
}
return S_OK;
}
STDMETHOD(get_NextFloat)(BSTR Name, float *pValue)
{
VARIANT v;
v.vt = VT_BSTR;
v.bstrVal = Name;
VARIANT vOut;
HRESULT hRes = get_Next( v, &vOut );
if( hRes == S_FALSE )
return E_FAIL;
if( vOut.vt == VT_R4 )
*pValue = vOut.fltVal;
else if( vOut.vt == VT_R8 )
*pValue = static_cast< float >( vOut.dblVal );
else
{
_ASSERT( FALSE );
return E_FAIL;
}
return S_OK;
}
STDMETHOD(get_NextObject)(BSTR Name, IMessageIterator **pValue)
{
VARIANT v;
v.vt = VT_BSTR;
v.bstrVal = Name;
VARIANT vOut;
HRESULT hRes = get_Next( v, &vOut );
if( hRes == S_FALSE )
return E_FAIL;
if( vOut.vt != VT_DISPATCH )
{
_ASSERT( FALSE );
return E_FAIL;
}
return vOut.pdispVal->QueryInterface ( pValue );
}
STDMETHOD(get_NextObjectIndex)(IMessageIterator **pValue)
{
VARIANT v;
v.vt = VT_ERROR;
CComVariant vOut;
HRESULT hRes = get_Next( v, &vOut );
if( hRes == S_FALSE )
return E_FAIL;
if( vOut.vt != VT_DISPATCH )
{
_ASSERT( FALSE );
return E_FAIL;
}
return vOut.pdispVal->QueryInterface ( pValue );
}
STDMETHOD(Reset)()
{
m_nIndex = -1;
return S_OK;
}
STDMETHOD(get_Message)(IMessage **ppMessage)
{
if( ppMessage == NULL )
{
_ASSERT( FALSE );
return E_POINTER;
}
static_cast< ImplT * >( this )->getSource()->QueryInterface( IID_IMessage, reinterpret_cast< void ** >( ppMessage ) );
return S_OK;
}
};
class IMessageIteratorSublistImpl
: public IMessageIteratorImpl< IMessageIteratorSublistImpl >
{
public:
cMessage *m_pSource;
DWORD m_dwStartIndex,
m_dwEndIndex;
cMessage *getSource()
{
return m_pSource;
}
DWORD getStartIndex()
{
return m_dwStartIndex;
}
DWORD getEndIndex()
{
return m_dwEndIndex;
}
void init( cMessage *pMessage, DWORD dwStructIndex )
{
m_pSource = pMessage;
m_dwStartIndex = dwStructIndex + 1;
m_dwEndIndex = dwStructIndex + ( m_pSource->m_fields.begin() + dwStructIndex )->m_nOwns;
IMessageIteratorImpl< IMessageIteratorSublistImpl >::init();
}
};
#endif

View file

@ -0,0 +1,207 @@
// MessageLoaders.cpp
// Implementation of message loaders for various data types
#include "StdAfx.h"
#include "MessageLoaders.h"
// The boatload of decoding classes
template< class ValueT >
class cVariantLoader
: public cFieldLoader
{
public:
virtual void *skip( void *pData )
{
return reinterpret_cast< BYTE * >( pData ) + sizeof( ValueT );
}
virtual void *align( void *pData, void *pStart )
{
size_t nOffset = reinterpret_cast< BYTE * >( pData ) - reinterpret_cast< BYTE * >( pStart );
if( ( nOffset % sizeof( ValueT ) ) == 0 )
return pData;
return ( reinterpret_cast< BYTE * >( pStart ) + nOffset + sizeof( ValueT ) - ( nOffset % sizeof( ValueT ) ) );
}
virtual bool testValue( void *pData, void *pEnd )
{
return ( ( reinterpret_cast< BYTE * >( pData ) + sizeof( ValueT ) ) <= reinterpret_cast< BYTE * >( pEnd ) );
}
ValueT &valueOf( void *pvData )
{
return *reinterpret_cast< ValueT * >( pvData );
}
};
class cByteLoader
: public cVariantLoader< BYTE >
{
public:
virtual void getValue( void *pvData, LPVARIANT pDest )
{
pDest->vt = VT_UI1;
pDest->bVal = valueOf( pvData );
}
virtual long getNumber( void *pvData )
{
return valueOf( pvData );
}
};
class cShortLoader
: public cVariantLoader< short >
{
public:
virtual void getValue( void *pvData, LPVARIANT pDest )
{
pDest->vt = VT_I2;
pDest->iVal = valueOf( pvData );
}
virtual long getNumber( void *pvData )
{
return valueOf( pvData );
}
};
class cLongLoader
: public cVariantLoader< long >
{
public:
virtual void getValue( void *pvData, LPVARIANT pDest )
{
pDest->vt = VT_I4;
pDest->lVal = valueOf( pvData );
}
virtual long getNumber( void *pvData )
{
return valueOf( pvData );
}
};
class cFloatLoader
: public cVariantLoader< float >
{
public:
virtual void getValue( void *pvData, LPVARIANT pDest )
{
pDest->vt = VT_R4;
pDest->fltVal = valueOf( pvData );
}
};
class cDoubleLoader
: public cVariantLoader< double >
{
public:
virtual void getValue( void *pvData, LPVARIANT pDest )
{
pDest->vt = VT_R8;
pDest->dblVal = valueOf( pvData );
}
};
class cStringLoader
: public cFieldLoader
{
public:
virtual void *skip( void *pvData )
{
WORD wLength = *reinterpret_cast< WORD * >( pvData ) + sizeof( WORD );
if( ( wLength % sizeof( DWORD ) ) != 0 )
wLength += sizeof( DWORD ) - ( wLength % sizeof( DWORD ) );
return reinterpret_cast< BYTE * >( pvData ) + wLength;
}
virtual void *align( void *pvData, void * )
{
// Error, this is not a valid alignment type
_ASSERTE( FALSE );
return pvData;
}
virtual bool testValue( void *pvData, void *pvEnd )
{
WORD wLength = *reinterpret_cast< WORD * >( pvData ) + sizeof( WORD ),
wField = wLength;
if( ( wField % sizeof( DWORD ) ) != 0 )
wField += sizeof( DWORD ) - ( wField % sizeof( DWORD ) );
// It fits inside the packet, so our field isn't too big
if( ( reinterpret_cast< BYTE * >( pvData ) + wField ) > reinterpret_cast< BYTE * >( pvEnd ) )
return false;
// Strings are no longer NULL-Terminated in the stream
//if( *( reinterpret_cast< char * >( pvData ) + wLength - 1 ) != '\0' )
// This string is not NULL terminated
// return false;
// Anything else just makes the string ugly, but won't lead to a memory
// overrun, so let them play
return true;
}
virtual void getValue( void *pvData, LPVARIANT pDest )
{
pDest->vt = VT_BSTR;
USES_CONVERSION;
WORD wLength = *(WORD *) pvData;
// make new string
char *szString = new char[wLength + 1];
szString[wLength] = 0;
memcpy( szString, (((BYTE*) pvData) + sizeof( WORD )), wLength );
pDest->bstrVal = A2BSTR( szString );
delete [] szString;
}
};
long cFieldLoader::getNumber( void *pvData )
{
// This default implementation does not support this conversion
_ASSERTE( FALSE );
return 0;
}
cFieldLoader *cFieldLoader::lookup( const _bstr_t &strName )
{
cFieldLoaderMap::iterator i = g_primitives.find( strName );
if( i == g_primitives.end() )
return NULL;
return i->second.get();
}
void cFieldLoader::init()
{
addLoader( _T( "BYTE" ), new cByteLoader );
addLoader( _T( "WORD" ), new cShortLoader );
addLoader( _T( "DWORD" ), new cLongLoader );
addLoader( _T( "float" ), new cFloatLoader );
addLoader( _T( "double" ), new cDoubleLoader );
addLoader( _T( "String" ), new cStringLoader );
}
void cFieldLoader::term()
{
g_primitives.clear();
}
void cFieldLoader::addLoader( LPCTSTR szName, cFieldLoader *pLoader )
{
g_primitives.insert( cFieldLoaderMap::value_type( szName, VSBridge::auto_ptr< cFieldLoader >( pLoader ) ) );
}
cFieldLoader::cFieldLoaderMap cFieldLoader::g_primitives;

View file

@ -0,0 +1,28 @@
// MessageLoaders.h
// Declaration of Primitive Data Type loaders for encoded message data
#ifndef __MESSAGELOADERS_H
#define __MESSAGELOADERS_H
class cFieldLoader
{
public:
virtual void *skip(void *) = 0;
virtual void *align(void *pData, void *pStart) = 0;
virtual bool testValue(void *pData, void *pEnd) = 0;
virtual void getValue( void *, LPVARIANT pDest ) = 0;
virtual long getNumber( void *pvData );
static cFieldLoader *lookup( const _bstr_t &strName );
static void init();
static void term();
private:
static void addLoader( LPCTSTR szName, cFieldLoader *pLoader );
typedef std::map< _bstr_t, VSBridge::auto_ptr< cFieldLoader > > cFieldLoaderMap;
static cFieldLoaderMap g_primitives;
};
#endif

View file

@ -0,0 +1,727 @@
// MessageParsers.cpp
// Implementation of parsers and runtime objects for parsing message data
#include "StdAfx.h"
#include "DecalNet.h"
#include "MessageParsers.h"
#include "MessageLoaders.h"
#include "MessageStruct.h"
#include "MessageVector.h"
class cStructElement
: public cMessage::cMessageElement
{
public:
cMessage::cElementList m_members;
virtual bool load( cMessage::cLoadContext &context )
{
// Walk through the list of members and have them load
int nIndex = context.addField( this, NULL );
for( cMessage::cElementList::iterator i = m_members.begin(); i != m_members.end(); ++ i )
{
if( !i->get()->load( cMessage::cLoadContext( &context ) ) )
return false;
}
// Update the field count
context.groupField( nIndex );
return true;
}
virtual void getValue( cMessage *pMessage, cMessage::cFieldList::iterator i, LPVARIANT pDest )
{
if( i->m_pDisp.p == NULL )
{
// Create the vector object
CComObject< cMessageStructIter > *pVecDisp;
CComObject< cMessageStructIter >::CreateInstance( &pVecDisp );
pVecDisp->init( pMessage, ( i - pMessage->m_fields.begin() ) );
i->m_pDisp = pVecDisp;
}
else
i->m_pDisp->Reset();
pDest->vt = VT_DISPATCH;
i->m_pDisp->QueryInterface ( IID_IMessageMember, reinterpret_cast< LPVOID * > ( &pDest->pdispVal ) );
}
};
class cFieldParser
: public cElementParser
{
public:
class cFieldElement
: public cMessage::cMessageElement
{
public:
cFieldLoader *m_pLoader;
virtual bool load( cMessage::cLoadContext &context )
{
if( !m_pLoader->testValue( context.getMessage()->m_pEndCrack, context.getMessage()->m_pEndData ) )
{
// The element failed, this will usually indicate bad schema
_ASSERTE( FALSE );
return false;
}
context.addField( this, context.getMessage()->m_pEndCrack );
context.getMessage()->m_pEndCrack = reinterpret_cast< BYTE * >( m_pLoader->skip( context.getMessage()->m_pEndCrack ) );
return true;
}
virtual void getValue( cMessage *, cMessage::cFieldList::iterator i, LPVARIANT pDest )
{
m_pLoader->getValue( i->m_pvData, pDest );
}
virtual long getNumber( cMessage::cFieldList::iterator i )
{
return m_pLoader->getNumber( i->m_pvData );
}
};
// Strings
static _bstr_t g_strType;
static _bstr_t g_strName;
virtual cMessage::cMessageElement *parse( cContext &context, MSXML::IXMLDOMElementPtr &pElement )
{
// Locate the data type in the list
_variant_t strDataType = pElement->getAttribute( g_strType );
if( strDataType.vt != VT_BSTR )
{
// Schema error
_ASSERTE( strDataType.vt == VT_BSTR );
return NULL;
}
_bstr_t bstrDataType = strDataType;
cFieldLoader *pField = cFieldLoader::lookup( bstrDataType );
if( pField == NULL )
return parseStruct( context, pElement, bstrDataType );
_variant_t strName = pElement->getAttribute( g_strName );
if( strName.vt != VT_BSTR )
{
_ASSERTE( strName.vt == VT_BSTR );
return NULL;
}
cFieldElement *pFieldElement = new cFieldElement;
pFieldElement->m_strName = strName;
pFieldElement->m_pLoader = pField;
return pFieldElement;
}
cMessage::cMessageElement *parseStruct( cContext &context, MSXML::IXMLDOMElementPtr &pElement, const _bstr_t &strType )
{
// Locate the data type in the list
_variant_t strName = pElement->getAttribute( cFieldParser::g_strName );
if( strName.vt != VT_BSTR )
{
// Schema error
_ASSERTE( strName.vt == VT_BSTR );
return NULL;
}
// We have the field name, now look up data type schema
USES_CONVERSION;
TCHAR szQuery[ 255 ];
::_stprintf( szQuery, _T( "/schema/datatypes/type[@name='%s']" ),
OLE2T( strType ) );
MSXML::IXMLDOMElementPtr pStruct = pElement->ownerDocument->selectSingleNode( szQuery );
if( pStruct.GetInterfacePtr() == NULL )
{
// Could not cross reference the structure
_ASSERTE( pStruct.GetInterfacePtr() != NULL );
return NULL;
}
VSBridge::auto_ptr< cStructElement > pStructElement( new cStructElement() );
pStructElement->m_strName = strName;
if( context.parseChildren( pStructElement->m_members, pStruct ) )
return pStructElement.release();
return NULL;
}
};
_bstr_t cFieldParser::g_strType( _T( "type" ) );
_bstr_t cFieldParser::g_strName( _T( "name" ) );
class cMaskParser
: public cElementParser
{
public:
class cMaskElement
: public cMessage::cMessageElement
{
public:
cMessage::cMessageElement *m_pValue;
class cMask
{
public:
DWORD m_dwValue;
DWORD m_dwFirstChild,
m_dwLastChild;
};
typedef std::vector< cMask > cMaskMap;
cMaskMap m_masks;
cMessage::cElementList m_members;
virtual bool load( cMessage::cLoadContext &context )
{
// First, look for our value element in the message
cMessage::cFieldList::iterator iField = context.lookupField( m_pValue );
if( iField == context.getMessage()->m_fields.end() )
{
// Could not find a mask source - most likely a bad name of some kind
_ASSERTE( FALSE );
return false;
}
_ASSERT( iField->m_pSchema == m_pValue );
long nMaskValue = iField->m_pSchema->getNumber( iField );
// Walk through the mask values and load all of the fields in range
for( cMaskMap::iterator i = m_masks.begin(); i != m_masks.end(); ++ i )
{
if( ( nMaskValue & i->m_dwValue ) == 0 )
continue;
// This is a valid mask load up all teh fields in range
cMessage::cElementList::iterator m_end = m_members.begin() + i->m_dwLastChild;
for( cMessage::cElementList::iterator j = m_members.begin() + i->m_dwFirstChild; j != m_end; ++ j )
{
if( !j->get()->load( context ) )
return false;
}
}
return true;
}
virtual void getValue( cMessage *, cMessage::cFieldList::iterator, LPVARIANT )
{
// This element should never insert itself into the message list
_ASSERTE( FALSE );
}
};
static _bstr_t g_strMask;
static _bstr_t g_strValue;
virtual cMessage::cMessageElement *parse( cContext &context, MSXML::IXMLDOMElementPtr &pElement )
{
_variant_t vName = pElement->getAttribute( cFieldParser::g_strName );
if( vName.vt != VT_BSTR )
{
// It must have the name field
_ASSERTE( vName.vt == VT_BSTR );
return NULL;
}
// Find a matching element in the schema
cMessage::cMessageElement *pName = context.findElement( vName.bstrVal );
if( pName == NULL )
{
// The mask field was not found
_ASSERTE( pName != NULL );
return NULL;
}
// Create the mask element
VSBridge::auto_ptr< cMaskElement > pMaskElement( new cMaskElement );
pMaskElement->m_pValue = pName;
// Walk through each of the mask values
USES_CONVERSION;
MSXML::IXMLDOMNodeListPtr pMaskList = pElement->selectNodes( g_strMask );
for( MSXML::IXMLDOMElementPtr pMask = pMaskList->nextNode(); pMask.GetInterfacePtr() != NULL; pMask = pMaskList->nextNode() )
{
_variant_t vValue = pMask->getAttribute( g_strValue );
if( vValue.vt != VT_BSTR )
{
_ASSERTE( vName.vt == VT_BSTR );
return NULL;
}
// Make sure it has the 'hex' prefix
if( vValue.bstrVal[ 0 ] != OLESTR( '0' ) )
{
_ASSERTE( vValue.bstrVal[ 0 ] == OLESTR( '0' ) );
return NULL;
}
if( vValue.bstrVal[ 1 ] != OLESTR( 'x' ) )
{
_ASSERTE( vValue.bstrVal[ 1 ] == OLESTR( 'x' ) );
return NULL;
}
// Attempt to convert the remaining number
long nMaskValue;
if( ::_stscanf( OLE2T( vValue.bstrVal + 2 ), _T( "%X" ), &nMaskValue ) != 1 )
{
// Could not convert value
_ASSERTE( FALSE );
return NULL;
}
long nStartOffset = pMaskElement->m_members.size();
context.parseChildren( pMaskElement->m_members, pMask );
cMaskElement::cMask mask = { nMaskValue, nStartOffset, pMaskElement->m_members.size() };
pMaskElement->m_masks.push_back( mask );
}
return pMaskElement.release();
}
};
_bstr_t cMaskParser::g_strMask( _T( "mask" ) );
_bstr_t cMaskParser::g_strValue( _T( "value" ) );
class cAlignParser
: public cElementParser
{
public:
class cAlignElement
: public cMessage::cMessageElement
{
public:
cFieldLoader *m_pLoader;
virtual bool load( cMessage::cLoadContext &context )
{
void *pAlign = m_pLoader->align( context.getMessage()->m_pEndCrack, context.getMessage()->m_pStartCrack );
if( pAlign > context.getMessage()->m_pEndData )
{
_ASSERTE( FALSE );
return false;
}
context.getMessage()->m_pEndCrack = reinterpret_cast< BYTE * >( pAlign );
return true;
}
virtual void getValue( cMessage *, cMessage::cFieldList::iterator i, LPVARIANT pDest )
{
// This should never associate itself with a field
_ASSERTE( FALSE );
}
};
virtual cMessage::cMessageElement *parse( cContext &context, MSXML::IXMLDOMElementPtr &pElement )
{
// Locate the data type in the list
_variant_t strDataType = pElement->getAttribute( cFieldParser::g_strType );
if( strDataType.vt != VT_BSTR )
{
// Schema error
_ASSERTE( strDataType.vt == VT_BSTR );
return NULL;
}
_bstr_t bstrDataType = strDataType;
cFieldLoader *pField = cFieldLoader::lookup( bstrDataType );
if( pField == NULL )
{
_ASSERTE( FALSE );
return NULL;
}
cAlignElement *pAlignElement = new cAlignElement;
pAlignElement->m_pLoader = pField;
return pAlignElement;
}
};
class cVectorParser
: public cElementParser
{
public:
class cVectorElement
: public cMessage::cMessageElement
{
public:
cMessage::cMessageElement *m_pLength;
VSBridge::auto_ptr< cMessage::cMessageElement > m_pStruct;
int m_nSkip;
DWORD m_dwMask;
virtual bool load( cMessage::cLoadContext &context )
{
// First, look for our value element in the message
cMessage::cFieldList::iterator iField = context.lookupField( m_pLength );
if( iField == context.getMessage()->m_fields.end() )
{
// Could not find a mask source - most likely a bad name of some kind
_ASSERTE( FALSE );
return NULL;
}
_ASSERT( iField->m_pSchema == m_pLength );
long nLength = iField->m_pSchema->getNumber( iField ) - m_nSkip;
if (m_dwMask != 0)
{
DWORD dwTemp = (DWORD) nLength & m_dwMask;
DWORD dwTempMask = m_dwMask;
// Shift the length field right as far as we can.
while (! (dwTempMask & 0x1))
{
dwTempMask >>= 1;
dwTemp >>= 1;
}
nLength = (long) dwTemp;
}
// Insert a record for ourself
DWORD dwIndex = context.addField( this, NULL );
for( int i = 0; i < nLength; ++ i )
{
// Insert a record for the current struct
if( !m_pStruct->load( cMessage::cLoadContext( &context ) ) )
return false;
}
// Update the used field count
context.groupField( dwIndex );
return true;
}
virtual void getValue( cMessage *pMessage, cMessage::cFieldList::iterator i, LPVARIANT pDest )
{
if( i->m_pDisp.p == NULL )
{
// Create the vector object
CComObject< cMessageVectorIter > *pVecDisp;
CComObject< cMessageVectorIter >::CreateInstance( &pVecDisp );
pVecDisp->init( pMessage, ( i - pMessage->m_fields.begin() ) );
i->m_pDisp = pVecDisp;
}
else
i->m_pDisp->Reset();
pDest->vt = VT_DISPATCH;
i->m_pDisp->QueryInterface ( IID_IMessageMember, reinterpret_cast< LPVOID * > ( &pDest->pdispVal ) );
}
};
static _bstr_t g_strLength,
g_strSkip,
g_strMask;
virtual cMessage::cMessageElement *parse( cContext &context, MSXML::IXMLDOMElementPtr &pElement )
{
_variant_t vName = pElement->getAttribute( cFieldParser::g_strName );
if( vName.vt != VT_BSTR )
{
// It must have the name field
_ASSERTE( vName.vt == VT_BSTR );
return NULL;
}
_variant_t vLength = pElement->getAttribute( g_strLength ),
vSkip = pElement->getAttribute( g_strSkip ),
vMask = pElement->getAttribute( g_strMask );
if( vLength.vt != VT_BSTR )
{
// It must have the name field
_ASSERTE( vLength.vt == VT_BSTR );
return NULL;
}
long nSkip = 0;
if( vSkip.vt != VT_NULL )
{
try
{
nSkip = vSkip;
}
catch( ... )
{
// Failed to make the conversion
_ASSERT( FALSE );
return NULL;
}
}
DWORD dwMask = 0;
if( vMask.vt != VT_NULL )
{
dwMask = ::wcstoul (vMask.bstrVal, NULL, 16);
}
cMessage::cMessageElement *pLength = context.findElement( vLength.bstrVal );
if( pLength == NULL )
{
// The mask field was not found
_ASSERTE( pLength != NULL );
return NULL;
}
VSBridge::auto_ptr< cStructElement > pStructElement( new cStructElement );
if( !context.parseChildren( pStructElement->m_members, pElement ) )
return NULL;
cVectorElement *pVector = new cVectorElement;
pVector->m_strName = vName;
pVector->m_pLength = pLength;
pVector->m_nSkip = nSkip;
pVector->m_dwMask = dwMask;
pVector->m_pStruct = VSBridge::auto_ptr< cMessage::cMessageElement >( pStructElement.release() );
return pVector;
}
};
_bstr_t cVectorParser::g_strLength( _T( "length" ) );
_bstr_t cVectorParser::g_strSkip( _T( "skip" ) );
_bstr_t cVectorParser::g_strMask( _T( "mask" ) );
class cSwitchParser
: public cElementParser
{
public:
class cSwitchElement
: public cMessage::cMessageElement
{
public:
cMessage::cMessageElement *m_pValue;
class cCase
{
public:
DWORD m_dwValue;
DWORD m_dwFirstChild,
m_dwLastChild;
};
typedef std::vector< cCase > cCaseMap;
cCaseMap m_cases;
cMessage::cElementList m_members;
virtual bool load( cMessage::cLoadContext &context )
{
// First, look for our value element in the message
cMessage::cFieldList::iterator iField = context.lookupField( m_pValue );
if( iField == context.getMessage()->m_fields.end() )
{
// Could not find a mask source - most likely a bad name of some kind
_ASSERTE( FALSE );
return NULL;
}
_ASSERT( iField->m_pSchema == m_pValue );
long nCaseValue = iField->m_pSchema->getNumber( iField );
// Walk through the mask values and load all of the fields in range
for( cCaseMap::iterator i = m_cases.begin(); i != m_cases.end(); ++ i )
{
if( nCaseValue != i->m_dwValue )
continue;
// This is a valid mask load up all teh fields in range
cMessage::cElementList::iterator m_end = m_members.begin() + i->m_dwLastChild;
for( cMessage::cElementList::iterator j = m_members.begin() + i->m_dwFirstChild; j != m_end; ++ j )
{
if( !j->get()->load( context ) )
return false;
}
// For now we short circuit cases
break;
}
return true;
}
virtual void getValue( cMessage *, cMessage::cFieldList::iterator, LPVARIANT )
{
// This element should never insert itself into the message list
_ASSERTE( FALSE );
}
};
static _bstr_t g_strCase;
virtual cMessage::cMessageElement *parse( cContext &context, MSXML::IXMLDOMElementPtr &pElement )
{
_variant_t vName = pElement->getAttribute( cFieldParser::g_strName );
if( vName.vt != VT_BSTR )
{
// It must have the name field
_ASSERTE( vName.vt == VT_BSTR );
return NULL;
}
// Find a matching element in the schema
cMessage::cMessageElement *pName = context.findElement( vName.bstrVal );
if( pName == NULL )
{
// The mask field was not found
_ASSERTE( pName != NULL );
return NULL;
}
// Create the mask element
VSBridge::auto_ptr< cSwitchElement > pSwitchElement( new cSwitchElement );
pSwitchElement->m_pValue = pName;
// Walk through each of the mask values
USES_CONVERSION;
MSXML::IXMLDOMNodeListPtr pCaseList = pElement->selectNodes( g_strCase );
for( MSXML::IXMLDOMElementPtr pCase = pCaseList->nextNode(); pCase.GetInterfacePtr() != NULL; pCase = pCaseList->nextNode() )
{
_variant_t vValue = pCase->getAttribute( cMaskParser::g_strValue );
if( vValue.vt != VT_BSTR )
{
_ASSERTE( vName.vt == VT_BSTR );
return NULL;
}
// Make sure it has the 'hex' prefix
if( vValue.bstrVal[ 0 ] != OLESTR( '0' ) )
{
_ASSERTE( vValue.bstrVal[ 0 ] == OLESTR( '0' ) );
return NULL;
}
if( vValue.bstrVal[ 1 ] != OLESTR( 'x' ) )
{
_ASSERTE( vValue.bstrVal[ 1 ] == OLESTR( 'x' ) );
return NULL;
}
// Attempt to convert the remaining number
long nCaseValue;
if( ::_stscanf( OLE2T( vValue.bstrVal + 2 ), _T( "%X" ), &nCaseValue ) != 1 )
{
// Could not convert value
_ASSERTE( FALSE );
return NULL;
}
long nStartOffset = pSwitchElement->m_members.size();
context.parseChildren( pSwitchElement->m_members, pCase );
cSwitchElement::cCase _case = { nCaseValue, nStartOffset, pSwitchElement->m_members.size() };
pSwitchElement->m_cases.push_back( _case );
}
return pSwitchElement.release();
}
};
_bstr_t cSwitchParser::g_strCase( _T( "case" ) );
cMessage::cMessageElement *cElementParser::cContext::findElement( const _bstr_t &strElement )
{
for( cContext *pContext = this; pContext != NULL; pContext = pContext->m_pParent )
{
for( cMessage::cElementList::iterator i = m_pElements->begin() + m_dwStartOffset; i != m_pElements->end(); ++ i )
{
if( i->get()->m_strName == strElement )
return i->get();
}
}
return NULL;
}
bool cElementParser::cContext::parseChildren( MSXML::IXMLDOMElementPtr &pElement )
{
MSXML::IXMLDOMNodeListPtr pChildList = pElement->selectNodes( g_strAll );
for( MSXML::IXMLDOMElementPtr pChild = pChildList->nextNode(); pChild.GetInterfacePtr() != NULL; pChild = pChildList->nextNode() )
{
_bstr_t strElementName = pChild->tagName;
cElementParser *pParser = cElementParser::lookup( strElementName );
if( pParser == NULL )
{
// Could not find a parse for this element type
_ASSERTE( FALSE );
return false;
}
cMessage::cMessageElement *pElement = pParser->parse( *this, pChild );
if( pElement == NULL )
return false;
m_pElements->push_back( cMessage::cElementList::value_type( pElement ) );
}
return true;
}
_bstr_t cElementParser::cContext::g_strAll( _T( "*" ) );
bool cElementParser::cContext::parseChildren( cMessage::cElementList &elements, MSXML::IXMLDOMElementPtr &pElement )
{
cContext c( &elements, this );
return c.parseChildren( pElement );
}
cElementParser *cElementParser::lookup( const _bstr_t &strElement )
{
cElementParserMap::iterator i = g_parsers.find( strElement );
if( i == g_parsers.end() )
return NULL;
return i->second.get();
}
void cElementParser::init()
{
addParser( _T( "field" ), new cFieldParser );
addParser( _T( "maskmap" ), new cMaskParser );
addParser( _T( "vector" ), new cVectorParser );
addParser( _T( "switch" ), new cSwitchParser );
addParser( _T( "align" ), new cAlignParser );
}
void cElementParser::term()
{
g_parsers.clear();
}
void cElementParser::addParser( LPCTSTR szName, cElementParser *pParser )
{
g_parsers.insert( cElementParserMap::value_type( szName, VSBridge::auto_ptr< cElementParser >( pParser ) ) );
}
cElementParser::cElementParserMap cElementParser::g_parsers;

View file

@ -0,0 +1,48 @@
// MessageParsers.h
// Declaration of class cMessageParser - base class for parsing the
// XML Schema
#ifndef __MESSAGEPARSERS_H
#define __MESSAGEPARSERS_H
#include "Message.h"
class cElementParser
{
public:
class cContext
{
cContext *m_pParent;
cMessage::cElementList *m_pElements;
DWORD m_dwStartOffset;
public:
cContext( cMessage::cElementList *pElements, cContext *pParent = NULL )
: m_pParent( pParent ),
m_pElements( pElements ),
m_dwStartOffset( pElements->size() )
{
}
cMessage::cMessageElement *findElement( const _bstr_t &strElement );
bool parseChildren( MSXML::IXMLDOMElementPtr &pElement );
bool parseChildren( cMessage::cElementList &elements, MSXML::IXMLDOMElementPtr &pElement );
static _bstr_t g_strAll;
};
virtual cMessage::cMessageElement *parse( cContext &context, MSXML::IXMLDOMElementPtr &pElement ) = 0;
static cElementParser *lookup( const _bstr_t &strElement );
static void init();
static void term();
private:
static void addParser( LPCTSTR szElement, cElementParser *pParser );
typedef std::map< _bstr_t, VSBridge::auto_ptr< cElementParser > > cElementParserMap;
static cElementParserMap g_parsers;
};
#endif

View file

@ -0,0 +1,8 @@
// MessageRoot.cpp : Implementation of cMessageRoot
#include "stdafx.h"
#include "DecalNet.h"
#include "MessageRoot.h"
/////////////////////////////////////////////////////////////////////////////
// cMessageRoot

View file

@ -0,0 +1,90 @@
// MessageRoot.h : Declaration of the cMessageRoot
#ifndef __MESSAGEROOT_H_
#define __MESSAGEROOT_H_
#include "resource.h" // main symbols
#include "MessageImpl.h"
/////////////////////////////////////////////////////////////////////////////
// cMessageRoot
class ATL_NO_VTABLE cMessageRoot :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<cMessageRoot, &CLSID_MessageRoot>,
public IMessageIteratorImpl< cMessageRoot >
{
public:
cMessageRoot()
{
}
cMessage *m_pSource;
cMessage *getSource()
{
return m_pSource;
}
DWORD getStartIndex()
{
return 0;
}
DWORD getEndIndex()
{
return m_pSource->m_fields.size();
}
DWORD getNextIndex()
{
if( m_nIndex != -1 )
return getNextIndex( m_dwIterator );
DWORD dwIterator = getStartIndex();
while( dwIterator == m_pSource->m_fields.size() )
{
if( !m_pSource->loadNextElement() )
return eEndIndex;
}
return dwIterator;
}
DWORD getNextIndex( DWORD dwIndex )
{
// Calculate the next index
DWORD dwNextIndex = dwIndex + ( m_pSource->m_fields.begin() + dwIndex )->m_nOwns;
// Insert this loop to make sure the cracking is done far enough ahead
// This is a loop because it's entirely possible that loading a message element
// will produce no fields (it's a rule that dosen't apply)
while( dwNextIndex == m_pSource->m_fields.size() )
{
if( !m_pSource->loadNextElement() )
return eEndIndex;
}
return dwNextIndex;
}
void init( cMessage *pSource )
{
m_pSource = pSource;
IMessageIteratorImpl< cMessageRoot >::init();
}
DECLARE_REGISTRY_RESOURCEID(IDR_MESSAGEROOT)
DECLARE_PROTECT_FINAL_CONSTRUCT()
BEGIN_COM_MAP(cMessageRoot)
COM_INTERFACE_ENTRY(IMessageIterator)
COM_INTERFACE_ENTRY(IDispatch)
END_COM_MAP()
public:
};
#endif //__MESSAGEROOT_H_

View file

@ -0,0 +1,96 @@
// MessageStruct.cpp : Implementation of cMessageStruct
#include "stdafx.h"
#include "DecalNet.h"
#include "MessageStruct.h"
#include "Message.h"
/////////////////////////////////////////////////////////////////////////////
// cMessageIteratorStruct
/////////////////////////////////////////////////////////////////////////////
// cMessageStruct
STDMETHODIMP cMessageStructIter::get_Count(long *pVal)
{
_ASSERTE( pVal != NULL );
cMessage::cFieldList::iterator i_begin = m_pSource->m_fields.begin() + m_dwStartIndex;
cMessage::cFieldList::iterator i_end = m_pSource->m_fields.begin() + getEndIndex();
*pVal = 0;
for( cMessage::cFieldList::iterator i = i_begin; i != i_end; i += i->m_nOwns )
++ ( *pVal );
return S_OK;
}
STDMETHODIMP cMessageStructIter::get_MemberName(long Index, BSTR *pVal)
{
_ASSERTE( pVal != NULL );
_ASSERTE( Index >= 0 );
USES_CONVERSION;
cMessage::cFieldList::iterator i_begin = m_pSource->m_fields.begin() + m_dwStartIndex;
cMessage::cFieldList::iterator i_end = m_pSource->m_fields.begin() + getEndIndex();
for( cMessage::cFieldList::iterator i = i_begin; i != i_end; i += i->m_nOwns, -- Index )
{
if( Index == 0 )
{
*pVal = OLE2BSTR( i->m_pSchema->m_strName );
return S_OK;
}
}
_ASSERTE( FALSE );
return E_INVALIDARG;
}
STDMETHODIMP cMessageStructIter::get_Member(VARIANT vIndex, VARIANT *pVal)
{
cMessage::cFieldList::iterator i_begin = m_pSource->m_fields.begin() + m_dwStartIndex;
cMessage::cFieldList::iterator i_end = m_pSource->m_fields.begin() + getEndIndex();
if( vIndex.vt == VT_BSTR )
{
_bstr_t bstrIndex = vIndex;
for( cMessage::cFieldList::iterator i = i_begin; i != i_end; i += i->m_nOwns )
{
if( bstrIndex == i->m_pSchema->m_strName )
{
i->m_pSchema->getValue( m_pSource, i, pVal );
return S_OK;
}
}
}
HRESULT hRes = ::VariantChangeType( &vIndex, &vIndex, 0, VT_I4 );
if( FAILED( hRes ) )
{
_ASSERTE( FALSE );
return hRes;
}
// Check if the value is in range
long nIndex = vIndex.lVal;
if( nIndex < 0 )
{
_ASSERTE( nIndex >= 0 );
return E_INVALIDARG;
}
for( cMessage::cFieldList::iterator i = i_begin; i != i_end; i += i->m_nOwns, -- nIndex )
{
if( nIndex == 0 )
{
i->m_pSchema->getValue( m_pSource, i, pVal );
return S_OK;
}
}
return S_OK;
}

View file

@ -0,0 +1,34 @@
// MessageStruct.h : Declaration of the cMessageStruct
#ifndef __MESSAGESTRUCT_H_
#define __MESSAGESTRUCT_H_
#include "resource.h" // main symbols
#include "MessageImpl.h"
/////////////////////////////////////////////////////////////////////////////
// cMessageStruct
class ATL_NO_VTABLE cMessageStructIter :
public CComObjectRootEx<CComSingleThreadModel>,
public IDispatchImpl<IMessageMember, &IID_IMessageMember, &LIBID_DecalNet>,
public IMessageIteratorSublistImpl
{
public:
cMessageStructIter()
{
}
BEGIN_COM_MAP(cMessageStructIter)
COM_INTERFACE_ENTRY(IMessageIterator)
COM_INTERFACE_ENTRY(IMessageMember)
COM_INTERFACE_ENTRY2(IDispatch, IMessageMember)
END_COM_MAP()
public:
// IMessageStruct Implementation
STDMETHOD(get_Count)(/*[out, retval]*/ long *pVal);
STDMETHOD(get_MemberName)(long Index, /*[out, retval]*/ BSTR *pVal);
STDMETHOD(get_Member)(VARIANT vIndex, /*[out, retval]*/ VARIANT *pVal);
};
#endif //__MESSAGESTRUCT_H_

View file

@ -0,0 +1,103 @@
// MessageVector.cpp : Implementation of cMessageVector
#include "stdafx.h"
#include "DecalNet.h"
#include "MessageVector.h"
#include "Message.h"
/////////////////////////////////////////////////////////////////////////////
// cMessageVector
STDMETHODIMP cMessageVectorIter::get_MemberName(BSTR *pVal)
{
if( pVal == NULL )
{
_ASSERT( FALSE );
return E_POINTER;
}
if( m_nIndex == -1 || m_dwIterator == eEndIndex )
{
// We are before the beginning or after the end
_ASSERT( FALSE );
return E_FAIL;
}
USES_CONVERSION;
TCHAR strIndex[ 12 ];
::_stprintf( strIndex, _T( "%i" ), m_nIndex );
*pVal = T2BSTR( strIndex );
return S_OK;
}
/////////////////////////////////////////////////////////////////////////////
// cMessageVector
STDMETHODIMP cMessageVectorIter::get_MemberName(long nIndex, BSTR *pVal)
{
_ASSERTE( pVal != NULL );
_ASSERTE( nIndex >= 0 );
USES_CONVERSION;
TCHAR strIndex[ 12 ];
::_stprintf( strIndex, _T( "%i" ), nIndex );
*pVal = T2BSTR( strIndex );
return S_OK;
}
STDMETHODIMP cMessageVectorIter::get_Count(long *pVal)
{
_ASSERTE( pVal != NULL );
cMessage::cFieldList::iterator i_begin = m_pSource->m_fields.begin() + m_dwStartIndex;
cMessage::cFieldList::iterator i_end = m_pSource->m_fields.begin() + getEndIndex();
*pVal = 0;
for( cMessage::cFieldList::iterator i = i_begin; i != i_end; i += i->m_nOwns )
++ ( *pVal );
return S_OK;
}
STDMETHODIMP cMessageVectorIter::get_Member(VARIANT vIndex, VARIANT *pVal)
{
_ASSERTE( pVal != NULL );
HRESULT hRes = ::VariantChangeType( &vIndex, &vIndex, 0, VT_I4 );
if( FAILED( hRes ) )
{
_ASSERTE( FALSE );
return hRes;
}
// Check if the value is in range
long Index = vIndex.lVal;
if( Index < 0 )
{
_ASSERTE( Index >= 0 );
return E_INVALIDARG;
}
cMessage::cFieldList::iterator i_begin = m_pSource->m_fields.begin() + m_dwStartIndex;
cMessage::cFieldList::iterator i_end = m_pSource->m_fields.begin() + getEndIndex();
for( cMessage::cFieldList::iterator i = i_begin; i != i_end; i += i->m_nOwns, -- Index )
{
if( Index == 0 )
{
i->m_pSchema->getValue( m_pSource, i, pVal );
return S_OK;
}
}
_ASSERTE( FALSE );
return E_INVALIDARG;
}

View file

@ -0,0 +1,37 @@
// MessageVector.h : Declaration of the cMessageVector
#ifndef __MESSAGEVECTOR_H_
#define __MESSAGEVECTOR_H_
#include "resource.h" // main symbols
#include "MessageImpl.h"
/////////////////////////////////////////////////////////////////////////////
// cMessageVector
class ATL_NO_VTABLE cMessageVectorIter :
public CComObjectRootEx<CComSingleThreadModel>,
public IDispatchImpl<IMessageMember, &IID_IMessageMember, &LIBID_DecalNet>,
public IMessageIteratorSublistImpl
{
public:
cMessageVectorIter()
{
}
BEGIN_COM_MAP(cMessageVectorIter)
COM_INTERFACE_ENTRY(IMessageMember)
COM_INTERFACE_ENTRY(IMessageIterator)
COM_INTERFACE_ENTRY2(IDispatch, IMessageMember)
END_COM_MAP()
public:
// IMessageIterator Overrides
STDMETHOD(get_MemberName)(BSTR *pVal);
// IMessageMember Implementation
STDMETHOD(get_Count)(/*[out, retval]*/ long *pVal);
STDMETHOD(get_Member)(VARIANT vIndex, /*[out, retval]*/ VARIANT *pVal);
STDMETHOD(get_MemberName)(long Index, BSTR *pVal);
};
#endif //__MESSAGEVECTOR_H_

View file

@ -0,0 +1,460 @@
// NetService.cpp : Implementation of cNetService
#include "stdafx.h"
#include "DecalNet.h"
#include "NetService.h"
#include <time.h>
#include "Message.h"
#include <ApiHook.h>
#include "ProtocolHook.h"
#include "FilterAdapterV1.h"
#define _OUTGOING_PACKETS_
//#define _LOGGING
extern DWORD HookCall (DWORD dwCallAddress, DWORD dwReplacement);
extern void ReceiveBlob();
bool (__cdecl*LockMemoryPages)(void *);
bool g_bLockMemoryPages = false;
DWORD g_dwReceiveBlobReadyCall = 0;
DWORD g_dwReceiveBlobReadyProc = 0;
DWORD g_dwNetBlobObjectDataOffset = 0;
DWORD g_dwNetBlobObjectSizeOffset = 0;
/////////////////////////////////////////////////////////////////////////////
// cNetService
// Functions for hooking from wsock32.dll
int PASCAL recvfromF( SOCKET s, char FAR* buf, int len, int flags, struct sockaddr FAR* from, int FAR* fromlen );
int PASCAL sendtoF( SOCKET s, const char FAR* buf, int len, int flags, const struct sockaddr FAR* to, int tolen );
static cHookDescriptor _hooks[] = {
{ eByOrdinal, _T( "fsock32.dll" ), _T( "recvfrom" ), 17, reinterpret_cast< DWORD >( recvfromF ), 0 },
{ eByOrdinal, _T( "wsock32.dll" ), _T( "recvfrom" ), 17, reinterpret_cast< DWORD >( recvfromF ), 0 },
};
static cHookDescriptor _hooksOut[] = {
{ eByOrdinal, _T( "wsock32.dll" ), _T( "sendto" ), 20, reinterpret_cast< DWORD >( sendtoF ), 0 },
};
HRESULT cNetService::onInitialize()
{
if( g_pService == NULL )
{
g_pService = this;
m_pDecal->get_Hooks( &m_pHooks );
long lTemp = 0;
m_pHooks->QueryMemLoc( _bstr_t( "ReceiveBlobReadyCall" ), &lTemp );
g_dwReceiveBlobReadyCall = lTemp, lTemp = 0;
m_pHooks->QueryMemLoc( _bstr_t( "NetBlobObjectDataOffset" ), &lTemp );
g_dwNetBlobObjectDataOffset = lTemp, lTemp = 0;
m_pHooks->QueryMemLoc( _bstr_t( "NetBlobObjectSizeOffset" ), &lTemp );
g_dwNetBlobObjectSizeOffset = lTemp, lTemp = 0;
m_pHooks->QueryMemLoc( _bstr_t( "LockMemoryPages" ), &lTemp );
if( lTemp )
g_bLockMemoryPages = true;
LockMemoryPages = (bool(__cdecl*)(void*)) lTemp, lTemp = 0;
if( g_dwReceiveBlobReadyCall && g_dwNetBlobObjectDataOffset && g_dwNetBlobObjectSizeOffset )
g_dwReceiveBlobReadyProc = HookCall( g_dwReceiveBlobReadyCall, (DWORD) ReceiveBlob );
else
{
g_dwReceiveBlobReadyCall = 0; // just in case.
hookFunctions( _hooks, 2, true );
if( _hooks[ 0 ].m_pOldFunction != 0 )
g_fn_recvfrom = reinterpret_cast< fn_recvfrom >( _hooks[ 0 ].m_pOldFunction );
else if( _hooks[ 1 ].m_pOldFunction != 0 )
g_fn_recvfrom = reinterpret_cast< fn_recvfrom >( _hooks[ 1 ].m_pOldFunction );
else
_ASSERTE( false );
}
}
#ifdef _OUTGOING_PACKETS_
hookFunctions( _hooksOut, 1, true );
if( _hooksOut[ 0 ].m_pOldFunction != 0 )
g_fn_sendto = reinterpret_cast< fn_sendto >( _hooksOut[ 0 ].m_pOldFunction );
else
_ASSERTE( false );
#endif
m_stack.start( this );
// Start all of the network filters
{
CComPtr< IDecalEnum > pEnum;
HRESULT hRes = m_pDecal->get_Configuration( _bstr_t( _T( "NetworkFilters" ) ), GUID_NULL, &pEnum );
if( FAILED( hRes ) )
return hRes;
while( pEnum->Next() == S_OK )
{
// Unlike services, network filters are allowed to fail
VARIANT_BOOL bEnabled;
HRESULT hRes = pEnum->get_Enabled ( &bEnabled );
_ASSERTE ( SUCCEEDED ( hRes ) );
if ( !bEnabled )
continue;
cFilter f;
pEnum->get_ComClass( &f.m_clsid );
hRes = pEnum->CreateInstance( __uuidof( INetworkFilter2 ), reinterpret_cast< void ** >( &f.m_p ) );
if( FAILED( hRes ) )
{
// Heads up that a filter is failing to init
_ASSERT( FALSE );
continue;
}
hRes = f.m_p->Initialize( this );
if( SUCCEEDED( hRes ) )
{
f.m_ver = eVersion2;
m_filters.push_back( f );
}
}
}
// Prepare the message container
CComObject< cMessage > *pMessage;
CComObject< cMessage >::CreateInstance( &pMessage );
pMessage->AddRef();
pMessage->m_pService = this;
pMessage->init();
m_pMessage = pMessage;
return S_OK;
}
void cNetService::onTerminate()
{
m_pMessage->term();
// The release should destroy it
m_pMessage->Release();
m_pMessage = NULL;
// Kill all of the network filters in reverse order
while( !m_filters.empty() )
{
cFilterList::iterator i_end = ( -- m_filters.end() );
i_end->m_p->Terminate();
m_filters.erase( i_end );
}
m_filters.clear();
m_stack.stop();
if( g_pService == this )
{
#ifdef _OUTGOING_PACKETS_
hookFunctions( _hooksOut, 1, false );
#endif
if( g_dwReceiveBlobReadyCall )
HookCall( g_dwReceiveBlobReadyCall, g_dwReceiveBlobReadyProc );
else
hookFunctions( _hooks, 2, false );
g_pService = NULL;
}
m_pHooks.Release();
}
int PASCAL recvfromF( SOCKET s, char FAR* buf, int len, int flags, struct sockaddr FAR* from, int FAR* fromlen )
{
_ASSERTE( cNetService::g_pService != NULL );
int iRes = cNetService::g_fn_recvfrom( s, buf, len, flags, from, fromlen );
#ifdef _LOGGING_
if( iRes != SOCKET_ERROR && cNetService::g_pService != NULL )
{
char *harro = new char[256];
_snprintf(harro, 256, "recvfrom( %d, %08X, %d, %d, %08X, %d ) = %d", s, buf, len, flags, from, fromlen, iRes);
m_pHooks->ChatOut(_bstr_t (harro), 0);
delete[] harro;
}
#endif
if( iRes != SOCKET_ERROR && cNetService::g_pService != NULL )
cNetService::g_pService->m_stack.processPacket( static_cast< DWORD >( iRes ), reinterpret_cast< BYTE * >( buf ) );
return iRes;
}
int PASCAL sendtoF( SOCKET s, const char FAR* buf, int len, int flags, const struct sockaddr FAR* to, int tolen )
{
_ASSERTE( cNetService::g_pService != NULL );
#ifdef _LOGGING_
char *harro = new char[256];
char *buffer = new char[512];
sprintf(harro, "sendto( %d, %08X, %d, %d, %s:%d, %d )",
s, buf, len, flags,
inet_ntoa( ((sockaddr_in *)(to))->sin_addr ),
ntohs( ((sockaddr_in *)(to))->sin_port ),
tolen);
m_pHooks->ChatOut(_bstr_t (harro), 0);
delete[] buffer;
delete[] harro;
#endif
int iRes = cNetService::g_fn_sendto( s, buf, len, flags, to, tolen );
if( iRes != SOCKET_ERROR && cNetService::g_pService != NULL )
cNetService::g_pService->m_stack.processPacketOut( static_cast< DWORD >( len ), reinterpret_cast< const BYTE * >( buf ) );
return iRes;
}
cNetService *cNetService::g_pService = NULL;
cNetService::fn_recvfrom cNetService::g_fn_recvfrom = NULL;
cNetService::fn_sendto cNetService::g_fn_sendto = NULL;
void cNetService::onMessage( ACMessage &msg )
{
_ASSERTE( m_pMessage != NULL );
DWORD dwMessageCode = msg.getType();
if( dwMessageCode == 0xF7C7 )
m_pDecal->StartPlugins();
else if(( dwMessageCode == 0xF653 ) || ( dwMessageCode == 0xF659 ))
m_pDecal->StopPlugins();
m_pMessage->crackMessage( msg.getData (), msg.getSize () );
// if( g_bLockMemoryPages )
// if( !LockMemoryPages( reinterpret_cast< void * >(m_pMessage) ) )
// return;
// Dispatch the message to all of the network filters
for( cFilterList::iterator i = m_filters.begin(); i != m_filters.end(); ++ i )
i->m_p->DispatchServer( m_pMessage );
}
void cNetService::onMessageOut( ACMessage &msg )
{
_ASSERTE( m_pMessage != NULL );
DWORD dwMessageCode = msg.getType();
m_pMessage->crackMessage( msg.getData (), msg.getSize () );
// Dispatch the message to all of the network filters
for( cFilterList::iterator i = m_filters.begin(); i != m_filters.end(); ++ i )
i->m_p->DispatchClient( m_pMessage );
}
STDMETHODIMP cNetService::BeforePlugins()
{
USES_CONVERSION;
// Startup version 1 network filters
RegKey hkeyNF;
if ( hkeyNF.Open ( HKEY_LOCAL_MACHINE, _T( "Software\\Decal\\NetworkFilters" ), KEY_READ ) == ERROR_SUCCESS )
{
// Enum the values
DWORD dwSize = 64;
TCHAR szCLSID[ 64 ];
for ( int i = 0; ::RegEnumValue ( hkeyNF, i, szCLSID, &dwSize, NULL, NULL, NULL, NULL ) == ERROR_SUCCESS; ++ i )
{
// Reset the sizes
dwSize = 64;
// Try to convert the string
cFilter f;
HRESULT hRes = ::CLSIDFromString ( T2OLE ( szCLSID ), &f.m_clsid );
if ( FAILED ( hRes ) )
// This is not a CLSID
continue;
// Check for enablement
DWORD dwEnabled;
hkeyNF.QueryDWORDValue ( szCLSID, dwEnabled );
if ( !dwEnabled )
continue;
// We have a CLSID - try to create the object and the adapter
CComObject< cFilterAdapterV1 > *pAdapter;
hRes = CComObject< cFilterAdapterV1 >::CreateInstance ( &pAdapter );
if ( FAILED ( hRes ) )
{
_ASSERT ( FALSE );
continue;
}
f.m_p = pAdapter;
hRes = pAdapter->init ( f.m_clsid );
if( SUCCEEDED( hRes ) )
{
f.m_ver = eVersion1;
m_filters.push_back( f );
}
}
}
return S_OK;
}
STDMETHODIMP cNetService::AfterPlugins()
{
// Remove all version 1 network filters
for ( cFilterList::iterator i = m_filters.begin (); i != m_filters.end (); )
{
if ( i->m_ver == eVersion1 )
i = m_filters.erase ( i );
else
++ i;
}
return S_OK;
}
STDMETHODIMP cNetService::Lookup( BSTR strName, IUnknown **ppvItf )
{
// Attempt to convert the name to a GUID
CLSID clsid;
HRESULT hRes;
if( strName[ 0 ] == OLECHAR( '{' ) )
hRes = ::CLSIDFromString( strName, &clsid );
else
hRes = ::CLSIDFromProgID( strName, &clsid );
if( FAILED( hRes ) )
{
_ASSERT( FALSE );
return E_INVALIDARG;
}
// Walk through the list of filters to find our match
for( cFilterList::iterator i = m_filters.begin(); i != m_filters.end(); ++ i )
{
if( i->m_clsid == clsid )
return i->m_p->QueryInterface( IID_IUnknown, reinterpret_cast< void ** >( ppvItf ) );
}
// Could not find a network filter with that class ID
_ASSERT( FALSE );
return E_INVALIDARG;
}
STDMETHODIMP cNetService::get_Decal(IDecal **pVal)
{
return m_pDecal->QueryInterface( pVal );
}
STDMETHODIMP cNetService::get_Filter(REFCLSID clsid, REFIID iid, LPVOID *pVal)
{
for( cFilterList::iterator i = m_filters.begin(); i != m_filters.end(); ++ i )
{
if( i->m_clsid == clsid )
return i->m_p->QueryInterface( iid, pVal );
}
return E_INVALIDARG;
}
STDMETHODIMP cNetService::get_FilterVB(BSTR strProgID, LPDISPATCH *pVal)
{
_ASSERTE( strProgID != NULL );
_ASSERTE( pVal != NULL );
// Prepend a fully-qualified service id
_bstr_t strPath ( _T( "services\\DecalNet.NetService\\" ) );
strPath += strProgID;
return m_pDecal->get_Object ( strPath, IID_IDispatch, reinterpret_cast< LPVOID * > ( pVal ) );
}
STDMETHODIMP cNetService::get_Hooks(IACHooks **pVal)
{
return m_pHooks->QueryInterface( pVal );
}
void __stdcall OnReceiveBlob (DWORD *pStructure)
{
LPBYTE pPacket = (LPBYTE) (pStructure [g_dwNetBlobObjectDataOffset]);
DWORD dwSize = pStructure [g_dwNetBlobObjectSizeOffset];
if (cNetService::g_pService)
{
HookedMessage msg (pPacket, dwSize);
cNetService::g_pService->onMessage (msg);
}
}
void __declspec (naked) ReceiveBlob()
{
_asm
{
push ecx
push ecx
call OnReceiveBlob
pop ecx
jmp g_dwReceiveBlobReadyProc
}
}
// Returns the function which previously was being called, after replacing it with the new call.
DWORD HookCall (DWORD dwCallAddress, DWORD dwReplacement)
{
DWORD* pTemp = (DWORD *) (dwCallAddress + 1);
HANDLE hProcess = OpenProcess
(
PROCESS_VM_WRITE | PROCESS_VM_OPERATION,
FALSE,
GetCurrentProcessId ()
);
DWORD dwOriginal = 0;
if (hProcess)
{
dwOriginal = (*pTemp) + dwCallAddress + 5;
DWORD dwTemp = dwReplacement - (dwCallAddress + 5);
if (WriteProcessMemory
(
hProcess,
pTemp,
&dwTemp,
sizeof (DWORD),
NULL
))
{
}
else
{
dwOriginal = 0;
}
CloseHandle (hProcess);
}
return dwOriginal ;
}

View file

@ -0,0 +1,86 @@
// NetService.h : Declaration of the cNetService
#ifndef __NETSERVICE_H_
#define __NETSERVICE_H_
#include "resource.h" // main symbols
#include <DecalImpl.h>
#include "ProtocolStack.h"
class cMessage;
/////////////////////////////////////////////////////////////////////////////
// cNetService
class ATL_NO_VTABLE cNetService :
public CComObjectRootEx<CComMultiThreadModel>,
public CComCoClass<cNetService, &CLSID_NetService>,
public INetService,
public IDecalServiceImpl< cNetService >,
public IDecalDirectory,
public ACMessageSink
{
public:
cNetService()
{
}
cMessageStack m_stack;
// IDecalServiceImpl overrides
HRESULT onInitialize();
void onTerminate();
CComPtr< IACHooks > m_pHooks;
static cNetService *g_pService;
typedef int (PASCAL *fn_recvfrom)(SOCKET, char FAR*, int , int, struct sockaddr FAR*, int FAR*);
typedef int (PASCAL *fn_sendto)(SOCKET, const char FAR*, int , int, const struct sockaddr FAR*, int);
static fn_recvfrom g_fn_recvfrom;
static fn_sendto g_fn_sendto;
// ACMessageSink overrides
virtual void onMessage( ACMessage& );
virtual void onMessageOut( ACMessage& );
// The network filter list
enum ePluginVersion { eVersion1, eVersion2 };
struct cFilter
{
ePluginVersion m_ver;
CLSID m_clsid;
CComPtr< INetworkFilter2 > m_p;
};
typedef std::list< cFilter > cFilterList;
cFilterList m_filters;
// The message parsing container
cMessage *m_pMessage;
DECLARE_REGISTRY_RESOURCEID(IDR_NETSERVICE)
DECLARE_PROTECT_FINAL_CONSTRUCT()
BEGIN_COM_MAP(cNetService)
COM_INTERFACE_ENTRY(INetService)
COM_INTERFACE_ENTRY(IDecalService)
COM_INTERFACE_ENTRY(IDecalDirectory)
END_COM_MAP()
public:
// IDecalService
STDMETHOD(BeforePlugins)();
STDMETHOD(AfterPlugins)();
// IDecalDirectory
STDMETHOD(Lookup)(BSTR strName, IUnknown **ppvItf);
// INetService
STDMETHOD(get_Decal)(/*[out, retval]*/ IDecal * *pVal);
STDMETHOD(get_Hooks)(IACHooks **pVal);
STDMETHOD(get_Filter)(REFCLSID clsid, REFIID iid, /*[out, retval]*/ LPVOID *pVal);
STDMETHOD(get_FilterVB)(BSTR strProgID, /*[out, retval]*/ LPDISPATCH *pVal);
};
#endif //__NETSERVICE_H_

View file

@ -0,0 +1,43 @@
HKCR
{
DecalNet.NetService.1 = s 'NetService Class'
{
CLSID = s '{C8C406F8-BA2E-4964-8B04-FF38394A8E0E}'
}
DecalNet.NetService = s 'NetService Class'
{
CLSID = s '{C8C406F8-BA2E-4964-8B04-FF38394A8E0E}'
CurVer = s 'DecalNet.NetService.1'
}
NoRemove CLSID
{
ForceRemove {C8C406F8-BA2E-4964-8B04-FF38394A8E0E} = s 'NetService Class'
{
ProgID = s 'DecalNet.NetService.1'
VersionIndependentProgID = s 'DecalNet.NetService'
ForceRemove 'Programmable'
InprocServer32 = s '%MODULE%'
{
val ThreadingModel = s 'Both'
}
'TypeLib' = s '{572B87C4-93BD-46B3-A291-CD58181D25DC}'
}
}
}
HKLM
{
NoRemove SOFTWARE
{
NoRemove Decal
{
NoRemove Services
{
ForceRemove {C8C406F8-BA2E-4964-8B04-FF38394A8E0E} = s 'Decal Networking Service'
{
val Enabled = d '1'
}
}
}
}
}

View file

@ -0,0 +1,44 @@
#pragma once
#include "ACMessage.h"
class HookedMessage : public ACMessage
{
public:
HookedMessage (BYTE *pData, DWORD dwSize)
{
_ASSERTE (pData != NULL);
_ASSERTE (m_dwSize >= 4);
m_pData = pData;
m_dwSize = dwSize;
}
virtual BYTE *getData ()
{
_ASSERTE (m_pData != NULL);
return m_pData;
}
virtual DWORD getSize ()
{
return m_dwSize;
}
virtual DWORD getType ()
{
_ASSERTE (m_pData);
_ASSERTE (m_dwSize >= sizeof (DWORD));
if (m_pData && m_dwSize >= sizeof (DWORD))
{
return * (DWORD *) m_pData;
}
return 0;
}
protected:
LPBYTE m_pData;
DWORD m_dwSize;
};

View file

@ -0,0 +1,313 @@
// ProtocolStack.cpp
// Implementation of class cProtocolStack
#include "stdafx.h"
#include "ProtocolStack.h"
cMessageStack::cProtocolMessage::cProtocolMessage( BYTE *pbData )
: m_pbData( NULL ),
m_pbReceived( NULL ),
m_bOwn( false )
{
cMessageHeader *pHeader = reinterpret_cast< cMessageHeader * >( pbData );
if( pHeader->m_wFragmentCount == 1 )
{
// This is the only fragment, we use a direct pointer for dispatching
m_pbData = pbData;
return;
}
// This message has multiple fragments, create a buffer
m_pbData = new BYTE[ calcMessageLength( pbData ) ];
m_pbReceived = new bool[ pHeader->m_wFragmentCount ];
::memset( m_pbReceived, 0, sizeof( bool ) * pHeader->m_wFragmentCount );
m_bOwn = true;
// Two initializers, with
// Copy the header into the new buffer
::memcpy( m_pbData, pbData, sizeof( cMessageHeader ) );
insertFragment( pbData );
}
cMessageStack::cProtocolMessage::cProtocolMessage( const cProtocolMessage &msg )
: m_pbData( msg.m_pbData ),
m_bOwn( msg.m_bOwn ),
m_pbReceived( msg.m_pbReceived )
{
//msg.m_pbData = NULL;
msg.m_bOwn = false;
//msg.m_pbReceived = NULL;
}
cMessageStack::cProtocolMessage::~cProtocolMessage()
{
if( m_bOwn )
{
delete[] m_pbData;
delete[] m_pbReceived;
}
}
cMessageStack::cProtocolMessage &cMessageStack::cProtocolMessage::operator= ( const cProtocolMessage &msg )
{
if( &msg == this )
// Do not copy to self
return *this;
if( m_bOwn )
{
delete[] m_pbData;
delete[] m_pbReceived;
}
m_pbData = msg.m_pbData;
m_pbReceived = msg.m_pbReceived;
m_bOwn = msg.m_bOwn;
//msg.m_pbData = NULL;
msg.m_bOwn = false;
//msg.m_pbReceived = NULL;
return *this;
}
bool cMessageStack::cProtocolMessage::isComplete() const
{
if( m_pbReceived == NULL )
// This is a single fragment
return true;
// Walk through all of the sections and make sure that we've found all the fragments
bool *pbEndReceived = m_pbReceived + getMessageHeader()->m_wFragmentCount;
for( bool *i = m_pbReceived; i != pbEndReceived; ++ i )
{
if( !(*i) )
return false;
}
// No unreceiced fragments found - it must be complete
return true;
}
bool cMessageStack::cProtocolMessage::fragmentMatch( BYTE *pFragmentStart )
{
cMessageHeader *pThis = getMessageHeader(),
*pOther = reinterpret_cast< cMessageHeader * >( pFragmentStart );
return ( pThis->m_dwObjectID == pOther->m_dwObjectID && pThis->m_dwSequence == pOther->m_dwSequence );
}
#define MESSAGE_BODY 448
void cMessageStack::cProtocolMessage::insertFragment( BYTE *pFragmentStart )
{
cMessageHeader *pHeader = reinterpret_cast< cMessageHeader * >( pFragmentStart );
if( m_pbReceived[ pHeader->m_wFragmentIndex ] )
// This fragment has already been inserted
return;
BYTE *pInsertLocation = m_pbData + sizeof( cMessageHeader ) + ( MESSAGE_BODY * pHeader->m_wFragmentIndex );
::memcpy( pInsertLocation, pFragmentStart + sizeof( cMessageHeader ), pHeader->m_wFragmentLength - sizeof( cMessageHeader ) );
// Mark this fragment as received
m_pbReceived[ pHeader->m_wFragmentIndex ] = true;
if( pHeader->m_wFragmentIndex == ( pHeader->m_wFragmentCount - 1 ) )
getMessageHeader()->m_wFragmentLength = ( pHeader->m_wFragmentCount - 1 ) * MESSAGE_BODY + pHeader->m_wFragmentLength;
}
DWORD cMessageStack::cProtocolMessage::calcMessageLength( BYTE *pFragmentStart )
{
cMessageHeader *pHeader = reinterpret_cast< cMessageHeader * >( pFragmentStart );
return ( pHeader->m_wFragmentIndex == ( pHeader->m_wFragmentCount - 1 ) ) ?
( pHeader->m_wFragmentCount - 1 ) * MESSAGE_BODY + pHeader->m_wFragmentLength : pHeader->m_wFragmentCount * MESSAGE_BODY + sizeof( cMessageHeader );
}
cMessageStack::cMessageStack()
: m_pCallback( NULL )
{
}
cMessageStack::~cMessageStack()
{
// Make sure we clean up and intermediate steps
stop();
}
void cMessageStack::start( ACMessageSink *pCallback )
{
// Setting this enables messages
m_pCallback = pCallback;
}
void cMessageStack::stop()
{
// Clean out the message list since these will never be matched
m_messages.clear();
m_pCallback = NULL;
}
void cMessageStack::processPacket( DWORD dwLength, BYTE *pbPayload )
{
// First filter based on our status and the message type
if( m_pCallback == NULL )
// We currently only support send or receive type messages
return;
// AC messages must be at least as big as a packet header.+ a message header
if (dwLength < (sizeof (cPacketHeader) + sizeof (cMessageHeader)))
return;
// Filter non-application messages
cPacketHeader *pHeader = reinterpret_cast< cPacketHeader * >( pbPayload );
if((pHeader->m_wTotalSize) != (dwLength - sizeof(cPacketHeader)))
return;
DWORD dwOffset = 0;
if (pHeader->m_dwFlags & 0x00100000)
// 8 extra header bytes
dwOffset += 8;
if (pHeader->m_dwFlags & 0x00200000)
// 6 extra header bytes
dwOffset += 6;
if (pHeader->m_dwFlags & 0x00800000)
// 4 extra header bytes
dwOffset += 4;
if (dwLength < (dwOffset + sizeof (cMessageHeader)))
return;
splitPacket( dwLength - dwOffset, pbPayload + dwOffset );
}
void cMessageStack::processPacketOut( DWORD dwLength, const BYTE *pbPayload )
{
// First filter based on our status and the message type
if( m_pCallback == NULL )
// We currently only support send or receive type messages
return;
// AC messages must be at least as big as a packet header.+ a message header
if (dwLength < (sizeof (cPacketHeader) + sizeof (cMessageHeader)))
return;
// Filter non-application messages
const cPacketHeader *pHeader = reinterpret_cast< const cPacketHeader * >( pbPayload );
if((pHeader->m_wTotalSize) != (dwLength - sizeof(cPacketHeader)))
return;
DWORD dwOffset = 0;
if (pHeader->m_dwFlags & 0x00100000)
// 8 extra header bytes
dwOffset += 8;
if (pHeader->m_dwFlags & 0x00200000)
// 6 extra header bytes
dwOffset += 6;
if (pHeader->m_dwFlags & 0x00800000)
// 4 extra header bytes
dwOffset += 4;
if (dwLength < (dwOffset + sizeof (cMessageHeader)))
return;
splitPacketOut( dwLength - dwOffset, const_cast<const BYTE *>(pbPayload + dwOffset) );
}
void cMessageStack::splitPacket( DWORD dwLength, BYTE *pbPayload )
{
DWORD dwFragLength = 0;
BYTE *i_end_packet = pbPayload + dwLength;
for( BYTE *iFrag = pbPayload + sizeof( cPacketHeader ); iFrag != i_end_packet; iFrag += dwFragLength )
{
dwFragLength = reinterpret_cast< cMessageHeader * >( iFrag )->m_wFragmentLength;
if( dwFragLength == 0 || ( iFrag + dwFragLength ) > i_end_packet )
// We are off the end somehow
return;
// First walk through our cached fragments and see if one will take this fragment
for( cMessageList::iterator i = m_messages.begin(); i != m_messages.end(); ++ i )
{
if( i->fragmentMatch( iFrag ) )
{
i->insertFragment( iFrag );
if( i->isComplete() )
{
// Remove it from the list and dispatch the message
m_pCallback->onMessage( *i );
m_messages.erase( i );
}
break;
}
}
if( i != m_messages.end() )
// The fragment was found in the list
continue;
// Ok, we have a new fragment on our hands - generate the fragment object
cProtocolMessage msg( iFrag );
if( msg.isComplete() )
// It's only one piece, dispatch right away
m_pCallback->onMessage( msg );
else
// This requires more parts add it into the queue to wait
m_messages.push_back( msg );
}
}
void cMessageStack::splitPacketOut( DWORD dwLength, const BYTE *pbPayload )
{
DWORD dwFragLength = 0;
BYTE *i_end_packet = const_cast< BYTE * >(pbPayload) + dwLength;
for( BYTE *iFrag = const_cast< BYTE * >(pbPayload) + sizeof( cPacketHeader ); iFrag != i_end_packet; iFrag += dwFragLength )
{
dwFragLength = reinterpret_cast< const cMessageHeader * >( iFrag )->m_wFragmentLength;
if( dwFragLength == 0 || ( iFrag + dwFragLength ) > i_end_packet )
// We are off the end somehow
return;
// First walk through our cached fragments and see if one will take this fragment
for( cMessageList::iterator i = m_messages.begin(); i != m_messages.end(); ++ i )
{
if( i->fragmentMatch( iFrag ) )
{
i->insertFragment( iFrag );
if( i->isComplete() )
{
// Remove it from the list and dispatch the message
m_pCallback->onMessageOut( *i );
m_messages.erase( i );
}
break;
}
}
if( i != m_messages.end() )
// The fragment was found in the list
continue;
// Ok, we have a new fragment on our hands - generate the fragment object
cProtocolMessage msg( iFrag );
if( msg.isComplete() )
// It's only one piece, dispatch right away
m_pCallback->onMessageOut( msg );
else
// This requires more parts add it into the queue to wait
m_messages.push_back( msg );
}
}

View file

@ -0,0 +1,106 @@
// ProtocolStack.h
// Declaration of class cProtocolStack
#ifndef __PROTOCOLSTACK_H
#define __PROTOCOLSTACK_H
#include "ACMessage.h"
#define DEFAULT_HEADER_SIZE 16
#define FRAGMENT_SIZE 448
#pragma pack( push, 1 )
// The packet header
struct cPacketHeader
{
DWORD m_dwSequence;
DWORD m_dwFlags;
DWORD m_dwCRC;
WORD m_wUnk1;
WORD m_wUnk2;
WORD m_wTotalSize;
WORD m_wUnk3;
};
#pragma pack( pop )
class cMessageStack
{
public:
#pragma pack( push, 1 )
struct cMessageHeader
{
DWORD m_dwSequence;
DWORD m_dwObjectID;
WORD m_wFragmentCount;
WORD m_wFragmentLength;
WORD m_wFragmentIndex,
m_wUnknown1;
};
#pragma pack( pop )
class cProtocolMessage : public ACMessage
{
protected:
mutable BYTE *m_pbData;
mutable bool *m_pbReceived;
mutable bool m_bOwn;
public:
cProtocolMessage( BYTE *pbData );
cProtocolMessage( const cProtocolMessage &msg );
~cProtocolMessage();
cMessageHeader *getMessageHeader() const
{
return reinterpret_cast< cMessageHeader * >( m_pbData );
}
cProtocolMessage &operator= ( const cProtocolMessage &msg );
// ACMessage interface implementation for protocol stack
virtual BYTE *getData ()
{
return m_pbData + sizeof( cMessageHeader );
}
virtual DWORD getSize ()
{
return getMessageHeader()->m_wFragmentLength - sizeof( cMessageHeader );
}
virtual DWORD getType ()
{
return *reinterpret_cast< DWORD * >( m_pbData + sizeof( cMessageHeader ) );
}
bool isComplete() const;
bool fragmentMatch( BYTE *pFragmentStart );
void insertFragment( BYTE *pFragmentStart );
static DWORD calcMessageLength( BYTE *pbHeader );
};
private:
typedef std::list< cProtocolMessage > cMessageList;
ACMessageSink *m_pCallback;
cMessageList m_messages;
public:
cMessageStack();
~cMessageStack();
void start( ACMessageSink * );
void stop();
void processPacket( DWORD dwLength, BYTE *pbPayload );
void processPacketOut( DWORD dwLength, const BYTE *pbPayload );
private:
void splitPacket( DWORD dwLength, BYTE *pbPayload );
void splitPacketOut( DWORD dwLength, const BYTE *pbPayload );
};
#endif

View file

@ -0,0 +1,12 @@
// stdafx.cpp : source file that includes just the standard includes
// stdafx.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information
#include "stdafx.h"
#ifdef _ATL_STATIC_REGISTRY
#include <statreg.h>
#include <statreg.cpp>
#endif
#include <atlimpl.cpp>

45
Native/DecalNet/StdAfx.h Normal file
View file

@ -0,0 +1,45 @@
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently,
// but are changed infrequently
#if !defined(AFX_STDAFX_H__88F425A2_1F36_4573_B1E2_C32EF26B2CBA__INCLUDED_)
#define AFX_STDAFX_H__88F425A2_1F36_4573_B1E2_C32EF26B2CBA__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#define STRICT
#define _WIN32_WINDOWS 0x0410
#define _ATL_APARTMENT_THREADED
#pragma warning(disable:4530)
//C Library includes
#include <stdio.h>
#include <stdlib.h>
#include <atlbase.h>
#include <atlcrypt.h>
//You may derive a class from CComModule and use it if you want to override
//something, but do not change the name of _Module
extern CComModule _Module;
#include <atlcom.h>
#include <Decal.h>
#include <time.h>
#include <list>
#include <string>
#include <map>
#include <deque>
#include <vector>
#include "../Include/VSBridge.h"
#import <msxml.dll>
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_STDAFX_H__88F425A2_1F36_4573_B1E2_C32EF26B2CBA__INCLUDED)

View file

@ -0,0 +1,108 @@
// WebRequest.cpp : Implementation of cWebRequest
#include "stdafx.h"
#include "DecalNet.h"
#include "WebRequest.h"
/////////////////////////////////////////////////////////////////////////////
// cWebRequest
STDMETHODIMP cWebRequest::Get(BSTR strURL)
{
USES_CONVERSION;
HRESULT hRes = ::URLOpenStream( NULL, OLE2T( strURL ), 0, this );
m_strPost = _bstr_t();
return hRes;
}
STDMETHODIMP cWebRequest::Post(BSTR strURL, BSTR strPostData)
{
USES_CONVERSION;
m_strPost = strPostData;
HRESULT hRes = ::URLOpenStream( NULL, OLE2T( strURL ), 0, this );
return hRes;
}
STDMETHODIMP cWebRequest::GetBindInfo(DWORD *pgrfBINDF, BINDINFO *pbindinfo)
{
USES_CONVERSION;
*pgrfBINDF = BINDF_ASYNCHRONOUS | BINDF_GETNEWESTVERSION | BINDF_ASYNCSTORAGE | BINDF_GETNEWESTVERSION | BINDF_NOWRITECACHE;
if( m_strPost.length() != 0 )
{
// We're doing a post operation - set the data into an HGLOBAL
::memset( pbindinfo, 0, sizeof( BINDINFO ) );
pbindinfo->cbSize = sizeof( BINDINFO );
pbindinfo->szExtraInfo = NULL;
LPCSTR strPost = OLE2A( m_strPost );
int nLength = m_strPost.length();
pbindinfo->stgmedData.tymed = TYMED_HGLOBAL;
pbindinfo->stgmedData.hGlobal = ::GlobalAlloc( GPTR, nLength );
pbindinfo->stgmedData.pUnkForRelease = static_cast< IBindStatusCallback * >( this );
pbindinfo->stgmedData.pUnkForRelease->AddRef();
::memcpy( pbindinfo->stgmedData.hGlobal, strPost, nLength );
// pbindinfo->grfBindInfoF = 0;
pbindinfo->dwBindVerb = BINDVERB_POST;
pbindinfo->dwCodePage = 0;
pbindinfo->cbstgmedData = nLength;
pbindinfo->grfBindInfoF = BINDINFOF_URLENCODESTGMEDDATA;
}
else
pbindinfo->dwBindVerb = BINDVERB_GET;
return S_OK;
}
STDMETHODIMP cWebRequest::OnDataAvailable(DWORD grfBSCF, DWORD dwSize, FORMATETC *pfmetc, STGMEDIUM *pstgmed )
{
if( pstgmed->tymed != TYMED_ISTREAM )
// We only support IStream format
return E_INVALIDARG;
char *strStr = new char[ dwSize + 1 ];
pstgmed->pstm->Read( strStr, dwSize, NULL );
strStr[ dwSize ] = '\0';
m_strResult += strStr;
delete[] strStr;
return S_OK;
}
STDMETHODIMP cWebRequest::OnStopBinding(HRESULT hr, LPCWSTR sz)
{
m_pBinding.Release();
m_strPost = _bstr_t();
Fire_End( ( SUCCEEDED( hr ) ) ? 200 : 400, m_strResult );
return S_OK;
}
STDMETHODIMP cWebRequest::BeginningTransaction(LPCWSTR szURL, LPCWSTR szHeaders, DWORD, LPWSTR *pszAdditionalRequestHeaders)
{
if( m_strPost.length() == 0 )
{
*pszAdditionalRequestHeaders = NULL;
return S_OK;
}
// Append a content-type so the server will understand that this is a form submission
LPCWSTR wszContent = L"Content-Type: application/x-www-form-urlencoded\r\n";
*pszAdditionalRequestHeaders = reinterpret_cast< LPWSTR >( ::CoTaskMemAlloc( sizeof( wchar_t ) * ( ::wcslen( wszContent ) + 1 ) ) );
::wcscpy( *pszAdditionalRequestHeaders, wszContent );
return S_OK;
}
STDMETHODIMP cWebRequest::OnResponse(DWORD dwResponseCode, LPCWSTR szResponseHeaders, LPCWSTR szRequestHeaders, LPWSTR *pszAdditionalRequestHeaders)
{
*pszAdditionalRequestHeaders = NULL;
return S_OK;
}

View file

@ -0,0 +1,92 @@
// WebRequest.h : Declaration of the cWebRequest
#ifndef __WEBREQUEST_H_
#define __WEBREQUEST_H_
#include "resource.h" // main symbols
#include "DecalNetCP.h"
/////////////////////////////////////////////////////////////////////////////
// cWebRequest
class ATL_NO_VTABLE cWebRequest :
public CComObjectRootEx<CComMultiThreadModel>,
public CComCoClass<cWebRequest, &CLSID_WebRequest>,
public IConnectionPointContainerImpl<cWebRequest>,
public IBindStatusCallback,
public IHttpNegotiate,
public IProvideClassInfo2Impl< &CLSID_WebRequest, &DIID_IWebRequestEvents, &LIBID_DecalNet >,
public IDispatchImpl<IWebRequest, &IID_IWebRequest, &LIBID_DecalNet>,
public CProxyIWebRequestEvents< cWebRequest >
{
public:
cWebRequest()
{
}
_bstr_t m_strResult;
_bstr_t m_strPost;
CComPtr< IBinding > m_pBinding;
DECLARE_REGISTRY_RESOURCEID(IDR_WEBREQUEST)
DECLARE_PROTECT_FINAL_CONSTRUCT()
BEGIN_COM_MAP(cWebRequest)
COM_INTERFACE_ENTRY(IBindStatusCallback)
COM_INTERFACE_ENTRY(IWebRequest)
COM_INTERFACE_ENTRY(IDispatch)
COM_INTERFACE_ENTRY(IHttpNegotiate)
COM_INTERFACE_ENTRY_IMPL(IConnectionPointContainer)
COM_INTERFACE_ENTRY(IProvideClassInfo)
COM_INTERFACE_ENTRY(IProvideClassInfo2)
END_COM_MAP()
BEGIN_CONNECTION_POINT_MAP(cWebRequest)
CONNECTION_POINT_ENTRY(DIID_IWebRequestEvents)
END_CONNECTION_POINT_MAP()
// IWebRequest
public:
STDMETHOD(Post)(BSTR strURL, BSTR strPostData);
STDMETHOD(Get)(BSTR strURL);
// IBindStatusCallback
STDMETHOD(GetBindInfo)(DWORD *pgrfBINDF, BINDINFO *pbindinfo);
STDMETHOD(GetPriority)(LONG *pnPriority)
{
*pnPriority = THREAD_PRIORITY_NORMAL;
return S_OK;
}
STDMETHOD(OnDataAvailable)(DWORD grfBSCF, DWORD dwSize, FORMATETC *pfmtetc, STGMEDIUM *pstgmed);
STDMETHOD(OnLowResource)(DWORD)
{
return E_NOTIMPL;
}
STDMETHOD(OnObjectAvailable)(REFIID, IUnknown *)
{
return E_NOTIMPL;
}
STDMETHOD(OnProgress)(ULONG, ULONG, ULONG, LPCWSTR)
{
return E_NOTIMPL;
}
STDMETHOD(OnStartBinding)(DWORD, IBinding *pBinding)
{
m_pBinding = pBinding;
// Reset the result
m_strResult = _bstr_t( _T( "" ) );
Fire_Begin();
return S_OK;
}
STDMETHOD(OnStopBinding)(HRESULT hr, LPCWSTR);
// IHttpNegotiate
STDMETHOD(BeginningTransaction)(LPCWSTR szURL, LPCWSTR szHeaders, DWORD, LPWSTR *pszAdditionalRequestHeaders);
STDMETHOD(OnResponse)(DWORD dwResponseCode, LPCWSTR szResponseHeaders, LPCWSTR szRequestHeaders, LPWSTR *pszAdditionalRequestHeaders);
};
#endif //__WEBREQUEST_H_

View file

@ -0,0 +1,26 @@
HKCR
{
DecalNet.WebRequest.1 = s 'WebRequest Class'
{
CLSID = s '{15631E36-55CB-4D16-ADE7-74D9F8A5F4B6}'
}
DecalNet.WebRequest = s 'WebRequest Class'
{
CLSID = s '{15631E36-55CB-4D16-ADE7-74D9F8A5F4B6}'
CurVer = s 'DecalNet.WebRequest.1'
}
NoRemove CLSID
{
ForceRemove {15631E36-55CB-4D16-ADE7-74D9F8A5F4B6} = s 'WebRequest Class'
{
ProgID = s 'DecalNet.WebRequest.1'
VersionIndependentProgID = s 'DecalNet.WebRequest'
ForceRemove 'Programmable'
InprocServer32 = s '%MODULE%'
{
val ThreadingModel = s 'Both'
}
'TypeLib' = s '{572B87C4-93BD-46B3-A291-CD58181D25DC}'
}
}
}

View file

@ -0,0 +1,19 @@
//{{NO_DEPENDENCIES}}
// Microsoft Developer Studio generated include file.
// Used by DecalNet.rc
//
#define IDS_PROJNAME 100
#define IDR_NETSERVICE 101
#define IDR_WEBREQUEST 102
#define IDR_MESSAGEROOT 103
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 201
#define _APS_NEXT_COMMAND_VALUE 32768
#define _APS_NEXT_CONTROL_VALUE 201
#define _APS_NEXT_SYMED_VALUE 104
#endif
#endif