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:
commit
d1442e3747
1382 changed files with 170725 additions and 0 deletions
16
Native/DecalNet/ACMessage.h
Normal file
16
Native/DecalNet/ACMessage.h
Normal 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;
|
||||
};
|
||||
74
Native/DecalNet/DecalNet.cpp
Normal file
74
Native/DecalNet/DecalNet.cpp
Normal 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);
|
||||
}
|
||||
|
||||
|
||||
9
Native/DecalNet/DecalNet.def
Normal file
9
Native/DecalNet/DecalNet.def
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
; DecalNet.def : Declares the module parameters.
|
||||
|
||||
LIBRARY "DecalNet.DLL"
|
||||
|
||||
EXPORTS
|
||||
DllCanUnloadNow PRIVATE
|
||||
DllGetClassObject PRIVATE
|
||||
DllRegisterServer PRIVATE
|
||||
DllUnregisterServer PRIVATE
|
||||
341
Native/DecalNet/DecalNet.dsp
Normal file
341
Native/DecalNet/DecalNet.dsp
Normal 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
134
Native/DecalNet/DecalNet.rc
Normal 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
|
||||
|
||||
1073
Native/DecalNet/DecalNet.vcproj
Normal file
1073
Native/DecalNet/DecalNet.vcproj
Normal file
File diff suppressed because it is too large
Load diff
60
Native/DecalNet/DecalNetCP.h
Normal file
60
Native/DecalNet/DecalNetCP.h
Normal 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
|
||||
11
Native/DecalNet/DecalNetps.def
Normal file
11
Native/DecalNet/DecalNetps.def
Normal 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
|
||||
16
Native/DecalNet/DecalNetps.mk
Normal file
16
Native/DecalNet/DecalNetps.mk
Normal 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
|
||||
21
Native/DecalNet/FilterAdapterV1.cpp
Normal file
21
Native/DecalNet/FilterAdapterV1.cpp
Normal 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 );
|
||||
}
|
||||
28
Native/DecalNet/FilterAdapterV1.h
Normal file
28
Native/DecalNet/FilterAdapterV1.h
Normal 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
393
Native/DecalNet/Message.cpp
Normal 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
161
Native/DecalNet/Message.h
Normal 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_
|
||||
363
Native/DecalNet/MessageImpl.h
Normal file
363
Native/DecalNet/MessageImpl.h
Normal 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
|
||||
207
Native/DecalNet/MessageLoaders.cpp
Normal file
207
Native/DecalNet/MessageLoaders.cpp
Normal 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;
|
||||
28
Native/DecalNet/MessageLoaders.h
Normal file
28
Native/DecalNet/MessageLoaders.h
Normal 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
|
||||
727
Native/DecalNet/MessageParsers.cpp
Normal file
727
Native/DecalNet/MessageParsers.cpp
Normal 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;
|
||||
48
Native/DecalNet/MessageParsers.h
Normal file
48
Native/DecalNet/MessageParsers.h
Normal 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
|
||||
8
Native/DecalNet/MessageRoot.cpp
Normal file
8
Native/DecalNet/MessageRoot.cpp
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
// MessageRoot.cpp : Implementation of cMessageRoot
|
||||
#include "stdafx.h"
|
||||
#include "DecalNet.h"
|
||||
#include "MessageRoot.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// cMessageRoot
|
||||
|
||||
90
Native/DecalNet/MessageRoot.h
Normal file
90
Native/DecalNet/MessageRoot.h
Normal 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_
|
||||
96
Native/DecalNet/MessageStruct.cpp
Normal file
96
Native/DecalNet/MessageStruct.cpp
Normal 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;
|
||||
}
|
||||
34
Native/DecalNet/MessageStruct.h
Normal file
34
Native/DecalNet/MessageStruct.h
Normal 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_
|
||||
103
Native/DecalNet/MessageVector.cpp
Normal file
103
Native/DecalNet/MessageVector.cpp
Normal 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;
|
||||
}
|
||||
37
Native/DecalNet/MessageVector.h
Normal file
37
Native/DecalNet/MessageVector.h
Normal 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_
|
||||
460
Native/DecalNet/NetService.cpp
Normal file
460
Native/DecalNet/NetService.cpp
Normal 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 ;
|
||||
}
|
||||
|
||||
86
Native/DecalNet/NetService.h
Normal file
86
Native/DecalNet/NetService.h
Normal 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_
|
||||
43
Native/DecalNet/NetService.rgs
Normal file
43
Native/DecalNet/NetService.rgs
Normal 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'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
44
Native/DecalNet/ProtocolHook.h
Normal file
44
Native/DecalNet/ProtocolHook.h
Normal 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;
|
||||
};
|
||||
313
Native/DecalNet/ProtocolStack.cpp
Normal file
313
Native/DecalNet/ProtocolStack.cpp
Normal 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 );
|
||||
}
|
||||
}
|
||||
106
Native/DecalNet/ProtocolStack.h
Normal file
106
Native/DecalNet/ProtocolStack.h
Normal 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
|
||||
12
Native/DecalNet/StdAfx.cpp
Normal file
12
Native/DecalNet/StdAfx.cpp
Normal 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
45
Native/DecalNet/StdAfx.h
Normal 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)
|
||||
108
Native/DecalNet/WebRequest.cpp
Normal file
108
Native/DecalNet/WebRequest.cpp
Normal 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;
|
||||
}
|
||||
92
Native/DecalNet/WebRequest.h
Normal file
92
Native/DecalNet/WebRequest.h
Normal 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_
|
||||
26
Native/DecalNet/WebRequest.rgs
Normal file
26
Native/DecalNet/WebRequest.rgs
Normal 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}'
|
||||
}
|
||||
}
|
||||
}
|
||||
19
Native/DecalNet/resource.h
Normal file
19
Native/DecalNet/resource.h
Normal 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
|
||||
Loading…
Add table
Add a link
Reference in a new issue