Initial commit: ROW Client source code
Game client codebase including: - CharacterActionControl: Character and creature management - GlobalScript: Network, items, skills, quests, utilities - RYLClient: Main client application with GUI and event handlers - Engine: 3D rendering engine (RYLGL) - MemoryManager: Custom memory allocation - Library: Third-party dependencies (DirectX, boost, etc.) - Tools: Development utilities 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
# Microsoft Developer Studio Project File - Name="MedParamBase" - Package Owner=<4>
|
||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Static Library" 0x0104
|
||||
|
||||
CFG=MedParamBase - 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 "MedParamBase.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 "MedParamBase.mak" CFG="MedParamBase - Win32 Debug"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "MedParamBase - Win32 Release" (based on "Win32 (x86) Static Library")
|
||||
!MESSAGE "MedParamBase - Win32 Debug" (based on "Win32 (x86) Static Library")
|
||||
!MESSAGE
|
||||
|
||||
# Begin Project
|
||||
# PROP AllowPerConfigDependencies 0
|
||||
# PROP Scc_ProjName ""
|
||||
# PROP Scc_LocalPath ""
|
||||
CPP=cl.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "MedParamBase - Win32 Release"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "Release"
|
||||
# PROP BASE Intermediate_Dir "Release"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "Release"
|
||||
# PROP Intermediate_Dir "Release"
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
|
||||
# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\..\..\..\..\include" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
|
||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||
# ADD RSC /l 0x409 /d "NDEBUG" /d "WIN32"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LIB32=link.exe -lib
|
||||
# ADD BASE LIB32 /nologo
|
||||
# ADD LIB32 /nologo
|
||||
|
||||
!ELSEIF "$(CFG)" == "MedParamBase - 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 Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
|
||||
# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /I "..\..\..\..\..\..\include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
|
||||
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||
# ADD RSC /l 0x409 /d "_DEBUG" /d "WIN32"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LIB32=link.exe -lib
|
||||
# ADD BASE LIB32 /nologo
|
||||
# ADD LIB32 /nologo
|
||||
|
||||
!ENDIF
|
||||
|
||||
# Begin Target
|
||||
|
||||
# Name "MedParamBase - Win32 Release"
|
||||
# Name "MedParamBase - Win32 Debug"
|
||||
# Begin Group "Source Files"
|
||||
|
||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\alist.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\param.cpp
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Header Files"
|
||||
|
||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\alist.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\param.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\validate.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# End Target
|
||||
# End Project
|
||||
@@ -0,0 +1,119 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: AList.cpp
|
||||
//
|
||||
// Desc: DirectShow sample code - implementation of AListItem and AList
|
||||
// classes.
|
||||
//
|
||||
// Copyright (c) 1998-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <windows.h>
|
||||
#include "alist.h"
|
||||
|
||||
LONG AListItem::GetCount(void) const
|
||||
{
|
||||
LONG l;
|
||||
const AListItem *li;
|
||||
|
||||
for(l=0,li=this; li!=NULL ; li=li->m_pNext,++l);
|
||||
return l;
|
||||
}
|
||||
|
||||
AListItem* AListItem::Cat(AListItem *pItem)
|
||||
{
|
||||
AListItem *li;
|
||||
|
||||
if(this==NULL)
|
||||
return pItem;
|
||||
for(li=this ; li->m_pNext!=NULL ; li=li->m_pNext);
|
||||
li->m_pNext=pItem;
|
||||
return this;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// AListItem::Remove
|
||||
|
||||
AListItem* AListItem::Remove(AListItem *pItem)
|
||||
{
|
||||
AListItem *li,*prev;
|
||||
|
||||
//treat remove(NULL) same as item not found in list
|
||||
if (pItem==NULL)
|
||||
return this;
|
||||
|
||||
if(pItem==this)
|
||||
return m_pNext;
|
||||
prev=NULL;
|
||||
for(li=this; li!=NULL && li!=pItem ; li=li->m_pNext)
|
||||
prev=li;
|
||||
if(li==NULL) // item not found in list
|
||||
return this;
|
||||
|
||||
// here it is guaranteed that prev is non-NULL since we checked for
|
||||
// that condition at the very beginning
|
||||
|
||||
prev->SetNext(li->m_pNext);
|
||||
li->SetNext(NULL);
|
||||
|
||||
// SetNext on pItem to NULL
|
||||
pItem->SetNext(NULL);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
AListItem* AListItem::GetPrev(AListItem *pItem) const
|
||||
{
|
||||
const AListItem *li,*prev;
|
||||
|
||||
prev=NULL;
|
||||
for(li=this ; li!=NULL && li!=pItem ; li=li->m_pNext)
|
||||
prev=li;
|
||||
return (AListItem*)prev;
|
||||
}
|
||||
|
||||
AListItem * AListItem::GetItem(LONG index)
|
||||
|
||||
{
|
||||
AListItem *scan;
|
||||
for (scan = this; scan!=NULL && index; scan = scan->m_pNext)
|
||||
{
|
||||
index--;
|
||||
}
|
||||
return (scan);
|
||||
}
|
||||
|
||||
void AList::InsertBefore(AListItem *pItem,AListItem *pInsert)
|
||||
|
||||
{
|
||||
AListItem *prev = GetPrev(pItem);
|
||||
pInsert->SetNext(pItem);
|
||||
if (prev) prev->SetNext(pInsert);
|
||||
else m_pHead = pInsert;
|
||||
}
|
||||
|
||||
|
||||
void AList::AddTail(AListItem *pItem)
|
||||
{
|
||||
if (m_pHead == NULL)
|
||||
{
|
||||
AddHead(pItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pHead = m_pHead->AddTail(pItem);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void AList::Reverse()
|
||||
|
||||
{
|
||||
AList Temp;
|
||||
AListItem *pItem;
|
||||
while ((pItem = RemoveHead()) != 0)
|
||||
{
|
||||
Temp.AddHead(pItem);
|
||||
}
|
||||
Cat(Temp.GetHead());
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: AList.h
|
||||
//
|
||||
// Desc: DirectShow sample code - definitions of AListItem and AList classes.
|
||||
//
|
||||
// Copyright (c) 1998-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __ALIST_H__
|
||||
#define __ALIST_H__
|
||||
|
||||
class AListItem
|
||||
{
|
||||
public:
|
||||
AListItem() { m_pNext=NULL; };
|
||||
AListItem *GetNext() const {return m_pNext;};
|
||||
void SetNext(AListItem *pNext) {m_pNext=pNext;};
|
||||
LONG GetCount() const;
|
||||
AListItem* Cat(AListItem* pItem);
|
||||
AListItem* AddTail(AListItem* pItem) {return Cat(pItem);};
|
||||
AListItem* Remove(AListItem* pItem);
|
||||
AListItem* GetPrev(AListItem *pItem) const;
|
||||
AListItem* GetItem(LONG index);
|
||||
|
||||
private:
|
||||
AListItem *m_pNext;
|
||||
};
|
||||
|
||||
class AList
|
||||
{
|
||||
public:
|
||||
AList() {m_pHead=NULL;};
|
||||
AListItem *GetHead() const { return m_pHead;};
|
||||
|
||||
void RemoveAll() { m_pHead=NULL;};
|
||||
LONG GetCount() const {return m_pHead->GetCount();};
|
||||
AListItem *GetItem(LONG index) { return m_pHead->GetItem(index);};
|
||||
void InsertBefore(AListItem *pItem,AListItem *pInsert);
|
||||
void Cat(AListItem *pItem) {m_pHead=m_pHead->Cat(pItem);};
|
||||
void Cat(AList *pList)
|
||||
{
|
||||
// assert(pList!=NULL);
|
||||
m_pHead=m_pHead->Cat(pList->GetHead());
|
||||
};
|
||||
void AddHead(AListItem *pItem)
|
||||
{
|
||||
// assert(pItem!=NULL);
|
||||
pItem->SetNext(m_pHead);
|
||||
m_pHead=pItem;
|
||||
}
|
||||
void AddTail(AListItem *pItem);// {m_pHead=m_pHead->AddTail(pItem);};
|
||||
void Remove(AListItem *pItem) {m_pHead=m_pHead->Remove(pItem);};
|
||||
AListItem *GetPrev(AListItem *pItem) const {return m_pHead->GetPrev(pItem);};
|
||||
AListItem *GetTail() const {return GetPrev(NULL);};
|
||||
BOOL IsEmpty(void) const {return (m_pHead==NULL);};
|
||||
AListItem *RemoveHead(void)
|
||||
{
|
||||
AListItem *li;
|
||||
li=m_pHead;
|
||||
if(m_pHead)
|
||||
m_pHead=m_pHead->GetNext();
|
||||
// li->SetNext(NULL);
|
||||
return li;
|
||||
}
|
||||
void Reverse();
|
||||
|
||||
protected:
|
||||
AListItem *m_pHead;
|
||||
};
|
||||
|
||||
#endif // __ALIST_H__
|
||||
@@ -0,0 +1,575 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: Param.cpp
|
||||
//
|
||||
// Desc: DirectShow sample code - definition of CParamsManager class.
|
||||
//
|
||||
// Copyright (c) 1999-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <windows.h>
|
||||
#include <medparam.h>
|
||||
#include "alist.h"
|
||||
#include "param.h"
|
||||
#include "dmerror.h"
|
||||
#include "param.h"
|
||||
#include "math.h"
|
||||
#include "validate.h"
|
||||
|
||||
// Disable some /W4 level warnings
|
||||
#pragma warning(disable:4296 4100 4505)
|
||||
|
||||
|
||||
CCurveList::~CCurveList()
|
||||
{
|
||||
while(this->GetHead())
|
||||
{
|
||||
delete this->RemoveHead();
|
||||
}
|
||||
}
|
||||
|
||||
CParamsManager::CParamsManager()
|
||||
|
||||
{
|
||||
m_fDirty = FALSE;
|
||||
m_cTimeFormats = 0;
|
||||
m_pguidTimeFormats = NULL;
|
||||
m_guidCurrentTimeFormat = GUID_NULL;
|
||||
m_cParams = 0;
|
||||
m_pCurveLists = NULL;
|
||||
m_pParamInfos = NULL;
|
||||
m_dwActiveBits = 0;
|
||||
InitializeCriticalSection(&m_ParamsCriticalSection);
|
||||
}
|
||||
|
||||
CParamsManager::~CParamsManager()
|
||||
{
|
||||
delete[] m_pguidTimeFormats;
|
||||
delete[] m_pCurveLists;
|
||||
delete[] m_pParamInfos;
|
||||
DeleteCriticalSection(&m_ParamsCriticalSection);
|
||||
}
|
||||
|
||||
HRESULT CParamsManager::InitParams(DWORD cTimeFormats, const GUID *pguidTimeFormats, DWORD dwFormatIndex, MP_TIMEDATA mptdTimeData, DWORD cParams, ParamInfo *pParamInfo)
|
||||
{
|
||||
//check that the index is in a valid range
|
||||
if (0 > dwFormatIndex || dwFormatIndex >= cTimeFormats || cParams > sizeof(DWORD) * 8)
|
||||
return E_INVALIDARG;
|
||||
|
||||
m_pCurveLists = new CCurveList[cParams];
|
||||
if (!m_pCurveLists)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
// save the time formats
|
||||
m_pguidTimeFormats = new GUID[cTimeFormats];
|
||||
if (!m_pguidTimeFormats)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
for (DWORD dwIndex = 0; dwIndex < cTimeFormats; dwIndex++)
|
||||
{
|
||||
memcpy(&m_pguidTimeFormats[dwIndex], &pguidTimeFormats[dwIndex], sizeof(*pguidTimeFormats));
|
||||
}
|
||||
|
||||
// save the count of formats
|
||||
m_cTimeFormats = cTimeFormats;
|
||||
|
||||
// save the current time format
|
||||
m_guidCurrentTimeFormat = m_pguidTimeFormats[dwFormatIndex];
|
||||
|
||||
// save the TimeData
|
||||
m_mptdCurrentTimeData = mptdTimeData;
|
||||
|
||||
// save the parameter info
|
||||
m_pParamInfos
|
||||
= new ParamInfo[cParams];
|
||||
if (!m_pParamInfos)
|
||||
return E_OUTOFMEMORY;
|
||||
for (dwIndex = 0; dwIndex < cParams; dwIndex++)
|
||||
{
|
||||
if (pParamInfo[dwIndex].dwIndex < cParams)
|
||||
{
|
||||
memcpy(&m_pParamInfos[pParamInfo[dwIndex].dwIndex],&pParamInfo[dwIndex],sizeof(ParamInfo));
|
||||
}
|
||||
}
|
||||
m_cParams = cParams;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CParamsManager::GetParamCount(DWORD *pdwParams)
|
||||
|
||||
{
|
||||
if (pdwParams == NULL)
|
||||
return E_POINTER;
|
||||
|
||||
*pdwParams = m_cParams;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CParamsManager::GetParamInfo(DWORD dwParamIndex,MP_PARAMINFO *pInfo)
|
||||
|
||||
{
|
||||
if (!pInfo)
|
||||
{
|
||||
return E_POINTER;
|
||||
}
|
||||
if (dwParamIndex < m_cParams)
|
||||
{
|
||||
*pInfo = m_pParamInfos[dwParamIndex].MParamInfo;
|
||||
return S_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT CParamsManager::GetParamText(DWORD dwParamIndex,WCHAR **ppwchText)
|
||||
|
||||
{
|
||||
if (!ppwchText)
|
||||
{
|
||||
return E_POINTER;
|
||||
}
|
||||
if (dwParamIndex < m_cParams)
|
||||
{
|
||||
// write string of format: "Label\0Unit\0Enums1\0Enum2\0...EnumN\0\0"
|
||||
ParamInfo &pinfo = m_pParamInfos[dwParamIndex];
|
||||
int iUnit = wcslen(pinfo.MParamInfo.szLabel) + 1; // begin writing unit text here
|
||||
int iEnums = iUnit + wcslen(pinfo.MParamInfo.szUnitText) + 1; // begin writing enum text here
|
||||
int iEnd = iEnums + wcslen(pinfo.pwchText) + 1; // write the final (second) null terminator here
|
||||
WCHAR *pwsz = static_cast<WCHAR *>(CoTaskMemAlloc((iEnd + 1) * sizeof(WCHAR)));
|
||||
if (!pwsz)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
// wcscpy will write into various points of the string, neatly terminating each with a null
|
||||
wcscpy(pwsz, pinfo.MParamInfo.szLabel);
|
||||
wcscpy(pwsz + iUnit, pinfo.MParamInfo.szUnitText);
|
||||
wcscpy(pwsz + iEnums, pinfo.pwchText);
|
||||
|
||||
// The text field was defined with commas to separate the enum values.
|
||||
// Replace them with NULL characters now.
|
||||
for (WCHAR *pwch = pwsz + iEnums; *pwch; ++pwch)
|
||||
{
|
||||
if (*pwch == L',')
|
||||
*pwch = L'\0';
|
||||
}
|
||||
|
||||
pwsz[iEnd] = L'\0';
|
||||
|
||||
*ppwchText = pwsz;
|
||||
return S_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT CParamsManager::GetNumTimeFormats(DWORD *pdwNumTimeFormats)
|
||||
|
||||
{
|
||||
if (!pdwNumTimeFormats)
|
||||
{
|
||||
return E_POINTER;
|
||||
}
|
||||
*pdwNumTimeFormats = m_cTimeFormats;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CParamsManager::GetSupportedTimeFormat(DWORD dwFormatIndex,GUID *pguidTimeFormat)
|
||||
|
||||
{
|
||||
if (!pguidTimeFormat)
|
||||
{
|
||||
return E_POINTER;
|
||||
}
|
||||
if (dwFormatIndex >= m_cTimeFormats)
|
||||
{
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
*pguidTimeFormat = m_pguidTimeFormats[dwFormatIndex];
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CParamsManager::GetCurrentTimeFormat( GUID *pguidTimeFormat,MP_TIMEDATA *pTimeData)
|
||||
|
||||
{
|
||||
HRESULT hr=S_OK;
|
||||
|
||||
// Parameter Validation
|
||||
if ((pguidTimeFormat == NULL) || (pTimeData == NULL))
|
||||
{
|
||||
hr = E_POINTER;
|
||||
}
|
||||
|
||||
// Return the values
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
*pguidTimeFormat = m_guidCurrentTimeFormat;
|
||||
*pTimeData = m_mptdCurrentTimeData;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
HRESULT CParamsManager::CopyParamsFromSource( CParamsManager * pSource)
|
||||
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
DWORD dwIndex;
|
||||
|
||||
for (dwIndex = 0; dwIndex < m_cTimeFormats; dwIndex++)
|
||||
{
|
||||
if (pSource->m_guidCurrentTimeFormat == m_pguidTimeFormats[dwIndex])
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
hr = InitParams(pSource->m_cTimeFormats, pSource->m_pguidTimeFormats, dwIndex, pSource->m_mptdCurrentTimeData, pSource->m_cParams,pSource->m_pParamInfos);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
for (dwIndex = 0; dwIndex < m_cParams; dwIndex++)
|
||||
{
|
||||
CCurveItem *pCurve = pSource->m_pCurveLists[dwIndex].GetHead();
|
||||
for (;pCurve;pCurve = pCurve->GetNext())
|
||||
{
|
||||
CCurveItem *pNew = new CCurveItem;
|
||||
if (!pNew)
|
||||
{
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
pNew->m_Envelope = pCurve->m_Envelope;
|
||||
m_pCurveLists[dwIndex].AddTail(pNew);
|
||||
}
|
||||
}
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
void
|
||||
CParamsManager ::UpdateActiveParams(REFERENCE_TIME rtTime, UpdateCallback &rThis)
|
||||
{
|
||||
if (!m_dwActiveBits)
|
||||
return; // nothing to recalc
|
||||
|
||||
DWORD dwBit = 1;
|
||||
for (DWORD dwIndex = 0; dwIndex < m_cParams; dwIndex++, dwBit = dwBit << 1)
|
||||
{
|
||||
if (m_dwActiveBits & dwBit)
|
||||
{
|
||||
float fVal = 0;
|
||||
HRESULT hr = GetParamFloat(dwIndex, rtTime, &fVal);
|
||||
rThis.SetParamUpdate(dwIndex, fVal);
|
||||
if (hr == S_FALSE)
|
||||
m_dwActiveBits &= ~dwBit; // we're beyond the last curve, don't need to recalc next time
|
||||
|
||||
//TraceI(6, "DMO value: time %I64d, param #%d, current value %hf\n", rtTime, dwIndex, fVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline float ValRange(float valToClip, float valMin, float valMax)
|
||||
{
|
||||
return valToClip < valMin
|
||||
? valMin
|
||||
: (valToClip > valMax ? valMax : valToClip);
|
||||
}
|
||||
|
||||
HRESULT CParamsManager::GetParamFloat(DWORD dwParamIndex,REFERENCE_TIME rtTime,float *pval)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
if (dwParamIndex >= m_cParams)
|
||||
return E_INVALIDARG;
|
||||
|
||||
EnterCriticalSection(&m_ParamsCriticalSection);
|
||||
CCurveList *pList = &m_pCurveLists[dwParamIndex];
|
||||
ParamInfo *pInfo = &m_pParamInfos[dwParamIndex];
|
||||
|
||||
// if no points, then neutral value
|
||||
CCurveItem *pCurveHead = pList->GetHead();
|
||||
if (!pCurveHead)
|
||||
{
|
||||
*pval = pInfo->MParamInfo.mpdNeutralValue;
|
||||
LeaveCriticalSection(&m_ParamsCriticalSection);
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
// Find the curve during or before the requested time
|
||||
// If the time is during a curve, we will use that.
|
||||
// If not, we need the end value of the previous curve.
|
||||
// Our list keeps these in backwards order, so we are scanning from the
|
||||
// highest point in time backwards.
|
||||
|
||||
for (CCurveItem *pCurve = pCurveHead; pCurve && pCurve->m_Envelope.rtStart > rtTime;pCurve = pCurve->GetNext());
|
||||
|
||||
// If there is no pCurve, there was no curve prior to or during rtTime. Give up.
|
||||
if (!pCurve)
|
||||
{
|
||||
*pval = pInfo->MParamInfo.mpdNeutralValue;
|
||||
LeaveCriticalSection(&m_ParamsCriticalSection);
|
||||
return S_OK;
|
||||
}
|
||||
// Now, if pCurve ends before the requested time,
|
||||
// return the final value of pCurve, since that will hold until the start of the next curve.
|
||||
if (pCurve->m_Envelope.rtEnd < rtTime)
|
||||
{
|
||||
*pval = pCurve->m_Envelope.valEnd;
|
||||
LeaveCriticalSection(&m_ParamsCriticalSection);
|
||||
if (pCurve == pCurveHead)
|
||||
return S_FALSE; // past last curve
|
||||
else
|
||||
return S_OK; // there are more curves ahead
|
||||
}
|
||||
|
||||
// If we get this far, the curve must bound rtTime.
|
||||
|
||||
if (pCurve->m_Envelope.iCurve & MP_CURVE_JUMP)
|
||||
{
|
||||
*pval = pCurve->m_Envelope.valEnd;
|
||||
LeaveCriticalSection(&m_ParamsCriticalSection);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
REFERENCE_TIME rtTimeChange = pCurve->m_Envelope.rtEnd - pCurve->m_Envelope.rtStart;
|
||||
REFERENCE_TIME rtTimeIntermediate = rtTime - pCurve->m_Envelope.rtStart;
|
||||
|
||||
float fltScalingX = static_cast<float>(rtTimeIntermediate) / rtTimeChange; // horizontal distance along curve between 0 and 1
|
||||
float fltScalingY; // height of curve at that point between 0 and 1 based on curve function
|
||||
switch (pCurve->m_Envelope.iCurve)
|
||||
{
|
||||
case MP_CURVE_SQUARE:
|
||||
fltScalingY = fltScalingX * fltScalingX;
|
||||
break;
|
||||
case MP_CURVE_INVSQUARE:
|
||||
fltScalingY = (float) sqrt(fltScalingX);
|
||||
break;
|
||||
case MP_CURVE_SINE:
|
||||
// <20><> Maybe we should have a lookup table here?
|
||||
fltScalingY = (float) (sin(fltScalingX * 3.1415926535 - (3.1415926535/2)) + 1) / 2;
|
||||
break;
|
||||
case MP_CURVE_LINEAR:
|
||||
default:
|
||||
fltScalingY = fltScalingX;
|
||||
}
|
||||
|
||||
// Find out if we need to pull the start point from the previous curve,
|
||||
// the default neutral value, or the current curve.
|
||||
float fStartVal = pCurve->m_Envelope.valStart;
|
||||
if (pCurve->m_Envelope.flags & MPF_ENVLP_BEGIN_NEUTRALVAL)
|
||||
{
|
||||
fStartVal = pInfo->MParamInfo.mpdNeutralValue;
|
||||
}
|
||||
// Currentval, if it exists, will override neutralval.
|
||||
if (pCurve->m_Envelope.flags & MPF_ENVLP_BEGIN_CURRENTVAL)
|
||||
{
|
||||
// Take advantage of the fact that these are inserted in backwards order.
|
||||
// Scan for the previous curve that ends before this time.
|
||||
CCurveItem *pPrevious = pCurve->GetNext();
|
||||
for (;pPrevious && pPrevious->m_Envelope.rtEnd > rtTime;pPrevious = pPrevious->GetNext());
|
||||
if (pPrevious)
|
||||
{
|
||||
fStartVal = pPrevious->m_Envelope.valEnd;
|
||||
}
|
||||
}
|
||||
|
||||
// Apply that scaling to the range of the actual points
|
||||
*pval = (pCurve->m_Envelope.valEnd - fStartVal) * fltScalingY + fStartVal;
|
||||
|
||||
LeaveCriticalSection(&m_ParamsCriticalSection);
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT CParamsManager::GetParamInt(DWORD dwParamIndex,REFERENCE_TIME rt,long *pval)
|
||||
|
||||
{
|
||||
HRESULT hr = E_POINTER;
|
||||
if (pval)
|
||||
{
|
||||
float fVal;
|
||||
hr = GetParamFloat(dwParamIndex,rt,&fVal);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
*pval = (long) (fVal + 1/2); // Round.
|
||||
}
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// IMediaParams
|
||||
|
||||
HRESULT CParamsManager::GetParam(DWORD dwParamIndex,MP_DATA *pValue)
|
||||
{
|
||||
V_INAME(CParams::GetParam);
|
||||
V_PTR_WRITE(pValue, MP_DATA);
|
||||
|
||||
if (dwParamIndex >= m_cParams)
|
||||
return E_INVALIDARG;
|
||||
|
||||
EnterCriticalSection(&m_ParamsCriticalSection);
|
||||
|
||||
CCurveList *pList = &m_pCurveLists[dwParamIndex];
|
||||
ParamInfo *pInfo = &m_pParamInfos[dwParamIndex];
|
||||
// if no points, then neutral value
|
||||
CCurveItem *pCurve = pList->GetHead();
|
||||
if (pCurve)
|
||||
{
|
||||
*pValue = pCurve->m_Envelope.valEnd;
|
||||
}
|
||||
else
|
||||
{
|
||||
*pValue = pInfo->MParamInfo.mpdNeutralValue;
|
||||
}
|
||||
LeaveCriticalSection(&m_ParamsCriticalSection);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CParamsManager::SetParam(DWORD dwParamIndex,MP_DATA value)
|
||||
{
|
||||
V_INAME(CParams::SetParam);
|
||||
|
||||
if (dwParamIndex >= m_cParams)
|
||||
return E_INVALIDARG;
|
||||
|
||||
EnterCriticalSection(&m_ParamsCriticalSection);
|
||||
m_fDirty = TRUE;
|
||||
CCurveList *pList = &m_pCurveLists[dwParamIndex];
|
||||
// ParamInfo *pInfo = &m_pParamInfos[dwParamIndex];
|
||||
|
||||
// If we've already got a list, just force the most recent curve item to this value.
|
||||
// Otherwise, create a node and add it.
|
||||
CCurveItem *pCurve = pList->GetHead();
|
||||
if (!pCurve)
|
||||
{
|
||||
pCurve = new CCurveItem;
|
||||
if (pCurve)
|
||||
{
|
||||
pCurve->m_Envelope.rtStart = 0x8000000000000000; // Max negative.
|
||||
pCurve->m_Envelope.rtEnd = 0x7FFFFFFFFFFFFFFF; // Max positive.
|
||||
pCurve->m_Envelope.flags = 0;
|
||||
pList->AddHead(pCurve);
|
||||
}
|
||||
else
|
||||
{
|
||||
LeaveCriticalSection(&m_ParamsCriticalSection);
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
}
|
||||
pCurve->m_Envelope.valStart = value;
|
||||
pCurve->m_Envelope.valEnd = value;
|
||||
pCurve->m_Envelope.iCurve = MP_CURVE_JUMP;
|
||||
LeaveCriticalSection(&m_ParamsCriticalSection);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CParamsManager::AddEnvelope(
|
||||
DWORD dwParamIndex,
|
||||
DWORD cPoints,
|
||||
MP_ENVELOPE_SEGMENT *ppEnvelope)
|
||||
{
|
||||
V_INAME(CParams::AddEnvelope);
|
||||
V_PTR_READ(ppEnvelope, *ppEnvelope);
|
||||
|
||||
if (dwParamIndex >= m_cParams)
|
||||
return E_INVALIDARG;
|
||||
|
||||
if (!m_pParamInfos)
|
||||
return DMUS_E_NOT_INIT;
|
||||
|
||||
HRESULT hr = S_OK;
|
||||
EnterCriticalSection(&m_ParamsCriticalSection);
|
||||
m_fDirty = TRUE;
|
||||
|
||||
CCurveList *pList = &m_pCurveLists[dwParamIndex];
|
||||
ParamInfo *pInfo = &m_pParamInfos[dwParamIndex];
|
||||
|
||||
DWORD dwCount;
|
||||
for (dwCount = 0; dwCount < cPoints; dwCount++)
|
||||
{
|
||||
CCurveItem *pCurve = new CCurveItem;
|
||||
if (!pCurve)
|
||||
{
|
||||
hr = E_OUTOFMEMORY;
|
||||
break;
|
||||
}
|
||||
pCurve->m_Envelope = ppEnvelope[dwCount];
|
||||
pCurve->m_Envelope.valEnd = ValRange(pCurve->m_Envelope.valEnd,
|
||||
pInfo->MParamInfo.mpdMinValue, pInfo->MParamInfo.mpdMaxValue);
|
||||
pCurve->m_Envelope.valStart = ValRange(pCurve->m_Envelope.valStart,
|
||||
pInfo->MParamInfo.mpdMinValue, pInfo->MParamInfo.mpdMaxValue);
|
||||
pList->AddHead(pCurve);
|
||||
m_dwActiveBits |= 1 << dwParamIndex; // next call to UpdateActiveParams will ensure the parameter's value is recalculated
|
||||
|
||||
//TraceI(6, "DMO envelope: time %I64d-%I64d, param #%d, value %hf-%hf\n",
|
||||
// pCurve->m_Envelope.rtStart, pCurve->m_Envelope.rtEnd,
|
||||
// dwParamIndex, pCurve->m_Envelope.valStart, pCurve->m_Envelope.valEnd);
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&m_ParamsCriticalSection);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT CParamsManager::FlushEnvelope(
|
||||
DWORD dwParamIndex,
|
||||
REFERENCE_TIME refTimeStart,
|
||||
REFERENCE_TIME refTimeEnd)
|
||||
{
|
||||
if (dwParamIndex >= m_cParams)
|
||||
return E_INVALIDARG;
|
||||
|
||||
if (!m_pParamInfos)
|
||||
return DMUS_E_NOT_INIT;
|
||||
|
||||
if (refTimeStart >= refTimeEnd)
|
||||
return E_INVALIDARG;
|
||||
|
||||
EnterCriticalSection(&m_ParamsCriticalSection);
|
||||
m_fDirty = TRUE;
|
||||
CCurveList *pList = &m_pCurveLists[dwParamIndex];
|
||||
// ParamInfo *pInfo = &m_pParamInfos[dwParamIndex];
|
||||
|
||||
CCurveList TempList;
|
||||
CCurveItem *pCurve;
|
||||
while ((pCurve = pList->RemoveHead()) != 0)
|
||||
{
|
||||
if ((pCurve->m_Envelope.rtStart >= refTimeStart) &&
|
||||
(pCurve->m_Envelope.rtEnd <= refTimeEnd))
|
||||
{
|
||||
delete pCurve;
|
||||
}
|
||||
else
|
||||
{
|
||||
TempList.AddHead(pCurve);
|
||||
}
|
||||
}
|
||||
while ((pCurve = TempList.RemoveHead()) != 0)
|
||||
{
|
||||
pList->AddHead(pCurve);
|
||||
}
|
||||
LeaveCriticalSection(&m_ParamsCriticalSection);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CParamsManager::SetTimeFormat(
|
||||
GUID guidTimeFormat,
|
||||
MP_TIMEDATA mpTimeData)
|
||||
{
|
||||
for (DWORD dwIndex = 0; dwIndex < m_cTimeFormats; dwIndex++)
|
||||
{
|
||||
if (guidTimeFormat == m_pguidTimeFormats[dwIndex])
|
||||
{
|
||||
m_guidCurrentTimeFormat = m_pguidTimeFormats[dwIndex];
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: Param.h
|
||||
//
|
||||
// Desc: DirectShow sample code - definitions of CCurveItem, CCurveList,
|
||||
// and CParamsManager classes.
|
||||
//
|
||||
// Copyright (c) 1999-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#ifndef __TOOLPARAM_H__
|
||||
#define __TOOLPARAM_H__
|
||||
|
||||
|
||||
|
||||
#include "medparam.h"
|
||||
#include "alist.h"
|
||||
|
||||
typedef struct _ParamInfo
|
||||
{
|
||||
DWORD dwIndex; // Which parameter.
|
||||
MP_PARAMINFO MParamInfo; // Standard MediaParams structure.
|
||||
WCHAR * pwchText; // Array of text names for enumerated types.
|
||||
} ParamInfo;
|
||||
|
||||
class CCurveItem : public AListItem
|
||||
{
|
||||
public:
|
||||
CCurveItem* GetNext() { return (CCurveItem*)AListItem::GetNext();}
|
||||
MP_ENVELOPE_SEGMENT m_Envelope; // Envelope segment.
|
||||
};
|
||||
|
||||
class CCurveList : public AList
|
||||
{
|
||||
public:
|
||||
// void Clear();
|
||||
void AddHead(CCurveItem* pCurveItem) { AList::AddHead((AListItem*)pCurveItem);}
|
||||
// void Insert(CCurveItem* pCurveItem);
|
||||
CCurveItem* GetHead(){return (CCurveItem*)AList::GetHead();}
|
||||
// CCurveItem* GetItem(LONG lIndex){return (CCurveItem*)AList::GetItem(lIndex);}
|
||||
CCurveItem* RemoveHead(){ return (CCurveItem*)AList::RemoveHead();}
|
||||
// void Remove(CCurveItem* pCurveItem){AList::Remove((AListItem*)pCurveItem);}
|
||||
// void AddTail(CCurveItem* pCurveItem){AList::AddTail((AListItem*)pCurveItem);}
|
||||
// CCurveItem* GetTail(){ return (CCurveItem*)AList::GetTail();}
|
||||
~CCurveList();
|
||||
};
|
||||
|
||||
#define MAX_REF_TIME 0x7FFFFFFFFFFFFFFF
|
||||
#define MP_CAPS_ALL MP_CAPS_CURVE_JUMP | MP_CAPS_CURVE_LINEAR | MP_CAPS_CURVE_SQUARE | MP_CAPS_CURVE_INVSQUARE | MP_CAPS_CURVE_SINE
|
||||
|
||||
class CParamsManager : public IMediaParams, public IMediaParamInfo
|
||||
{
|
||||
public:
|
||||
CParamsManager();
|
||||
~CParamsManager();
|
||||
|
||||
// IUnknown
|
||||
STDMETHOD(QueryInterface)(REFIID, LPVOID FAR *) PURE;
|
||||
STDMETHOD_(ULONG, AddRef)() PURE;
|
||||
STDMETHOD_(ULONG, Release)() PURE;
|
||||
|
||||
// IMediaParams
|
||||
STDMETHODIMP GetParam(DWORD dwParamIndex, MP_DATA *pValue);
|
||||
STDMETHODIMP SetParam(DWORD dwParamIndex,MP_DATA value);
|
||||
STDMETHODIMP AddEnvelope(DWORD dwParamIndex,DWORD cPoints,MP_ENVELOPE_SEGMENT *ppEnvelope);
|
||||
STDMETHODIMP FlushEnvelope( DWORD dwParamIndex,REFERENCE_TIME refTimeStart,REFERENCE_TIME refTimeEnd);
|
||||
STDMETHODIMP SetTimeFormat( GUID guidTimeFormat,MP_TIMEDATA mpTimeData);
|
||||
|
||||
// IMediaParamInfo
|
||||
STDMETHODIMP GetParamCount(DWORD *pdwParams);
|
||||
STDMETHODIMP GetParamInfo(DWORD dwParamIndex,MP_PARAMINFO *pInfo);
|
||||
STDMETHODIMP GetParamText(DWORD dwParamIndex,WCHAR **ppwchText);
|
||||
STDMETHODIMP GetNumTimeFormats(DWORD *pdwNumTimeFormats);
|
||||
STDMETHODIMP GetSupportedTimeFormat(DWORD dwFormatIndex,GUID *pguidTimeFormat);
|
||||
STDMETHODIMP GetCurrentTimeFormat( GUID *pguidTimeFormat,MP_TIMEDATA *pTimeData);
|
||||
|
||||
// other (non-COM) functions
|
||||
HRESULT InitParams(DWORD cTimeFormats, const GUID *pguidTimeFormats, DWORD dwFormatIndex, MP_TIMEDATA mptdTimeData, DWORD cParams, ParamInfo *pParamInfos);
|
||||
HRESULT GetParamFloat(DWORD dwParamIndex,REFERENCE_TIME rtTime,float *pval); // returns S_FALSE if rtTime is after the end time of the last curve
|
||||
HRESULT GetParamInt (DWORD dwParamIndex,REFERENCE_TIME rt,long *pval); // returns S_FALSE if rtTime is after the end time of the last curve
|
||||
HRESULT CopyParamsFromSource(CParamsManager * pSource);
|
||||
|
||||
// parameter control curve handling
|
||||
class UpdateCallback
|
||||
{
|
||||
public:
|
||||
// Define this in derived classes if you are going to use UpdateActiveParams.
|
||||
// Called by CParamsManager inside UpdateActiveParams to update the effect's internal state variables.
|
||||
// SetParamUpdate should be the same as SetParam, except that DMO defer the call to the base class
|
||||
// (CParamsManager::SetParam) in SetParam but should not do so in SetParamUpdate.
|
||||
virtual HRESULT SetParamUpdate(DWORD dwParamIndex, MP_DATA value) = 0;
|
||||
};
|
||||
// function that calls SetParam to adjust the value of all parameters that may have changed to their
|
||||
// new values at time rtTime
|
||||
void UpdateActiveParams(REFERENCE_TIME rtTime, UpdateCallback &rThis); // rThis should be the derived class (*this)
|
||||
DWORD GetActiveParamBits() { return m_dwActiveBits; }
|
||||
|
||||
protected:
|
||||
// data
|
||||
|
||||
CRITICAL_SECTION m_ParamsCriticalSection;
|
||||
BOOL m_fDirty; // Has data changed since last file load or save?
|
||||
DWORD m_cTimeFormats; // Number of supported time formats.
|
||||
GUID *m_pguidTimeFormats; // Array of supported time formats.
|
||||
GUID m_guidCurrentTimeFormat; // The time format we're set to.
|
||||
MP_TIMEDATA m_mptdCurrentTimeData; // The unit of measure for the current time format.
|
||||
DWORD m_cParams; // Number of parameters.
|
||||
ParamInfo *m_pParamInfos; // Array of ParamInfo structures, one for each parameter.
|
||||
CCurveList *m_pCurveLists; // Array of Curve lists, one for each parameter.
|
||||
DWORD m_dwActiveBits; // Tracks the params that currently have curves active.
|
||||
};
|
||||
|
||||
#endif // __TOOLPARAM_H__
|
||||
@@ -0,0 +1,304 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: Validate.h
|
||||
//
|
||||
// Desc: DirectShow sample code - parameter validation macros.
|
||||
//
|
||||
// Copyright (c) 1997-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
// Summary:
|
||||
//
|
||||
// V_INAME(interfacename) - Set the interface name for error display
|
||||
// V_STRUCTPTR_READ(ptr,type) - A dwSize struct which we will read
|
||||
// V_STRUCTPTR_WRITE(ptr,type) - A dwSize struct which we will read/write
|
||||
// V_PTR_READ(ptr,type) - A typed ptr w/o a dwSize which we will read
|
||||
// V_PTR_WRITE(ptr,type) - A typed ptr w/o a dwSize which we will read/write
|
||||
// V_PTR_WRITE_OPT(ptr,type) - An optional typed ptr w/o a dwSize which we will read/write
|
||||
// V_BUFPTR_READ(ptr,size) - A variable-size buffer that we will read
|
||||
// V_BUFPTR_READ_OPT(ptr,size) - An optional variable-size buffer that we will read
|
||||
// V_BUFPTR_WRITE(ptr,size) - A variable-size buffer that we will read/write
|
||||
// V_BUFPTR_WRITE_OPT(ptr,size) - An optional variable-size buffer that we will read/write
|
||||
// V_PTRPTR_WRITE(ptrptr) - A pointer to a pointer to write to
|
||||
// V_PTRPTR_WRITE_OPT(ptrptr) - A pointer to a pointer to write to that is optional
|
||||
// V_PUNKOUTER(punk) - A pointer to a controlling unknown, aggregation supported
|
||||
// V_PUNKOUTER_NOADD(punk) - A pointer to a controlling unknown, aggregation not supported
|
||||
// V_INTERFACE(ptr) - A pointer to a COM interface
|
||||
// V_INTERFACE_OPT(ptr) - An optional pointer to a COM interface
|
||||
// V_REFGUID(ref) - A reference to a GUID (type REFGUID)
|
||||
// V_HWND(hwnd) - A window handle
|
||||
// V_HWNDOPT(hwnd) - An optional window handle
|
||||
//
|
||||
// For handling different versions of structures:
|
||||
//
|
||||
// V_STRUCTPTR_READ_VER(ptr,ver) - Begin a struct version block for read access
|
||||
// At the end, 'ver' will contain the
|
||||
// discovered version of the struct
|
||||
// V_STRUCTPTR_READ_VER_CASE(base,ver) - Test struct against version ver of
|
||||
// type 'base'.
|
||||
// V_STRUCTPTR_READ_VER_END(base,ptr) - End a struct version block
|
||||
//
|
||||
// V_STRUCTPTR_WRITE_VER(ptr,ver) - Struct version block for write access
|
||||
// V_STRUCTPTR_WRITE_VER_CASE(base,ver)
|
||||
// V_STRUCTPTR_WRITE_VER_END(base,ptr)
|
||||
//
|
||||
// The struct version block expects type names of a base type followed by a
|
||||
// numeric version, such as
|
||||
//
|
||||
// typedef struct { } FOO7;
|
||||
// typedef struct { } FOO8;
|
||||
//
|
||||
// In the header FOO and LPFOO are conditionally typedef'd based on a version
|
||||
// #define. The DLL will be compiled with the latest version number and hence
|
||||
// the largest version of the struct.
|
||||
//
|
||||
// Since Windows headers are compiled by default with 8-byte alignment, adding
|
||||
// one DWORD may not cause the size of the structure to change. If this happens
|
||||
// you will get a 'case label already used' error on one of the VER_CASE macros.
|
||||
// If this happens, you can get around it by adding a dwReserved field to the
|
||||
// end of the struct to force the padding.
|
||||
//
|
||||
// 'optional' means the pointer is allowed to be NULL by the interface specification.
|
||||
//
|
||||
// Sample usage:
|
||||
//
|
||||
// int IDirectMusic::SetFooBarInterface(
|
||||
// LPDMUS_REQUESTED_CAPS pCaps, // Caps w/ dwSize (read-only)
|
||||
// LPVOID pBuffer, // Buffer we will fill in
|
||||
// DWORD cbSize, // Size of the buffer
|
||||
// PDIRECTMUSICBAR pBar) // Callback interface for bar on this buffer
|
||||
// {
|
||||
// V_INTERFACE(IDirectMusic::SetFooBarInterface);
|
||||
// V_BUFPTR_WRITE(pBuffer, cbSize);
|
||||
// V_INTERFACE(pBar);
|
||||
// DWORD dwCapsVer; // Must be a DWORD!!!
|
||||
//
|
||||
// V_STRUCTPTR_READ_VER(pCaps, dwCapsVer);
|
||||
// V_STRUCTPTR_READ_VER_CASE(DMUS_REQUESTED_CAPS, 7);
|
||||
// V_STRUCTPTR_READ_VER_CASE(DMUS_REQUESTED_CAPS, 8);
|
||||
// V_STRUCTPTR_READ_VER_END_(DMUS_REQUESTED_CAPS, pCaps);
|
||||
//
|
||||
// // At this point, if we are still in the function we have a valid pCaps
|
||||
// // pointer and dwCapsVer is either 7 or 8, indicating the version of
|
||||
// // the struct passed in.
|
||||
//
|
||||
// ...
|
||||
// }
|
||||
//
|
||||
#ifndef _VALIDATE_H_
|
||||
#define _VALIDATE_H_
|
||||
|
||||
|
||||
#ifdef DBG
|
||||
#include <stddef.h>
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
// To turn on DebugBreak on parameter error, use the following or -DRIP_BREAK in the build:
|
||||
//
|
||||
//#define RIP_BREAK 1
|
||||
|
||||
#ifdef RIP_BREAK
|
||||
#define _RIP_BREAK DebugBreak();
|
||||
#else
|
||||
#define _RIP_BREAK
|
||||
#endif
|
||||
|
||||
#define V_INAME(x) \
|
||||
static const char __szValidateInterfaceName[] = #x;
|
||||
|
||||
#define RIP_E_POINTER(ptr) \
|
||||
{ Trace(-1, "%s: Invalid pointer " #ptr "\n", __szValidateInterfaceName); \
|
||||
_RIP_BREAK \
|
||||
return E_POINTER; }
|
||||
|
||||
#define RIP_E_INVALIDARG(ptr) \
|
||||
{ Trace(-1, "%s: Invalid argument " #ptr "\n", __szValidateInterfaceName); \
|
||||
_RIP_BREAK \
|
||||
return E_INVALIDARG; }
|
||||
|
||||
#define RIP_E_HANDLE(h) \
|
||||
{ Trace(-1, "%s: Invalid handle " #h "\n", __szValidateInterfaceName); \
|
||||
_RIP_BREAK \
|
||||
return E_HANDLE; }
|
||||
|
||||
#define RIP_W_INVALIDSIZE(ptr) \
|
||||
{ Trace(-1, "%s: " #ptr "->dwSize matches no known structure size. Defaulting to oldest structure.\n", \
|
||||
__szValidateInterfaceName); \
|
||||
_RIP_BREAK \
|
||||
}
|
||||
|
||||
#define RIP_E_INVALIDSIZE(ptr) \
|
||||
{ Trace(-1, "%s: " #ptr "->dwSize is too small\n", __szValidateInterfaceName); \
|
||||
_RIP_BREAK \
|
||||
return E_INVALIDARG; }
|
||||
|
||||
#define RIP_E_BLOCKVSDWSIZE(ptr) \
|
||||
{ Trace(-1, "%s: " #ptr " does not point to as much memory as " #ptr "->dwSize indicates\n", \
|
||||
__szValidateInterfaceName); \
|
||||
_RIP_BREAK \
|
||||
return E_INVALIDARG; }
|
||||
|
||||
// NOTE: The DebugBreak() not in #ifdef is intentional - this is something that
|
||||
// must be fixed in our code, not an app-generated error.
|
||||
//
|
||||
#define V_ASSERT(exp) \
|
||||
{ if (!(exp)) { \
|
||||
Trace(-1, "%s@%s: %s\n", __FILE__, __LINE__, #exp); \
|
||||
DebugBreak(); }}
|
||||
|
||||
#else
|
||||
|
||||
#define V_INAME(x)
|
||||
#define RIP_E_POINTER(ptr) { return E_POINTER; }
|
||||
#define RIP_E_INVALIDARG(ptr) { return E_INVALIDARG; }
|
||||
#define RIP_E_HANDLE(h) { return E_HANDLE; }
|
||||
#define RIP_E_BLOCKVSDWSIZE(ptr) { return E_INVALIDARG; }
|
||||
#define RIP_W_INVALIDSIZE(ptr)
|
||||
#define RIP_E_INVALIDSIZE(ptr) { return E_INVALIDARG; }
|
||||
#define V_ASSERT(exp)
|
||||
|
||||
#endif // DBG
|
||||
|
||||
// A passed struct we will only read from or may write to. Must be a struct
|
||||
// with a dwSize.
|
||||
//
|
||||
// int foo(CFoo *pFoo)
|
||||
// ...
|
||||
// V_STRUCTPTR_READ(pFoo, CFoo);
|
||||
// V_STRUCTPTR_WRITE(pFoo, CFoo);
|
||||
//
|
||||
// Use _PTR_ variants for structs w/o a dwSize
|
||||
//
|
||||
#define V_STRUCTPTR_READ(ptr,type) \
|
||||
{ V_ASSERT(offsetof(type, dwSize) == 0); \
|
||||
if (IsBadReadPtr(ptr, sizeof(DWORD))) RIP_E_BLOCKVSDWSIZE(ptr); \
|
||||
if (ptr->dwSize < sizeof(type)) RIP_E_INVALIDSIZE(ptr); \
|
||||
if (IsBadReadPtr(ptr, (ptr)->dwSize)) RIP_E_BLOCKVSDWSIZE(ptr); }
|
||||
|
||||
#define V_STRUCTPTR_WRITE(ptr,type) \
|
||||
{ V_ASSERT(offsetof(type, dwSize) == 0); \
|
||||
if (IsBadReadPtr(ptr, sizeof(DWORD))) RIP_E_BLOCKVSDWSIZE(ptr); \
|
||||
if (ptr->dwSize < sizeof(type)) RIP_E_INVALIDSIZE(ptr); \
|
||||
if (IsBadWritePtr(ptr, (ptr)->dwSize)) RIP_E_BLOCKVSDWSIZE(ptr); }
|
||||
|
||||
#define V_PTR_READ(ptr,type) \
|
||||
{ if (IsBadReadPtr(ptr, sizeof(type))) RIP_E_POINTER(ptr); }
|
||||
|
||||
#define V_PTR_WRITE(ptr,type) \
|
||||
{ if (IsBadWritePtr(ptr, sizeof(type))) RIP_E_POINTER(ptr); }
|
||||
|
||||
#define V_PTR_WRITE_OPT(ptr,type) \
|
||||
{ if (ptr) if (IsBadWritePtr(ptr, sizeof(type))) RIP_E_POINTER(ptr); }
|
||||
|
||||
// A buffer pointer with separate length (not defined by the pointer type) we will only
|
||||
// read from or may write to.
|
||||
//
|
||||
// int foo(LPVOID *pBuffer, DWORD cbBuffer)
|
||||
// ...
|
||||
// V_BUFPTR_READ(pBuffer, cbBuffer);
|
||||
// V_BUFPTR_WRITE(pBuffer, cbBuffer);
|
||||
//
|
||||
#define V_BUFPTR_READ(ptr,len) \
|
||||
{ if (IsBadReadPtr(ptr, len)) RIP_E_POINTER(ptr); }
|
||||
|
||||
#define V_BUFPTR_READ_OPT(ptr,len) \
|
||||
{ if (ptr) V_BUFPTR_READ(ptr,len); }
|
||||
|
||||
#define V_BUFPTR_WRITE(ptr,len) \
|
||||
{ if (IsBadWritePtr(ptr, len)) RIP_E_POINTER(ptr); }
|
||||
|
||||
#define V_BUFPTR_WRITE_OPT(ptr,len) \
|
||||
{ if (ptr) V_BUFPTR_WRITE(ptr,len); }
|
||||
|
||||
// A pointer to a pointer (such as a pointer to an interface pointer) to return
|
||||
//
|
||||
// int foo(IReturnMe **ppRet)
|
||||
// ...
|
||||
// V_PTRPTR_WRITE(ppRet);
|
||||
// V_PTRPTR_WRITE_OPT(ppRet);
|
||||
//
|
||||
#define V_PTRPTR_WRITE(ptr) \
|
||||
{ if (IsBadWritePtr(ptr, sizeof(void*))) RIP_E_POINTER(ptr); }
|
||||
|
||||
#define V_PTRPTR_WRITE_OPT(ptr) \
|
||||
{ if (ptr) if (IsBadWritePtr(ptr, sizeof(void*))) RIP_E_POINTER(ptr); }
|
||||
|
||||
// A pointer to a controlling unknown
|
||||
//
|
||||
#define V_PUNKOUTER(punk) \
|
||||
{ if (punk && IsBadCodePtr(punk)) RIP_E_POINTER(ptr); }
|
||||
|
||||
// A pointer to a controlling unknown for which we don't support aggregation
|
||||
//
|
||||
#define V_PUNKOUTER_NOAGG(punk) \
|
||||
{ if (punk && IsBadReadPtr(punk, sizeof(IUnknown))) RIP_E_POINTER(ptr); \
|
||||
if (punk) return CLASS_E_NOAGGREGATION; }
|
||||
|
||||
// Validate an incoming interface pointer.
|
||||
//
|
||||
struct _V_GENERIC_INTERFACE
|
||||
{
|
||||
FARPROC *(__vptr[1]);
|
||||
};
|
||||
|
||||
#define V_INTERFACE(ptr) \
|
||||
{ if (IsBadReadPtr(ptr, sizeof(_V_GENERIC_INTERFACE))) RIP_E_POINTER(ptr); \
|
||||
if (IsBadReadPtr(*reinterpret_cast<_V_GENERIC_INTERFACE*>(ptr)->__vptr, sizeof(FARPROC))) \
|
||||
RIP_E_POINTER(ptr); \
|
||||
if (IsBadCodePtr(*(reinterpret_cast<_V_GENERIC_INTERFACE*>(ptr)->__vptr)[0])) RIP_E_POINTER(ptr); }
|
||||
|
||||
#define V_INTERFACE_OPT(ptr) \
|
||||
{ if (ptr) V_INTERFACE(ptr); }
|
||||
|
||||
// Validation for a reference to a GUID, which we only ever read.
|
||||
//
|
||||
#define V_REFGUID(ref) \
|
||||
{ if (IsBadReadPtr((void*)&ref, sizeof(GUID))) RIP_E_POINTER((void*)&ref); }
|
||||
|
||||
// Validation for a window handle
|
||||
//
|
||||
#define V_HWND(h) \
|
||||
{ if (!IsWindow(h)) RIP_E_HANDLE(h); }
|
||||
|
||||
#define V_HWND_OPT(h) \
|
||||
{ if (h) if (!IsWindow(h)) RIP_E_HANDLE(h); }
|
||||
|
||||
// Validation for multiple sized structs based on version
|
||||
//
|
||||
#define V_STRUCTPTR_READ_VER(ptr,ver) \
|
||||
{ ver = 7; DWORD *pdw = &ver; \
|
||||
if (IsBadReadPtr(ptr, sizeof(DWORD))) RIP_E_BLOCKVSDWSIZE(ptr); \
|
||||
if (IsBadReadPtr(ptr, (ptr)->dwSize)) RIP_E_BLOCKVSDWSIZE(ptr); \
|
||||
switch ((ptr)->dwSize) {
|
||||
|
||||
#define V_STRUCTPTR_READ_VER_CASE(basetype,ver) \
|
||||
case sizeof(basetype##ver) : \
|
||||
V_ASSERT(offsetof(basetype##ver, dwSize) == 0); \
|
||||
*pdw = ver; break;
|
||||
|
||||
#define V_STRUCTPTR_READ_VER_END(basetype,ptr) \
|
||||
default : if ((ptr)->dwSize > sizeof(basetype##7)) \
|
||||
{ RIP_W_INVALIDSIZE(ptr); } else \
|
||||
RIP_E_INVALIDSIZE(ptr); }}
|
||||
|
||||
|
||||
#define V_STRUCTPTR_WRITE_VER(ptr,ver) \
|
||||
{ ver = 7; DWORD *pdw = &ver; \
|
||||
if (IsBadReadPtr(ptr, sizeof(DWORD))) RIP_E_BLOCKVSDWSIZE(ptr); \
|
||||
if (IsBadWritePtr(ptr, (ptr)->dwSize)) RIP_E_BLOCKVSDWSIZE(ptr); \
|
||||
switch ((ptr)->dwSize) {
|
||||
|
||||
#define V_STRUCTPTR_WRITE_VER_CASE(basetype,ver) \
|
||||
case sizeof(basetype##ver) : \
|
||||
V_ASSERT(offsetof(basetype##ver, dwSize) == 0); \
|
||||
*pdw = ver; break;
|
||||
|
||||
#define V_STRUCTPTR_WRITE_VER_END(basetype,ptr) \
|
||||
default : if ((ptr)->dwSize > sizeof(basetype##7)) \
|
||||
{ RIP_W_INVALIDSIZE(ptr); } else \
|
||||
RIP_E_INVALIDSIZE(ptr); }}
|
||||
|
||||
|
||||
|
||||
#endif // _VALIDATE_H_
|
||||
Reference in New Issue
Block a user