Open source more tools
This commit is contained in:
Родитель
af9d02bcb8
Коммит
b5e500bdda
|
@ -0,0 +1,2 @@
|
|||
DIRS = \
|
||||
source
|
|
@ -0,0 +1,80 @@
|
|||
#include <Windows.h>
|
||||
#include <algorithm>
|
||||
#include <math.h>
|
||||
#include "AppendArray.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
inline size_t RoundUpToPowerOf2(size_t num32)
|
||||
{
|
||||
num32--;
|
||||
num32 |= num32 >> 1;
|
||||
num32 |= num32 >> 2;
|
||||
num32 |= num32 >> 4;
|
||||
num32 |= num32 >> 8;
|
||||
num32 |= num32 >> 16;
|
||||
#if _WIN64
|
||||
num32 |= num32 >> 32;
|
||||
#endif
|
||||
num32++;
|
||||
|
||||
return num32;
|
||||
}
|
||||
|
||||
AppendArray::AppendArray()
|
||||
{
|
||||
dataSize = 0;
|
||||
currentCapacity = MIN_ALLOC_COUNT;
|
||||
currentBufIdx = 0;
|
||||
currentFreeSize = currentCapacity;
|
||||
buffer.push_back(new char[currentCapacity]);
|
||||
currentPtrInBuf = buffer[0];
|
||||
}
|
||||
|
||||
AppendArray::~AppendArray()
|
||||
{
|
||||
for_each(buffer.begin(), buffer.end(), [](char * ptr){
|
||||
delete [] ptr;
|
||||
});
|
||||
}
|
||||
|
||||
void AppendArray::Add(char * str)
|
||||
{
|
||||
size_t sizeNeeded = strlen(str) + 1;
|
||||
if (sizeNeeded > currentFreeSize)
|
||||
{
|
||||
size_t sizeNeededRounded = RoundUpToPowerOf2(sizeNeeded);
|
||||
size_t newSize = max(sizeNeededRounded, currentFreeSize * 2);
|
||||
char * newBuf = new char[newSize];
|
||||
buffer.push_back(newBuf);
|
||||
currentBufIdx++;
|
||||
currentCapacity = newSize;
|
||||
currentFreeSize = newSize;
|
||||
currentPtrInBuf = newBuf;
|
||||
}
|
||||
|
||||
memcpy(currentPtrInBuf, str, sizeNeeded);
|
||||
indexList.push_back(currentPtrInBuf);
|
||||
currentPtrInBuf += sizeNeeded;
|
||||
currentFreeSize -= sizeNeeded;
|
||||
|
||||
dataSize += sizeNeeded;
|
||||
}
|
||||
|
||||
char * AppendArray::GetPtr(size_t index)
|
||||
{
|
||||
if (index >= indexList.size())
|
||||
return 0;
|
||||
else
|
||||
return indexList[index];
|
||||
}
|
||||
|
||||
size_t AppendArray::RecordCount()
|
||||
{
|
||||
return indexList.size();
|
||||
}
|
||||
|
||||
size_t AppendArray::DataSize()
|
||||
{
|
||||
return dataSize;
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
#pragma once
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class AppendArray
|
||||
{
|
||||
public:
|
||||
AppendArray();
|
||||
~AppendArray();
|
||||
void Add(char *);
|
||||
char * GetPtr(size_t index);
|
||||
size_t RecordCount();
|
||||
size_t DataSize();
|
||||
private:
|
||||
static const size_t MIN_ALLOC_COUNT = 1024;
|
||||
size_t allocCnt;
|
||||
vector<char *> buffer;
|
||||
int currentBufIdx;
|
||||
size_t currentCapacity;
|
||||
size_t currentFreeSize;
|
||||
char * currentPtrInBuf;
|
||||
|
||||
deque<char *> indexList;
|
||||
|
||||
size_t dataSize;
|
||||
};
|
|
@ -0,0 +1,31 @@
|
|||
#pragma once
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
namespace SoraDbgPlot { namespace Lock {
|
||||
|
||||
class CSLock
|
||||
{
|
||||
public:
|
||||
CSLock() {
|
||||
|
||||
::InitializeCriticalSection(&_cs);
|
||||
}
|
||||
~CSLock()
|
||||
{
|
||||
::DeleteCriticalSection(&_cs);
|
||||
}
|
||||
void Lock()
|
||||
{
|
||||
::EnterCriticalSection(&_cs);
|
||||
}
|
||||
|
||||
void Unlock()
|
||||
{
|
||||
::LeaveCriticalSection(&_cs);
|
||||
}
|
||||
private:
|
||||
CRITICAL_SECTION _cs;
|
||||
};
|
||||
|
||||
}}
|
|
@ -0,0 +1,46 @@
|
|||
#pragma once
|
||||
|
||||
#include <Windows.h>
|
||||
#include "CSLock.h"
|
||||
|
||||
namespace SoraDbgPlot { namespace Lock {
|
||||
class CSRecursiveLock
|
||||
{
|
||||
public:
|
||||
CSRecursiveLock()
|
||||
{
|
||||
_tid = 0;
|
||||
_recursiveCount = 0;
|
||||
}
|
||||
~CSRecursiveLock()
|
||||
{
|
||||
}
|
||||
|
||||
void Lock()
|
||||
{
|
||||
DWORD tid = ::GetCurrentThreadId();
|
||||
|
||||
if (tid != _tid)
|
||||
{
|
||||
_lock.Lock();
|
||||
_tid = tid;
|
||||
}
|
||||
|
||||
::InterlockedIncrement(&_recursiveCount);
|
||||
}
|
||||
|
||||
void Unlock()
|
||||
{
|
||||
if (::InterlockedDecrement(&_recursiveCount) == 0)
|
||||
{
|
||||
_tid = 0;
|
||||
_lock.Unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
CSLock _lock;
|
||||
volatile DWORD _tid;
|
||||
volatile unsigned long _recursiveCount;
|
||||
};
|
||||
}};
|
|
@ -0,0 +1,138 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{54730AD7-5B11-493B-ADCC-8E4EC3C0204A}</ProjectGuid>
|
||||
<SccProjectName>
|
||||
</SccProjectName>
|
||||
<SccAuxPath>
|
||||
</SccAuxPath>
|
||||
<SccLocalPath>
|
||||
</SccLocalPath>
|
||||
<SccProvider>
|
||||
</SccProvider>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>Common</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>v110</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>v110</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<CallingConvention>StdCall</CallingConvention>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<TreatWChar_tAsBuiltInType>false</TreatWChar_tAsBuiltInType>
|
||||
<AdditionalIncludeDirectories>..\..\..\kernel\core\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<TreatWChar_tAsBuiltInType>false</TreatWChar_tAsBuiltInType>
|
||||
<AdditionalIncludeDirectories>..\..\..\kernel\core\inc</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<None Include="ReadMe.txt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="AppendArray.h" />
|
||||
<ClInclude Include="CSLock.h" />
|
||||
<ClInclude Include="CSRecursiveLock.h" />
|
||||
<ClInclude Include="DACL_Control.h" />
|
||||
<ClInclude Include="DataQueue.h" />
|
||||
<ClInclude Include="DynamicArray.h" />
|
||||
<ClInclude Include="ErrMsg.h" />
|
||||
<ClInclude Include="Event.h" />
|
||||
<ClInclude Include="FileHelper.h" />
|
||||
<ClInclude Include="FrameWithSizeFilter.h" />
|
||||
<ClInclude Include="ILog.h" />
|
||||
<ClInclude Include="LogWithFileBackup.h" />
|
||||
<ClInclude Include="PathName.h" />
|
||||
<ClInclude Include="ReadWriteLock.h" />
|
||||
<ClInclude Include="RingBuffer.h" />
|
||||
<ClInclude Include="RingBufferWithTimeStamp.h" />
|
||||
<ClInclude Include="Runnable.h" />
|
||||
<ClInclude Include="RWTaskQueue.h" />
|
||||
<ClInclude Include="SharedSerialNumGenerator.h" />
|
||||
<ClInclude Include="ShareMemHelper.h" />
|
||||
<ClInclude Include="std_memory.h" />
|
||||
<ClInclude Include="Strategy.h" />
|
||||
<ClInclude Include="TaskCoordinator.h" />
|
||||
<ClInclude Include="TaskSimple.h" />
|
||||
<ClInclude Include="TaskQueue.h" />
|
||||
<ClInclude Include="TaskQueueRequester.h" />
|
||||
<ClInclude Include="TempBuffer.h" />
|
||||
<ClInclude Include="TimeStampQueue.h" />
|
||||
<ClInclude Include="WaitableLatestTaskQueue.h" />
|
||||
<ClInclude Include="Writable.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="AppendArray.cpp" />
|
||||
<ClCompile Include="ErrMsg.cpp" />
|
||||
<ClCompile Include="Event.cpp" />
|
||||
<ClCompile Include="FileHelper.cpp" />
|
||||
<ClCompile Include="ILog.cpp" />
|
||||
<ClCompile Include="LogWithFileBackup.cpp" />
|
||||
<ClCompile Include="PathName.cpp" />
|
||||
<ClCompile Include="TaskQueue.cpp" />
|
||||
<ClCompile Include="TempBuffer.cpp" />
|
||||
<ClCompile Include="TimeStampQueue.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
|
@ -0,0 +1,193 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Log">
|
||||
<UniqueIdentifier>{d7de7e63-403d-468c-ae31-cb43d834bcc1}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="AppendArray">
|
||||
<UniqueIdentifier>{f9426287-32ec-4f24-bdfb-b719d5d38965}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="RingBuffer">
|
||||
<UniqueIdentifier>{fc77e29f-4bdd-4951-973b-295d85eb5b26}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="DataFilter">
|
||||
<UniqueIdentifier>{bb7b48c6-b159-4fb8-b6dc-a5e3f41d9703}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Writable">
|
||||
<UniqueIdentifier>{862eed55-ae25-4b28-af1d-c773eb9971c3}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="DynamicArray">
|
||||
<UniqueIdentifier>{69a8d289-e1e5-4349-b585-dfb2d180add3}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="SerialNum">
|
||||
<UniqueIdentifier>{b62095c5-01a4-41d8-9ed4-a1215883d951}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Event">
|
||||
<UniqueIdentifier>{a3428d2b-5505-429f-9ff7-3d7bf05e8119}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Task">
|
||||
<UniqueIdentifier>{90ae29f2-86bf-40a4-a539-45457b4e9332}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Strategy">
|
||||
<UniqueIdentifier>{0b385ccb-5070-4328-94f8-2773ab93eb4f}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="DataQueue">
|
||||
<UniqueIdentifier>{f670156b-c3ab-478f-8a0d-9787ab6d4d33}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Lock">
|
||||
<UniqueIdentifier>{f0a99025-3248-4449-8231-de5bf5547fce}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Task\Runnable">
|
||||
<UniqueIdentifier>{809e8963-bea5-4180-ab7f-7abadf5225be}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Task\Runnable\Task">
|
||||
<UniqueIdentifier>{e2a5e64f-6ff5-48f1-be7a-996abef6fa54}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Helper">
|
||||
<UniqueIdentifier>{92f04332-33c6-41d2-b4bb-7133f29947c3}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="ShareMem">
|
||||
<UniqueIdentifier>{a2fa4a28-d584-4423-8e92-6e0b6bed1490}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="TempBuffer">
|
||||
<UniqueIdentifier>{6253eabc-0081-4011-a347-4d053d11f599}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="File">
|
||||
<UniqueIdentifier>{21350b9f-d893-4900-9bf2-91ced0a7d001}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="ErrMsg">
|
||||
<UniqueIdentifier>{677a99bb-78fa-47e0-9684-348cb22031c7}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="ReadMe.txt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="ILog.h">
|
||||
<Filter>Log</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="LogWithFileBackup.h">
|
||||
<Filter>Log</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="AppendArray.h">
|
||||
<Filter>AppendArray</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="RingBuffer.h">
|
||||
<Filter>RingBuffer</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="RingBufferWithTimeStamp.h">
|
||||
<Filter>RingBuffer</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="TimeStampQueue.h">
|
||||
<Filter>RingBuffer</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="FrameWithSizeFilter.h">
|
||||
<Filter>DataFilter</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Writable.h">
|
||||
<Filter>Writable</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DynamicArray.h">
|
||||
<Filter>DynamicArray</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SharedSerialNumGenerator.h">
|
||||
<Filter>SerialNum</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Event.h">
|
||||
<Filter>Event</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="WaitableLatestTaskQueue.h">
|
||||
<Filter>Task</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Strategy.h">
|
||||
<Filter>Strategy</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DataQueue.h">
|
||||
<Filter>DataQueue</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CSLock.h">
|
||||
<Filter>Lock</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="TaskQueue.h">
|
||||
<Filter>Task</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CSRecursiveLock.h">
|
||||
<Filter>Lock</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ReadWriteLock.h">
|
||||
<Filter>Lock</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="RWTaskQueue.h">
|
||||
<Filter>Task</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="TaskQueueRequester.h">
|
||||
<Filter>Task</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Runnable.h">
|
||||
<Filter>Task\Runnable</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="TaskCoordinator.h">
|
||||
<Filter>Task\Runnable\Task</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="TaskSimple.h">
|
||||
<Filter>Task\Runnable\Task</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="std_memory.h">
|
||||
<Filter>Helper</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="TempBuffer.h">
|
||||
<Filter>TempBuffer</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="FileHelper.h">
|
||||
<Filter>File</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PathName.h">
|
||||
<Filter>File</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ErrMsg.h">
|
||||
<Filter>ErrMsg</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DACL_Control.h">
|
||||
<Filter>ShareMem</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ShareMemHelper.h">
|
||||
<Filter>ShareMem</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="LogWithFileBackup.cpp">
|
||||
<Filter>Log</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ILog.cpp">
|
||||
<Filter>Log</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="AppendArray.cpp">
|
||||
<Filter>AppendArray</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="TimeStampQueue.cpp">
|
||||
<Filter>RingBuffer</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="TaskQueue.cpp">
|
||||
<Filter>Task</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Event.cpp">
|
||||
<Filter>Event</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="TempBuffer.cpp">
|
||||
<Filter>TempBuffer</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="FileHelper.cpp">
|
||||
<Filter>File</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PathName.cpp">
|
||||
<Filter>File</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ErrMsg.cpp">
|
||||
<Filter>ErrMsg</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -0,0 +1,10 @@
|
|||
""
|
||||
{
|
||||
"FILE_VERSION" = "9237"
|
||||
"ENLISTMENT_CHOICE" = "NEVER"
|
||||
"PROJECT_FILE_RELATIVE_PATH" = ""
|
||||
"NUMBER_OF_EXCLUDED_FILES" = "0"
|
||||
"ORIGINAL_PROJECT_FILE_PATH" = ""
|
||||
"NUMBER_OF_NESTED_PROJECTS" = "0"
|
||||
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
#include <Windows.h>
|
||||
#include <Sddl.h>
|
||||
|
||||
static inline BOOL CreateDACLWithAllAccess(SECURITY_ATTRIBUTES * pSA)
|
||||
{
|
||||
char * szSD = "D:" // Discretionary ACL
|
||||
"(A;OICI;GA;;;BG)" // full control to built-in guests
|
||||
"(A;OICI;GA;;;AN)" // full control to anonymous logon
|
||||
"(A;OICI;GA;;;AU)" // Allow full control to authenticated users
|
||||
"(A;OICI;GA;;;BA)"; // Allow full control to administrators
|
||||
|
||||
if (NULL == pSA)
|
||||
return FALSE;
|
||||
|
||||
return ConvertStringSecurityDescriptorToSecurityDescriptorA(
|
||||
szSD,
|
||||
SDDL_REVISION_1,
|
||||
&(pSA->lpSecurityDescriptor),
|
||||
NULL);
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
#pragma once
|
||||
|
||||
#include <Windows.h>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
namespace SoraDbgPlot { namespace DataQueue {
|
||||
|
||||
class DataQueue
|
||||
{
|
||||
public:
|
||||
struct DataItem
|
||||
{
|
||||
char * ptr;
|
||||
size_t length;
|
||||
};
|
||||
|
||||
DataQueue(size_t size)
|
||||
{
|
||||
::InitializeCriticalSection(&_cs);
|
||||
_index = 0;
|
||||
_size = 0;
|
||||
_list = new DataItem[size];
|
||||
for (size_t i = 0; i < size; i++)
|
||||
{
|
||||
_list[i].ptr = 0;
|
||||
_list[i].length = 0;
|
||||
}
|
||||
_capacity = size;
|
||||
}
|
||||
|
||||
~DataQueue()
|
||||
{
|
||||
Clear();
|
||||
delete [] _list;
|
||||
::DeleteCriticalSection(&_cs);
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
this->Read([this](const char * ptr, size_t length){
|
||||
delete [] ptr;
|
||||
});
|
||||
}
|
||||
|
||||
void Write(const char * ptr, size_t length)
|
||||
{
|
||||
Lock();
|
||||
|
||||
if (_size < _capacity)
|
||||
{
|
||||
_index = (_index + 1) % _capacity;
|
||||
_size = min(_size + 1, _capacity);
|
||||
|
||||
DataItem & item = _list[_index];
|
||||
|
||||
item.ptr = new char[length];
|
||||
item.length = length;
|
||||
memcpy(item.ptr, ptr, length);
|
||||
}
|
||||
|
||||
Unlock();
|
||||
}
|
||||
|
||||
void Read(const std::function<void(const char * ptr, const size_t length)> & f)
|
||||
{
|
||||
Lock();
|
||||
|
||||
size_t start = _index - _size + 1;
|
||||
while(_size > 0)
|
||||
{
|
||||
DataItem & item = _list[start % _capacity];
|
||||
ASSERT(item.ptr);
|
||||
f(item.ptr, item.length);
|
||||
//delete [] item.ptr;
|
||||
//item.ptr = 0;
|
||||
//item.length = 0;
|
||||
start++;
|
||||
_size--;
|
||||
}
|
||||
|
||||
Unlock();
|
||||
}
|
||||
|
||||
private:
|
||||
void Lock() {
|
||||
::EnterCriticalSection(&_cs);
|
||||
}
|
||||
|
||||
void Unlock()
|
||||
{
|
||||
::LeaveCriticalSection(&_cs);
|
||||
}
|
||||
|
||||
DataItem * _list;
|
||||
size_t _index;
|
||||
size_t _size;
|
||||
size_t _capacity;
|
||||
CRITICAL_SECTION _cs;
|
||||
};
|
||||
|
||||
}}
|
|
@ -0,0 +1,87 @@
|
|||
#pragma once
|
||||
|
||||
#include <assert.h>
|
||||
#include <vector>
|
||||
|
||||
namespace SoraDbgPlot
|
||||
{
|
||||
class DynamicArray // a slow implementation
|
||||
{
|
||||
public:
|
||||
DynamicArray()
|
||||
{
|
||||
_capacity = 4096;
|
||||
_buffer = new char[_capacity];
|
||||
_wPtr = _buffer;
|
||||
}
|
||||
|
||||
~DynamicArray()
|
||||
{
|
||||
delete [] _buffer;
|
||||
}
|
||||
|
||||
|
||||
void Write(const void * ptr, size_t size, size_t & countWritten)
|
||||
{
|
||||
size_t sizeUsable = SizeUsable();
|
||||
if (size > sizeUsable)
|
||||
{
|
||||
size_t sizeRequired = (size - sizeUsable) + _capacity;
|
||||
size_t sizeReallocate = 1;
|
||||
while(sizeReallocate < sizeRequired)
|
||||
sizeReallocate *= 2;
|
||||
Reallocate(sizeReallocate);
|
||||
assert(SizeUsable() >= size);
|
||||
}
|
||||
|
||||
memcpy(_wPtr, ptr, size);
|
||||
_wPtr += size;
|
||||
countWritten = size;
|
||||
}
|
||||
|
||||
void Reserve(size_t count)
|
||||
{
|
||||
Reallocate(count);
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
_wPtr = _buffer;
|
||||
}
|
||||
|
||||
size_t Size()
|
||||
{
|
||||
return _wPtr - _buffer;
|
||||
}
|
||||
|
||||
const void * Ptr()
|
||||
{
|
||||
return _buffer;
|
||||
}
|
||||
|
||||
private:
|
||||
size_t SizeUsable()
|
||||
{
|
||||
return _capacity - (_wPtr - _buffer);
|
||||
}
|
||||
|
||||
void Reallocate(size_t size)
|
||||
{
|
||||
if (size <= _capacity)
|
||||
return;
|
||||
|
||||
char * newBuffer = new char[size];
|
||||
size_t sizeToCopy = _wPtr - _buffer;
|
||||
if (sizeToCopy > 0)
|
||||
memcpy(newBuffer, _buffer, sizeToCopy);
|
||||
delete [] _buffer;
|
||||
_buffer = newBuffer;
|
||||
_capacity = size;
|
||||
_wPtr = _buffer + sizeToCopy;
|
||||
}
|
||||
|
||||
char * _buffer;
|
||||
size_t _capacity;
|
||||
char * _wPtr;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
#include "ErrMsg.h"
|
||||
|
||||
#include <Windows.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
using namespace SoraDbgPlot::Msg;
|
||||
|
||||
const int Message::MAX_MSG_SIZE = 1024;
|
||||
|
||||
Message::Message()
|
||||
{
|
||||
_tmpBuf = new wchar_t[MAX_MSG_SIZE];
|
||||
Reset();
|
||||
}
|
||||
|
||||
Message::~Message()
|
||||
{
|
||||
if (_tmpBuf)
|
||||
delete [] _tmpBuf;
|
||||
}
|
||||
|
||||
void Message::Append(const wchar_t * format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
vswprintf_s(_tmpBuf, MAX_MSG_SIZE, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
_tmpBuf[MAX_MSG_SIZE - 1] = 0;
|
||||
|
||||
wchar_t * ptr = _tmpBuf;
|
||||
wchar_t c;
|
||||
while( (c = *ptr++) != 0 )
|
||||
{
|
||||
_msg.push_back(c);
|
||||
}
|
||||
}
|
||||
|
||||
void Message::Reset()
|
||||
{
|
||||
_msg.clear();
|
||||
}
|
||||
|
||||
Message::operator const wchar_t *()
|
||||
{
|
||||
if(_msg.size() == 0)
|
||||
{
|
||||
_msg.push_back(0);
|
||||
}
|
||||
else if (_msg[_msg.size()-1] != 0)
|
||||
{
|
||||
_msg.push_back(0);
|
||||
}
|
||||
|
||||
return &_msg[0];
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
#pragma once
|
||||
|
||||
#include <wchar.h>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
|
||||
namespace SoraDbgPlot { namespace Msg {
|
||||
|
||||
class Message
|
||||
{
|
||||
public:
|
||||
Message();
|
||||
~Message();
|
||||
void Append(const wchar_t * format, ...);
|
||||
void Reset();
|
||||
operator const wchar_t *();
|
||||
private:
|
||||
std::vector<wchar_t> _msg;
|
||||
static const int MAX_MSG_SIZE;
|
||||
wchar_t * _tmpBuf;
|
||||
};
|
||||
|
||||
}}
|
|
@ -0,0 +1,38 @@
|
|||
#include "Event.h"
|
||||
|
||||
static volatile long __eventHandlerCount = 0;
|
||||
|
||||
using namespace SoraDbgPlot::Event;
|
||||
|
||||
#ifdef _DEBUG
|
||||
|
||||
int __stdcall SoraDbgPlot::Event::EventHandlerCount()
|
||||
{
|
||||
return __eventHandlerCount;
|
||||
}
|
||||
|
||||
void __stdcall SoraDbgPlot::Event::EventHandlerCountModify(int count, int sign)
|
||||
{
|
||||
if (count == 1)
|
||||
{
|
||||
if (sign)
|
||||
::InterlockedIncrement(&__eventHandlerCount);
|
||||
else
|
||||
::InterlockedDecrement(&__eventHandlerCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (sign == 0)
|
||||
count = -count;
|
||||
|
||||
while(1)
|
||||
{
|
||||
int ori = __eventHandlerCount;
|
||||
int target = __eventHandlerCount + count;
|
||||
if (::InterlockedCompareExchange(&__eventHandlerCount, target, ori) == ori)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,112 @@
|
|||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <Windows.h>
|
||||
#include "CSRecursiveLock.h"
|
||||
|
||||
namespace SoraDbgPlot { namespace Event {
|
||||
|
||||
#define CALLBACK_TYPE std::function<void(const void *, const T &)>
|
||||
|
||||
#ifdef _DEBUG
|
||||
int __stdcall EventHandlerCount();
|
||||
void __stdcall EventHandlerCountModify(int count, int sign);
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
class Event
|
||||
{
|
||||
public:
|
||||
Event()
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
_fortest = new char[13];
|
||||
#endif
|
||||
}
|
||||
|
||||
~Event()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
HANDLE Subscribe(const std::function<void(const void *, const T &)> & f) {
|
||||
auto fp = std::make_shared<CALLBACK_TYPE>(f);
|
||||
_lock.Lock();
|
||||
_callbacks.insert(
|
||||
std::make_pair(
|
||||
(HANDLE)fp.get(), fp
|
||||
)
|
||||
);
|
||||
|
||||
#ifdef _DEBUG
|
||||
SoraDbgPlot::Event::EventHandlerCountModify(1, true);
|
||||
#endif
|
||||
|
||||
_lock.Unlock();
|
||||
return (HANDLE)fp.get();
|
||||
}
|
||||
|
||||
bool UnSubscribe(HANDLE h) {
|
||||
|
||||
bool ret = false;
|
||||
|
||||
_lock.Lock();
|
||||
|
||||
auto iter = _callbacks.find(h);
|
||||
if (iter != _callbacks.end())
|
||||
{
|
||||
_callbacks.erase(iter);
|
||||
#ifdef _DEBUG
|
||||
SoraDbgPlot::Event::EventHandlerCountModify(1, 0);
|
||||
#endif
|
||||
ret = true;
|
||||
}
|
||||
|
||||
_lock.Unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Raise(const void * sender, const T & e) const {
|
||||
|
||||
_lock.Lock();
|
||||
std::for_each(_callbacks.begin(), _callbacks.end(), [sender, e](std::pair<HANDLE, std::shared_ptr<CALLBACK_TYPE> > pair){
|
||||
(*(pair.second))(sender, e);
|
||||
});
|
||||
_lock.Unlock();
|
||||
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
_lock.Lock();
|
||||
int handlerCount = _callbacks.size();
|
||||
_callbacks.clear();
|
||||
|
||||
#ifdef _DEBUG
|
||||
SoraDbgPlot::Event::EventHandlerCountModify(handlerCount, 0);
|
||||
if (_fortest) {
|
||||
delete [] _fortest;
|
||||
_fortest = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
_lock.Unlock();
|
||||
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
std::map<HANDLE, std::shared_ptr<CALLBACK_TYPE > > _callbacks;
|
||||
mutable SoraDbgPlot::Lock::CSRecursiveLock _lock;
|
||||
#ifdef _DEBUG
|
||||
char * _fortest;
|
||||
#endif
|
||||
};
|
||||
|
||||
#undef CALLBACK_TYPE
|
||||
|
||||
}}
|
|
@ -0,0 +1,41 @@
|
|||
#include "FileHelper.h"
|
||||
|
||||
bool SoraDbgPlot::File::CreateDirectoryRecursive(const wchar_t * __folder)
|
||||
{
|
||||
bool bSucc;
|
||||
|
||||
wchar_t * folderDup = _wcsdup(__folder);
|
||||
int strlength = wcslen(folderDup);
|
||||
|
||||
// remove the last '\'
|
||||
if ( *(folderDup + strlength - 1) == '\\' )
|
||||
folderDup[strlength - 1] = 0;
|
||||
|
||||
wchar_t * ptr = (wchar_t *)(folderDup + strlength - 1);
|
||||
|
||||
while(ptr > folderDup && *ptr != '\\')
|
||||
--ptr;
|
||||
|
||||
if (ptr == folderDup) // root
|
||||
bSucc = true;
|
||||
else
|
||||
{
|
||||
*ptr = 0;
|
||||
bSucc = CreateDirectoryRecursive(folderDup);
|
||||
|
||||
if (bSucc)
|
||||
{
|
||||
*ptr = '\\';
|
||||
BOOL bRes = CreateDirectoryW(folderDup, NULL);
|
||||
if (!bRes && GetLastError() != ERROR_ALREADY_EXISTS)
|
||||
bSucc = false;
|
||||
bSucc = true;
|
||||
}
|
||||
else
|
||||
bSucc = false;
|
||||
}
|
||||
|
||||
delete [] folderDup;
|
||||
|
||||
return bSucc;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
namespace SoraDbgPlot { namespace File {
|
||||
|
||||
bool CreateDirectoryRecursive(const wchar_t * __folder);
|
||||
|
||||
}}
|
|
@ -0,0 +1,407 @@
|
|||
#pragma once
|
||||
|
||||
#include <Windows.h>
|
||||
#include "Writable.h"
|
||||
#include "DynamicArray.h"
|
||||
#include "RingBufferWithTimeStamp.h"
|
||||
#include "Event.h"
|
||||
#include "ErrMsg.h"
|
||||
|
||||
namespace SoraDbgPlot
|
||||
{
|
||||
template <typename T>
|
||||
class FrameWithSizeInfoWriter
|
||||
{
|
||||
public:
|
||||
struct FlushDataEvent { char * ptr; size_t length; unsigned long long timestamp; };
|
||||
SoraDbgPlot::Event::Event<FlushDataEvent> EventFlushData;
|
||||
|
||||
public:
|
||||
FrameWithSizeInfoWriter(RingBufferWithTimeStamp<T> * writable)
|
||||
{
|
||||
_writable = writable;
|
||||
_dynamicArray = new SoraDbgPlot::DynamicArray();
|
||||
Init();
|
||||
}
|
||||
|
||||
FrameWithSizeInfoWriter()
|
||||
{
|
||||
_writable = 0;
|
||||
_dynamicArray = new SoraDbgPlot::DynamicArray();
|
||||
Init();
|
||||
}
|
||||
|
||||
~FrameWithSizeInfoWriter()
|
||||
{
|
||||
delete _dynamicArray;
|
||||
}
|
||||
|
||||
void Init()
|
||||
{
|
||||
_idExpected = 0;
|
||||
_sizeTarget = 0;
|
||||
_timestamp = (unsigned long long)-1;
|
||||
_bDiscardFlag = false;
|
||||
_bFirstPackage = true;
|
||||
_state = &_getSizeState;
|
||||
}
|
||||
|
||||
void Write(const void * ptr, size_t size, size_t & sizeWritten)
|
||||
{
|
||||
#ifdef DEBUG_INTERNAL_DATAFILTER
|
||||
_msg.Reset();
|
||||
#endif
|
||||
assert(_state == &_getSizeState);
|
||||
|
||||
char * ptrC = (char *)ptr;
|
||||
do {
|
||||
size_t sizeProcessed;
|
||||
_state->Handle(ptrC, size, sizeProcessed, this);
|
||||
ptrC += sizeProcessed;
|
||||
size -= sizeProcessed;
|
||||
} while(size > 0);
|
||||
}
|
||||
|
||||
private:
|
||||
size_t _sizeTarget;
|
||||
RingBufferWithTimeStamp<T> * _writable;
|
||||
DynamicArray * _dynamicArray;
|
||||
unsigned long long _timestamp;
|
||||
|
||||
private:
|
||||
|
||||
void FlushBufferIfTestPassed()
|
||||
{
|
||||
if (_bDiscardFlag)
|
||||
{
|
||||
#ifdef DEBUG_INTERNAL_DATAFILTER
|
||||
_msg.Append(L"Discard data: %d bytes\n", _dynamicArray->Size());
|
||||
ReportErrorState();
|
||||
_msg.Reset();
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
if (_writable)
|
||||
_writable->Write((const T *)_dynamicArray->Ptr(), _dynamicArray->Size() / sizeof(T), _timestamp);
|
||||
FlushDataEvent e;
|
||||
e.ptr = (char *)_dynamicArray->Ptr();
|
||||
e.length = _dynamicArray->Size();
|
||||
e.timestamp = _timestamp;
|
||||
|
||||
this->EventFlushData.Raise(this, e);
|
||||
|
||||
_dynamicArray->Reset();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class State
|
||||
{
|
||||
public:
|
||||
virtual void Handle(
|
||||
const void * ptr,
|
||||
size_t size,
|
||||
size_t & sizeProcessed,
|
||||
FrameWithSizeInfoWriter<T> * context) = 0;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class GetSizeState : public State<T>
|
||||
{
|
||||
public:
|
||||
void Handle(
|
||||
const void * ptr,
|
||||
size_t size,
|
||||
size_t & sizeProcessed,
|
||||
FrameWithSizeInfoWriter<T> * context)
|
||||
{
|
||||
const size_t sizeExpected = sizeof(__int16);
|
||||
|
||||
#ifdef DEBUG_INTERNAL_DATAFILTER
|
||||
context->_msg.Reset();
|
||||
context->_msg.Append(L"h(g, %d)", size);
|
||||
#endif
|
||||
|
||||
if (size < sizeExpected)
|
||||
{
|
||||
#ifdef DEBUG_INTERNAL_DATAFILTER
|
||||
context->_msg.Append(L"e(1, %d)", size);
|
||||
#endif
|
||||
context->_state = &context->_errorState;
|
||||
sizeProcessed = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
__int16 sizeTarget = *(__int16 *)ptr;
|
||||
|
||||
#ifdef DEBUG_INTERNAL_DATAFILTER
|
||||
context->_msg.Append(L"(%d, %d)", sizeTarget, sizeTarget % (64*sizeof(int)));
|
||||
#endif
|
||||
|
||||
if (sizeTarget == 0)
|
||||
{
|
||||
sizeProcessed = sizeExpected;
|
||||
return;
|
||||
}
|
||||
else if ((int)sizeTarget == -1)
|
||||
{
|
||||
context->_dynamicArray->Reset();
|
||||
sizeProcessed = sizeExpected;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
context->_sizeTarget = sizeTarget;
|
||||
context->_state = &context->_getIdState;
|
||||
sizeProcessed = sizeExpected;
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class GetIdState : public State<T>
|
||||
{
|
||||
public:
|
||||
void Handle(
|
||||
const void * ptr,
|
||||
size_t size,
|
||||
size_t & sizeProcessed,
|
||||
FrameWithSizeInfoWriter<T> * context)
|
||||
{
|
||||
#ifdef DEBUG_INTERNAL_DATAFILTER
|
||||
context->_msg.Reset();
|
||||
context->_msg.Append(L"h(id, %d)", size);
|
||||
#endif
|
||||
|
||||
size_t sizeExpected = sizeof(__int16);
|
||||
|
||||
if (size < sizeExpected)
|
||||
{
|
||||
#ifdef DEBUG_INTERNAL_DATAFILTER
|
||||
context->_msg.Append(L"e(2, %d)", size);
|
||||
#endif
|
||||
context->_state = &context->_errorState;
|
||||
sizeProcessed = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
__int16 id = *(__int16 *)ptr;
|
||||
#ifdef DEBUG_INTERNAL_DATAFILTER
|
||||
context->_msg.Append(L"(%d)", id);
|
||||
#endif
|
||||
|
||||
if (id == context->_idExpected)
|
||||
context->_idExpected++;
|
||||
else
|
||||
{
|
||||
context->_bDiscardFlag = true;
|
||||
#ifdef DEBUG_INTERNAL_DATAFILTER
|
||||
context->_msg.Append(L"Id Error\n");
|
||||
context->_msg.Append(L"%d expected, %d got\n", context->_idExpected, id);
|
||||
context->ReportErrorState();
|
||||
context->_msg.Reset();
|
||||
#endif
|
||||
}
|
||||
|
||||
if (id == 0) // first packet
|
||||
{
|
||||
context->_bDiscardFlag = false;
|
||||
context->_dynamicArray->Reset();
|
||||
context->_bFirstPackage = true;
|
||||
}
|
||||
else
|
||||
context->_bFirstPackage = false;
|
||||
|
||||
context->_state = &context->_getTimeStampState;
|
||||
sizeProcessed = sizeExpected;
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class GetTimeStampState : public State<T>
|
||||
{
|
||||
public:
|
||||
void Handle(
|
||||
const void * ptr,
|
||||
size_t size,
|
||||
size_t & sizeProcessed,
|
||||
FrameWithSizeInfoWriter<T> * context)
|
||||
{
|
||||
size_t sizeExpected = sizeof(unsigned long long);
|
||||
|
||||
#ifdef DEBUG_INTERNAL_DATAFILTER
|
||||
context->_msg.Append(L"h(t, %d)", size);
|
||||
#endif
|
||||
if (size < sizeExpected)
|
||||
{
|
||||
#ifdef DEBUG_INTERNAL_DATAFILTER
|
||||
context->_msg.Append(L"e(1, %d)", size);
|
||||
#endif
|
||||
context->_state = &context->_errorState;
|
||||
sizeProcessed = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned long long timestamp = *(unsigned long long *)ptr;
|
||||
|
||||
#ifdef DEBUG_INTERNAL_DATAFILTER
|
||||
context->_msg.Append(L"(%I64d)", timestamp);
|
||||
#endif
|
||||
if (context->_bFirstPackage) // check timestamp increment
|
||||
{
|
||||
if ( (timestamp < context->_timestamp) && (context->_timestamp != (unsigned long long)(-1)) )
|
||||
{
|
||||
#ifdef DEBUG_INTERNAL_DATAFILTER
|
||||
context->_msg.Append(L"timestamp Error\n");
|
||||
context->_msg.Append(L"last timestamp is %I64d, but current is %I64d\n", context->_timestamp, timestamp);
|
||||
context->ReportErrorState();
|
||||
context->_msg.Reset();
|
||||
#endif
|
||||
context->_bDiscardFlag = true;
|
||||
}
|
||||
}
|
||||
else if ( (timestamp != context->_timestamp) ) // check if timestamp is the same
|
||||
{
|
||||
#ifdef DEBUG_INTERNAL_DATAFILTER
|
||||
context->_msg.Append(L"timestamp Error\n");
|
||||
context->_msg.Append(L"%I64d expected, %I64d got\n", context->_timestamp, timestamp);
|
||||
context->ReportErrorState();
|
||||
context->_msg.Reset();
|
||||
#endif
|
||||
|
||||
context->_bDiscardFlag = true;
|
||||
}
|
||||
|
||||
context->_timestamp = timestamp;
|
||||
|
||||
context->_state = &context->_saveDataState;
|
||||
sizeProcessed = sizeExpected;
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class SaveDataState : public State<T>
|
||||
{
|
||||
public:
|
||||
void Handle(
|
||||
const void * ptr,
|
||||
size_t size,
|
||||
size_t & sizeProcessed,
|
||||
FrameWithSizeInfoWriter<T> * context)
|
||||
{
|
||||
#ifdef DEBUG_INTERNAL_DATAFILTER
|
||||
context->_msg.Append(L"h(s, %d)", size);
|
||||
#endif
|
||||
|
||||
size_t sizeToWrite = context->_sizeTarget
|
||||
- sizeof(__int16) // id
|
||||
- sizeof(unsigned long long) // timestamp
|
||||
- sizeof(char); // controlFlag
|
||||
|
||||
if (size < sizeToWrite)
|
||||
{
|
||||
#ifdef DEBUG_INTERNAL_DATAFILTER
|
||||
context->_msg.Append(L"e(1, %d)", sizeToWrite);
|
||||
#endif
|
||||
context->_state = &context->_errorState;
|
||||
sizeProcessed = 0;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t discard;
|
||||
|
||||
context->_dynamicArray->Write(ptr, sizeToWrite, discard);
|
||||
context->_state = &context->_getControlFlagState;
|
||||
sizeProcessed = sizeToWrite;
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class GetControlFlagState : public State<T>
|
||||
{
|
||||
public:
|
||||
void Handle(
|
||||
const void * ptr,
|
||||
size_t size,
|
||||
size_t & sizeProcessed,
|
||||
FrameWithSizeInfoWriter<T> * context)
|
||||
{
|
||||
#ifdef DEBUG_INTERNAL_DATAFILTER
|
||||
context->_msg.Append(L"h(c, %d)\n", size);
|
||||
#endif
|
||||
|
||||
|
||||
if (size < sizeof(char))
|
||||
{
|
||||
#ifdef DEBUG_INTERNAL_DATAFILTER
|
||||
context->_msg.Append(L"e(1, %d)", size);
|
||||
#endif
|
||||
context->_state = &context->_errorState;
|
||||
sizeProcessed = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
char controlFlag = *(char *)ptr;
|
||||
if (controlFlag == 1)
|
||||
{
|
||||
context->FlushBufferIfTestPassed();
|
||||
context->_idExpected = 0;
|
||||
}
|
||||
|
||||
context->_state = &context->_getSizeState;
|
||||
sizeProcessed = 1;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class ErrorState : public State<T>
|
||||
{
|
||||
void Handle(
|
||||
const void * ptr,
|
||||
size_t size,
|
||||
size_t & sizeProcessed,
|
||||
FrameWithSizeInfoWriter<T> * context)
|
||||
{
|
||||
#ifdef DEBUG_INTERNAL_DATAFILTER
|
||||
context->_msg.Append(L"Fatal Error!\n");
|
||||
context->_msg.Append(L"############\n");
|
||||
context->ReportErrorState();
|
||||
#endif
|
||||
context->_dynamicArray->Reset();
|
||||
context->_state = &context->_getSizeState;
|
||||
sizeProcessed = size;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
State<T> * _state;
|
||||
GetSizeState<T> _getSizeState;
|
||||
GetIdState<T> _getIdState;
|
||||
GetTimeStampState<T> _getTimeStampState;
|
||||
SaveDataState<T> _saveDataState;
|
||||
GetControlFlagState<T> _getControlFlagState;
|
||||
ErrorState<T> _errorState;
|
||||
|
||||
bool _bDiscardFlag;
|
||||
bool _bFirstPackage;
|
||||
__int16 _idExpected;
|
||||
|
||||
#ifdef DEBUG_INTERNAL_DATAFILTER
|
||||
void ReportErrorState()
|
||||
{
|
||||
::OutputDebugString(L"Data Filter error\n");
|
||||
::OutputDebugString((const wchar_t *)_msg);
|
||||
}
|
||||
#endif
|
||||
|
||||
SoraDbgPlot::Msg::Message _msg;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,140 @@
|
|||
#pragma once
|
||||
|
||||
template <typename Key, typename Value>
|
||||
class HashEntry
|
||||
{
|
||||
public:
|
||||
HashEntry();
|
||||
HashEntry(Key key, Value value);
|
||||
Key key;
|
||||
Value value;
|
||||
HashEntry<Key, Value> * _next;
|
||||
};
|
||||
|
||||
template <typename Key, typename Value>
|
||||
HashEntry<Key, Value>::HashEntry() :
|
||||
_next(0)
|
||||
{}
|
||||
|
||||
template <typename Key, typename Value>
|
||||
HashEntry<Key, Value>::HashEntry(Key key, Value value) :
|
||||
_next(0)
|
||||
{
|
||||
this->key = key;
|
||||
this->value = value;
|
||||
}
|
||||
|
||||
template <typename Key, typename Value, int _hashTableSize, unsigned long (*HashCodeFcn)(Key key), bool (*EqualKey)(Key key1, Key key2)>
|
||||
class SimpleHashTable
|
||||
{
|
||||
public:
|
||||
SimpleHashTable();
|
||||
~SimpleHashTable();
|
||||
void Insert(Key key, Value value);
|
||||
HashEntry<Key, Value> * Find(Key key);
|
||||
void Foreach(bool (*VisitorFunc)(Key key, Value value));
|
||||
void Clear();
|
||||
private:
|
||||
HashEntry<Key, Value> * hashBucket[_hashTableSize];
|
||||
void InsertToList(HashEntry<Key, Value> ** ppEntryHead, HashEntry<Key, Value> * pEntryToInsert);
|
||||
HashEntry<Key, Value> ** HashCode2EntryListHead(unsigned long hashCode);
|
||||
void DeleteEntryList(HashEntry<Key, Value> ** ppEntry);
|
||||
};
|
||||
|
||||
template <typename Key, typename Value, int _hashTableSize, unsigned long (*HashCodeFcn)(Key key), bool (*EqualKey)(Key key1, Key key2)>
|
||||
SimpleHashTable<Key, Value, _hashTableSize, HashCodeFcn, EqualKey>::SimpleHashTable()
|
||||
{
|
||||
for (int i = 0; i < _hashTableSize; i++)
|
||||
{
|
||||
hashBucket[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Key, typename Value, int _hashTableSize, unsigned long (*HashCodeFcn)(Key key), bool (*EqualKey)(Key key1, Key key2)>
|
||||
SimpleHashTable<Key, Value, _hashTableSize, HashCodeFcn, EqualKey>::~SimpleHashTable()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
template <typename Key, typename Value, int _hashTableSize, unsigned long (*HashCodeFcn)(Key key), bool (*EqualKey)(Key key1, Key key2)>
|
||||
void SimpleHashTable<Key, Value, _hashTableSize, HashCodeFcn, EqualKey>::Clear()
|
||||
{
|
||||
for (int i = 0; i < _hashTableSize; i++)
|
||||
{
|
||||
DeleteEntryList(this->hashBucket + i);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Key, typename Value, int _hashTableSize, unsigned long (*HashCodeFcn)(Key key), bool (*EqualKey)(Key key1, Key key2)>
|
||||
void SimpleHashTable<Key, Value, _hashTableSize, HashCodeFcn, EqualKey>::DeleteEntryList(HashEntry<Key, Value> ** ppEntry)
|
||||
{
|
||||
if (*ppEntry == 0)
|
||||
return;
|
||||
|
||||
DeleteEntryList(&(*ppEntry)->_next);
|
||||
delete *ppEntry;
|
||||
*ppEntry = 0;
|
||||
}
|
||||
|
||||
template <typename Key, typename Value, int _hashTableSize, unsigned long (*HashCodeFcn)(Key key), bool (*EqualKey)(Key key1, Key key2)>
|
||||
void SimpleHashTable<Key, Value, _hashTableSize, HashCodeFcn, EqualKey>::Insert(Key key, Value value)
|
||||
{
|
||||
HashEntry<Key, Value> ** ppHashEntryListHead = HashCode2EntryListHead(HashCodeFcn(key));
|
||||
HashEntry<Key, Value> * hashEntry = new HashEntry<Key, Value>(key, value);
|
||||
InsertToList(ppHashEntryListHead, hashEntry);
|
||||
}
|
||||
|
||||
template <typename Key, typename Value, int _hashTableSize, unsigned long (*HashCodeFcn)(Key key), bool (*EqualKey)(Key key1, Key key2)>
|
||||
HashEntry<Key, Value> ** SimpleHashTable<Key, Value, _hashTableSize, HashCodeFcn, EqualKey>::HashCode2EntryListHead(unsigned long hashCode)
|
||||
{
|
||||
return this->hashBucket + hashCode % _hashTableSize;
|
||||
}
|
||||
|
||||
template <typename Key, typename Value, int _hashTableSize, unsigned long (*HashCodeFcn)(Key key), bool (*EqualKey)(Key key1, Key key2)>
|
||||
void SimpleHashTable<Key, Value, _hashTableSize, HashCodeFcn, EqualKey>::InsertToList(HashEntry<Key, Value> ** ppEntryHead, HashEntry<Key, Value> * pEntryToInsert)
|
||||
{
|
||||
HashEntry<Key, Value> * pEntryHead = *ppEntryHead;
|
||||
if (pEntryHead == 0)
|
||||
{
|
||||
*ppEntryHead = pEntryToInsert;
|
||||
}
|
||||
else
|
||||
{
|
||||
HashEntry<Key, Value> * p = pEntryHead;
|
||||
while(p->_next != 0) p = p->_next;
|
||||
p->_next = pEntryToInsert;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Key, typename Value, int _hashTableSize, unsigned long (*HashCodeFcn)(Key key), bool (*EqualKey)(Key key1, Key key2)>
|
||||
HashEntry<Key, Value> * SimpleHashTable<Key, Value, _hashTableSize, HashCodeFcn, EqualKey>::Find(Key key)
|
||||
{
|
||||
HashEntry<Key, Value> ** ppHashEntryListHead = HashCode2EntryListHead(HashCodeFcn(key));
|
||||
|
||||
HashEntry<Key, Value> * pEntry = *ppHashEntryListHead;
|
||||
while (pEntry != 0)
|
||||
{
|
||||
if (EqualKey(pEntry->key, key))
|
||||
return pEntry;
|
||||
pEntry = pEntry->_next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename Key, typename Value, int _hashTableSize, unsigned long (*HashCodeFcn)(Key key), bool (*EqualKey)(Key key1, Key key2)>
|
||||
void SimpleHashTable<Key, Value, _hashTableSize, HashCodeFcn, EqualKey>::Foreach(bool (*VisitorFunc)(Key key, Value value))
|
||||
{
|
||||
for (int i = 0; i < _hashTableSize; i++)
|
||||
{
|
||||
HashEntry<Key, Value> * pEntry = this->hashBucket[i];
|
||||
while(pEntry != 0)
|
||||
{
|
||||
bool continueLoop = VisitorFunc(pEntry->key, pEntry->value);
|
||||
if (! continueLoop)
|
||||
break;
|
||||
|
||||
pEntry = pEntry->_next;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
#include "ILog.h"
|
||||
|
||||
ILog::~ILog() {}
|
|
@ -0,0 +1,15 @@
|
|||
#pragma once
|
||||
|
||||
#include <wchar.h>
|
||||
|
||||
class ILog
|
||||
{
|
||||
public:
|
||||
virtual bool AddRecord(const char * logMsg) = 0;
|
||||
virtual char * Record(int index) = 0;
|
||||
virtual int RecordCount() = 0;
|
||||
virtual ~ILog() = 0;
|
||||
virtual bool Export(const wchar_t * filename) = 0;
|
||||
virtual void ClearData() = 0;
|
||||
};
|
||||
|
|
@ -0,0 +1,336 @@
|
|||
#include <Windows.h>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <memory>
|
||||
#include "LogWithFileBackup.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
int LogWithBackUpFile::index = 0;
|
||||
SpinLock LogWithBackUpFile::__lockFile;
|
||||
|
||||
LogWithBackUpFile * LogWithBackUpFile::Make(const char * folder, const char * name)
|
||||
{
|
||||
LogWithBackUpFile * logObj = new LogWithBackUpFile();
|
||||
|
||||
__lockFile.Lock();
|
||||
HRESULT hr = logObj->CreateFile(folder, name);
|
||||
__lockFile.Unlock();
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
return logObj;
|
||||
else
|
||||
{
|
||||
delete logObj;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
LogWithBackUpFile::LogWithBackUpFile() :
|
||||
logfileW(INVALID_HANDLE_VALUE),
|
||||
logfileR(INVALID_HANDLE_VALUE),
|
||||
idxfileW(INVALID_HANDLE_VALUE),
|
||||
idxfileR(INVALID_HANDLE_VALUE),
|
||||
recordCount(0),
|
||||
_bFileIsFull(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
LogWithBackUpFile::~LogWithBackUpFile()
|
||||
{
|
||||
SafeCloseHandles();
|
||||
}
|
||||
|
||||
HRESULT LogWithBackUpFile::CreateFile(const char * folder, const char * name)
|
||||
{
|
||||
do {
|
||||
this->foldername = folder;
|
||||
if (!CreateDirectoryRecursive(this->foldername.c_str()))
|
||||
break;
|
||||
|
||||
ostringstream os;
|
||||
os << folder << "\\" << name << ".txt";
|
||||
this->logfileName = os.str();
|
||||
|
||||
ostringstream os2;
|
||||
os2 << folder << "\\" << name << ".idx";
|
||||
this->idxfileName = os2.str();
|
||||
|
||||
auto CreateForAppend = [](const string & name){
|
||||
return CreateFileA(
|
||||
name.c_str(),
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ,
|
||||
NULL,
|
||||
CREATE_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
NULL
|
||||
);
|
||||
};
|
||||
|
||||
logfileW = CreateForAppend(this->logfileName);
|
||||
if (logfileW == INVALID_HANDLE_VALUE)
|
||||
break;
|
||||
|
||||
idxfileW = CreateForAppend(this->idxfileName);
|
||||
if (idxfileW == INVALID_HANDLE_VALUE)
|
||||
break;
|
||||
|
||||
auto OpenForReadIfExist = [](const string & name){
|
||||
return CreateFileA(
|
||||
name.c_str(),
|
||||
GENERIC_READ,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
NULL
|
||||
);
|
||||
};
|
||||
|
||||
logfileR = OpenForReadIfExist(this->logfileName);
|
||||
if (logfileR == INVALID_HANDLE_VALUE)
|
||||
break;
|
||||
|
||||
idxfileR = OpenForReadIfExist(this->idxfileName);
|
||||
if (idxfileR == INVALID_HANDLE_VALUE)
|
||||
break;
|
||||
|
||||
return 0;
|
||||
|
||||
} while(0);
|
||||
|
||||
SafeCloseHandles();
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool LogWithBackUpFile::AddRecord(const char * logMsg)
|
||||
{
|
||||
if (_bFileIsFull)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this->logfileW == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
if (this->idxfileW == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
|
||||
bool bFileIsFull = false;
|
||||
|
||||
int lenLogMsg = strlen(logMsg);
|
||||
int logFileSize = GetFileSize(this->logfileW, NULL);
|
||||
int indexFileSize = GetFileSize(this->idxfileW, NULL);
|
||||
|
||||
const int FILE_SIZE_LIMIT = INT_MAX;
|
||||
|
||||
if ( (((__int64)logFileSize + lenLogMsg) > FILE_SIZE_LIMIT) ||
|
||||
((__int64)indexFileSize + sizeof(IdxRecord)) > FILE_SIZE_LIMIT)
|
||||
{
|
||||
bFileIsFull = true;
|
||||
}
|
||||
else do {
|
||||
DWORD numWritten = 0;
|
||||
|
||||
::SetFilePointer(this->logfileW, 0, 0, 2);
|
||||
::WriteFile(this->logfileW, logMsg, lenLogMsg, &numWritten, NULL);
|
||||
if (numWritten < lenLogMsg) // log file is full
|
||||
{
|
||||
bFileIsFull = true;
|
||||
break;
|
||||
}
|
||||
|
||||
IdxRecord idxRecord;
|
||||
idxRecord.offset = logFileSize;
|
||||
idxRecord.length = lenLogMsg;
|
||||
|
||||
::SetFilePointer(this->idxfileW, 0, 0, 2);
|
||||
::WriteFile(this->idxfileW, &idxRecord, sizeof(idxRecord), &numWritten, NULL);
|
||||
if (numWritten < sizeof(idxRecord))
|
||||
{
|
||||
bFileIsFull = true;
|
||||
break;
|
||||
}
|
||||
|
||||
++recordCount;
|
||||
|
||||
} while(0);
|
||||
|
||||
if (bFileIsFull)
|
||||
{
|
||||
_bFileIsFull = true;
|
||||
++recordCount; // for the last error message
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
char * LogWithBackUpFile::Record(int index)
|
||||
{
|
||||
if (_bFileIsFull)
|
||||
{
|
||||
if (index == recordCount - 1)
|
||||
{
|
||||
return strdup("Error: log buffer is full\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (this->logfileR == INVALID_HANDLE_VALUE)
|
||||
return 0;
|
||||
if (this->idxfileR == INVALID_HANDLE_VALUE)
|
||||
return 0;
|
||||
if (index >= recordCount)
|
||||
return 0;
|
||||
|
||||
IdxRecord idxRecord;
|
||||
DWORD numRead;
|
||||
|
||||
if (::SetFilePointer(this->idxfileR, index*sizeof(IdxRecord), 0, 0) == INVALID_SET_FILE_POINTER)
|
||||
return 0;
|
||||
|
||||
BOOL bSucc = ::ReadFile(this->idxfileR, &idxRecord, sizeof(IdxRecord), &numRead, NULL);
|
||||
if (!bSucc)
|
||||
return 0;
|
||||
|
||||
if (::SetFilePointer(this->logfileR, idxRecord.offset, 0, 0) == INVALID_SET_FILE_POINTER)
|
||||
return 0;
|
||||
|
||||
char * readBuf = new char[idxRecord.length+1];
|
||||
readBuf[idxRecord.length] = 0;
|
||||
bSucc = ::ReadFile(this->logfileR, readBuf, idxRecord.length, &numRead, NULL);
|
||||
if (bSucc)
|
||||
return readBuf;
|
||||
else
|
||||
{
|
||||
delete [] readBuf;
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int LogWithBackUpFile::RecordCount()
|
||||
{
|
||||
return recordCount;
|
||||
}
|
||||
|
||||
void LogWithBackUpFile::SafeCloseHandles()
|
||||
{
|
||||
auto SafeCloseHandle = [](HANDLE& handle){
|
||||
if (handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
CloseHandle(handle);
|
||||
handle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
};
|
||||
|
||||
SafeCloseHandle(logfileW);
|
||||
SafeCloseHandle(logfileR);
|
||||
SafeCloseHandle(idxfileW);
|
||||
SafeCloseHandle(idxfileR);
|
||||
}
|
||||
|
||||
|
||||
bool LogWithBackUpFile::CreateDirectoryRecursive(const char * __folder)
|
||||
{
|
||||
bool bSucc;
|
||||
|
||||
char * folderDup = _strdup(__folder);
|
||||
int strlength = strlen(folderDup);
|
||||
|
||||
// remove the last '\'
|
||||
if ( *(folderDup + strlength - 1) == '\\' )
|
||||
folderDup[strlength - 1] = 0;
|
||||
|
||||
char * ptr = (char *)(folderDup + strlength - 1);
|
||||
|
||||
while(ptr > folderDup && *ptr != '\\')
|
||||
--ptr;
|
||||
|
||||
if (ptr == folderDup) // root
|
||||
bSucc = true;
|
||||
else
|
||||
{
|
||||
*ptr = 0;
|
||||
bSucc = CreateDirectoryRecursive(folderDup);
|
||||
|
||||
if (bSucc)
|
||||
{
|
||||
*ptr = '\\';
|
||||
BOOL bRes = CreateDirectoryA(folderDup, NULL);
|
||||
if (!bRes && GetLastError() != ERROR_ALREADY_EXISTS)
|
||||
bSucc = false;
|
||||
bSucc = true;
|
||||
}
|
||||
else
|
||||
bSucc = false;
|
||||
}
|
||||
|
||||
delete [] folderDup;
|
||||
|
||||
return bSucc;
|
||||
}
|
||||
|
||||
bool LogWithBackUpFile::Export(const wchar_t * filename)
|
||||
{
|
||||
auto hfileOutput = ::CreateFileW(
|
||||
filename,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ,
|
||||
NULL,
|
||||
CREATE_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (hfileOutput == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
|
||||
const int MAX_COUNT = 1*1024*1024;
|
||||
std::unique_ptr<char []> readBuf(new char[MAX_COUNT]);
|
||||
|
||||
|
||||
DWORD numRead;
|
||||
DWORD numWrite;
|
||||
int offset = 0;
|
||||
|
||||
do {
|
||||
::SetFilePointer(this->logfileR, offset, 0, 0);
|
||||
BOOL bSucc = ::ReadFile(this->logfileR, readBuf.get(), MAX_COUNT, &numRead, NULL);
|
||||
if (bSucc == FALSE)
|
||||
break;
|
||||
if (numRead == 0)
|
||||
break;
|
||||
|
||||
::SetFilePointer(hfileOutput, 0, 0, 2);
|
||||
bSucc = ::WriteFile(hfileOutput, readBuf.get(), numRead, &numWrite, NULL);
|
||||
if (bSucc == FALSE)
|
||||
break;
|
||||
if (numRead < MAX_COUNT || numWrite < numRead)
|
||||
break;
|
||||
offset += MAX_COUNT;
|
||||
} while(1);
|
||||
|
||||
CloseHandle(hfileOutput);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void LogWithBackUpFile::ClearData()
|
||||
{
|
||||
auto ResetFile = [](HANDLE hFile){
|
||||
::SetFilePointer(hFile, 0, 0, 0);
|
||||
::SetEndOfFile(hFile);
|
||||
};
|
||||
|
||||
ResetFile(this->idxfileR);
|
||||
ResetFile(this->idxfileW);
|
||||
ResetFile(this->logfileR);
|
||||
ResetFile(this->logfileW);
|
||||
|
||||
this->recordCount = 0;
|
||||
this->_bFileIsFull = false;
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <Windows.h>
|
||||
#include "ILog.h"
|
||||
#include "SpinLock.h"
|
||||
|
||||
class LogWithBackUpFile : public ILog
|
||||
{
|
||||
public:
|
||||
// Factory
|
||||
static LogWithBackUpFile * __stdcall Make(const char * folder, const char * name);
|
||||
static SpinLock __lockFile;
|
||||
|
||||
public:
|
||||
struct IdxRecord
|
||||
{
|
||||
int offset;
|
||||
int length;
|
||||
};
|
||||
|
||||
// ILog interface
|
||||
bool AddRecord(const char * logMsg);
|
||||
char * Record(int index);
|
||||
int RecordCount();
|
||||
~LogWithBackUpFile();
|
||||
|
||||
private:
|
||||
static int index;
|
||||
|
||||
private:
|
||||
LogWithBackUpFile();
|
||||
HRESULT CreateFile(const char * folder, const char * name);
|
||||
void SafeCloseHandles();
|
||||
bool CreateDirectoryRecursive(const char * folder);
|
||||
|
||||
std::string foldername;
|
||||
std::string logfileName;
|
||||
std::string idxfileName;
|
||||
|
||||
HANDLE logfileW;
|
||||
HANDLE idxfileW;
|
||||
|
||||
HANDLE logfileR;
|
||||
HANDLE idxfileR;
|
||||
|
||||
int recordCount;
|
||||
|
||||
bool _bFileIsFull;
|
||||
|
||||
public:
|
||||
virtual bool Export(const wchar_t * filename);
|
||||
virtual void ClearData();
|
||||
};
|
||||
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
#include "PathName.h"
|
||||
|
||||
const wchar_t * PathName::__reserved_char = L"\\/:*?\"<>| ";
|
||||
|
||||
PathName::PathName()
|
||||
{
|
||||
}
|
||||
|
||||
void PathName::AppendWithEscape(const wchar_t * name, wchar_t creplace)
|
||||
{
|
||||
const wchar_t * ptr = name;
|
||||
wchar_t c;
|
||||
while( (c = *ptr) != 0 )
|
||||
{
|
||||
if (IsReserved(c))
|
||||
c = creplace;
|
||||
_path.push_back(c);
|
||||
++ptr;
|
||||
}
|
||||
}
|
||||
|
||||
void PathName::Append(const wchar_t * name)
|
||||
{
|
||||
const wchar_t * ptr = name;
|
||||
wchar_t c;
|
||||
while( (c = *ptr) != 0 )
|
||||
{
|
||||
_path.push_back(c);
|
||||
++ptr;
|
||||
}
|
||||
}
|
||||
|
||||
void PathName::Reset()
|
||||
{
|
||||
_path.clear();
|
||||
}
|
||||
|
||||
PathName::operator const wchar_t *()
|
||||
{
|
||||
if ( (_path.size() == 0) ||
|
||||
_path[_path.size()-1] != 0
|
||||
)
|
||||
{
|
||||
_path.push_back(0);
|
||||
}
|
||||
|
||||
return &_path[0];
|
||||
}
|
||||
|
||||
bool PathName::IsReserved(wchar_t c)
|
||||
{
|
||||
for (auto ptr = __reserved_char; *ptr != 0; ++ptr)
|
||||
{
|
||||
if (*ptr == c)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
|
||||
#include <Windows.h>
|
||||
#include <vector>
|
||||
|
||||
class PathName
|
||||
{
|
||||
public:
|
||||
PathName();
|
||||
|
||||
void AppendWithEscape(const wchar_t * name, wchar_t creplace);
|
||||
|
||||
void Append(const wchar_t * name);
|
||||
|
||||
void Reset();
|
||||
|
||||
operator const wchar_t *();
|
||||
|
||||
private:
|
||||
bool IsReserved(wchar_t c);
|
||||
|
||||
private:
|
||||
static const wchar_t * __reserved_char;
|
||||
std::vector<wchar_t> _path;
|
||||
};
|
|
@ -0,0 +1,136 @@
|
|||
#pragma once
|
||||
|
||||
#include <assert.h>
|
||||
#include <functional>
|
||||
#include <list>
|
||||
#include "ReadWriteLock.h"
|
||||
|
||||
#if 0
|
||||
|
||||
namespace SoraDbgPlot { namespace Task {
|
||||
|
||||
class RWTaskQueue
|
||||
{
|
||||
public:
|
||||
typedef std::function<void(void)> TaskFunc;
|
||||
private:
|
||||
enum TaskType
|
||||
{
|
||||
TYPE_READ,
|
||||
TYPE_WRITE,
|
||||
};
|
||||
|
||||
struct Task
|
||||
{
|
||||
TaskType _type;
|
||||
TaskFunc _func;
|
||||
};
|
||||
|
||||
public:
|
||||
RWTaskQueue()
|
||||
{
|
||||
_exeToken = 0;
|
||||
_activeCount = 0;
|
||||
}
|
||||
|
||||
~RWTaskQueue()
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
bool bBreak = false;
|
||||
_lockList.Lock();
|
||||
if (_taskList.size() == 0)
|
||||
bBreak = true;
|
||||
_lockList.Unlock();
|
||||
|
||||
if (bBreak) break;
|
||||
}
|
||||
}
|
||||
|
||||
void DoTaskWrite(const TaskFunc & f)
|
||||
{
|
||||
::InterlockedIncrement(&_activeCount);
|
||||
|
||||
_lockRunning.LockWrite();
|
||||
f();
|
||||
_lockRunning.UnlockWrite();
|
||||
|
||||
if (::InterlockedDecrement(&_activeCount) == 0)
|
||||
ExecuteTaskAsync(false);
|
||||
}
|
||||
|
||||
void QueueTaskRead();
|
||||
void QueueTaskWrite();
|
||||
|
||||
private:
|
||||
void ExecuteTaskAsync(bool doPop)
|
||||
{
|
||||
std::list<TaskFunc *> _newTaskList;
|
||||
|
||||
_lockList.Lock();
|
||||
|
||||
if (doPop)
|
||||
{
|
||||
_exeToken = false;
|
||||
}
|
||||
|
||||
if (_exeToken == false)
|
||||
{
|
||||
if (_taskList.size() > 0)
|
||||
{
|
||||
|
||||
|
||||
_exeToken = true;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
_lockList.Unlock();
|
||||
|
||||
while(_newTaskList.si
|
||||
|
||||
if (_newTaskList.size() > 0)
|
||||
{
|
||||
BOOL succ = QueueUserWorkItem(ThreadExecuteTask, this, WT_EXECUTEDEFAULT);
|
||||
assert(succ != 0);
|
||||
}
|
||||
}
|
||||
|
||||
static DWORD WINAPI ThreadExecuteTask(__in LPVOID lpParameter)
|
||||
{
|
||||
auto queue = (TaskQueue *)lpParameter;
|
||||
|
||||
//::InterlockedIncrement(&queue->_activeCnt);
|
||||
|
||||
queue->_lockRunning.Lock();
|
||||
queue->_task();
|
||||
queue->_lockRunning.Unlock();
|
||||
|
||||
//queue->_lockList.Lock();
|
||||
//queue->_taskList.pop_front();
|
||||
//queue->_lockList.Unlock();
|
||||
|
||||
//if (::InterlockedDecrement(&queue->_activeCnt) == 0)
|
||||
queue->ExecuteTaskAsync(true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
TaskFunc _task;
|
||||
std::list<Task> _taskList;
|
||||
SoraDbgPlot::Lock::RWLock _lockRunning;
|
||||
SoraDbgPlot::Lock::CSLock _lockList;
|
||||
//SoraDbgPlot::Lock::CSRecursiveLock _lockRunning;
|
||||
//SoraDbgPlot::Lock::CSLock _lockList;
|
||||
//HANDLE _evenTaskComplete;
|
||||
//volatile unsigned long _activeCnt;
|
||||
volatile unsigned long _exeToken;
|
||||
volatile unsigned long _activeCount;
|
||||
TaskType _taskType;
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,29 @@
|
|||
========================================================================
|
||||
STATIC LIBRARY : Common Project Overview
|
||||
========================================================================
|
||||
|
||||
AppWizard has created this Common library project for you.
|
||||
|
||||
No source files were created as part of your project.
|
||||
|
||||
|
||||
Common.vcxproj
|
||||
This is the main project file for VC++ projects generated using an Application Wizard.
|
||||
It contains information about the version of Visual C++ that generated the file, and
|
||||
information about the platforms, configurations, and project features selected with the
|
||||
Application Wizard.
|
||||
|
||||
Common.vcxproj.filters
|
||||
This is the filters file for VC++ projects generated using an Application Wizard.
|
||||
It contains information about the association between the files in your project
|
||||
and the filters. This association is used in the IDE to show grouping of files with
|
||||
similar extensions under a specific node (for e.g. ".cpp" files are associated with the
|
||||
"Source Files" filter).
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
Other notes:
|
||||
|
||||
AppWizard uses "TODO:" comments to indicate parts of the source code you
|
||||
should add to or customize.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
|
@ -0,0 +1,52 @@
|
|||
#pragma once
|
||||
|
||||
#include "CSRecursiveLock.h"
|
||||
|
||||
namespace SoraDbgPlot { namespace Lock {
|
||||
|
||||
class RWLock
|
||||
{
|
||||
public:
|
||||
RWLock()
|
||||
{
|
||||
_readCount = 0;
|
||||
}
|
||||
~RWLock()
|
||||
{
|
||||
}
|
||||
|
||||
void LockWrite()
|
||||
{
|
||||
_wlock.Lock();
|
||||
}
|
||||
|
||||
void UnlockWrite()
|
||||
{
|
||||
_wlock.Unlock();
|
||||
}
|
||||
|
||||
void LockRead()
|
||||
{
|
||||
_rlock.Lock();
|
||||
_readCount++;
|
||||
if (_readCount == 1)
|
||||
_wlock.Lock();
|
||||
_rlock.Unlock();
|
||||
}
|
||||
|
||||
void UnlockRead()
|
||||
{
|
||||
_rlock.Lock();
|
||||
_readCount--;
|
||||
if (_readCount == 0)
|
||||
_wlock.Unlock();
|
||||
_rlock.Unlock();
|
||||
}
|
||||
|
||||
private:
|
||||
SoraDbgPlot::Lock::CSLock _rlock;
|
||||
SoraDbgPlot::Lock::CSLock _wlock;
|
||||
int _readCount;
|
||||
};
|
||||
|
||||
}}
|
|
@ -0,0 +1,165 @@
|
|||
#pragma once
|
||||
|
||||
#include <Windows.h>
|
||||
#include <exception>
|
||||
#include <functional>
|
||||
|
||||
template <typename T>
|
||||
class RingBuffer
|
||||
{
|
||||
public:
|
||||
RingBuffer(size_t count);
|
||||
~RingBuffer();
|
||||
size_t Write(const T * ptr, size_t count);
|
||||
bool Read(size_t start, size_t len, T * addr, size_t maxLen, size_t & sizeRead);
|
||||
T operator[](size_t index);
|
||||
size_t Size();
|
||||
size_t Capacity();
|
||||
size_t WriteIndex();
|
||||
void Reset();
|
||||
|
||||
typedef std::function<void(const T *, size_t)> ExportFunc;
|
||||
bool Export(const ExportFunc &);
|
||||
bool ExportRange(size_t start, size_t length, const ExportFunc &);
|
||||
|
||||
private:
|
||||
T * _buffer;
|
||||
T * _pWrite;
|
||||
size_t _dataCount;
|
||||
size_t _maxCount;
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
RingBuffer<T>::RingBuffer(size_t count) {
|
||||
_maxCount = count;
|
||||
_buffer = new T[_maxCount];
|
||||
_pWrite = _buffer;
|
||||
_dataCount = 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
RingBuffer<T>::~RingBuffer()
|
||||
{
|
||||
delete [] _buffer;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
size_t RingBuffer<T>::Write(const T * ptr, size_t count)
|
||||
{
|
||||
if (count <= 0)
|
||||
return 0;
|
||||
|
||||
size_t cntToWrite = min(count, _maxCount);
|
||||
_dataCount = min(_dataCount + cntToWrite, _maxCount);
|
||||
|
||||
size_t retCnt = cntToWrite;
|
||||
|
||||
size_t cntToBufEnd = _buffer + _maxCount - _pWrite;
|
||||
size_t count1 = min(cntToBufEnd, cntToWrite);
|
||||
memcpy(_pWrite, ptr, count1 * sizeof(T));
|
||||
|
||||
cntToWrite -= count1;
|
||||
_pWrite += count1;
|
||||
if (_pWrite == _buffer + _maxCount)
|
||||
_pWrite = _buffer;
|
||||
|
||||
if (cntToWrite > 0)
|
||||
{
|
||||
ptr = ptr + count1;
|
||||
memcpy(_pWrite, ptr, cntToWrite * sizeof(T));
|
||||
_pWrite += cntToWrite;
|
||||
}
|
||||
|
||||
return retCnt;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool RingBuffer<T>::Read(size_t start, size_t len, T * addr, size_t maxLen, size_t & sizeRead)
|
||||
{
|
||||
size_t sizeToRead = min(maxLen, len);
|
||||
sizeRead = sizeToRead;
|
||||
|
||||
size_t s1 = (_maxCount - start);
|
||||
s1 = min(s1, len);
|
||||
memcpy(addr, _buffer + start, sizeof(T) * s1);
|
||||
addr += s1;
|
||||
sizeToRead -= s1;
|
||||
if (sizeToRead > 0)
|
||||
{
|
||||
size_t s2 = sizeToRead;
|
||||
memcpy(addr, _buffer, sizeof(T) * s2);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T RingBuffer<T>::operator[](size_t index) {
|
||||
if (index < 0 || index >= _dataCount)
|
||||
throw std::exception("index out of range");
|
||||
|
||||
T * ptr = _pWrite - 1 - index;
|
||||
if (ptr < _buffer)
|
||||
ptr += _maxCount;
|
||||
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
size_t RingBuffer<T>::Size()
|
||||
{
|
||||
return _dataCount;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
size_t RingBuffer<T>::Capacity()
|
||||
{
|
||||
return _maxCount;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
size_t RingBuffer<T>::WriteIndex()
|
||||
{
|
||||
return _pWrite - _buffer;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void RingBuffer<T>::Reset()
|
||||
{
|
||||
_pWrite = _buffer;
|
||||
_dataCount = 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool RingBuffer<T>::Export(const ExportFunc & f)
|
||||
{
|
||||
return ExportRange(0, _dataCount, f);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool RingBuffer<T>::ExportRange(size_t start, size_t length, const ExportFunc & f)
|
||||
{
|
||||
int lengthToProcess = length;
|
||||
|
||||
if (lengthToProcess <= 0)
|
||||
return false;
|
||||
|
||||
int indexStart = _pWrite - _buffer - start - lengthToProcess;
|
||||
if (indexStart < 0)
|
||||
{
|
||||
indexStart += _maxCount;
|
||||
int length1 = _maxCount - indexStart; // till end of buffer
|
||||
f(_buffer + indexStart, length1);
|
||||
indexStart += length1;
|
||||
indexStart = indexStart % _maxCount;
|
||||
lengthToProcess -= length1;
|
||||
}
|
||||
|
||||
if (lengthToProcess <= 0)
|
||||
return true;
|
||||
|
||||
f(_buffer + indexStart, lengthToProcess);
|
||||
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,144 @@
|
|||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include "RingBuffer.h"
|
||||
#include "TimeStampQueue.h"
|
||||
|
||||
template <typename T>
|
||||
class RingBufferWithTimeStamp
|
||||
{
|
||||
public:
|
||||
RingBufferWithTimeStamp(size_t size);
|
||||
~RingBufferWithTimeStamp();
|
||||
size_t Write(const T * ptr, size_t count, unsigned long long timeStamp);
|
||||
bool GetTimeStampBySample(size_t index, unsigned long long & timestamp);
|
||||
bool GetNearestOldTimeStamp(unsigned long long in, unsigned long long & out, size_t & outIdx);
|
||||
size_t Size();
|
||||
size_t RecordCount();
|
||||
bool GetDataSizeByTimeStampIdx(size_t idx, size_t & out);
|
||||
bool ReadDataByTimeStampIdx(size_t idx, T * addr, size_t maxLen, size_t & sizeRead);
|
||||
|
||||
T operator[] (size_t index);
|
||||
void Reset();
|
||||
|
||||
typedef std::function<void(const T *, size_t)> ExportFunc;
|
||||
bool Export(const ExportFunc &);
|
||||
bool ExportRange(size_t start, size_t length, const ExportFunc &);
|
||||
|
||||
private:
|
||||
RingBuffer<T> * _ringBuffer;
|
||||
TimeStampQueue * _timeStampQueue;
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
RingBufferWithTimeStamp<T>::RingBufferWithTimeStamp(size_t size)
|
||||
{
|
||||
_ringBuffer = new RingBuffer<T>(size);
|
||||
_timeStampQueue = new TimeStampQueue(size);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
RingBufferWithTimeStamp<T>::~RingBufferWithTimeStamp()
|
||||
{
|
||||
delete _ringBuffer;
|
||||
delete _timeStampQueue;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
size_t RingBufferWithTimeStamp<T>::Write(const T * ptr, size_t count, unsigned long long timeStamp)
|
||||
{
|
||||
if (count < 0)
|
||||
return 0;
|
||||
|
||||
size_t writeIdx1 = _ringBuffer->WriteIndex();
|
||||
size_t cntWritten = _ringBuffer->Write(ptr, count);
|
||||
size_t writeIdx2 = _ringBuffer->WriteIndex();
|
||||
DataRecord record;
|
||||
record._start = writeIdx1;
|
||||
record._size = (writeIdx2 - writeIdx1) % _ringBuffer->Capacity();
|
||||
|
||||
record._timestamp = timeStamp;
|
||||
|
||||
_timeStampQueue->AddRecord(record);
|
||||
|
||||
return cntWritten;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool RingBufferWithTimeStamp<T>::GetTimeStampBySample(size_t index, unsigned long long & timestamp)
|
||||
{
|
||||
size_t targetIndex = (_ringBuffer->WriteIndex() - 1 - index) % _ringBuffer->Capacity();
|
||||
return _timeStampQueue->Search(targetIndex, timestamp);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool RingBufferWithTimeStamp<T>::GetNearestOldTimeStamp(unsigned long long timestamp, unsigned long long & out, size_t & outIdx)
|
||||
{
|
||||
return _timeStampQueue->SearchNearestTimeStamp(timestamp, out, outIdx);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
size_t RingBufferWithTimeStamp<T>::Size()
|
||||
{
|
||||
return _ringBuffer->Size();
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
size_t RingBufferWithTimeStamp<T>::RecordCount()
|
||||
{
|
||||
return _timeStampQueue->Size();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T RingBufferWithTimeStamp<T>::operator[] (size_t index)
|
||||
{
|
||||
return (*_ringBuffer)[index];
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void RingBufferWithTimeStamp<T>::Reset()
|
||||
{
|
||||
_ringBuffer->Reset();
|
||||
_timeStampQueue->Reset();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool RingBufferWithTimeStamp<T>::GetDataSizeByTimeStampIdx(size_t idx, size_t & out)
|
||||
{
|
||||
DataRecord record;
|
||||
bool found = _timeStampQueue->GetDataRecord(idx, record);
|
||||
if (found)
|
||||
{
|
||||
out = record._size;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool RingBufferWithTimeStamp<T>::ReadDataByTimeStampIdx(size_t idx, T * addr, size_t maxLen, size_t & sizeRead)
|
||||
{
|
||||
DataRecord record;
|
||||
bool found = _timeStampQueue->GetDataRecord(idx, record);
|
||||
if (!found)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return this->_ringBuffer->Read(record._start, record._size, addr, maxLen, sizeRead);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool RingBufferWithTimeStamp<T>::Export(const ExportFunc & f)
|
||||
{
|
||||
return _ringBuffer->Export(f);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool RingBufferWithTimeStamp<T>::ExportRange(size_t start, size_t length, const ExportFunc & f)
|
||||
{
|
||||
return _ringBuffer->ExportRange(start, length, f);
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace SoraDbgPlot { namespace Task {
|
||||
|
||||
class Runnable : public std::enable_shared_from_this<Runnable>
|
||||
{
|
||||
public:
|
||||
virtual void Run() = 0;
|
||||
virtual std::shared_ptr<Runnable> ContinueWith(std::shared_ptr<Runnable>) = 0;
|
||||
virtual ~Runnable() {}
|
||||
};
|
||||
|
||||
}}
|
|
@ -0,0 +1,46 @@
|
|||
#pragma once
|
||||
|
||||
#include <Windows.h>
|
||||
#include <assert.h>
|
||||
#include "_share_mem_if.h"
|
||||
#include "_share_lock_if.h"
|
||||
#include "DACL_Control.h"
|
||||
|
||||
static inline ShareLock * AllocateSharedEvent(
|
||||
BOOL bManualReset,
|
||||
BOOL bInitialState,
|
||||
LPCWSTR lpName)
|
||||
{
|
||||
ShareLock * lock = NULL;
|
||||
SECURITY_ATTRIBUTES sa;
|
||||
CreateDACLWithAllAccess(&sa);
|
||||
lock = ShareLock::AllocateShareEvent(&sa, bManualReset, bInitialState, lpName);
|
||||
LocalFree(sa.lpSecurityDescriptor);
|
||||
return lock;
|
||||
}
|
||||
|
||||
static inline ShareMem * AllocateSharedMem(const wchar_t * name, int size, ShareMemClassInit * initFunc, void * context = 0)
|
||||
{
|
||||
ShareMem * sm = NULL;
|
||||
SECURITY_ATTRIBUTES sa;
|
||||
BOOL succ = CreateDACLWithAllAccess(&sa);
|
||||
sm = ShareMem::AllocateShareMem(
|
||||
INVALID_HANDLE_VALUE,
|
||||
&sa,
|
||||
PAGE_READWRITE,
|
||||
size,
|
||||
name,
|
||||
FILE_MAP_ALL_ACCESS,
|
||||
initFunc,
|
||||
context
|
||||
);
|
||||
LocalFree(sa.lpSecurityDescriptor);
|
||||
return sm;
|
||||
}
|
||||
|
||||
static inline BOOL DummyShareMemClassInit(ShareMem* sm, void* context)
|
||||
{ return TRUE; } // do nothing
|
||||
|
||||
#ifdef ASSERT
|
||||
#undef ASSERT
|
||||
#endif
|
|
@ -0,0 +1,42 @@
|
|||
#pragma once
|
||||
|
||||
#include <Windows.h>
|
||||
#include <assert.h>
|
||||
//#include "_share_mem_if.h"
|
||||
#include "ShareMemHelper.h"
|
||||
|
||||
namespace SoraDbgPlot { namespace Common
|
||||
{
|
||||
class SharedSerialNumGenerator
|
||||
{
|
||||
public:
|
||||
SharedSerialNumGenerator(const wchar_t * sharedName)
|
||||
{
|
||||
_sm = AllocateSharedMem(
|
||||
sharedName,
|
||||
4,
|
||||
SharedMemInit,
|
||||
0);
|
||||
}
|
||||
|
||||
~SharedSerialNumGenerator()
|
||||
{
|
||||
ShareMem::FreeShareMem(_sm);
|
||||
}
|
||||
|
||||
unsigned int GetSerialNum()
|
||||
{
|
||||
volatile unsigned int * addr = (unsigned int *)_sm->GetAddress();
|
||||
return ::InterlockedIncrement(addr);
|
||||
}
|
||||
|
||||
static BOOL SharedMemInit(ShareMem* sm, void* context)
|
||||
{
|
||||
int * addr = (int *)sm->GetAddress();
|
||||
*addr = 0;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
ShareMem * _sm;
|
||||
};
|
||||
}}
|
|
@ -0,0 +1,66 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
template <typename ValueType>
|
||||
class SimpleVector
|
||||
{
|
||||
public:
|
||||
SimpleVector();
|
||||
~SimpleVector();
|
||||
void Append(ValueType value);
|
||||
void Foreach(bool (*VisitorFunc)(int index, ValueType value));
|
||||
private:
|
||||
void Realloc();
|
||||
|
||||
static const int DEFAULT_SIZE = 64;
|
||||
ValueType * _buffer;
|
||||
int _size;
|
||||
int _index;
|
||||
};
|
||||
|
||||
template <typename ValueType>
|
||||
SimpleVector<ValueType>::SimpleVector()
|
||||
{
|
||||
_size = DEFAULT_SIZE;
|
||||
_buffer = new ValueType[_size];
|
||||
_index = 0;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
SimpleVector<ValueType>::~SimpleVector()
|
||||
{
|
||||
delete [] _buffer;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
void SimpleVector<ValueType>::Append(ValueType value)
|
||||
{
|
||||
if (_index == _size)
|
||||
Realloc();
|
||||
|
||||
_buffer[_index++] = value;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
void SimpleVector<ValueType>::Realloc()
|
||||
{
|
||||
_size *= 2;
|
||||
ValueType * newBuf = new ValueType[_size];
|
||||
if (_index > 0)
|
||||
memcpy(newBuf, _buffer, _index*sizeof(ValueType));
|
||||
delete [] _buffer;
|
||||
_buffer = newBuf;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
void SimpleVector<ValueType>::Foreach(bool (*VisitorFunc)(int index, ValueType value))
|
||||
{
|
||||
for (int i = 0; i < _index; i++)
|
||||
{
|
||||
bool continueLoop = VisitorFunc(i, _buffer[i]);
|
||||
if (!continueLoop)
|
||||
break;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
class SpinLock
|
||||
{
|
||||
public:
|
||||
SpinLock() {
|
||||
value = 0;
|
||||
}
|
||||
void Lock() {
|
||||
while(::InterlockedCompareExchange(&value, 1, 0) != 0);
|
||||
}
|
||||
void Unlock() {
|
||||
InterlockedExchange(&value, 0);
|
||||
}
|
||||
private:
|
||||
volatile LONG value;
|
||||
};
|
|
@ -0,0 +1,59 @@
|
|||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <Windows.h>
|
||||
#include "CSRecursiveLock.h"
|
||||
|
||||
namespace SoraDbgPlot { namespace Strategy {
|
||||
|
||||
template <typename T, typename R>
|
||||
class Strategy
|
||||
{
|
||||
typedef std::function<void(const void *, const T &, R &)> CallbackType;
|
||||
public:
|
||||
void Set(const CallbackType & f) {
|
||||
_lock.Lock();
|
||||
_callback.reset();
|
||||
_callback = std::make_shared<CallbackType>(f);
|
||||
_lock.Unlock();
|
||||
}
|
||||
|
||||
void UnSet() {
|
||||
_lock.Lock();
|
||||
_callback.reset();
|
||||
_lock.Unlock();
|
||||
}
|
||||
|
||||
bool Call(const void * sender, const T & e, R & r) {
|
||||
|
||||
bool ret = false;
|
||||
|
||||
_lock.Lock();
|
||||
|
||||
if (_callback.get())
|
||||
{
|
||||
(*_callback)(sender, e, r);
|
||||
ret = true;
|
||||
}
|
||||
|
||||
_lock.Unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
_lock.Lock();
|
||||
_callback.reset();
|
||||
_lock.Unlock();
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<CallbackType > _callback;
|
||||
SoraDbgPlot::Lock::CSRecursiveLock _lock;
|
||||
};
|
||||
|
||||
}}
|
|
@ -0,0 +1,83 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <list>
|
||||
#include <assert.h>
|
||||
#include "Runnable.h"
|
||||
#include "TaskSimple.h"
|
||||
|
||||
namespace SoraDbgPlot { namespace Task {
|
||||
|
||||
class TaskCoordinator : public Runnable
|
||||
{
|
||||
public:
|
||||
TaskCoordinator(std::shared_ptr<SoraDbgPlot::Task::TaskQueue> queue)
|
||||
{
|
||||
_taskQueue = queue;
|
||||
}
|
||||
|
||||
~TaskCoordinator()
|
||||
{
|
||||
int debug = 10;
|
||||
}
|
||||
|
||||
void AddTask(std::shared_ptr<TaskSimple> t)
|
||||
{
|
||||
_taskList.push_back(t);
|
||||
}
|
||||
|
||||
void AddTask(std::shared_ptr<TaskSimple> t[], int count)
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
_taskList.push_back(t[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void Run()
|
||||
{
|
||||
if (_taskList.size() == 0)
|
||||
_runnableContinue->Run();
|
||||
|
||||
auto shared_me = std::dynamic_pointer_cast<TaskCoordinator, Runnable>(shared_from_this());
|
||||
_remainCount = 0;
|
||||
std::for_each(_taskList.begin(), _taskList.end(), [shared_me](std::shared_ptr<TaskSimple> task){
|
||||
shared_me -> _remainCount++;
|
||||
auto shared_me_2 = shared_me;
|
||||
|
||||
task->ContinueWith(std::make_shared<SoraDbgPlot::Task::TaskSimple>(shared_me_2->_taskQueue, [shared_me_2](){
|
||||
if (::InterlockedDecrement(&shared_me_2->_remainCount) == 0)
|
||||
{
|
||||
if (shared_me_2->_runnableContinue)
|
||||
shared_me_2->_runnableContinue->Run();
|
||||
|
||||
shared_me_2->_taskList.clear();
|
||||
}
|
||||
}));
|
||||
|
||||
task->Run();
|
||||
});
|
||||
}
|
||||
|
||||
virtual std::shared_ptr<Runnable> ContinueWith(std::shared_ptr<Runnable> t)
|
||||
{
|
||||
if (_runnableContinue)
|
||||
return _runnableContinue->ContinueWith(t);
|
||||
else
|
||||
{
|
||||
_runnableContinue = t;
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
TaskCoordinator(const TaskCoordinator &) {}
|
||||
TaskCoordinator(TaskCoordinator &&) {}
|
||||
|
||||
private:
|
||||
std::shared_ptr<Runnable> _runnableContinue;
|
||||
std::list<std::shared_ptr<TaskSimple> > _taskList;
|
||||
volatile unsigned long _remainCount;
|
||||
std::shared_ptr<SoraDbgPlot::Task::TaskQueue> _taskQueue;
|
||||
};
|
||||
}}
|
|
@ -0,0 +1,18 @@
|
|||
#include <Windows.h>
|
||||
#include "TaskQueue.h"
|
||||
|
||||
using namespace SoraDbgPlot::Task;
|
||||
|
||||
volatile unsigned long SoraDbgPlot::Task::TaskQueue::__countQueue = 0;
|
||||
HANDLE SoraDbgPlot::Task::TaskQueue::__eventWait = ::CreateEvent(NULL, FALSE, TRUE, NULL);
|
||||
volatile bool SoraDbgPlot::Task::TaskQueue::__clean = false;
|
||||
|
||||
#ifdef _DEBUG
|
||||
volatile unsigned long SoraDbgPlot::Task::TaskQueue::__taskCntInQueue = 0;
|
||||
volatile unsigned long SoraDbgPlot::Task::TaskQueue::__taskCntToRun = 0;
|
||||
volatile unsigned long SoraDbgPlot::Task::TaskQueue::__taskCntRunning = 0;
|
||||
volatile unsigned long SoraDbgPlot::Task::TaskQueue::__taskQueueOpCount = 0;
|
||||
#endif
|
||||
|
||||
volatile unsigned long SoraDbgPlot::Task::TaskQueue::__sid = 0;
|
||||
volatile unsigned long SoraDbgPlot::Task::TaskQueue::__taskNum = 0;
|
|
@ -0,0 +1,266 @@
|
|||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <assert.h>
|
||||
#include "CSLock.h"
|
||||
#include "CSRecursiveLock.h"
|
||||
#include "ReadWriteLock.h"
|
||||
|
||||
namespace SoraDbgPlot { namespace Task {
|
||||
|
||||
class TaskQueue : public std::enable_shared_from_this<TaskQueue>
|
||||
{
|
||||
public:
|
||||
typedef std::function<void(void)> TaskFunc;
|
||||
|
||||
TaskQueue()
|
||||
{
|
||||
::InterlockedIncrement(&TaskQueue::__countQueue);
|
||||
_exeToken = TASK_TOKEN_NOT_TAKEN;
|
||||
}
|
||||
|
||||
private:
|
||||
TaskQueue(const TaskQueue &) {}
|
||||
TaskQueue(TaskQueue &&) {}
|
||||
|
||||
public:
|
||||
~TaskQueue()
|
||||
{
|
||||
::SetEvent(TaskQueue::__eventWait);
|
||||
::InterlockedDecrement(&TaskQueue::__countQueue);
|
||||
}
|
||||
|
||||
void DoTask(const TaskFunc & f)
|
||||
{
|
||||
_lockRunning.Lock();
|
||||
f();
|
||||
_lockRunning.Unlock();
|
||||
|
||||
ExecuteTaskAsync();
|
||||
}
|
||||
|
||||
void QueueTask(const TaskFunc & f)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
::InterlockedIncrement(&__taskQueueOpCount);
|
||||
#endif
|
||||
|
||||
::InterlockedIncrement(&__taskNum);
|
||||
::InterlockedIncrement(&__sid);
|
||||
|
||||
TaskStruct taskStruct;
|
||||
taskStruct._func = f;
|
||||
taskStruct._doClean = false;
|
||||
|
||||
_lockList.Lock();
|
||||
_taskList.push_back(taskStruct);
|
||||
#ifdef _DEBUG
|
||||
::InterlockedIncrement(&__taskCntInQueue);
|
||||
#endif
|
||||
_lockList.Unlock();
|
||||
|
||||
ExecuteTaskAsync();
|
||||
|
||||
#ifdef _DEBUG
|
||||
::InterlockedDecrement(&__taskQueueOpCount);
|
||||
#endif
|
||||
}
|
||||
|
||||
void QueueTask(const TaskFunc & f, const TaskFunc & cleanFunc)
|
||||
{
|
||||
|
||||
::InterlockedIncrement(&__taskNum);
|
||||
::InterlockedIncrement(&__sid);
|
||||
|
||||
TaskStruct taskStruct;
|
||||
taskStruct._func = f;
|
||||
taskStruct._cleanFunc = cleanFunc;
|
||||
taskStruct._doClean = true;
|
||||
|
||||
_lockList.Lock();
|
||||
_taskList.push_back(taskStruct);
|
||||
|
||||
#ifdef _DEBUG
|
||||
::InterlockedIncrement(&__taskCntInQueue);
|
||||
#endif
|
||||
_lockList.Unlock();
|
||||
|
||||
ExecuteTaskAsync();
|
||||
}
|
||||
|
||||
private:
|
||||
static DWORD WINAPI ThreadExecuteTask(__in LPVOID lpParameter)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
::InterlockedIncrement(&__taskCntRunning);
|
||||
::InterlockedDecrement(&__taskCntToRun);
|
||||
#endif
|
||||
|
||||
auto queue = (TaskQueue *)lpParameter;
|
||||
auto SThis = queue->_me;
|
||||
|
||||
queue->_lockRunning.Lock();
|
||||
|
||||
if (!__clean)
|
||||
{
|
||||
queue->_task._func();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (queue->_task._doClean)
|
||||
queue->_task._cleanFunc();
|
||||
}
|
||||
|
||||
queue->_lockRunning.Unlock();
|
||||
|
||||
queue->_task._func = [](){};
|
||||
queue->_task._cleanFunc = [](){};
|
||||
queue->_task._doClean = false;
|
||||
queue->_me.reset();
|
||||
|
||||
queue->_lockList.Lock();
|
||||
queue->_exeToken = TASK_TOKEN_NOT_TAKEN;
|
||||
queue->_lockList.Unlock();
|
||||
|
||||
queue->ExecuteTaskAsync();
|
||||
|
||||
#ifdef _DEBUG
|
||||
::InterlockedDecrement(&__taskCntRunning);
|
||||
#endif
|
||||
::InterlockedDecrement(&__taskNum);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ExecuteTaskAsync()
|
||||
{
|
||||
bool takeATask = false;
|
||||
|
||||
_lockList.Lock();
|
||||
|
||||
if (_exeToken == TASK_TOKEN_NOT_TAKEN)
|
||||
{
|
||||
if (_taskList.size() > 0)
|
||||
{
|
||||
_task = _taskList.front();
|
||||
_taskList.pop_front();
|
||||
#ifdef _DEBUG
|
||||
::InterlockedDecrement(&__taskCntInQueue);
|
||||
#endif
|
||||
_exeToken = TASK_TOKEN_TAKEN;
|
||||
_me = shared_from_this();
|
||||
takeATask = true;
|
||||
}
|
||||
}
|
||||
|
||||
_lockList.Unlock();
|
||||
|
||||
if (takeATask)
|
||||
{
|
||||
BOOL succ = QueueUserWorkItem(ThreadExecuteTask, this, WT_EXECUTEDEFAULT);
|
||||
if (succ != 0)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
::InterlockedIncrement(&__taskCntToRun);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct TaskStruct
|
||||
{
|
||||
TaskFunc _func;
|
||||
TaskFunc _cleanFunc;
|
||||
bool _doClean;
|
||||
};
|
||||
|
||||
TaskStruct _task;
|
||||
std::list<TaskStruct> _taskList;
|
||||
SoraDbgPlot::Lock::CSLock _lockRunning;
|
||||
SoraDbgPlot::Lock::CSLock _lockList;
|
||||
volatile unsigned long _exeToken;
|
||||
std::shared_ptr<TaskQueue> _me;
|
||||
|
||||
enum {
|
||||
TASK_TOKEN_TAKEN,
|
||||
TASK_TOKEN_NOT_TAKEN
|
||||
};
|
||||
|
||||
// resource management
|
||||
public:
|
||||
static int __stdcall WaitAndClean(DWORD time)
|
||||
{
|
||||
__clean = true;
|
||||
while(1)
|
||||
{
|
||||
::WaitForSingleObject(__eventWait, time);
|
||||
int activeCount = __countQueue;
|
||||
if (activeCount == 0)
|
||||
{
|
||||
::CloseHandle(__eventWait);
|
||||
}
|
||||
|
||||
return activeCount;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
static unsigned long MonitorQueueNum()
|
||||
{
|
||||
return __countQueue;
|
||||
}
|
||||
|
||||
static unsigned long MonitorTaskInQueue()
|
||||
{
|
||||
return __taskCntInQueue;
|
||||
}
|
||||
|
||||
static unsigned long MonitorTaskCntToRun()
|
||||
{
|
||||
return __taskCntToRun;
|
||||
}
|
||||
|
||||
static unsigned long MonitorTaskCntRunning()
|
||||
{
|
||||
return __taskCntRunning;
|
||||
}
|
||||
|
||||
static unsigned long MonitorTaskQueueOpCnt()
|
||||
{
|
||||
return __taskQueueOpCount;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static unsigned long Sid()
|
||||
{
|
||||
return __sid;
|
||||
}
|
||||
|
||||
static unsigned long RemainingTask()
|
||||
{
|
||||
return __taskNum;
|
||||
}
|
||||
|
||||
private:
|
||||
#ifdef _DEBUG
|
||||
static volatile unsigned long __taskCntInQueue;
|
||||
static volatile unsigned long __taskCntToRun;
|
||||
static volatile unsigned long __taskCntRunning;
|
||||
static volatile unsigned long __taskQueueOpCount;
|
||||
#endif
|
||||
static HANDLE __eventWait;
|
||||
static volatile unsigned long __countQueue;
|
||||
static volatile bool __clean;
|
||||
static volatile unsigned long __sid;
|
||||
static volatile unsigned long __taskNum;
|
||||
};
|
||||
|
||||
}}
|
|
@ -0,0 +1,20 @@
|
|||
#pragma once
|
||||
|
||||
#if 0
|
||||
|
||||
namespace SoraDbgPlot { namespace Task {
|
||||
|
||||
class TaskQueueRequester
|
||||
{
|
||||
public:
|
||||
TaskQueueRequester(size_t size)
|
||||
{
|
||||
_maxSize = size;
|
||||
}
|
||||
private:
|
||||
size_t _maxSize;
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,71 @@
|
|||
#pragma once
|
||||
|
||||
#include <assert.h>
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
#include "TaskQueue.h"
|
||||
#include "Runnable.h"
|
||||
|
||||
namespace SoraDbgPlot { namespace Task
|
||||
{
|
||||
class TaskSimple : public Runnable
|
||||
{
|
||||
public:
|
||||
TaskSimple(std::shared_ptr<TaskQueue> queue, const TaskQueue::TaskFunc & f)
|
||||
{
|
||||
_func = f;
|
||||
_dtor = [](){};
|
||||
_taskQueue = queue;
|
||||
}
|
||||
|
||||
TaskSimple(std::shared_ptr<TaskQueue> queue, const TaskQueue::TaskFunc & f, const TaskQueue::TaskFunc & dtor)
|
||||
{
|
||||
_func = f;
|
||||
_dtor = dtor;
|
||||
_taskQueue = queue;
|
||||
}
|
||||
|
||||
~TaskSimple()
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
std::shared_ptr<SoraDbgPlot::Task::Runnable> ContinueWith(std::shared_ptr<SoraDbgPlot::Task::Runnable> t)
|
||||
{
|
||||
if (_runnableContinue)
|
||||
return _runnableContinue->ContinueWith(t);
|
||||
else
|
||||
{
|
||||
_runnableContinue = t;
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
void Run()
|
||||
{
|
||||
auto func = _func;
|
||||
auto dtor = _dtor;
|
||||
auto runnableContinue = _runnableContinue;
|
||||
_taskQueue->QueueTask([func, runnableContinue](){
|
||||
func();
|
||||
if (runnableContinue)
|
||||
runnableContinue->Run();
|
||||
}, [dtor, runnableContinue](){
|
||||
dtor();
|
||||
if (runnableContinue)
|
||||
runnableContinue->Run();
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
TaskSimple(const TaskSimple & other) {}
|
||||
TaskSimple(TaskSimple && other) {}
|
||||
|
||||
private:
|
||||
TaskQueue::TaskFunc _func;
|
||||
TaskQueue::TaskFunc _dtor;
|
||||
std::shared_ptr<TaskQueue> _taskQueue;
|
||||
std::shared_ptr<Runnable> _runnableContinue;
|
||||
};
|
||||
}}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
#include "TempBuffer.h"
|
||||
|
||||
using namespace SoraDbgPlot::Buffer;
|
||||
|
||||
static const int DEFAULT_KEPT_SIZE = 4*1024;
|
||||
|
||||
TempBuffer::TempBuffer()
|
||||
{
|
||||
_buf = 0;
|
||||
_size = 0;
|
||||
_sizeKept = DEFAULT_KEPT_SIZE;
|
||||
}
|
||||
|
||||
TempBuffer::~TempBuffer()
|
||||
{
|
||||
if (_buf)
|
||||
delete [] _buf;
|
||||
}
|
||||
|
||||
void TempBuffer::ConfigKeptSize(int sizeKept)
|
||||
{
|
||||
_sizeKept = sizeKept;
|
||||
}
|
||||
|
||||
char * TempBuffer::UseBuf(int size)
|
||||
{
|
||||
if (size <= _size)
|
||||
{
|
||||
return _buf;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_size > 0)
|
||||
{
|
||||
delete [] _buf;
|
||||
_size = 0;
|
||||
}
|
||||
_buf = new char[size];
|
||||
_size = size;
|
||||
}
|
||||
|
||||
return _buf;
|
||||
}
|
||||
|
||||
void TempBuffer::ReturnBuf()
|
||||
{
|
||||
if (_size > _sizeKept)
|
||||
{
|
||||
delete [] _buf;
|
||||
_size = 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
namespace SoraDbgPlot { namespace Buffer {
|
||||
|
||||
class TempBuffer
|
||||
{
|
||||
public:
|
||||
TempBuffer();
|
||||
~TempBuffer();
|
||||
void ConfigKeptSize(int sizeKept);
|
||||
char * UseBuf(int size);
|
||||
void ReturnBuf();
|
||||
private:
|
||||
char * _buf;
|
||||
int _size;
|
||||
int _sizeKept;
|
||||
};
|
||||
|
||||
}}
|
|
@ -0,0 +1,165 @@
|
|||
#include "TimeStampQueue.h"
|
||||
|
||||
TimeStampQueue::TimeStampQueue(size_t boundaryValue) {
|
||||
_recordBoundary = boundaryValue;
|
||||
}
|
||||
|
||||
bool TimeStampQueue::Search(size_t index, unsigned long long & timestamp)
|
||||
{
|
||||
size_t resIndex;
|
||||
bool found = Search(index, resIndex);
|
||||
if (found)
|
||||
{
|
||||
timestamp = _records[resIndex]._timestamp;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool TimeStampQueue::SearchNearestTimeStamp(unsigned long long in, unsigned long long & out, size_t & outIdx)
|
||||
{
|
||||
if (_records.size() == 0)
|
||||
return false;
|
||||
|
||||
DataRecord baseRecord = _records[0];
|
||||
|
||||
// binary search
|
||||
size_t begin = 0;
|
||||
size_t end = _records.size();
|
||||
size_t middle;
|
||||
|
||||
while(end - begin > 1)
|
||||
{
|
||||
middle = (end + begin) / 2;
|
||||
DataRecord record = _records[middle];
|
||||
if (record._timestamp == in)
|
||||
{
|
||||
out = in;
|
||||
outIdx = _records.size() - 1 - middle;
|
||||
return true;
|
||||
}
|
||||
else if (record._timestamp < in)
|
||||
{
|
||||
begin = middle;
|
||||
}
|
||||
else
|
||||
{
|
||||
end = middle;
|
||||
}
|
||||
}
|
||||
|
||||
middle = begin;
|
||||
DataRecord record = _records[middle];
|
||||
out = in;
|
||||
outIdx = _records.size() - 1 - middle;
|
||||
if (record._timestamp < in)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void TimeStampQueue::AddRecord(const DataRecord & record)
|
||||
{
|
||||
size_t resIndex;
|
||||
bool found = Search( record._start + record._size - 1, resIndex);
|
||||
if (found)
|
||||
{
|
||||
size_t newStart = record._start + record._size;
|
||||
auto iter = _records.begin() + resIndex;
|
||||
|
||||
size_t dist = newStart - iter->_start;
|
||||
if (dist < 0)
|
||||
dist += _recordBoundary;
|
||||
else if (dist > _recordBoundary)
|
||||
dist -= _recordBoundary;
|
||||
|
||||
if (dist < iter->_size) // modify the record
|
||||
{
|
||||
iter->_start = newStart % _recordBoundary;
|
||||
iter->_size -= dist;
|
||||
_records.erase(_records.begin(), _records.begin() + resIndex);
|
||||
}
|
||||
else // discard the record
|
||||
{
|
||||
_records.erase(_records.begin(), _records.begin() + resIndex + 1);
|
||||
}
|
||||
}
|
||||
_records.push_back(record);
|
||||
}
|
||||
|
||||
void TimeStampQueue::Reset()
|
||||
{
|
||||
_records.clear();
|
||||
}
|
||||
|
||||
bool TimeStampQueue::GetDataRecord(size_t idx, DataRecord & record)
|
||||
{
|
||||
size_t size = Size();
|
||||
|
||||
if (idx >= size)
|
||||
return false;
|
||||
|
||||
record = _records[size - idx - 1];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t TimeStampQueue::Size()
|
||||
{
|
||||
return _records.size();
|
||||
}
|
||||
|
||||
bool TimeStampQueue::Search(size_t index, size_t & outIndex)
|
||||
{
|
||||
if (_records.size() == 0)
|
||||
return false;
|
||||
|
||||
DataRecord baseRecord = _records[0];
|
||||
|
||||
// binary search
|
||||
size_t begin = 0;
|
||||
size_t end = _records.size();
|
||||
if (index < baseRecord._start)
|
||||
index += _recordBoundary;
|
||||
if (index > baseRecord._start + _recordBoundary)
|
||||
index -= _recordBoundary;
|
||||
|
||||
while(end - begin > 1)
|
||||
{
|
||||
size_t middle = (begin + end) / 2;
|
||||
DataRecord record = _records[middle];
|
||||
if (record._start < baseRecord._start)
|
||||
record._start += _recordBoundary;
|
||||
|
||||
if (index < record._start)
|
||||
{
|
||||
end = middle;
|
||||
}
|
||||
else if (index >= record._start + record._size)
|
||||
{
|
||||
begin = middle;
|
||||
}
|
||||
else // find it
|
||||
{
|
||||
outIndex = middle;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
DataRecord beginRecord = _records[begin];
|
||||
|
||||
if (beginRecord._start <= index &&
|
||||
beginRecord._start + beginRecord._size > index)
|
||||
{
|
||||
outIndex = begin;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
#pragma once
|
||||
|
||||
#include <deque>
|
||||
#include <algorithm>
|
||||
|
||||
struct DataRecord
|
||||
{
|
||||
size_t _start;
|
||||
size_t _size;
|
||||
unsigned long long _timestamp;
|
||||
};
|
||||
|
||||
class TimeStampQueue
|
||||
{
|
||||
public:
|
||||
TimeStampQueue(size_t boundaryValue);
|
||||
|
||||
bool Search(size_t index, unsigned long long & timestamp);
|
||||
|
||||
bool SearchNearestTimeStamp(unsigned long long in, unsigned long long & out, size_t & outIdx);
|
||||
|
||||
void AddRecord(const DataRecord & record);
|
||||
|
||||
void Reset();
|
||||
|
||||
size_t Size();
|
||||
|
||||
bool GetDataRecord(size_t idx, DataRecord & record);
|
||||
|
||||
private:
|
||||
std::deque<DataRecord> _records;
|
||||
size_t _recordBoundary;
|
||||
|
||||
bool Search(size_t index, size_t & outIndex);
|
||||
};
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <Windows.h>
|
||||
|
||||
namespace SoraDbgPlot { namespace Task {
|
||||
|
||||
class WaitableLatestTaskQueue
|
||||
{
|
||||
typedef std::function<void(void)> TaskType;
|
||||
|
||||
public:
|
||||
WaitableLatestTaskQueue() {
|
||||
::InitializeCriticalSection(&_cs);
|
||||
_eventTaskComplete = ::CreateEvent(NULL, FALSE, TRUE, NULL);
|
||||
_bTaskRunning = false;
|
||||
_bTaskInQueue = false;
|
||||
}
|
||||
|
||||
~WaitableLatestTaskQueue()
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
bool bBreak = false;
|
||||
::WaitForSingleObject(_eventTaskComplete, INFINITE);
|
||||
|
||||
::EnterCriticalSection(&_cs);
|
||||
if (_bTaskRunning == false && _bTaskInQueue == false)
|
||||
{
|
||||
bBreak = true;
|
||||
}
|
||||
::LeaveCriticalSection(&_cs);
|
||||
|
||||
if (bBreak) break;
|
||||
}
|
||||
::CloseHandle(_eventTaskComplete);
|
||||
::DeleteCriticalSection(&_cs);
|
||||
}
|
||||
|
||||
void QueueTask(const TaskType & task)
|
||||
{
|
||||
bool bExecute = false;
|
||||
|
||||
::EnterCriticalSection(&_cs);
|
||||
if (!_bTaskRunning)
|
||||
{
|
||||
_bTaskRunning = true;
|
||||
_taskRunning = task;
|
||||
bExecute = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_bTaskInQueue = true;
|
||||
_taskInQueue = task;
|
||||
}
|
||||
|
||||
::LeaveCriticalSection(&_cs);
|
||||
|
||||
if (bExecute)
|
||||
ExecuteTask();
|
||||
}
|
||||
|
||||
private:
|
||||
void ExecuteTask()
|
||||
{
|
||||
QueueUserWorkItem(ThreadExecuteTask, this, WT_EXECUTEDEFAULT);
|
||||
}
|
||||
|
||||
static DWORD WINAPI ThreadExecuteTask(__in LPVOID lpParameter)
|
||||
{
|
||||
auto queue = (WaitableLatestTaskQueue *)lpParameter;
|
||||
queue->_taskRunning();
|
||||
|
||||
bool bExecute = false;
|
||||
|
||||
::EnterCriticalSection(&queue->_cs);
|
||||
if (queue->_bTaskInQueue)
|
||||
{
|
||||
bExecute = true;
|
||||
queue->_taskRunning = queue->_taskInQueue;
|
||||
queue->_bTaskInQueue = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
queue->_bTaskRunning = false;
|
||||
}
|
||||
|
||||
::LeaveCriticalSection(&queue->_cs);
|
||||
|
||||
if (bExecute)
|
||||
queue->ExecuteTask();
|
||||
|
||||
::SetEvent(queue->_eventTaskComplete);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
volatile bool _bTaskInQueue;
|
||||
volatile bool _bTaskRunning;
|
||||
TaskType _taskInQueue;
|
||||
TaskType _taskRunning;
|
||||
|
||||
CRITICAL_SECTION _cs;
|
||||
|
||||
HANDLE _eventTaskComplete;
|
||||
};
|
||||
}}
|
|
@ -0,0 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
namespace SoraDbgPlot
|
||||
{
|
||||
class Writable
|
||||
{
|
||||
public:
|
||||
virtual void Write(const void * ptr, size_t size, size_t & sizeWritten) = 0;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#define SP(a) std::shared_ptr<a>
|
||||
#define MSP(a) std::make_shared<a>
|
|
@ -0,0 +1,42 @@
|
|||
#include "stdafx.h"
|
||||
#include "AsyncObject.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
AsyncObject::AsyncObject()
|
||||
{
|
||||
_taskQueue = make_shared<SoraDbgPlot::Task::TaskQueue>();
|
||||
}
|
||||
|
||||
AsyncObject::~AsyncObject()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void AsyncObject::DoLater(const std::function<void(void)> & f)
|
||||
{
|
||||
_taskQueue->QueueTask([f](){
|
||||
f();
|
||||
});
|
||||
}
|
||||
|
||||
void AsyncObject::DoLater(const std::function<void(void)> & f, const std::function<void(void)> & dtor)
|
||||
{
|
||||
_taskQueue->QueueTask([f](){
|
||||
f();
|
||||
}, [dtor](){
|
||||
dtor();
|
||||
});
|
||||
}
|
||||
|
||||
void AsyncObject::DoNow(const std::function<void(void)> & f)
|
||||
{
|
||||
_taskQueue->DoTask([f](){
|
||||
f();
|
||||
});
|
||||
}
|
||||
|
||||
std::shared_ptr<SoraDbgPlot::Task::TaskQueue> AsyncObject::TaskQueue()
|
||||
{
|
||||
return _taskQueue;
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include "TaskQueue.h"
|
||||
|
||||
class AsyncObject : public std::enable_shared_from_this<AsyncObject>
|
||||
{
|
||||
public:
|
||||
AsyncObject();
|
||||
virtual ~AsyncObject();
|
||||
void DoLater(const std::function<void(void)> & f);
|
||||
void DoLater(const std::function<void(void)> & f, const std::function<void(void)> & dtor);
|
||||
void DoNow(const std::function<void(void)> & f);
|
||||
std::shared_ptr<SoraDbgPlot::Task::TaskQueue> TaskQueue();
|
||||
|
||||
private:
|
||||
std::shared_ptr<SoraDbgPlot::Task::TaskQueue> _taskQueue;
|
||||
};
|
|
@ -0,0 +1,93 @@
|
|||
// AutoLayoutSlider.cpp : implementation file
|
||||
//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "DbgPlotViewer.h"
|
||||
#include "AutoLayoutSlider.h"
|
||||
|
||||
|
||||
// AutoLayoutSlider
|
||||
|
||||
IMPLEMENT_DYNAMIC(AutoLayoutSlider, CWnd)
|
||||
|
||||
AutoLayoutSlider::AutoLayoutSlider()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
AutoLayoutSlider::~AutoLayoutSlider()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
BEGIN_MESSAGE_MAP(AutoLayoutSlider, CWnd)
|
||||
ON_WM_CREATE()
|
||||
ON_WM_SIZE()
|
||||
ON_WM_HSCROLL()
|
||||
END_MESSAGE_MAP()
|
||||
|
||||
|
||||
|
||||
// AutoLayoutSlider message handlers
|
||||
|
||||
|
||||
|
||||
|
||||
int AutoLayoutSlider::OnCreate(LPCREATESTRUCT lpCreateStruct)
|
||||
{
|
||||
if (CWnd::OnCreate(lpCreateStruct) == -1)
|
||||
return -1;
|
||||
|
||||
// TODO: Add your specialized creation code here
|
||||
CRect rectDummy;
|
||||
rectDummy.SetRectEmpty();
|
||||
this->_sliderCtrl.Create(WS_CHILD | WS_VISIBLE, rectDummy, this, 1);
|
||||
this->_sliderCtrl.SetRange(0, 80, 1); // hard code!!!
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void AutoLayoutSlider::OnSize(UINT nType, int cx, int cy)
|
||||
{
|
||||
CWnd::OnSize(nType, cx, cy);
|
||||
|
||||
// TODO: Add your message handler code here
|
||||
_sliderCtrl.MoveWindow(0, 0, cx, cy, 1);
|
||||
}
|
||||
|
||||
|
||||
void AutoLayoutSlider::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
|
||||
{
|
||||
// TODO: Add your message handler code here and/or call default
|
||||
|
||||
switch (nSBCode)
|
||||
{
|
||||
case SB_THUMBPOSITION:
|
||||
case SB_THUMBTRACK:
|
||||
{
|
||||
int pos = nPos*5 + 100; // hard code!!!
|
||||
EventAutoScale.Raise(this, pos);
|
||||
}
|
||||
break;
|
||||
case SB_ENDSCROLL:
|
||||
{
|
||||
int pos = this->_sliderCtrl.GetPos()*5 + 100; // hard code!!!
|
||||
EventAutoScale.Raise(this, pos);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
CWnd::OnHScroll(nSBCode, nPos, pScrollBar);
|
||||
}
|
||||
|
||||
|
||||
void AutoLayoutSlider::PostNcDestroy()
|
||||
{
|
||||
// TODO: Add your specialized code here and/or call the base class
|
||||
|
||||
EventAutoScale.Reset();
|
||||
|
||||
CWnd::PostNcDestroy();
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
#pragma once
|
||||
|
||||
|
||||
// AutoLayoutSlider
|
||||
|
||||
class AutoLayoutSlider : public CWnd
|
||||
{
|
||||
DECLARE_DYNAMIC(AutoLayoutSlider)
|
||||
|
||||
public:
|
||||
AutoLayoutSlider();
|
||||
virtual ~AutoLayoutSlider();
|
||||
|
||||
SoraDbgPlot::Event::Event<int> EventAutoScale;
|
||||
|
||||
private:
|
||||
CSliderCtrl _sliderCtrl;
|
||||
|
||||
protected:
|
||||
DECLARE_MESSAGE_MAP()
|
||||
public:
|
||||
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
|
||||
afx_msg void OnSize(UINT nType, int cx, int cy);
|
||||
afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
|
||||
virtual void PostNcDestroy();
|
||||
};
|
||||
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
// BaseProperty.cpp : implementation file
|
||||
//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "BaseProperty.h"
|
||||
|
||||
// BaseProperty
|
||||
|
||||
IMPLEMENT_DYNAMIC(BaseProperty, CMFCPropertyGridCtrl)
|
||||
|
||||
BaseProperty::BaseProperty()
|
||||
{
|
||||
}
|
||||
|
||||
BaseProperty::~BaseProperty()
|
||||
{
|
||||
_pvTaskQueue.Execute(true);
|
||||
}
|
||||
|
||||
|
||||
void BaseProperty::CloseProperty()
|
||||
{
|
||||
this->OnCloseProperty();
|
||||
}
|
||||
|
||||
BEGIN_MESSAGE_MAP(BaseProperty, CMFCPropertyGridCtrl)
|
||||
ON_WM_CREATE()
|
||||
ON_MESSAGE(WMME_EXE_TASKQUEUE, OnExeTaskQueue)
|
||||
END_MESSAGE_MAP()
|
||||
|
||||
|
||||
|
||||
// BaseProperty message handlers
|
||||
|
||||
|
||||
|
||||
|
||||
int BaseProperty::OnCreate(LPCREATESTRUCT lpCreateStruct)
|
||||
{
|
||||
if (CMFCPropertyGridCtrl::OnCreate(lpCreateStruct) == -1)
|
||||
return -1;
|
||||
|
||||
// TODO: Add your specialized creation code here
|
||||
this->EnableHeaderCtrl(FALSE);
|
||||
this->EnableDescriptionArea();
|
||||
this->SetVSDotNetLook();
|
||||
this->MarkModifiedProperties();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
CMFCPropertyGridProperty * BaseProperty::FindProperty(const wchar_t * name) const
|
||||
{
|
||||
CMFCPropertyGridProperty * property = NULL;
|
||||
for (int i = 0; i < this->GetPropertyCount(); i++)
|
||||
{
|
||||
CMFCPropertyGridProperty * aProperty = this->GetProperty(i);
|
||||
if (wcscmp(aProperty->GetName(), name) == 0)
|
||||
{
|
||||
property = aProperty;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return property;
|
||||
}
|
||||
|
||||
|
||||
void BaseProperty::PostNcDestroy()
|
||||
{
|
||||
// TODO: Add your specialized code here and/or call the base class
|
||||
|
||||
this->OnCloseProperty();
|
||||
EventClosed.Raise(this, true);
|
||||
|
||||
CMFCPropertyGridCtrl::PostNcDestroy();
|
||||
}
|
||||
|
||||
LRESULT BaseProperty::OnExeTaskQueue(WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
_pvTaskQueue.Execute(false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void BaseProperty::DoLater(std::function<void(bool)> f)
|
||||
{
|
||||
_pvTaskQueue.Queue(f);
|
||||
HWND hWnd = m_hWnd;
|
||||
if (hWnd)
|
||||
::PostMessage(hWnd, WMME_EXE_TASKQUEUE, 0, 0);
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include "Event.h"
|
||||
#include "CSRecursiveLock.h"
|
||||
#include "PassiveTaskQueue.h"
|
||||
|
||||
// BaseProperty
|
||||
#define WMME_EXE_TASKQUEUE (WM_APP+1)
|
||||
|
||||
class BaseProperty : public CMFCPropertyGridCtrl
|
||||
{
|
||||
DECLARE_DYNAMIC(BaseProperty)
|
||||
|
||||
public:
|
||||
BaseProperty();
|
||||
virtual ~BaseProperty();
|
||||
void CloseProperty();
|
||||
SoraDbgPlot::Event::Event<bool> EventClosed;
|
||||
void DoLater(std::function<void(bool)>);
|
||||
|
||||
protected:
|
||||
virtual void OnCloseProperty() = 0;
|
||||
|
||||
private:
|
||||
PassiveTaskQueue _pvTaskQueue;
|
||||
|
||||
protected:
|
||||
DECLARE_MESSAGE_MAP()
|
||||
public:
|
||||
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
|
||||
afx_msg LRESULT OnExeTaskQueue(WPARAM, LPARAM);
|
||||
|
||||
protected:
|
||||
CMFCPropertyGridProperty * FindProperty(const wchar_t * name) const;
|
||||
virtual void PostNcDestroy();
|
||||
};
|
|
@ -0,0 +1,219 @@
|
|||
#include "stdafx.h"
|
||||
#include "BitmapPlotWnd.h"
|
||||
|
||||
BEGIN_MESSAGE_MAP(BitmapPlotWnd, CPlotWnd)
|
||||
ON_WM_CREATE()
|
||||
ON_WM_SIZE()
|
||||
END_MESSAGE_MAP()
|
||||
|
||||
|
||||
BitmapPlotWnd::BitmapPlotWnd(void * userData) :
|
||||
CPlotWnd(userData)
|
||||
{
|
||||
_userData = userData;
|
||||
}
|
||||
|
||||
int BitmapPlotWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
|
||||
{
|
||||
if ( CPlotWnd::OnCreate(lpCreateStruct) == -1 )
|
||||
return -1;
|
||||
CRect rectDummy;
|
||||
rectDummy.SetRectEmpty();
|
||||
|
||||
_canvasWnd = new CWnd();
|
||||
_canvasWnd->Create(NULL, L"control", WS_CHILD | WS_VISIBLE, rectDummy, this, 0);
|
||||
|
||||
_controlWnd = new PlayControlWnd;
|
||||
_controlWnd->EventPlayClicked.Subscribe([this](const void * sender, const PlayControlWnd::PlayPauseEvent e){
|
||||
PlayPauseEvent ee;
|
||||
ee.IsPlay = e.IsPlay;
|
||||
this->EventPlayClicked.Raise(this, ee);
|
||||
});
|
||||
|
||||
_controlWnd->EventSpeedClicked.Subscribe([this](const void * sender, const PlayControlWnd::SpeedChangeEvent e){
|
||||
SpeedChangeEvent ee;
|
||||
ee.IsUp = e.IsUp;
|
||||
this->EventSpeedClicked.Raise(this, ee);
|
||||
});
|
||||
|
||||
_controlWnd->EventTrackBarSeeked.Subscribe([this](const void * sender, const PlayControlWnd::TrackBarSeekEvent & e) {
|
||||
SeekEvent ee;
|
||||
ee.Pos = e.Pos;
|
||||
this->EventSeek.Raise(this, ee);
|
||||
});
|
||||
|
||||
_controlWnd->Create(NULL, L"control", WS_CHILD | WS_VISIBLE, rectDummy, _canvasWnd, 0);
|
||||
|
||||
_subBitmapWnd = new SubBitmapPlotWnd(_userData);
|
||||
|
||||
_subBitmapWnd->EventWheel.Subscribe([this](const void * sender, const SubBitmapPlotWnd::WheelEvent & e) {
|
||||
WheelEvent ee;
|
||||
ee.IsUp = e.IsUp;
|
||||
this->EventWheel.Raise(this, ee);
|
||||
});
|
||||
|
||||
_subBitmapWnd->EventClicked.Subscribe([this](const void * sender, const SubBitmapPlotWnd::ClickEvent & e) {
|
||||
this->BringWindowToTop();
|
||||
CPlotWnd::BringToFrontEvent ee;
|
||||
this->EventBringToFront.Raise(this, ee);
|
||||
});
|
||||
|
||||
_subBitmapWnd->Create(NULL, L"bitmap", WS_CHILD | WS_VISIBLE, rectDummy, _canvasWnd, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void BitmapPlotWnd::OnSize(UINT nType, int cx, int cy)
|
||||
{
|
||||
const int CTRL_WND_HEIGHT = 17;
|
||||
CRect clientRect;
|
||||
this->CalcClientRect(&clientRect);
|
||||
|
||||
CRect canvasRect = clientRect;
|
||||
|
||||
_canvasWnd->MoveWindow(&canvasRect);
|
||||
|
||||
CRect controlRect;
|
||||
controlRect.SetRectEmpty();
|
||||
controlRect.right += clientRect.Width();
|
||||
controlRect.bottom += clientRect.Height();
|
||||
controlRect.top = controlRect.bottom - CTRL_WND_HEIGHT;
|
||||
|
||||
_controlWnd->MoveWindow(&controlRect, 1);
|
||||
|
||||
if (true)
|
||||
{
|
||||
CRect graphRect;
|
||||
graphRect.SetRectEmpty();
|
||||
graphRect.right += clientRect.Width();
|
||||
graphRect.bottom = controlRect.top;
|
||||
_subBitmapWnd->MoveWindow(&graphRect, 1);
|
||||
ResizeEvent e;
|
||||
e.cx = graphRect.Width();
|
||||
e.cy = graphRect.Height();
|
||||
this->EventBitmapResize.Raise(this, e);
|
||||
}
|
||||
|
||||
CPlotWnd::OnSize(nType, cx, cy);
|
||||
}
|
||||
|
||||
void BitmapPlotWnd::SetButtonStatePlay()
|
||||
{
|
||||
this->Invoke([this](bool close){
|
||||
if (close)
|
||||
return;
|
||||
|
||||
if (_controlWnd->m_hWnd)
|
||||
_controlWnd->SetButtonStatePlay();
|
||||
});
|
||||
}
|
||||
|
||||
void BitmapPlotWnd::SetButtonStatePause()
|
||||
{
|
||||
this->Invoke([this](bool close){
|
||||
if (close)
|
||||
return;
|
||||
|
||||
if (_controlWnd->m_hWnd)
|
||||
_controlWnd->SetButtonStatePause();
|
||||
});
|
||||
}
|
||||
|
||||
void BitmapPlotWnd::SetTrackBarViewWndRange(double right, double range)
|
||||
{
|
||||
this->Invoke([this, right, range](bool close){
|
||||
if (close)
|
||||
return;
|
||||
|
||||
if (_controlWnd->m_hWnd)
|
||||
_controlWnd->SetTrackBarWndPos(right, range);
|
||||
});
|
||||
}
|
||||
|
||||
void BitmapPlotWnd::SetBitmap(Bitmap * bitmap)
|
||||
{
|
||||
this->Invoke([this, bitmap](bool close){
|
||||
if (close)
|
||||
{
|
||||
delete bitmap;
|
||||
return;
|
||||
}
|
||||
|
||||
if (_subBitmapWnd->m_hWnd)
|
||||
this->_subBitmapWnd->SetBitmap(bitmap);
|
||||
else
|
||||
delete bitmap;
|
||||
});
|
||||
}
|
||||
|
||||
BitmapPlotWnd::~BitmapPlotWnd()
|
||||
{
|
||||
if (_controlWnd)
|
||||
{
|
||||
delete _controlWnd;
|
||||
_controlWnd = 0;
|
||||
}
|
||||
if (_subBitmapWnd)
|
||||
{
|
||||
delete _subBitmapWnd;
|
||||
_subBitmapWnd = 0;
|
||||
}
|
||||
if (_canvasWnd)
|
||||
{
|
||||
delete _canvasWnd;
|
||||
_canvasWnd = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void BitmapPlotWnd::AddSubPlotWnd(SubPlotWnd * subWnd, const CRect & rect)
|
||||
{
|
||||
this->Invoke([this, subWnd, rect](bool close){
|
||||
if (close)
|
||||
return;
|
||||
|
||||
if (m_hWnd == 0 || _subBitmapWnd->m_hWnd == 0)
|
||||
return;
|
||||
|
||||
CRect rect2 = rect;
|
||||
this->_subBitmapWnd->ScreenToClient(rect2);
|
||||
subWnd->CreateEx(0, NULL, L"", WS_CHILD | WS_VISIBLE, rect2, this->_subBitmapWnd, 0, 0);
|
||||
});
|
||||
}
|
||||
|
||||
void BitmapPlotWnd::AddSubPlotWndRelative(SubPlotWnd * subWnd, const CRect & rect)
|
||||
{
|
||||
this->Invoke([this, subWnd, rect](bool close){
|
||||
if (close)
|
||||
return;
|
||||
|
||||
if (m_hWnd == 0 || _subBitmapWnd->m_hWnd == 0)
|
||||
return;
|
||||
|
||||
CRect rect2 = rect;
|
||||
subWnd->CreateEx(0, NULL, L"", WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS, rect2, this->_subBitmapWnd, 0, 0);
|
||||
});
|
||||
}
|
||||
|
||||
void * BitmapPlotWnd::UserData()
|
||||
{
|
||||
return _userData;
|
||||
}
|
||||
|
||||
void BitmapPlotWnd::MyScreenToClient(CRect & rect)
|
||||
{
|
||||
this->_subBitmapWnd->ScreenToClient(&rect);
|
||||
}
|
||||
|
||||
void BitmapPlotWnd::MyScreenToClient(CPoint & point)
|
||||
{
|
||||
this->_subBitmapWnd->ScreenToClient(&point);
|
||||
}
|
||||
|
||||
void BitmapPlotWnd::EnableSpeedButtons(bool bEnable)
|
||||
{
|
||||
this->Invoke([this, bEnable](bool close){
|
||||
if (close) return;
|
||||
|
||||
this->_controlWnd->EnableSpeedButtons(bEnable);
|
||||
});
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
#pragma once
|
||||
|
||||
#include "PlotWnd.h"
|
||||
#include "PlayControlWnd.h"
|
||||
#include "SubBitmapPlotWnd.h"
|
||||
#include "Targetable.h"
|
||||
|
||||
class BitmapPlotWnd : public CPlotWnd
|
||||
{
|
||||
public:
|
||||
BitmapPlotWnd(void * userData);
|
||||
~BitmapPlotWnd();
|
||||
|
||||
public:
|
||||
PlayControlWnd * _controlWnd;
|
||||
SubBitmapPlotWnd * _subBitmapWnd;
|
||||
CWnd * _canvasWnd;
|
||||
|
||||
struct PlayPauseEvent { bool IsPlay; };
|
||||
struct SpeedChangeEvent { bool IsUp; };
|
||||
struct SeekEvent { double Pos; };
|
||||
struct WheelEvent { bool IsUp; };
|
||||
struct ResizeEvent { int x; int y; int cx; int cy; };
|
||||
|
||||
SoraDbgPlot::Event::Event<PlayPauseEvent> EventPlayClicked;
|
||||
SoraDbgPlot::Event::Event<SpeedChangeEvent> EventSpeedClicked;
|
||||
SoraDbgPlot::Event::Event<SeekEvent> EventSeek;
|
||||
SoraDbgPlot::Event::Event<WheelEvent> EventWheel;
|
||||
SoraDbgPlot::Event::Event<ResizeEvent> EventBitmapResize;
|
||||
|
||||
void SetBitmap(Bitmap * bitmap);
|
||||
void SetButtonStatePlay();
|
||||
void SetButtonStatePause();
|
||||
void SetTrackBarViewWndRange(double right, double range);
|
||||
void MyScreenToClient(CRect &);
|
||||
void MyScreenToClient(CPoint &);
|
||||
void EnableSpeedButtons(bool bEnable);
|
||||
|
||||
protected:
|
||||
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
|
||||
afx_msg void OnSize(UINT nType, int cx, int cy);
|
||||
DECLARE_MESSAGE_MAP()
|
||||
|
||||
public:
|
||||
void AddSubPlotWnd(SubPlotWnd * subWnd, const CRect & rect);
|
||||
void AddSubPlotWndRelative(SubPlotWnd * subWnd, const CRect & rect);
|
||||
|
||||
public:
|
||||
void * UserData();
|
||||
private:
|
||||
void * _userData;
|
||||
};
|
|
@ -0,0 +1,24 @@
|
|||
#include "stdafx.h"
|
||||
#include <math.h>
|
||||
#include "BitmapTypeSettings.h"
|
||||
|
||||
double SettingGetBitmapRangeMax(bool isLog)
|
||||
{
|
||||
double maxNormal = (double)INT_MAX * 10.0;
|
||||
return isLog ? log10(maxNormal) : maxNormal;
|
||||
}
|
||||
|
||||
double SettingGetBitmapRangeMin(bool isLog)
|
||||
{
|
||||
double maxNormal = (double)INT_MAX * 10.0;
|
||||
double minNormal = (double)INT_MIN * 10.0;
|
||||
return isLog ? -log10(maxNormal) : minNormal;
|
||||
}
|
||||
|
||||
double SettingGetBitmapRangeHalfDelta(bool isLog)
|
||||
{
|
||||
if (isLog)
|
||||
return 0.001;
|
||||
else
|
||||
return 1.0;
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
double SettingGetBitmapRangeMax(bool isLog);
|
||||
double SettingGetBitmapRangeMin(bool isLog);
|
||||
double SettingGetBitmapRangeHalfDelta(bool isLog);
|
|
@ -0,0 +1,7 @@
|
|||
#include "stdafx.h"
|
||||
#include "ChannelAddable.h"
|
||||
|
||||
void ChannelAddable::Clear()
|
||||
{
|
||||
PropObject::Clear();
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include "ProcessOpened.h"
|
||||
#include "ChannelOpened.h"
|
||||
|
||||
class ChannelAddable : public PropObject
|
||||
{
|
||||
public:
|
||||
virtual void Highlight(bool bHighlight) = 0;
|
||||
virtual bool Accept(std::shared_ptr<ChannelOpened>, CPoint pointIn, CPoint & pointOut) = 0;
|
||||
virtual void RequestAddChannel(std::shared_ptr<ProcessOpened>, std::shared_ptr<ChannelOpened>, CPoint pointIn) = 0;
|
||||
void Clear();
|
||||
};
|
|
@ -0,0 +1,297 @@
|
|||
#include "stdafx.h"
|
||||
#include <memory>
|
||||
#include "ChannelOpened.h"
|
||||
#include "SharedChannel.h"
|
||||
#include "ChannelProperty.h"
|
||||
#include "HelperFunc.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace SoraDbgPlot::Task;
|
||||
using namespace SoraDbgPlot::SharedObj;
|
||||
|
||||
ChannelOpened::ChannelOpened() :
|
||||
_color(RGB(200, 200, 200))
|
||||
{
|
||||
_spectrumSize = 1;
|
||||
_openCount = 0;
|
||||
_bAttatched = false;
|
||||
}
|
||||
|
||||
ChannelOpened::~ChannelOpened()
|
||||
{
|
||||
_sharedChannel.reset();
|
||||
}
|
||||
|
||||
void ChannelOpened::AttatchSharedChannelSync(shared_ptr<SoraDbgPlot::SharedObj::SharedChannel> sch)
|
||||
{
|
||||
auto shared_me = dynamic_pointer_cast<ChannelOpened, AsyncObject>(shared_from_this());
|
||||
TaskQueue()->DoTask([shared_me, sch](){
|
||||
if (sch)
|
||||
{
|
||||
if (shared_me->_sharedChannel)
|
||||
{
|
||||
shared_me->_sharedChannel->StrategyNewData.UnSet();
|
||||
shared_me->_sharedChannel.reset();
|
||||
}
|
||||
|
||||
shared_me->_sharedChannel = sch;
|
||||
|
||||
shared_me->_id = sch->Id();
|
||||
shared_me->_pid = sch->Pid();
|
||||
shared_me->_spectrumSize = sch->SpectrumDataSize();
|
||||
shared_me->_type = sch->Type();
|
||||
shared_me->_name = sch->Name();
|
||||
|
||||
shared_me->_bAttatched = true;
|
||||
|
||||
shared_me->ClearData();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void ChannelOpened::DeattatchSharedChannelSync()
|
||||
{
|
||||
auto SThis = dynamic_pointer_cast<ChannelOpened, AsyncObject>(shared_from_this());
|
||||
TaskQueue()->DoTask([SThis](){
|
||||
SThis->_sharedChannel.reset();
|
||||
SThis->_pid = -1;
|
||||
SThis->_bAttatched = false;
|
||||
});
|
||||
}
|
||||
|
||||
bool ChannelOpened::IsAttatched()
|
||||
{
|
||||
return _bAttatched;
|
||||
}
|
||||
|
||||
int ChannelOpened::Id()
|
||||
{
|
||||
int ret;
|
||||
auto shared_me = dynamic_pointer_cast<ChannelOpened, AsyncObject>(shared_from_this());
|
||||
TaskQueue()->DoTask([this, &ret](){
|
||||
ret = _id;
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ChannelOpened::Pid()
|
||||
{
|
||||
int ret;
|
||||
TaskQueue()->DoTask([this, &ret](){
|
||||
ret = _pid;
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ChannelOpened::SpectrumDataSize()
|
||||
{
|
||||
int ret;
|
||||
TaskQueue()->DoTask([this, &ret](){
|
||||
ret = _spectrumSize;
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
|
||||
wstring ChannelOpened::Name()
|
||||
{
|
||||
wstring ret;
|
||||
TaskQueue()->DoTask([this, &ret](){
|
||||
ret = _name;
|
||||
});
|
||||
return std::move(ret);
|
||||
}
|
||||
|
||||
ChannelType ChannelOpened::Type()
|
||||
{
|
||||
ChannelType ret;
|
||||
TaskQueue()->DoTask([this, &ret](){
|
||||
ret = _type;
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ChannelOpened::SetColor(COLORREF color)
|
||||
{
|
||||
auto shared_me = dynamic_pointer_cast<ChannelOpened, AsyncObject>(shared_from_this());
|
||||
TaskQueue()->QueueTask([shared_me, color](){
|
||||
shared_me->_color = color;
|
||||
});
|
||||
}
|
||||
|
||||
COLORREF ChannelOpened::Color()
|
||||
{
|
||||
COLORREF color;
|
||||
auto shared_me = dynamic_pointer_cast<ChannelOpened, AsyncObject>(shared_from_this());
|
||||
TaskQueue()->DoTask([shared_me, &color](){
|
||||
color = shared_me->_color;
|
||||
});
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
void ChannelOpened::Release()
|
||||
{
|
||||
auto SThis = dynamic_pointer_cast<ChannelOpened, AsyncObject>(shared_from_this());
|
||||
TaskQueue()->DoTask([SThis](){
|
||||
SThis->TaskFunc_Release();
|
||||
});
|
||||
}
|
||||
|
||||
void ChannelOpened::TaskFunc_Release()
|
||||
{
|
||||
if (_sharedChannel)
|
||||
{
|
||||
_sharedChannel.reset();
|
||||
_pid = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<TaskSimple> ChannelOpened::TaskUpdateData(std::shared_ptr<bool> updated)
|
||||
{
|
||||
auto SThis = dynamic_pointer_cast<ChannelOpened, AsyncObject>(shared_from_this());
|
||||
|
||||
shared_ptr<TaskSimple> task;
|
||||
|
||||
task = make_shared<TaskSimple>(TaskQueue(), [SThis, updated](){
|
||||
|
||||
if (updated.get())
|
||||
*updated = false;
|
||||
|
||||
if (SThis->_sharedChannel)
|
||||
{
|
||||
auto dataList = SThis->_sharedChannel->CheckOut();
|
||||
while(dataList->size() > 0)
|
||||
{
|
||||
if (updated.get())
|
||||
*updated = true;
|
||||
|
||||
auto iter = dataList->front();
|
||||
SThis->WriteData(iter.ptr, iter.length);
|
||||
dataList->pop_front();
|
||||
}
|
||||
}
|
||||
//TRACE1("ChannelOpened::TaskUpdateData [%d]\n", SThis->Id());
|
||||
});
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
void ChannelOpened::WriteData(const char * data, size_t length)
|
||||
{
|
||||
// do nothint
|
||||
}
|
||||
|
||||
std::shared_ptr<BaseProperty> ChannelOpened::CreatePropertyPage()
|
||||
{
|
||||
shared_ptr<ChannelProperty> propertyPage;
|
||||
|
||||
auto SThis = dynamic_pointer_cast<ChannelOpened, AsyncObject>(shared_from_this());
|
||||
TaskQueue()->DoTask([SThis, &propertyPage](){
|
||||
|
||||
wstring typeName = SThis->GetTypeName();
|
||||
|
||||
propertyPage = make_shared<ChannelProperty>(typeName, SThis->_name, SThis->_color);
|
||||
auto SThis2 = SThis;
|
||||
propertyPage->EventColor.Subscribe([SThis2](const void * sender, const COLORREF & color){
|
||||
auto SThis3 = SThis2;
|
||||
auto color2 = color;
|
||||
SThis3->DoLater([SThis3, color2](){
|
||||
SThis3->_color = color2;
|
||||
SThis3->OnColorUpdated();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return propertyPage;
|
||||
}
|
||||
|
||||
void ChannelOpened::OnColorUpdated()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
void ChannelOpened::GetRect(CRect & rect)
|
||||
{
|
||||
rect.SetRectEmpty();
|
||||
}
|
||||
|
||||
HRESULT ChannelOpened::CreateXmlElement(IXMLDOMDocument *pDom, IXMLDOMElement *pParent)
|
||||
{
|
||||
IXMLDOMElement *pElement=NULL;
|
||||
CreateAndAddElementNode(pDom, L"Channel", L"\n\t\t", pParent, &pElement);
|
||||
|
||||
this->AppendXmlProperty(pDom, pElement);
|
||||
CreateAndAddTextNode(pDom, L"\n\t\t", pElement);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT ChannelOpened::AppendXmlProperty(IXMLDOMDocument *pDom, IXMLDOMElement *pParent)
|
||||
{
|
||||
auto SThis = dynamic_pointer_cast<ChannelOpened, AsyncObject>(shared_from_this());
|
||||
this->DoNow([SThis, pDom, pParent](){
|
||||
|
||||
IXMLDOMElement *pElement = NULL;
|
||||
|
||||
CreateAndAddElementNode(pDom, L"SName", L"\n\t\t\t", pParent, &pElement);
|
||||
pElement->put_text((_bstr_t)SThis->_name.c_str());
|
||||
|
||||
CreateAndAddElementNode(pDom, L"SType", L"\n\t\t\t", pParent, &pElement);
|
||||
pElement->put_text(_bstr_t(typeid(*SThis).name()));
|
||||
|
||||
CreateAndAddElementNode(pDom, L"color", L"\n\t\t\t", pParent, &pElement);
|
||||
pElement->put_text((_bstr_t)SThis->_color);
|
||||
});
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT ChannelOpened::LoadXmlElement(MSXML2::IXMLDOMNodePtr pElement)
|
||||
{
|
||||
CString cs;
|
||||
MSXML2::IXMLDOMNodePtr pNode;
|
||||
|
||||
pNode = pElement->selectSingleNode(L"SName");
|
||||
if (pNode == 0)
|
||||
{
|
||||
this->_name = L"invalid name";
|
||||
}
|
||||
else
|
||||
{
|
||||
cs.Format(_T("%S"),(LPCSTR)pNode->text);
|
||||
this->_name = cs;
|
||||
}
|
||||
|
||||
pNode = pElement->selectSingleNode(L"color");
|
||||
if (pNode != 0)
|
||||
{
|
||||
this->_color = (atol)((LPCSTR)pNode->text);
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
bool ChannelOpened::Export(const CString &, bool bAll)
|
||||
{
|
||||
//::AfxMessageBox(L"not implemented");
|
||||
return false;
|
||||
}
|
||||
|
||||
void ChannelOpened::Clear()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
void ChannelOpened::SetOpenState(bool bOpened)
|
||||
{
|
||||
if (bOpened)
|
||||
::InterlockedIncrement(&_openCount);
|
||||
else
|
||||
::InterlockedDecrement(&_openCount);
|
||||
}
|
||||
|
||||
bool ChannelOpened::GetOpenState()
|
||||
{
|
||||
return _openCount > 0;
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include "SharedChannel.h"
|
||||
#include "TaskSimple.h"
|
||||
#include "PropObject.h"
|
||||
#include "BaseProperty.h"
|
||||
|
||||
class ChannelOpened : public PropObject
|
||||
{
|
||||
public:
|
||||
ChannelOpened();
|
||||
~ChannelOpened();
|
||||
|
||||
void AttatchSharedChannelSync(std::shared_ptr<SoraDbgPlot::SharedObj::SharedChannel>);
|
||||
void DeattatchSharedChannelSync();
|
||||
int Id();
|
||||
int Pid();
|
||||
int SpectrumDataSize();
|
||||
std::wstring Name();
|
||||
ChannelType Type();
|
||||
COLORREF Color();
|
||||
void Release();
|
||||
bool IsAttatched();
|
||||
virtual void Clear();
|
||||
|
||||
virtual bool Export(const CString &, bool bAll);
|
||||
|
||||
virtual std::shared_ptr<SoraDbgPlot::Task::TaskSimple> TaskUpdateData(std::shared_ptr<bool>);
|
||||
virtual void WriteData(const char * data, size_t length);
|
||||
virtual void GetRect(CRect & rect);
|
||||
|
||||
void SetColor(COLORREF color);
|
||||
|
||||
void TaskFunc_Release();
|
||||
|
||||
virtual HRESULT CreateXmlElement(IXMLDOMDocument *pDom, IXMLDOMElement *pe);
|
||||
virtual HRESULT AppendXmlProperty(IXMLDOMDocument *pDom, IXMLDOMElement *pParent);
|
||||
virtual HRESULT LoadXmlElement(MSXML2::IXMLDOMNodePtr pElement);
|
||||
|
||||
void SetOpenState(bool bOpened);
|
||||
bool GetOpenState();
|
||||
|
||||
private:
|
||||
std::shared_ptr<SoraDbgPlot::SharedObj::SharedChannel> _sharedChannel;
|
||||
volatile long _openCount;
|
||||
bool _bAttatched;
|
||||
|
||||
protected:
|
||||
int _id;
|
||||
int _pid;
|
||||
ChannelType _type;
|
||||
std::wstring _name;
|
||||
|
||||
protected:
|
||||
COLORREF _color;
|
||||
int _spectrumSize;
|
||||
|
||||
protected:
|
||||
std::shared_ptr<BaseProperty> CreatePropertyPage();
|
||||
virtual void OnColorUpdated();
|
||||
virtual void ClearData() = 0;
|
||||
};
|
|
@ -0,0 +1,170 @@
|
|||
#include "stdafx.h"
|
||||
#include <memory>
|
||||
#include "TaskQueue.h"
|
||||
#include "ChannelOpenedDots.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace SoraDbgPlot::Task;
|
||||
|
||||
shared_ptr<BaseProperty> ChannelOpenedDots::CreatePropertyPage()
|
||||
{
|
||||
return ChannelOpened::CreatePropertyPage();
|
||||
}
|
||||
|
||||
|
||||
void ChannelOpenedDots::Task_ProcessDrawDotsParam(std::shared_ptr<DrawDotsParam> param, bool bDrawOrGet)
|
||||
{
|
||||
if ( (bDrawOrGet == true) && (param->_bMaxInitialized == false) )
|
||||
return;
|
||||
|
||||
if (bDrawOrGet)
|
||||
{
|
||||
this->_latestIndex = param->_index;
|
||||
this->_range = param->_range;
|
||||
}
|
||||
|
||||
if (bDrawOrGet == false)
|
||||
{
|
||||
unsigned long long timestamp;
|
||||
bool succ = this->IndexToTimestamp(param->_index, timestamp);
|
||||
if (succ)
|
||||
{
|
||||
if (!param->_bTimeStampTaken)
|
||||
{
|
||||
param->_timeStamp = timestamp;
|
||||
param->_bTimeStampTaken = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
param->_timeStamp = max(param->_timeStamp, timestamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Graphics * g = param->_g;
|
||||
CRect rect = param->_rect;
|
||||
size_t start = param->_index;
|
||||
size_t size = param->_range;
|
||||
bool luminescence = param->_luminescence;
|
||||
double dispMax = param->_dispMaxValue;
|
||||
|
||||
CRect rectClient = rect;
|
||||
|
||||
double oldRange = dispMax * 2;
|
||||
int newRangeX = rectClient.Width();
|
||||
int newRangeY = rectClient.Height();
|
||||
|
||||
Gdiplus::Color color;
|
||||
color.SetFromCOLORREF(this->_color);
|
||||
|
||||
int redColor = color.GetRed();
|
||||
int greenColor = color.GetGreen();
|
||||
int blueColor = color.GetBlue();
|
||||
|
||||
for (size_t i = 0; i < size; i++)
|
||||
{
|
||||
size_t mappedIdx = start + i;
|
||||
if (mappedIdx >= _ringBuffer->Size() || mappedIdx < 0)
|
||||
continue;
|
||||
COMPLEX16 y = (*_ringBuffer)[mappedIdx];
|
||||
|
||||
if (bDrawOrGet)
|
||||
{
|
||||
Gdiplus::REAL re = float((y.re - (-dispMax)) * newRangeX / oldRange + rectClient.left);
|
||||
Gdiplus::REAL im = float((rectClient.bottom - (y.im - (-dispMax)) * newRangeY / oldRange));
|
||||
|
||||
|
||||
int alphaDot;
|
||||
if (luminescence)
|
||||
alphaDot = 255 * (size - i) / size;
|
||||
else
|
||||
alphaDot = 255;
|
||||
|
||||
Gdiplus::Color colorFrame(alphaDot, redColor, greenColor, blueColor);
|
||||
|
||||
Pen pen(colorFrame);
|
||||
|
||||
g->DrawLine(&pen, re-1.0f, im, re+1.0f, im);
|
||||
g->DrawLine(&pen, re, im-1.0f, re, im+1.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!param->_bMaxInitialized)
|
||||
{
|
||||
param->_dispMaxValue = y.re * y.re + y.im * y.im;
|
||||
param->_bMaxInitialized = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
param->_dispMaxValue = max(param->_dispMaxValue, y.re * y.re + y.im * y.im);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bDrawOrGet == false)
|
||||
if (param->_dispMaxValue > 0)
|
||||
{
|
||||
param->_dispMaxValue = sqrt(param->_dispMaxValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<SoraDbgPlot::Task::TaskSimple> ChannelOpenedDots::TaskProcessData(std::shared_ptr<DrawDotsParam> param, bool bDrawOrGet)
|
||||
{
|
||||
auto SThis = dynamic_pointer_cast<ChannelOpenedDots, AsyncObject>(shared_from_this());
|
||||
return make_shared<TaskSimple>(TaskQueue(), [SThis, param, bDrawOrGet](){
|
||||
SThis->Task_ProcessDrawDotsParam(param, bDrawOrGet);
|
||||
});
|
||||
}
|
||||
|
||||
const wchar_t * ChannelOpenedDots::GetTypeName()
|
||||
{
|
||||
return L"Dots Channel";
|
||||
}
|
||||
|
||||
bool ChannelOpenedDots::Export(const CString & filename, bool bAll)
|
||||
{
|
||||
auto SThis = dynamic_pointer_cast<ChannelOpenedDots, AsyncObject>(shared_from_this());
|
||||
this->DoLater([SThis, filename, bAll](){
|
||||
FILE * fp;
|
||||
errno_t ret = _wfopen_s(&fp, filename, L"wb");
|
||||
|
||||
if (ret == 0)
|
||||
{
|
||||
char * digitBuf = new char[128];
|
||||
|
||||
if (bAll)
|
||||
{
|
||||
SThis->_ringBuffer->Export([fp, digitBuf](const COMPLEX16 * ptr, size_t length){
|
||||
while(length > 0)
|
||||
{
|
||||
fprintf(fp, "%d %d\r\n", (*ptr).re, (*ptr).im);
|
||||
ptr++;
|
||||
length --;
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t start = SThis->_latestIndex;
|
||||
size_t length = SThis->_range;
|
||||
length = min(length, SThis->_ringBuffer->Size());
|
||||
|
||||
SThis->_ringBuffer->ExportRange(start, length, [fp, digitBuf](const COMPLEX16 * ptr, size_t length){
|
||||
while(length > 0)
|
||||
{
|
||||
fprintf(fp, "%d %d\r\n", (*ptr).re, (*ptr).im);
|
||||
ptr++;
|
||||
length --;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
delete [] digitBuf;
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
#pragma once
|
||||
|
||||
#include "ChannelOpenedFixedLengthType.h"
|
||||
#include "Event.h"
|
||||
#include "TaskQueue.h"
|
||||
#include "TaskSimple.h"
|
||||
#include "FrameWithSizeFilter.h"
|
||||
#include "RingBufferWithTimeStamp.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef _SORA_
|
||||
typedef struct tagComplex16
|
||||
{
|
||||
short re;
|
||||
short im;
|
||||
} COMPLEX16;
|
||||
#endif
|
||||
|
||||
struct DrawDotsParam
|
||||
{
|
||||
Graphics * _g;
|
||||
bool _bIsLog;
|
||||
CRect _rect;
|
||||
double _dispMaxValue;
|
||||
size_t _index;
|
||||
size_t _range;
|
||||
bool _luminescence;
|
||||
bool _bMaxInitialized;
|
||||
bool _bTimeStampTaken;
|
||||
unsigned long long _timeStamp;
|
||||
};
|
||||
|
||||
class ChannelOpenedDots : public ChannelOpenedFixedLengthType<COMPLEX16>
|
||||
{
|
||||
public:
|
||||
|
||||
std::shared_ptr<SoraDbgPlot::Task::TaskSimple> TaskProcessData(std::shared_ptr<DrawDotsParam>, bool bDrawOrGet);
|
||||
|
||||
virtual std::shared_ptr<BaseProperty> CreatePropertyPage();
|
||||
virtual const wchar_t * GetTypeName();
|
||||
virtual bool Export(const CString &, bool bAll);
|
||||
|
||||
private:
|
||||
void Task_ProcessDrawDotsParam(std::shared_ptr<DrawDotsParam> param, bool bDrawOrGet);
|
||||
};
|
|
@ -0,0 +1,2 @@
|
|||
#include "stdafx.h"
|
||||
#include "ChannelOpenedFixedLengthType.h"
|
|
@ -0,0 +1,96 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include "ChannelOpened.h"
|
||||
#include "RingBufferWithTimeStamp.h"
|
||||
#include "FrameWithSizeFilter.h"
|
||||
#include "TaskSimple.h"
|
||||
#include "AppSettings.h"
|
||||
|
||||
template <typename T>
|
||||
class ChannelOpenedFixedLengthType : public ChannelOpened
|
||||
{
|
||||
protected:
|
||||
virtual void WriteData(const char * data, size_t length);
|
||||
virtual void ClearData();
|
||||
|
||||
public:
|
||||
ChannelOpenedFixedLengthType();
|
||||
~ChannelOpenedFixedLengthType();
|
||||
|
||||
bool IndexToTimestamp(size_t index, unsigned long long & timestamp);
|
||||
bool Data(size_t index, T & data);
|
||||
size_t DataSize();
|
||||
virtual std::shared_ptr<SoraDbgPlot::Task::TaskSimple> TaskUpdateDataSize(std::shared_ptr<size_t>);
|
||||
|
||||
protected:
|
||||
SoraDbgPlot::FrameWithSizeInfoWriter<T> * _filter;
|
||||
RingBufferWithTimeStamp<T> * _ringBuffer;
|
||||
size_t _latestIndex;
|
||||
size_t _range;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void ChannelOpenedFixedLengthType<T>::WriteData(const char * data, size_t length)
|
||||
{
|
||||
auto SThis = std::dynamic_pointer_cast<ChannelOpenedFixedLengthType, AsyncObject>(shared_from_this());
|
||||
TaskQueue()->QueueTask([SThis, data, length](){
|
||||
size_t dummy;
|
||||
SThis->_filter->Write(data, length, dummy);
|
||||
delete [] data;
|
||||
}, [data](){
|
||||
delete [] data;
|
||||
});
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ChannelOpenedFixedLengthType<T>::ChannelOpenedFixedLengthType()
|
||||
{
|
||||
_ringBuffer = new RingBufferWithTimeStamp<T>(::SettingGetReplayBufferSize() / sizeof(T));
|
||||
_filter = new SoraDbgPlot::FrameWithSizeInfoWriter<T>(_ringBuffer);
|
||||
_latestIndex = 0;
|
||||
_range = 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ChannelOpenedFixedLengthType<T>::~ChannelOpenedFixedLengthType()
|
||||
{
|
||||
delete _filter;
|
||||
delete _ringBuffer;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool ChannelOpenedFixedLengthType<T>::Data(size_t index, T & data)
|
||||
{
|
||||
data = (*_ringBuffer)[index];
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
size_t ChannelOpenedFixedLengthType<T>::DataSize()
|
||||
{
|
||||
return _ringBuffer->Size();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool ChannelOpenedFixedLengthType<T>::IndexToTimestamp(size_t index, unsigned long long & timestamp)
|
||||
{
|
||||
return _ringBuffer->GetTimeStampBySample(index, timestamp);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::shared_ptr<SoraDbgPlot::Task::TaskSimple> ChannelOpenedFixedLengthType<T>::TaskUpdateDataSize(std::shared_ptr<size_t> size)
|
||||
{
|
||||
auto SThis = std::dynamic_pointer_cast<ChannelOpenedFixedLengthType, AsyncObject>(shared_from_this());
|
||||
return std::make_shared<SoraDbgPlot::Task::TaskSimple>(TaskQueue(), [SThis, size](){
|
||||
size_t oldSize = *size;
|
||||
size_t newSize = max(oldSize, SThis->_ringBuffer->Size());
|
||||
*size = newSize;
|
||||
});
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ChannelOpenedFixedLengthType<T>::ClearData()
|
||||
{
|
||||
_ringBuffer->Reset();
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
#include "stdafx.h"
|
||||
#include <assert.h>
|
||||
#include <memory>
|
||||
#include "ChannelOpenedLine.h"
|
||||
#include "TaskQueue.h"
|
||||
#include "ChannelProperty.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace SoraDbgPlot::Task;
|
||||
|
||||
shared_ptr<BaseProperty> ChannelOpenedLine::CreatePropertyPage()
|
||||
{
|
||||
return ChannelOpened::CreatePropertyPage();
|
||||
}
|
||||
|
||||
const wchar_t * ChannelOpenedLine::GetTypeName()
|
||||
{
|
||||
return L"Line Channel";
|
||||
}
|
||||
|
||||
bool ChannelOpenedLine::Export(const CString & filename, bool bAll)
|
||||
{
|
||||
auto SThis = dynamic_pointer_cast<ChannelOpenedLine, AsyncObject>(shared_from_this());
|
||||
|
||||
this->DoLater([SThis, filename, bAll](){
|
||||
FILE * fp;
|
||||
errno_t ret = _wfopen_s(&fp, filename, L"wb");
|
||||
|
||||
if (ret == 0)
|
||||
{
|
||||
char * digitBuf = new char[128];
|
||||
|
||||
if (bAll)
|
||||
{
|
||||
SThis->_ringBuffer->Export([fp, digitBuf](const int * ptr, size_t length){
|
||||
while(length > 0)
|
||||
{
|
||||
fprintf(fp, "%d\r\n", *ptr);
|
||||
ptr ++;
|
||||
length --;
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t start = SThis->_latestIndex;
|
||||
size_t length = SThis->_range;
|
||||
length = min(length, SThis->_ringBuffer->Size());
|
||||
|
||||
SThis->_ringBuffer->ExportRange(start, length, [fp, digitBuf](const int * ptr, size_t length){
|
||||
while(length > 0)
|
||||
{
|
||||
fprintf(fp, "%d\r\n", *ptr);
|
||||
ptr ++;
|
||||
length --;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
delete [] digitBuf;
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
#pragma once
|
||||
#include "ChannelOpenedLineType.h"
|
||||
#include "TaskQueue.h"
|
||||
|
||||
class ChannelOpenedLine : public ChannelOpenedLineType
|
||||
{
|
||||
public:
|
||||
virtual std::shared_ptr<BaseProperty> CreatePropertyPage();
|
||||
virtual const wchar_t * GetTypeName();
|
||||
virtual bool Export(const CString &, bool bAll);
|
||||
};
|
|
@ -0,0 +1,396 @@
|
|||
#include "stdafx.h"
|
||||
#include <Windows.h>
|
||||
#include "ChannelOpenedLineType.h"
|
||||
#include "Event.h"
|
||||
#include "TaskQueue.h"
|
||||
#include "HelperFunc.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace SoraDbgPlot::Task;
|
||||
|
||||
ChannelOpenedLineType::ChannelOpenedLineType()
|
||||
{
|
||||
_drawUsingSample = true; // defaut using sample
|
||||
}
|
||||
|
||||
shared_ptr<SoraDbgPlot::Task::TaskSimple> ChannelOpenedLineType::LineDataTask(std::shared_ptr<LineDataParam> param)
|
||||
{
|
||||
auto shared_me = dynamic_pointer_cast<ChannelOpenedLineType, AsyncObject>(shared_from_this());
|
||||
return make_shared<TaskSimple>(TaskQueue(), [shared_me, param](){
|
||||
shared_me->ProcessDrawLineParam(param);
|
||||
});
|
||||
}
|
||||
|
||||
void ChannelOpenedLineType::ProcessDrawLineParam(std::shared_ptr<LineDataParam> param)
|
||||
{
|
||||
size_t clientWidth = param->_clientWidth;
|
||||
size_t start = param->_index;
|
||||
size_t size = param->_range;
|
||||
|
||||
bool bDrawDot = (size > 0) && (clientWidth / size >= 5);
|
||||
bool bDrawType2 = (size > 0) && (clientWidth / size >= 1);
|
||||
|
||||
int width = clientWidth;
|
||||
|
||||
if (width == 0)
|
||||
return;
|
||||
|
||||
param->_color = Color();
|
||||
|
||||
if (!bDrawType2)
|
||||
{
|
||||
bool firstPoint = true;
|
||||
for (int i = 0; i < width; i++)
|
||||
{
|
||||
size_t mappedIdx = start + size - 1 - i * size / width;
|
||||
if (mappedIdx >= _ringBuffer->Size())
|
||||
continue;
|
||||
|
||||
int y = (*_ringBuffer)[mappedIdx];
|
||||
param->_list.push_back(y);
|
||||
}
|
||||
}
|
||||
|
||||
if (bDrawType2)
|
||||
{
|
||||
for (size_t i = 0; i < size; i++)
|
||||
{
|
||||
if (i + start >= _ringBuffer->Size())
|
||||
break;
|
||||
|
||||
int y = (*_ringBuffer)[i + start];
|
||||
param->_list.push_back(y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<SoraDbgPlot::Task::TaskSimple> ChannelOpenedLineType::TaskProcessData(std::shared_ptr<DrawLineParam> param, bool bDrawOrGet)
|
||||
{
|
||||
auto SThis = dynamic_pointer_cast<ChannelOpenedLineType, AsyncObject>(shared_from_this());
|
||||
return make_shared<TaskSimple>(TaskQueue(), [SThis, param, bDrawOrGet](){
|
||||
SThis->Task_ProcessDrawLineParam(param, bDrawOrGet);
|
||||
//TRACE1("task process data %d\n", bDrawOrGet ? 1 : 0);
|
||||
});
|
||||
}
|
||||
|
||||
void ChannelOpenedLineType::DrawUsingSample(bool bUseSample)
|
||||
{
|
||||
_drawUsingSample = bUseSample;
|
||||
}
|
||||
|
||||
void ChannelOpenedLineType::ProcessDrawLineParam(std::shared_ptr<DrawLineParam> param, bool bDrawOrGet)
|
||||
{
|
||||
auto shared_me = dynamic_pointer_cast<ChannelOpenedLineType, AsyncObject>(shared_from_this());
|
||||
TaskQueue()->DoTask([shared_me, param, bDrawOrGet](){
|
||||
shared_me->Task_ProcessDrawLineParam(param, bDrawOrGet);
|
||||
});
|
||||
}
|
||||
|
||||
void ChannelOpenedLineType::DrawLine(Gdiplus::Graphics * g, const Pen* pen, float x1, float y1, float x2, float y2, float maxY, float minY)
|
||||
{
|
||||
float deltaY = y2 - y1;
|
||||
float deltaX = x2 - x1;
|
||||
float baseX = x1;
|
||||
float baseY = y1;
|
||||
|
||||
y1 = min(maxY, y1);
|
||||
y1 = max(minY, y1);
|
||||
if (deltaY != 0.0)
|
||||
x1 = (y1 - baseY) * deltaX / deltaY + baseX;
|
||||
|
||||
y2 = min(maxY, y2);
|
||||
y2 = max(minY, y2);
|
||||
if (deltaY != 0.0)
|
||||
x2 = (y2 - baseY) * deltaX / deltaY + baseX;
|
||||
|
||||
g->DrawLine(pen, x1, y1, x2, y2);
|
||||
}
|
||||
|
||||
void ChannelOpenedLineType::Task_ProcessDrawLineParam(std::shared_ptr<DrawLineParam> param, bool bDrawOrGet)
|
||||
{
|
||||
if ( (bDrawOrGet == true) && (param->_bMaxMinInitialized == false) )
|
||||
return;
|
||||
|
||||
CRect rect = param->_rect;
|
||||
size_t start = IndexToSize(param->_index);
|
||||
size_t size = RangeToSize(param->_range);
|
||||
|
||||
if (bDrawOrGet)
|
||||
{
|
||||
this->_latestIndex = start;
|
||||
this->_range = size;
|
||||
}
|
||||
|
||||
if (bDrawOrGet == false)
|
||||
{
|
||||
unsigned long long timestamp;
|
||||
bool succ = this->IndexToTimestamp(param->_index, timestamp);
|
||||
if (succ)
|
||||
{
|
||||
if (!param->_bTimeStampTaken)
|
||||
{
|
||||
param->_timeStamp = timestamp;
|
||||
param->_bTimeStampTaken = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
param->_timeStamp = max(param->_timeStamp, timestamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool bDrawDot = (size > 0) && (rect.Width() / size >= 5);
|
||||
bool bDrawType2 = (size > 0) && (rect.Width() / size >= 1);
|
||||
|
||||
int width = rect.Width();
|
||||
|
||||
if (width == 0)
|
||||
return;
|
||||
|
||||
Gdiplus::REAL lastDispX, lastDispY;
|
||||
|
||||
Gdiplus::Color color;
|
||||
color.SetFromCOLORREF(this->Color());
|
||||
|
||||
Gdiplus::Color colorLine;
|
||||
|
||||
if (bDrawDot)
|
||||
colorLine = Gdiplus::Color(64, color.GetR(), color.GetG(), color.GetB());
|
||||
else
|
||||
colorLine = Gdiplus::Color(255, color.GetR(), color.GetG(), color.GetB());
|
||||
|
||||
Pen penLine(colorLine);
|
||||
|
||||
if (!bDrawType2) // more dots than pixels
|
||||
{
|
||||
if (_drawUsingSample)
|
||||
{
|
||||
bool firstPoint = true;
|
||||
for (int i = 0; i < width; i++)
|
||||
{
|
||||
size_t mappedIdx = start + size - 1 - i * size / width;
|
||||
if (mappedIdx >= _ringBuffer->Size())
|
||||
continue;
|
||||
|
||||
int y = (*_ringBuffer)[mappedIdx];
|
||||
double dataT = ::TransformCoordinate(y, param->_bIsLog);
|
||||
|
||||
if (bDrawOrGet)
|
||||
{
|
||||
Gdiplus::REAL dataY = this->GetClientY(dataT, rect, param->_dispMaxValue, param->_dispMinValue);
|
||||
Gdiplus::REAL dataX = (Gdiplus::REAL)(i + rect.left);
|
||||
|
||||
if (!firstPoint)
|
||||
this->DrawLine(param->_g, &penLine, lastDispX, lastDispY, dataX, dataY, (float)rect.bottom, (float)rect.top);
|
||||
else
|
||||
firstPoint = false;
|
||||
|
||||
lastDispX = dataX;
|
||||
lastDispY = dataY;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!param->_bMaxMinInitialized)
|
||||
{
|
||||
param->_dispMaxValue = dataT;
|
||||
param->_dispMinValue = dataT;
|
||||
param->_bMaxMinInitialized = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
param->_dispMaxValue = max(param->_dispMaxValue, dataT);
|
||||
param->_dispMinValue = min(param->_dispMinValue, dataT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
int rectWidth = max(0, rect.Width() - 1);
|
||||
|
||||
float maxValue;
|
||||
float minValue;
|
||||
float lastX = -1.0;
|
||||
float lastY;
|
||||
|
||||
bool firstPoint = true;
|
||||
Gdiplus::REAL dataY;
|
||||
Gdiplus::REAL dataX;
|
||||
|
||||
for (size_t i = 0; i < size; i++)
|
||||
{
|
||||
if (i + start >= _ringBuffer->Size())
|
||||
break;
|
||||
|
||||
int y = (*_ringBuffer)[i + start];
|
||||
double dataT = ::TransformCoordinate(y, param->_bIsLog);
|
||||
dataY = GetClientY(dataT, rect, param->_dispMaxValue, param->_dispMinValue);
|
||||
dataX = (Gdiplus::REAL)((size - i - 1) * rectWidth / (size - 1) + rect.left);
|
||||
|
||||
if (bDrawOrGet)
|
||||
{
|
||||
if (dataX != lastX)
|
||||
{
|
||||
if (lastX != -1.0)
|
||||
{
|
||||
this->DrawLine(param->_g, &penLine, lastX, minValue, lastX, maxValue, (float)rect.bottom, (float)rect.top);
|
||||
this->DrawLine(param->_g, &penLine, lastX, lastY, dataX, dataY, (float)rect.bottom, (float)rect.top);
|
||||
}
|
||||
|
||||
maxValue = dataY;
|
||||
minValue = dataY;
|
||||
lastX = dataX;
|
||||
}
|
||||
else
|
||||
{
|
||||
maxValue = max(dataY, maxValue);
|
||||
minValue = min(dataY, minValue);
|
||||
}
|
||||
|
||||
lastY = dataY;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!param->_bMaxMinInitialized)
|
||||
{
|
||||
param->_dispMaxValue = dataT;
|
||||
param->_dispMinValue = dataT;
|
||||
param->_bMaxMinInitialized = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
param->_dispMaxValue = max(param->_dispMaxValue, dataT);
|
||||
param->_dispMinValue = min(param->_dispMinValue, dataT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (lastX != -1.0)
|
||||
{
|
||||
this->DrawLine(param->_g, &penLine, lastX, minValue, lastX, maxValue, (float)rect.bottom, (float)rect.top);
|
||||
this->DrawLine(param->_g, &penLine, lastX, lastY, dataX, dataY, (float)rect.bottom, (float)rect.top);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bDrawType2)
|
||||
{
|
||||
Pen penDot(color, 1.5);
|
||||
int rectWidth = max(0, rect.Width() - 1);
|
||||
|
||||
if (size == 1)
|
||||
{
|
||||
if (start < _ringBuffer->Size())
|
||||
{
|
||||
int y = (*_ringBuffer)[start];
|
||||
double dataT = ::TransformCoordinate(y, param->_bIsLog);
|
||||
if (bDrawOrGet)
|
||||
{
|
||||
Gdiplus::REAL dataY = GetClientY(dataT, rect, param->_dispMaxValue, param->_dispMinValue);
|
||||
Gdiplus::REAL dataX = (Gdiplus::REAL)(rectWidth / 2 + rect.left);
|
||||
this->DrawDot(param->_g, dataX, dataY, penDot);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!param->_bMaxMinInitialized)
|
||||
{
|
||||
param->_dispMaxValue = dataT;
|
||||
param->_dispMinValue = dataT;
|
||||
param->_bMaxMinInitialized = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
param->_dispMaxValue = max(param->_dispMaxValue, dataT);
|
||||
param->_dispMinValue = min(param->_dispMinValue, dataT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
bool firstPoint = true;
|
||||
for (size_t i = 0; i < size; i++)
|
||||
{
|
||||
if (i + start >= _ringBuffer->Size())
|
||||
break;
|
||||
|
||||
int y = (*_ringBuffer)[i + start];
|
||||
double dataT = ::TransformCoordinate(y, param->_bIsLog);
|
||||
Gdiplus::REAL dataY = GetClientY(dataT, rect, param->_dispMaxValue, param->_dispMinValue);
|
||||
Gdiplus::REAL dataX = (Gdiplus::REAL)((size - i - 1) * rectWidth / (size - 1) + rect.left);
|
||||
|
||||
if (bDrawDot)
|
||||
this->DrawDot(param->_g, dataX, dataY, penDot, i == size - 1 ? 1 : 0);
|
||||
|
||||
if (bDrawOrGet)
|
||||
{
|
||||
if (firstPoint)
|
||||
{
|
||||
firstPoint = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->DrawLine(param->_g, &penLine, lastDispX, lastDispY, dataX, dataY, (float)rect.bottom, (float)rect.top);
|
||||
}
|
||||
lastDispX = dataX;
|
||||
lastDispY = dataY;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!param->_bMaxMinInitialized)
|
||||
{
|
||||
param->_dispMaxValue = dataT;
|
||||
param->_dispMinValue = dataT;
|
||||
param->_bMaxMinInitialized = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
param->_dispMaxValue = max(param->_dispMaxValue, dataT);
|
||||
param->_dispMinValue = min(param->_dispMinValue, dataT);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Gdiplus::REAL ChannelOpenedLineType::GetClientY(double y, const CRect & clientRect, double dispMaxValue, double dispMinValue)
|
||||
{
|
||||
double rangeOld = dispMaxValue - dispMinValue;
|
||||
int rangeNew = clientRect.bottom - clientRect.top;
|
||||
return float(clientRect.bottom -
|
||||
(y - dispMinValue) * rangeNew / rangeOld);
|
||||
}
|
||||
|
||||
void ChannelOpenedLineType::DrawDot(Graphics * g, double x, double y, const Pen & pen, int type)
|
||||
{
|
||||
int xx = (int)x;
|
||||
int yy = (int)y;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case 0:
|
||||
g->DrawLine(&pen, xx - 3, yy, xx + 3, yy);
|
||||
g->DrawLine(&pen, xx, yy - 3, xx, yy + 3);
|
||||
break;
|
||||
case 1:
|
||||
g->DrawLine(&pen, xx, yy, xx + 3, yy);
|
||||
g->DrawLine(&pen, xx, yy - 3, xx, yy + 3);
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
size_t ChannelOpenedLineType::RangeToSize(size_t range)
|
||||
{
|
||||
return range;
|
||||
}
|
||||
|
||||
|
||||
size_t ChannelOpenedLineType::IndexToSize(size_t index)
|
||||
{
|
||||
return index;
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
#pragma once
|
||||
|
||||
#include "ChannelOpenedFixedLengthType.h"
|
||||
#include "Event.h"
|
||||
#include "TaskQueue.h"
|
||||
#include "TaskSimple.h"
|
||||
#include "FrameWithSizeFilter.h"
|
||||
#include "RingBufferWithTimeStamp.h"
|
||||
|
||||
struct DrawLineParam
|
||||
{
|
||||
Graphics * _g;
|
||||
bool _bIsLog;
|
||||
CRect _rect;
|
||||
double _dispMaxValue;
|
||||
double _dispMinValue;
|
||||
size_t _index;
|
||||
size_t _range;
|
||||
bool _bMaxMinInitialized;
|
||||
unsigned long long _timeStamp;
|
||||
bool _bTimeStampTaken;
|
||||
};
|
||||
|
||||
struct LineInfoTask
|
||||
{
|
||||
size_t size;
|
||||
};
|
||||
|
||||
struct LineDataParam
|
||||
{
|
||||
size_t _index;
|
||||
size_t _range;
|
||||
COLORREF _color;
|
||||
size_t _clientWidth;
|
||||
std::list<int> _list;
|
||||
};
|
||||
|
||||
class ChannelOpenedLineType : public ChannelOpenedFixedLengthType<int>
|
||||
{
|
||||
public:
|
||||
ChannelOpenedLineType();
|
||||
std::shared_ptr<SoraDbgPlot::Task::TaskSimple> LineInfoTask(std::shared_ptr<LineInfoTask>);
|
||||
std::shared_ptr<SoraDbgPlot::Task::TaskSimple> LineDataTask(std::shared_ptr<LineDataParam>);
|
||||
void DrawUsingSample(bool bUseSample);
|
||||
|
||||
void ProcessDrawLineParam(std::shared_ptr<DrawLineParam> param, bool bDrawOrGet);
|
||||
std::shared_ptr<SoraDbgPlot::Task::TaskSimple> TaskProcessData(std::shared_ptr<DrawLineParam>, bool bDrawOrGet);
|
||||
|
||||
|
||||
protected:
|
||||
virtual size_t RangeToSize(size_t range);
|
||||
virtual size_t IndexToSize(size_t index);
|
||||
|
||||
private:
|
||||
void ProcessDrawLineParam(std::shared_ptr<LineDataParam> param);
|
||||
void ChannelOpenedLineType::Task_ProcessDrawLineParam(std::shared_ptr<DrawLineParam> param, bool bDrawOrGet);
|
||||
Gdiplus::REAL GetClientY(double y, const CRect & clientRect, double dispMaxValue, double dispMinValue);
|
||||
void DrawDot(Graphics * g, double x, double y, const Pen & pen, int type = 0);
|
||||
void DrawLine(Gdiplus::Graphics * g, const Pen* pen, float x1, float y1, float x2, float y2, float maxY, float minY);
|
||||
|
||||
bool _drawUsingSample;
|
||||
};
|
|
@ -0,0 +1,169 @@
|
|||
#include "stdafx.h"
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <ostream>
|
||||
#include "ChannelOpenedLog.h"
|
||||
#include "LogWithFileBackup.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace SoraDbgPlot::Task;
|
||||
|
||||
int ChannelOpenedLog::logObjIdx = 0;
|
||||
|
||||
ChannelOpenedLog::ChannelOpenedLog()
|
||||
{
|
||||
int logObjIdx = ChannelOpenedLog::logObjIdx++;
|
||||
|
||||
_color = RGB(0, 255, 0); // green;
|
||||
char dir[256];
|
||||
::GetCurrentDirectoryA(256, dir);
|
||||
std::ostringstream os;
|
||||
os << dir << "\\logs\\" << logObjIdx;
|
||||
|
||||
ostringstream osName;
|
||||
osName << logObjIdx;
|
||||
_logObj = LogWithBackUpFile::Make(os.str().c_str(), osName.str().c_str());
|
||||
|
||||
_writeFilter = new SoraDbgPlot::FrameWithSizeInfoWriter<char>();
|
||||
|
||||
_writeFilter->EventFlushData.Subscribe([this](const void * sender, const SoraDbgPlot::FrameWithSizeInfoWriter<char>::FlushDataEvent & e){
|
||||
|
||||
if (this->_logObj == 0)
|
||||
return;
|
||||
|
||||
size_t dataLen = e.length;
|
||||
if (dataLen >= 0)
|
||||
{
|
||||
int sizeNeeded = dataLen*2 + 1;
|
||||
char * dataBuf = _newLineFilterBuffer.UseBuf(sizeNeeded);
|
||||
|
||||
char * ptrSrc = e.ptr;
|
||||
char * ptrDest = dataBuf;
|
||||
char preChar;
|
||||
|
||||
while(ptrSrc < e.ptr + e.length)
|
||||
{
|
||||
char c = *ptrSrc;
|
||||
if (c != '\n')
|
||||
*ptrDest++ = c;
|
||||
else
|
||||
{
|
||||
if ( (ptrSrc == e.ptr) || preChar != '\r')
|
||||
{
|
||||
*ptrDest++ = '\r';
|
||||
*ptrDest++ = '\n';
|
||||
}
|
||||
}
|
||||
|
||||
ptrSrc++;
|
||||
preChar = c;
|
||||
}
|
||||
|
||||
*ptrDest = 0;
|
||||
|
||||
this->_logObj->AddRecord(dataBuf);
|
||||
|
||||
_newLineFilterBuffer.ReturnBuf();
|
||||
}
|
||||
});
|
||||
|
||||
_newLineFilterBuffer.ConfigKeptSize(16*1024);
|
||||
}
|
||||
|
||||
ChannelOpenedLog::~ChannelOpenedLog()
|
||||
{
|
||||
delete _writeFilter;
|
||||
|
||||
if (_logObj)
|
||||
delete _logObj;
|
||||
}
|
||||
|
||||
void ChannelOpenedLog::WriteData(const char * data, size_t length)
|
||||
{
|
||||
size_t sizeDummy;
|
||||
this->_writeFilter->Write(data, length, sizeDummy);
|
||||
delete [] data;
|
||||
}
|
||||
|
||||
size_t ChannelOpenedLog::DataSize()
|
||||
{
|
||||
if (_logObj)
|
||||
return _logObj->RecordCount();
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
char * ChannelOpenedLog::GetData(size_t index, bool bFromOldest)
|
||||
{
|
||||
char * txt = 0;
|
||||
auto SThis = dynamic_pointer_cast<ChannelOpenedLog, AsyncObject>(shared_from_this());
|
||||
TaskQueue()->DoTask([SThis, index, bFromOldest, &txt](){
|
||||
|
||||
if (SThis->_logObj)
|
||||
{
|
||||
size_t size = SThis->_logObj->RecordCount();
|
||||
if (size <= index)
|
||||
return;
|
||||
|
||||
size_t index2 = bFromOldest ? index : size - 1 - index;
|
||||
txt = SThis->_logObj->Record(index2);
|
||||
}
|
||||
else
|
||||
{
|
||||
txt = "Error creating log file.";
|
||||
}
|
||||
});
|
||||
|
||||
return txt;
|
||||
}
|
||||
|
||||
shared_ptr<TaskSimple> ChannelOpenedLog::TaskGetSize(shared_ptr<size_t> size)
|
||||
{
|
||||
auto SThis = dynamic_pointer_cast<ChannelOpenedLog, AsyncObject>(shared_from_this());
|
||||
auto task = make_shared<TaskSimple>(TaskQueue(), [SThis, size](){
|
||||
if (SThis->_logObj)
|
||||
*size = SThis->_logObj->RecordCount();
|
||||
else
|
||||
*size = 1;
|
||||
});
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
const wchar_t * ChannelOpenedLog::GetTypeName()
|
||||
{
|
||||
return L"Log Channel";
|
||||
}
|
||||
|
||||
bool ChannelOpenedLog::Export(const CString & filename, bool bAll)
|
||||
{
|
||||
auto SThis = dynamic_pointer_cast<ChannelOpenedLog, AsyncObject>(shared_from_this());
|
||||
|
||||
this->DoLater([SThis, filename, bAll](){
|
||||
if (SThis->_logObj)
|
||||
SThis->_logObj->Export(filename);
|
||||
else
|
||||
{
|
||||
auto hfileOutput = ::CreateFileW(
|
||||
filename,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ,
|
||||
NULL,
|
||||
CREATE_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (hfileOutput != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(hfileOutput);
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ChannelOpenedLog::ClearData()
|
||||
{
|
||||
if (this->_logObj)
|
||||
this->_logObj->ClearData();
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include "ChannelOpenedTextType.h"
|
||||
#include "FrameWithSizeFilter.h"
|
||||
#include "ILog.h"
|
||||
#include "TaskSimple.h"
|
||||
#include "TempBuffer.h"
|
||||
|
||||
class ChannelOpenedLog : public ChannelOpenedTextType
|
||||
{
|
||||
private:
|
||||
static int logObjIdx;
|
||||
|
||||
public:
|
||||
ChannelOpenedLog();
|
||||
~ChannelOpenedLog();
|
||||
|
||||
virtual std::shared_ptr<SoraDbgPlot::Task::TaskSimple> TaskGetSize(std::shared_ptr<size_t>);
|
||||
virtual const wchar_t * GetTypeName();
|
||||
virtual bool Export(const CString &, bool bAll);
|
||||
|
||||
protected:
|
||||
virtual void WriteData(const char * data, size_t length);
|
||||
virtual size_t DataSize();
|
||||
virtual char * GetData(size_t index, bool bFromOldest);
|
||||
virtual void ClearData();
|
||||
|
||||
private:
|
||||
ILog * _logObj;
|
||||
COLORREF _color;
|
||||
SoraDbgPlot::FrameWithSizeInfoWriter<char> * _writeFilter;
|
||||
|
||||
SoraDbgPlot::Buffer::TempBuffer _newLineFilterBuffer;
|
||||
};
|
|
@ -0,0 +1,109 @@
|
|||
#include "stdafx.h"
|
||||
#include <assert.h>
|
||||
#include <memory>
|
||||
#include "ChannelOpenedSpectrum.h"
|
||||
#include "TaskQueue.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace SoraDbgPlot::Task;
|
||||
|
||||
|
||||
ChannelOpenedSpectrum::ChannelOpenedSpectrum()
|
||||
{
|
||||
DrawUsingSample(false);
|
||||
}
|
||||
|
||||
shared_ptr<BaseProperty> ChannelOpenedSpectrum::CreatePropertyPage()
|
||||
{
|
||||
return ChannelOpened::CreatePropertyPage();
|
||||
}
|
||||
|
||||
size_t ChannelOpenedSpectrum::RangeToSize(size_t range)
|
||||
{
|
||||
return this->_spectrumSize;
|
||||
}
|
||||
|
||||
|
||||
size_t ChannelOpenedSpectrum::IndexToSize(size_t index)
|
||||
{
|
||||
return index * this->_spectrumSize;
|
||||
}
|
||||
|
||||
shared_ptr<TaskSimple> ChannelOpenedSpectrum::TaskUpdateDataSize(std::shared_ptr<size_t> size)
|
||||
{
|
||||
auto SThis = dynamic_pointer_cast<ChannelOpenedSpectrum, AsyncObject>(shared_from_this());
|
||||
return make_shared<TaskSimple>(TaskQueue(), [SThis, size](){
|
||||
size_t oldSize = *size;
|
||||
size_t mySize = SThis->_ringBuffer->Size() / SThis->_spectrumSize;
|
||||
size_t newSize = min(oldSize, mySize);
|
||||
*size = newSize;
|
||||
});
|
||||
}
|
||||
|
||||
const wchar_t * ChannelOpenedSpectrum::GetTypeName()
|
||||
{
|
||||
return L"Spectrum Channel";
|
||||
}
|
||||
|
||||
bool ChannelOpenedSpectrum::Export(const CString & filename, bool bAll)
|
||||
{
|
||||
auto SThis = dynamic_pointer_cast<ChannelOpenedSpectrum, AsyncObject>(shared_from_this());
|
||||
this->DoLater([SThis, filename, bAll](){
|
||||
FILE * fp;
|
||||
errno_t ret = _wfopen_s(&fp, filename, L"wb");
|
||||
|
||||
if (ret == 0)
|
||||
{
|
||||
size_t spectrumSize = SThis->SpectrumDataSize();
|
||||
|
||||
char * digitBuf = new char[128];
|
||||
//int * numBuf = new int[spectrumSize];
|
||||
size_t numOutput = 0;
|
||||
|
||||
if (bAll)
|
||||
{
|
||||
SThis->_ringBuffer->Export([fp, digitBuf, &numOutput, spectrumSize](const int * ptr, size_t length){
|
||||
while(length > 0)
|
||||
{
|
||||
fprintf(fp, "%d ", *ptr);
|
||||
numOutput++;
|
||||
if (numOutput == spectrumSize)
|
||||
{
|
||||
fprintf(fp, "\r\n");
|
||||
numOutput = 0;
|
||||
}
|
||||
ptr++;
|
||||
length --;
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t start = SThis->_latestIndex;
|
||||
size_t length = SThis->_range;
|
||||
length = min(length, SThis->_ringBuffer->Size());
|
||||
|
||||
SThis->_ringBuffer->ExportRange(start, length, [fp, digitBuf, &numOutput, spectrumSize](const int * ptr, size_t length){
|
||||
while(length > 0)
|
||||
{
|
||||
fprintf(fp, "%d ", *ptr);
|
||||
numOutput++;
|
||||
if (numOutput == spectrumSize)
|
||||
{
|
||||
fprintf(fp, "\r\n");
|
||||
numOutput = 0;
|
||||
}
|
||||
ptr++;
|
||||
length --;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
delete [] digitBuf;
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
#pragma once
|
||||
#include "ChannelOpenedLineType.h"
|
||||
#include "TaskQueue.h"
|
||||
|
||||
class ChannelOpenedSpectrum : public ChannelOpenedLineType
|
||||
{
|
||||
public:
|
||||
ChannelOpenedSpectrum();
|
||||
virtual std::shared_ptr<BaseProperty> CreatePropertyPage();
|
||||
virtual std::shared_ptr<SoraDbgPlot::Task::TaskSimple> TaskUpdateDataSize(std::shared_ptr<size_t>);
|
||||
virtual const wchar_t * GetTypeName();
|
||||
virtual bool Export(const CString &, bool bAll);
|
||||
|
||||
protected:
|
||||
virtual size_t RangeToSize(size_t range);
|
||||
virtual size_t IndexToSize(size_t index);
|
||||
};
|
|
@ -0,0 +1,330 @@
|
|||
#include "stdafx.h"
|
||||
#include "ChannelOpenedText.h"
|
||||
#include "SubPlotWnd.h"
|
||||
#include "HelperFunc.h"
|
||||
#include "AppSettings.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace SoraDbgPlot::Task;
|
||||
|
||||
ChannelOpenedText::ChannelOpenedText()
|
||||
{
|
||||
_plotWnd = 0;
|
||||
_latestTimeIdx = 0;
|
||||
_ringBuffer = new RingBufferWithTimeStamp<char>(::SettingGetReplayBufferSize() / sizeof(char));
|
||||
_filter = new SoraDbgPlot::FrameWithSizeInfoWriter<char>();
|
||||
_rect = CRect(0, 0, 10, 10);
|
||||
|
||||
_filter->EventFlushData.Subscribe([this](const void * sender, const SoraDbgPlot::FrameWithSizeInfoWriter<char>::FlushDataEvent & e){
|
||||
|
||||
size_t dataLen = e.length;
|
||||
if (dataLen >= 0)
|
||||
{
|
||||
int sizeNeeded = dataLen*2 + 1;
|
||||
|
||||
char * dataBuf = _newLineFilterBuffer.UseBuf(sizeNeeded);
|
||||
|
||||
char * ptrSrc = e.ptr;
|
||||
char * ptrDest = dataBuf;
|
||||
char preChar;
|
||||
|
||||
while(ptrSrc < e.ptr + e.length)
|
||||
{
|
||||
char c = *ptrSrc;
|
||||
if (c != '\n')
|
||||
*ptrDest++ = c;
|
||||
else
|
||||
{
|
||||
if ( (ptrSrc == e.ptr) || preChar != '\r')
|
||||
{
|
||||
*ptrDest++ = '\r';
|
||||
*ptrDest++ = '\n';
|
||||
}
|
||||
}
|
||||
|
||||
ptrSrc++;
|
||||
preChar = c;
|
||||
}
|
||||
|
||||
*ptrDest = 0;
|
||||
int length = ptrDest - dataBuf;
|
||||
|
||||
this->_ringBuffer->Write(dataBuf, length, e.timestamp);
|
||||
|
||||
_newLineFilterBuffer.ReturnBuf();
|
||||
}
|
||||
});
|
||||
|
||||
_newLineFilterBuffer.ConfigKeptSize(16*1024);
|
||||
}
|
||||
|
||||
ChannelOpenedText::~ChannelOpenedText()
|
||||
{
|
||||
delete _filter;
|
||||
delete _ringBuffer;
|
||||
}
|
||||
|
||||
void ChannelOpenedText::WriteData(const char * data, size_t length)
|
||||
{
|
||||
size_t dummy;
|
||||
this->_filter->Write(data, length, dummy);
|
||||
delete [] data;
|
||||
}
|
||||
|
||||
SubPlotWnd * ChannelOpenedText::CreateSubPlotWnd()
|
||||
{
|
||||
auto subWnd = new SubPlotWnd;
|
||||
|
||||
auto SThis = dynamic_pointer_cast<ChannelOpenedText, AsyncObject>(shared_from_this());
|
||||
|
||||
subWnd->EventMoveWindow.Subscribe([SThis](const void * sender, const CRect & rect){
|
||||
SThis->_rect = rect;
|
||||
});
|
||||
|
||||
subWnd->EventClosed.Subscribe([SThis](const void * sender, const bool & e){
|
||||
|
||||
auto SThis2 = SThis;
|
||||
SubPlotWnd * subPlotWnd = (SubPlotWnd *)sender;
|
||||
|
||||
SThis2->DoLater([SThis2, subPlotWnd](){
|
||||
if (SThis2->_plotWnd == subPlotWnd)
|
||||
SThis2->_plotWnd = 0;
|
||||
|
||||
auto subPlotWnd2 = subPlotWnd;
|
||||
SThis2->DoLater([subPlotWnd2](){
|
||||
delete subPlotWnd2;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
this->DoNow([SThis, subWnd](){
|
||||
subWnd->SetColor(SThis->_color);
|
||||
SThis->_plotWnd = subWnd;
|
||||
});
|
||||
|
||||
return subWnd;
|
||||
}
|
||||
|
||||
void ChannelOpenedText::SetRect(const CRect & rect)
|
||||
{
|
||||
auto shared_me = dynamic_pointer_cast<ChannelOpenedText, AsyncObject>(shared_from_this());
|
||||
TaskQueue()->QueueTask([shared_me, rect](){
|
||||
shared_me->_rect = rect;
|
||||
});
|
||||
}
|
||||
|
||||
std::shared_ptr<SoraDbgPlot::Task::TaskSimple> ChannelOpenedText::TaskGetSize(std::shared_ptr<size_t> size)
|
||||
{
|
||||
auto SThis = dynamic_pointer_cast<ChannelOpenedText, AsyncObject>(shared_from_this());
|
||||
auto task = make_shared<TaskSimple>(TaskQueue(), [SThis, size](){
|
||||
*size = SThis->_ringBuffer->RecordCount();
|
||||
});
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
size_t ChannelOpenedText::DataSize()
|
||||
{
|
||||
return this->_ringBuffer->RecordCount();
|
||||
}
|
||||
|
||||
char * ChannelOpenedText::GetData(size_t index, bool bFromOldest)
|
||||
{
|
||||
char * addr = 0;
|
||||
auto SThis = dynamic_pointer_cast<ChannelOpenedText, AsyncObject>(shared_from_this());
|
||||
TaskQueue()->DoTask([SThis, &addr, index, bFromOldest](){
|
||||
|
||||
size_t dataSize = SThis->DataSize();
|
||||
|
||||
if (dataSize <= index || index < 0)
|
||||
{
|
||||
addr = new char[1];
|
||||
addr[0] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
int index2 = bFromOldest ? dataSize - index - 1 : index;
|
||||
|
||||
size_t sizeOfData;
|
||||
bool succ = SThis->_ringBuffer->GetDataSizeByTimeStampIdx(index2, sizeOfData);
|
||||
|
||||
if (succ)
|
||||
{
|
||||
char * data = new char[sizeOfData + 1];
|
||||
size_t readSize;
|
||||
succ = SThis->_ringBuffer->ReadDataByTimeStampIdx(index2, data, sizeOfData, readSize);
|
||||
if (succ)
|
||||
{
|
||||
data[readSize] = 0;
|
||||
addr = data;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(FALSE);
|
||||
delete [] data;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
return addr;
|
||||
|
||||
}
|
||||
|
||||
void ChannelOpenedText::CloseSubPlotWnd()
|
||||
{
|
||||
auto SThis = dynamic_pointer_cast<ChannelOpenedText, AsyncObject>(shared_from_this());
|
||||
this->DoLater([SThis](){
|
||||
if (SThis->_plotWnd)
|
||||
{
|
||||
HWND hWnd = SThis->_plotWnd->m_hWnd;
|
||||
if (hWnd)
|
||||
::PostMessage(hWnd, WM_CLOSE, 0, 0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void ChannelOpenedText::SeekTimeStamp(unsigned long long timestamp)
|
||||
{
|
||||
auto SThis = dynamic_pointer_cast<ChannelOpenedText, AsyncObject>(shared_from_this());
|
||||
this->DoLater([SThis, timestamp](){
|
||||
if (SThis->DataSize() > 0)
|
||||
{
|
||||
unsigned long long out;
|
||||
size_t outIdx;
|
||||
bool found = SThis->_ringBuffer->GetNearestOldTimeStamp(timestamp, out, outIdx);
|
||||
if (found)
|
||||
SThis->_latestTimeIdx = outIdx;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void ChannelOpenedText::UpdateSubPlotWnd()
|
||||
{
|
||||
auto SThis = dynamic_pointer_cast<ChannelOpenedText, AsyncObject>(shared_from_this());
|
||||
this->DoLater([SThis](){
|
||||
if (SThis->_plotWnd)
|
||||
{
|
||||
if (SThis->DataSize() > 0)
|
||||
{
|
||||
char * data = SThis->GetData(SThis->_latestTimeIdx, false);
|
||||
CString str(data);
|
||||
SThis->_plotWnd->PlotText(str);
|
||||
delete [] data;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void ChannelOpenedText::GetRect(CRect & rect)
|
||||
{
|
||||
this->DoNow([this, &rect]() mutable {
|
||||
rect = this->_rect;
|
||||
});
|
||||
}
|
||||
|
||||
void ChannelOpenedText::OnColorUpdated()
|
||||
{
|
||||
ChannelOpenedTextType::OnColorUpdated();
|
||||
|
||||
auto SThis = dynamic_pointer_cast<ChannelOpenedText, AsyncObject>(shared_from_this());
|
||||
this->DoNow([SThis](){
|
||||
if (SThis->_plotWnd)
|
||||
{
|
||||
SThis->_plotWnd->SetColor(SThis->_color);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
HRESULT ChannelOpenedText::AppendXmlProperty(IXMLDOMDocument *pDom, IXMLDOMElement *pParent)
|
||||
{
|
||||
ChannelOpened::AppendXmlProperty(pDom, pParent);
|
||||
|
||||
auto SThis = dynamic_pointer_cast<ChannelOpenedText, AsyncObject>(shared_from_this());
|
||||
this->DoNow([SThis, pDom, pParent](){
|
||||
|
||||
IXMLDOMElement *pElement = NULL;
|
||||
|
||||
CreateAndAddElementNode(pDom, L"subRectTLX", L"\n\t\t\t", pParent, &pElement);
|
||||
pElement->put_text((_bstr_t)SThis->_rect.TopLeft().x);
|
||||
|
||||
CreateAndAddElementNode(pDom, L"subRectTLY", L"\n\t\t\t", pParent, &pElement);
|
||||
pElement->put_text((_bstr_t)SThis->_rect.TopLeft().y);
|
||||
|
||||
CreateAndAddElementNode(pDom, L"subRectBRX", L"\n\t\t\t", pParent, &pElement);
|
||||
pElement->put_text((_bstr_t)SThis->_rect.BottomRight().x);
|
||||
|
||||
CreateAndAddElementNode(pDom, L"subRectBRY", L"\n\t\t\t", pParent, &pElement);
|
||||
pElement->put_text((_bstr_t)SThis->_rect.BottomRight().y);
|
||||
});
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT ChannelOpenedText::LoadXmlElement(MSXML2::IXMLDOMNodePtr pElement)
|
||||
{
|
||||
ChannelOpened::LoadXmlElement(pElement);
|
||||
|
||||
CString cs;
|
||||
MSXML2::IXMLDOMNodePtr pNode;
|
||||
pNode = pElement->selectSingleNode(L"subRectTLX");
|
||||
if (pNode == 0)
|
||||
goto RET;
|
||||
int tlx = atoi((LPCSTR)(pNode->text));
|
||||
|
||||
pNode = pElement->selectSingleNode(L"subRectTLY");
|
||||
if (pNode == 0)
|
||||
goto RET;
|
||||
int tly =atoi((LPCSTR)(pNode->text));
|
||||
|
||||
pNode = pElement->selectSingleNode(L"subRectBRX");
|
||||
if (pNode == 0)
|
||||
goto RET;
|
||||
int brx =atoi((LPCSTR)(pNode->text));
|
||||
|
||||
pNode = pElement->selectSingleNode(L"subRectBRY");
|
||||
if (pNode == 0)
|
||||
goto RET;
|
||||
int bry = atoi((LPCSTR)(pNode->text));
|
||||
|
||||
this->_rect.SetRect(tlx,tly,brx,bry);
|
||||
|
||||
RET:
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
const wchar_t * ChannelOpenedText::GetTypeName()
|
||||
{
|
||||
return L"Text Channel";
|
||||
}
|
||||
|
||||
bool ChannelOpenedText::Export(const CString & filename, bool bAll)
|
||||
{
|
||||
auto SThis = dynamic_pointer_cast<ChannelOpenedText, AsyncObject>(shared_from_this());
|
||||
|
||||
this->DoLater([SThis, filename, bAll](){
|
||||
FILE * fp;
|
||||
errno_t ret = _wfopen_s(&fp, filename, L"wb");
|
||||
|
||||
if (ret == 0)
|
||||
{
|
||||
if (1)
|
||||
{
|
||||
SThis->_ringBuffer->Export([fp](const char * ptr, size_t length){
|
||||
fwrite(ptr, 1, length, fp);
|
||||
});
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ChannelOpenedText::ClearData()
|
||||
{
|
||||
this->_ringBuffer->Reset();
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include "TaskQueue.h"
|
||||
#include "ChannelOpenedTextType.h"
|
||||
#include "SubPlotWnd.h"
|
||||
#include "FrameWithSizeFilter.h"
|
||||
#include "RingBufferWithTimeStamp.h"
|
||||
#include "TempBuffer.h"
|
||||
|
||||
class ChannelOpenedText : public ChannelOpenedTextType
|
||||
{
|
||||
public:
|
||||
ChannelOpenedText();
|
||||
~ChannelOpenedText();
|
||||
void SetRect(const CRect & rect);
|
||||
SubPlotWnd * ChannelOpenedText::CreateSubPlotWnd();
|
||||
void CloseSubPlotWnd();
|
||||
void UpdateSubPlotWnd();
|
||||
void SeekTimeStamp(unsigned long long timestamp);
|
||||
virtual HRESULT AppendXmlProperty(IXMLDOMDocument *pDom, IXMLDOMElement *pParent);
|
||||
virtual HRESULT LoadXmlElement(MSXML2::IXMLDOMNodePtr pElement);
|
||||
virtual void GetRect(CRect & rect);
|
||||
virtual const wchar_t * GetTypeName();
|
||||
virtual bool Export(const CString &, bool bAll);
|
||||
|
||||
//virtual void CloseChannel();
|
||||
|
||||
protected:
|
||||
virtual void WriteData(const char * data, size_t length);
|
||||
virtual std::shared_ptr<SoraDbgPlot::Task::TaskSimple> TaskGetSize(std::shared_ptr<size_t>);
|
||||
virtual size_t DataSize();
|
||||
virtual char * GetData(size_t index, bool bFromOldest);
|
||||
virtual void OnColorUpdated();
|
||||
virtual void ClearData();
|
||||
|
||||
private:
|
||||
SoraDbgPlot::FrameWithSizeInfoWriter<char> * _filter;
|
||||
RingBufferWithTimeStamp<char> * _ringBuffer;
|
||||
SubPlotWnd * _plotWnd;
|
||||
CRect _rect;
|
||||
size_t _latestTimeIdx;
|
||||
|
||||
SoraDbgPlot::Buffer::TempBuffer _newLineFilterBuffer;
|
||||
};
|
|
@ -0,0 +1,33 @@
|
|||
#include "stdafx.h"
|
||||
#include "ChannelOpenedTextType.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
ChannelOpenedTextType::ChannelOpenedTextType()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
ChannelOpenedTextType::~ChannelOpenedTextType()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void ChannelOpenedTextType::OnColorUpdated()
|
||||
{
|
||||
EventColor.Raise(this, _color);
|
||||
}
|
||||
|
||||
void ChannelOpenedTextType::Clear()
|
||||
{
|
||||
EventColor.Reset();
|
||||
ChannelOpened::Clear();
|
||||
}
|
||||
|
||||
void ChannelOpenedTextType::ForColor(const std::function<void(COLORREF)> & f)
|
||||
{
|
||||
auto SThis = dynamic_pointer_cast<ChannelOpenedTextType, AsyncObject>(shared_from_this());
|
||||
this->DoLater([SThis, f](){
|
||||
f(SThis->_color);
|
||||
});
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
#pragma once
|
||||
#include "ChannelOpened.h"
|
||||
|
||||
class ChannelOpenedTextType : public ChannelOpened
|
||||
{
|
||||
public:
|
||||
ChannelOpenedTextType();
|
||||
~ChannelOpenedTextType();
|
||||
|
||||
SoraDbgPlot::Event::Event<COLORREF> EventColor;
|
||||
|
||||
void ForColor(const std::function<void(COLORREF)> & f);
|
||||
|
||||
virtual void Clear();
|
||||
virtual void OnColorUpdated();
|
||||
|
||||
virtual std::shared_ptr<SoraDbgPlot::Task::TaskSimple> TaskGetSize(std::shared_ptr<size_t>) = 0;
|
||||
virtual size_t DataSize() = 0;
|
||||
virtual char * GetData(size_t index, bool bFromOldest) = 0;
|
||||
};
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
// ChannelProperty.cpp : implementation file
|
||||
//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "DbgPlotViewer.h"
|
||||
#include "ChannelProperty.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
// ChannelProperty
|
||||
|
||||
IMPLEMENT_DYNAMIC(ChannelProperty, BaseProperty)
|
||||
|
||||
ChannelProperty::ChannelProperty(const wstring & typeName, const wstring & name, COLORREF color)
|
||||
{
|
||||
_typename = typeName;
|
||||
_name = name;
|
||||
_color = color;
|
||||
}
|
||||
|
||||
ChannelProperty::~ChannelProperty()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
BEGIN_MESSAGE_MAP(ChannelProperty, BaseProperty)
|
||||
ON_WM_CREATE()
|
||||
END_MESSAGE_MAP()
|
||||
|
||||
|
||||
|
||||
// ChannelProperty message handlers
|
||||
|
||||
|
||||
int ChannelProperty::OnCreate(LPCREATESTRUCT lpCreateStruct)
|
||||
{
|
||||
if (BaseProperty::OnCreate(lpCreateStruct) == -1)
|
||||
return -1;
|
||||
|
||||
CMFCPropertyGridProperty * pProp;
|
||||
|
||||
pProp = new CMFCPropertyGridProperty(_T("Type"), _typename.c_str());
|
||||
pProp->Enable(FALSE);
|
||||
this->AddProperty(pProp);
|
||||
|
||||
pProp = new CMFCPropertyGridProperty(_T("Name"), _name.c_str());
|
||||
pProp->Enable(FALSE);
|
||||
this->AddProperty(pProp);
|
||||
|
||||
CMFCPropertyGridColorProperty* pColorProp = new CMFCPropertyGridColorProperty(_T("Color"), _color, NULL);
|
||||
pColorProp->EnableOtherButton(_T("Other..."));
|
||||
pColorProp->EnableAutomaticButton(_T("Default"), ::GetSysColor(COLOR_3DFACE));
|
||||
this->AddProperty(pColorProp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void ChannelProperty::OnPropertyChanged(CMFCPropertyGridProperty* pProp) const
|
||||
{
|
||||
// TODO: Add your specialized code here and/or call the base class
|
||||
|
||||
if (wcscmp(pProp->GetName(), L"Color") == 0)
|
||||
{
|
||||
COLORREF color = ((CMFCPropertyGridColorProperty *)pProp)->GetColor();
|
||||
EventColor.Raise(0, color);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT(false); // impossible
|
||||
}
|
||||
|
||||
return BaseProperty::OnPropertyChanged(pProp);
|
||||
}
|
||||
|
||||
void ChannelProperty::OnCloseProperty()
|
||||
{
|
||||
EventColor.Reset();
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
#pragma once
|
||||
|
||||
#include "BaseProperty.h"
|
||||
#include "Event.h"
|
||||
|
||||
// ChannelProperty
|
||||
|
||||
class ChannelProperty : public BaseProperty
|
||||
{
|
||||
DECLARE_DYNAMIC(ChannelProperty)
|
||||
|
||||
public:
|
||||
ChannelProperty(const std::wstring &, const std::wstring &, COLORREF);
|
||||
virtual ~ChannelProperty();
|
||||
|
||||
protected:
|
||||
virtual void OnCloseProperty();
|
||||
|
||||
protected:
|
||||
DECLARE_MESSAGE_MAP()
|
||||
public:
|
||||
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
|
||||
virtual void OnPropertyChanged(CMFCPropertyGridProperty* pProp) const;
|
||||
|
||||
|
||||
public:
|
||||
void SetColor(COLORREF color);
|
||||
SoraDbgPlot::Event::Event<COLORREF> EventColor;
|
||||
|
||||
private:
|
||||
std::wstring _typename;
|
||||
std::wstring _name;
|
||||
COLORREF _color;
|
||||
};
|
||||
|
||||
|
|
@ -0,0 +1,418 @@
|
|||
// ChannelTreeCtrl.cpp : implementation file
|
||||
//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include <memory>
|
||||
#include "DbgPlotViewer.h"
|
||||
#include "ChannelTreeCtrl.h"
|
||||
#include "ChannelOpened.h"
|
||||
#include "ChannelOpenedLine.h"
|
||||
#include "ChannelOpenedDots.h"
|
||||
#include "ChannelOpenedLog.h"
|
||||
#include "ChannelOpenedText.h"
|
||||
#include "ChannelOpenedSpectrum.h"
|
||||
#include "PlotWnd.h"
|
||||
#include "ChannelAddable.h"
|
||||
#include "Targetable.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
// ChannelTreeCtrl
|
||||
|
||||
IMPLEMENT_DYNAMIC(ChannelTreeCtrl, CTreeCtrl)
|
||||
|
||||
ChannelTreeCtrl::ChannelTreeCtrl()
|
||||
{
|
||||
_bDragging = false;
|
||||
}
|
||||
|
||||
ChannelTreeCtrl::~ChannelTreeCtrl()
|
||||
{
|
||||
_pvTaskQueue.Execute(true);
|
||||
}
|
||||
|
||||
void ChannelTreeCtrl::UpdateTreeData(const std::map<std::shared_ptr<ProcessOpened>, std::set<std::shared_ptr<ChannelOpened> > > & tree)
|
||||
{
|
||||
_pvTaskQueue.Queue([this, tree](bool bClose){
|
||||
if (bClose)
|
||||
return;
|
||||
|
||||
this->_processChannelTree = tree;
|
||||
this->UpdateTreeView();
|
||||
});
|
||||
|
||||
HWND hWnd = m_hWnd;
|
||||
if (hWnd)
|
||||
::PostMessage(hWnd, WMME_EXE_TASKQUEUE, 0, 0);
|
||||
}
|
||||
|
||||
void ChannelTreeCtrl::UpdateTreeView()
|
||||
{
|
||||
this->SetRedraw(FALSE);
|
||||
this->DeleteAllItems();
|
||||
|
||||
for (auto iterPsChMap = _processChannelTree.begin(); iterPsChMap != _processChannelTree.end(); ++iterPsChMap)
|
||||
{
|
||||
auto process = iterPsChMap->first;
|
||||
CString str;
|
||||
str.Format(L"%s(%d)", process->Name().c_str(), process->Pid());
|
||||
|
||||
int imgIdx = true ? 10 : 11;
|
||||
|
||||
HTREEITEM hProcess = this->InsertItem(TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE| TVIF_SELECTEDIMAGE | TVIF_STATE, str.GetBuffer(), imgIdx, imgIdx, 0, 0, (LPARAM)process.get(), 0, TVI_SORT);
|
||||
|
||||
auto channelMap = iterPsChMap->second;
|
||||
for (auto iterChannel = channelMap.begin(); iterChannel != channelMap.end(); ++iterChannel)
|
||||
{
|
||||
auto channel = *iterChannel;
|
||||
CString str;
|
||||
str.Format(L"%s", channel->Name().c_str());
|
||||
|
||||
int imgIdx = 0;
|
||||
if (typeid(*channel) == typeid(ChannelOpenedLine))
|
||||
imgIdx = 0;
|
||||
else if (typeid(*channel) == typeid(ChannelOpenedDots))
|
||||
imgIdx = 2;
|
||||
else if (typeid(*channel) == typeid(ChannelOpenedSpectrum))
|
||||
imgIdx = 4;
|
||||
else if (typeid(*channel) == typeid(ChannelOpenedLog))
|
||||
imgIdx = 6;
|
||||
else if (typeid(*channel) == typeid(ChannelOpenedText))
|
||||
imgIdx = 8;
|
||||
|
||||
if (! channel->IsAttatched())
|
||||
imgIdx++;
|
||||
|
||||
HTREEITEM hItem = this->InsertItem(TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_STATE, str.GetBuffer(), imgIdx, imgIdx, 0, 0, (LPARAM)channel.get(), hProcess, TVI_SORT);
|
||||
}
|
||||
|
||||
this->Expand(hProcess, TVE_EXPAND);
|
||||
}
|
||||
|
||||
this->SetRedraw(TRUE);
|
||||
}
|
||||
|
||||
BEGIN_MESSAGE_MAP(ChannelTreeCtrl, CTreeCtrl)
|
||||
ON_NOTIFY_REFLECT(TVN_BEGINDRAG, &ChannelTreeCtrl::OnTvnBegindrag)
|
||||
ON_WM_MOUSEMOVE()
|
||||
ON_WM_CLOSE()
|
||||
ON_MESSAGE(WMME_EXE_TASKQUEUE, OnExeTaskQueue)
|
||||
ON_WM_LBUTTONUP()
|
||||
ON_NOTIFY_REFLECT(NM_CLICK, &ChannelTreeCtrl::OnNMClick)
|
||||
ON_WM_CONTEXTMENU()
|
||||
ON_NOTIFY_REFLECT(NM_RCLICK, &ChannelTreeCtrl::OnNMRClick)
|
||||
ON_COMMAND(ID_CLOSE_CHANNEL, OnCloseChannel)
|
||||
ON_COMMAND(ID_CHANNEL_SAVESELECTION, OnChannelSaveSelection)
|
||||
ON_COMMAND(ID_CHANNEL_SAVEALL, OnChannelSaveAll)
|
||||
ON_COMMAND(ID_CHANNEL_CLOSE, OnTextChannelClose)
|
||||
ON_COMMAND(ID_CHANNEL_EXPORT, OnTextChannelExport)
|
||||
END_MESSAGE_MAP()
|
||||
|
||||
|
||||
|
||||
// ChannelTreeCtrl message handlers
|
||||
|
||||
|
||||
|
||||
|
||||
void ChannelTreeCtrl::OnTvnBegindrag(NMHDR *pNMHDR, LRESULT *pResult)
|
||||
{
|
||||
LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
|
||||
// TODO: Add your control notification handler code here
|
||||
|
||||
auto obj = (PropObject *)pNMTreeView->itemNew.lParam;
|
||||
this->SelectItem(pNMTreeView->itemNew.hItem);
|
||||
auto spObj = obj->shared_from_this();
|
||||
auto channel = dynamic_pointer_cast<ChannelOpened, AsyncObject>(spObj);
|
||||
|
||||
if (channel && channel->IsAttatched())
|
||||
{
|
||||
TRACE0("Channel dragged\n");
|
||||
SetCapture();
|
||||
_bDragging = true;
|
||||
_channelDragged = channel;
|
||||
}
|
||||
|
||||
|
||||
*pResult = 0;
|
||||
}
|
||||
|
||||
|
||||
void ChannelTreeCtrl::OnMouseMove(UINT nFlags, CPoint point)
|
||||
{
|
||||
// TODO: Add your message handler code here and/or call default
|
||||
|
||||
if (_bDragging)
|
||||
{
|
||||
CPoint pointParam;
|
||||
auto obj = FindTarget(pointParam);
|
||||
|
||||
if (obj != _lastObj)
|
||||
{
|
||||
if (_lastObj)
|
||||
_lastObj->Highlight(false);
|
||||
|
||||
_lastObj = obj;
|
||||
}
|
||||
|
||||
if (obj)
|
||||
{
|
||||
::SetCursor(::LoadCursor(NULL, IDC_ARROW));
|
||||
obj->Highlight(true);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
::SetCursor(::LoadCursor(NULL, IDC_NO));
|
||||
}
|
||||
}
|
||||
|
||||
CTreeCtrl::OnMouseMove(nFlags, point);
|
||||
}
|
||||
|
||||
|
||||
void ChannelTreeCtrl::OnClose()
|
||||
{
|
||||
// TODO: Add your message handler code here and/or call default
|
||||
|
||||
//_pvTaskQueue.Execute(true);
|
||||
|
||||
CTreeCtrl::OnClose();
|
||||
}
|
||||
|
||||
LRESULT ChannelTreeCtrl::OnExeTaskQueue(WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
_pvTaskQueue.Execute(false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
shared_ptr<ChannelAddable> ChannelTreeCtrl::FindTarget(CPoint & pointOut)
|
||||
{
|
||||
CPoint screenCursorPoint;
|
||||
GetCursorPos(&screenCursorPoint);
|
||||
CWnd * wnd = WindowFromPoint(screenCursorPoint);
|
||||
|
||||
DWORD processId;
|
||||
::GetWindowThreadProcessId(wnd->GetSafeHwnd(), &processId);
|
||||
if ( processId != ::GetProcessId(::GetCurrentProcess()) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto targetable = dynamic_cast<Targetable *>(wnd);
|
||||
if (targetable)
|
||||
{
|
||||
auto channelAddable = (ChannelAddable *)targetable->UserData();
|
||||
ASSERT(channelAddable);
|
||||
|
||||
if (channelAddable->Accept(_channelDragged, screenCursorPoint, pointOut))
|
||||
return dynamic_pointer_cast<ChannelAddable, AsyncObject>(channelAddable->shared_from_this());
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ChannelTreeCtrl::OnLButtonUp(UINT nFlags, CPoint point)
|
||||
{
|
||||
// TODO: Add your message handler code here and/or call default
|
||||
|
||||
if (_bDragging)
|
||||
{
|
||||
CPoint pointOut;
|
||||
|
||||
auto obj = this->FindTarget(pointOut);
|
||||
|
||||
if (obj)
|
||||
{
|
||||
obj->Highlight(false);
|
||||
|
||||
if (_channelDragged->IsAttatched())
|
||||
{
|
||||
shared_ptr<ProcessOpened> processOpened;
|
||||
for (auto iterPs = _processChannelTree.begin(); iterPs != _processChannelTree.end(); ++iterPs)
|
||||
{
|
||||
auto process = iterPs->first;
|
||||
auto chMap = iterPs->second;
|
||||
auto iterCh = chMap.find(_channelDragged);
|
||||
if (iterCh != chMap.end())
|
||||
{
|
||||
processOpened = iterPs->first;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT(processOpened != 0);
|
||||
|
||||
obj->RequestAddChannel(processOpened, _channelDragged, pointOut);
|
||||
}
|
||||
}
|
||||
|
||||
ReleaseCapture();
|
||||
_lastObj = 0;
|
||||
_bDragging = false;
|
||||
}
|
||||
|
||||
CTreeCtrl::OnLButtonUp(nFlags, point);
|
||||
}
|
||||
|
||||
|
||||
void ChannelTreeCtrl::PostNcDestroy()
|
||||
{
|
||||
// TODO: Add your specialized code here and/or call the base class
|
||||
|
||||
_pvTaskQueue.Execute(true);
|
||||
|
||||
EventObjSelected.Reset();
|
||||
EventCloseChannel.Reset();
|
||||
EventClosed.Raise(this, true);
|
||||
|
||||
CTreeCtrl::PostNcDestroy();
|
||||
}
|
||||
|
||||
|
||||
void ChannelTreeCtrl::OnNMClick(NMHDR *pNMHDR, LRESULT *pResult)
|
||||
{
|
||||
DWORD dw = GetMessagePos(); // Mouse position
|
||||
CPoint p(GET_X_LPARAM(dw), GET_Y_LPARAM(dw));
|
||||
this->ScreenToClient(&p);
|
||||
|
||||
UINT htFlags = 0;
|
||||
HTREEITEM hHitItem= this->HitTest(p, &htFlags);
|
||||
|
||||
if (htFlags & TVHT_ONITEM)
|
||||
{
|
||||
auto obj = (PropObject *)this->GetItemData(hHitItem);
|
||||
auto spObj = dynamic_pointer_cast<PropObject, AsyncObject>(obj->shared_from_this());
|
||||
|
||||
this->EventObjSelected.Raise(this, spObj);
|
||||
}
|
||||
|
||||
*pResult = 0;
|
||||
}
|
||||
|
||||
bool ChannelTreeCtrl::ShowFileDialog(CString & filename)
|
||||
{
|
||||
CFileDialog dlgFile(FALSE, L"txt", 0, 6UL, L"Text file(*.txt)\0*.txt\0All file(*.*)\0*.*\0\0");
|
||||
CString fileName;
|
||||
const int c_cMaxFiles = 100;
|
||||
const int c_cbBuffSize = (c_cMaxFiles * (MAX_PATH + 1)) + 1;
|
||||
dlgFile.GetOFN().lpstrFile = fileName.GetBuffer(c_cbBuffSize);
|
||||
dlgFile.GetOFN().nMaxFile = c_cbBuffSize;
|
||||
|
||||
if (IDOK == dlgFile.DoModal())
|
||||
{
|
||||
|
||||
FILE * fp;
|
||||
errno_t ret = _wfopen_s(&fp, fileName, L"wb");
|
||||
|
||||
bool completeBlock = true;
|
||||
if (ret == 0)
|
||||
{
|
||||
fclose(fp);
|
||||
filename = fileName;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
CString errMsg;
|
||||
errMsg.Format(L"Open file error: %x\n", ret);
|
||||
::AfxMessageBox(errMsg);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void ChannelTreeCtrl::OnContextMenu(CWnd* /*pWnd*/, CPoint point)
|
||||
{
|
||||
bool bOpened = _contextMenuObj->GetOpenState();
|
||||
if (!bOpened)
|
||||
return;
|
||||
|
||||
auto channelText = dynamic_pointer_cast<ChannelOpenedText, PropObject>(_contextMenuObj);
|
||||
if (channelText)
|
||||
{
|
||||
theApp.GetContextMenuManager()->ShowPopupMenu(IDR_POPUP_TEXT_CHANNEL, point.x, point.y, this, TRUE);
|
||||
return;
|
||||
}
|
||||
|
||||
auto channelLog = dynamic_pointer_cast<ChannelOpenedLog, PropObject>(_contextMenuObj);
|
||||
if (channelLog)
|
||||
{
|
||||
theApp.GetContextMenuManager()->ShowPopupMenu(IDR_POPUP_TEXT_CHANNEL, point.x, point.y, this, TRUE);
|
||||
return;
|
||||
}
|
||||
|
||||
auto channel = dynamic_pointer_cast<ChannelOpened, PropObject>(_contextMenuObj);
|
||||
if (channel)
|
||||
{
|
||||
theApp.GetContextMenuManager()->ShowPopupMenu(IDR_POPUP_CHANNEL_EXPLORER, point.x, point.y, this, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ChannelTreeCtrl::OnNMRClick(NMHDR *pNMHDR, LRESULT *pResult)
|
||||
{
|
||||
DWORD dw = GetMessagePos(); // Mouse position
|
||||
CPoint p(GET_X_LPARAM(dw), GET_Y_LPARAM(dw));
|
||||
this->ScreenToClient(&p);
|
||||
|
||||
UINT htFlags = 0;
|
||||
HTREEITEM hHitItem= this->HitTest(p, &htFlags);
|
||||
|
||||
if (htFlags & TVHT_ONITEM)
|
||||
{
|
||||
HTREEITEM hItemOld = this->GetSelectedItem();
|
||||
this->SelectItem(hHitItem);
|
||||
|
||||
auto obj = (PropObject *)this->GetItemData(hHitItem);
|
||||
auto spObj = dynamic_pointer_cast<ChannelOpened, AsyncObject>(obj->shared_from_this());
|
||||
|
||||
if (spObj != 0)
|
||||
{
|
||||
_contextMenuObj = spObj;
|
||||
SendMessage(WM_CONTEXTMENU, (WPARAM) m_hWnd, GetMessagePos());
|
||||
}
|
||||
}
|
||||
|
||||
*pResult = 1;
|
||||
}
|
||||
|
||||
void ChannelTreeCtrl::OnCloseChannel()
|
||||
{
|
||||
this->EventCloseChannel.Raise(this, _contextMenuObj);
|
||||
}
|
||||
|
||||
void ChannelTreeCtrl::OnChannelSaveSelection()
|
||||
{
|
||||
CString fileName;
|
||||
bool succ = ShowFileDialog(fileName);
|
||||
if (succ)
|
||||
_contextMenuObj->Export(fileName, false);
|
||||
}
|
||||
|
||||
void ChannelTreeCtrl::OnChannelSaveAll()
|
||||
{
|
||||
CString fileName;
|
||||
bool succ = ShowFileDialog(fileName);
|
||||
if (succ)
|
||||
_contextMenuObj->Export(fileName, true);
|
||||
}
|
||||
|
||||
void ChannelTreeCtrl::OnTextChannelExport()
|
||||
{
|
||||
CString fileName;
|
||||
bool succ = ShowFileDialog(fileName);
|
||||
if (succ)
|
||||
_contextMenuObj->Export(fileName, true);
|
||||
}
|
||||
|
||||
void ChannelTreeCtrl::OnTextChannelClose()
|
||||
{
|
||||
this->EventCloseChannel.Raise(this, _contextMenuObj);
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
#pragma once
|
||||
|
||||
#include "ChannelOpened.h"
|
||||
#include "ProcessOpened.h"
|
||||
#include "PropObject.h"
|
||||
#include "PassiveTaskQueue.h"
|
||||
#include "ChannelAddable.h"
|
||||
#include "Event.h"
|
||||
|
||||
// ChannelTreeCtrl
|
||||
#define WMME_EXE_TASKQUEUE (WM_APP+1)
|
||||
|
||||
class ChannelTreeCtrl : public CTreeCtrl
|
||||
{
|
||||
DECLARE_DYNAMIC(ChannelTreeCtrl)
|
||||
|
||||
public:
|
||||
ChannelTreeCtrl();
|
||||
virtual ~ChannelTreeCtrl();
|
||||
|
||||
void UpdateTreeData(const std::map<std::shared_ptr<ProcessOpened>, std::set<std::shared_ptr<ChannelOpened> > > & tree);
|
||||
|
||||
SoraDbgPlot::Event::Event<bool> EventClosed;
|
||||
SoraDbgPlot::Event::Event<std::shared_ptr<PropObject> > EventObjSelected;
|
||||
|
||||
SoraDbgPlot::Event::Event<std::shared_ptr<ChannelOpened> > EventCloseChannel;
|
||||
|
||||
private:
|
||||
bool ShowFileDialog(CString & filename);
|
||||
|
||||
private:
|
||||
void UpdateTreeView();
|
||||
std::shared_ptr<ChannelAddable> FindTarget(CPoint & pointOut);
|
||||
|
||||
|
||||
protected:
|
||||
DECLARE_MESSAGE_MAP()
|
||||
|
||||
private:
|
||||
std::map<std::shared_ptr<ProcessOpened>, std::set<std::shared_ptr<ChannelOpened> > > _processChannelTree;
|
||||
|
||||
std::shared_ptr<ChannelOpened> _channelDragged;
|
||||
|
||||
bool _bDragging;
|
||||
std::shared_ptr<ChannelAddable> _lastObj;
|
||||
std::shared_ptr<ChannelOpened> _contextMenuObj;
|
||||
|
||||
void HighlightWindow(CWnd * wnd, bool highlight);
|
||||
public:
|
||||
afx_msg void OnTvnBegindrag(NMHDR *pNMHDR, LRESULT *pResult);
|
||||
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
|
||||
afx_msg void OnClose();
|
||||
afx_msg LRESULT OnExeTaskQueue(WPARAM, LPARAM);
|
||||
|
||||
private:
|
||||
PassiveTaskQueue _pvTaskQueue;
|
||||
public:
|
||||
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
|
||||
virtual void PostNcDestroy();
|
||||
afx_msg void OnNMClick(NMHDR *pNMHDR, LRESULT *pResult);
|
||||
afx_msg void OnContextMenu(CWnd* /*pWnd*/, CPoint /*point*/);
|
||||
afx_msg void OnNMRClick(NMHDR *pNMHDR, LRESULT *pResult); afx_msg void OnCloseChannel();
|
||||
afx_msg void OnChannelSaveSelection();
|
||||
afx_msg void OnChannelSaveAll();
|
||||
afx_msg void OnTextChannelExport();
|
||||
afx_msg void OnTextChannelClose();
|
||||
};
|
||||
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ClassDiagram />
|
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ClassDiagram />
|
|
@ -0,0 +1,147 @@
|
|||
#include "stdafx.h"
|
||||
#include "ControlPanelDriver.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
ControlPanelDriver::~ControlPanelDriver()
|
||||
{
|
||||
}
|
||||
|
||||
std::shared_ptr<CWnd> ControlPanelDriver::GetControlWnd()
|
||||
{
|
||||
shared_ptr<CWnd> ret;
|
||||
auto SThis = dynamic_pointer_cast<ControlPanelDriver, AsyncObject>(shared_from_this());
|
||||
this->DoNow([SThis, &ret](){
|
||||
if (SThis->_controlPanelList == 0)
|
||||
{
|
||||
SThis->_controlPanelList = make_shared<ControlPanelList>();
|
||||
}
|
||||
|
||||
ret = SThis->_controlPanelList;
|
||||
});
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ControlPanelDriver::AddProcessOpened(std::shared_ptr<ProcessOpened> process)
|
||||
{
|
||||
auto SThis = dynamic_pointer_cast<ControlPanelDriver, AsyncObject>(shared_from_this());
|
||||
this->DoLater([SThis, process](){
|
||||
|
||||
auto process2 = process;
|
||||
|
||||
auto iter = SThis->_processWndMap.find(process);
|
||||
if (iter == SThis->_processWndMap.end())
|
||||
{
|
||||
CString caption;
|
||||
caption.Format(L"%s(%d)", process2->Name().c_str(), process2->Pid());
|
||||
|
||||
auto wnd = make_shared<ControlPanelWnd>(caption);
|
||||
|
||||
wnd->EventPlayPause.Subscribe([process2](const void * sender, const bool & bPlayPause){
|
||||
process2->TraceBarPlayPause(bPlayPause);
|
||||
});
|
||||
|
||||
wnd->EventSingleStep.Subscribe([process2](const void * sender, const bool & dummy){
|
||||
process2->TraceBarSingleStep();
|
||||
});
|
||||
|
||||
wnd->EventTraceBarSizeChanged.Subscribe([process2](const void * sender, const CRect & rect){
|
||||
process2->SetBitmapRect(rect);
|
||||
});
|
||||
|
||||
wnd->EventTraceBarWheel.Subscribe([process2](const void * sender, const bool & isUp){
|
||||
process2->TrackBarWheel(isUp);
|
||||
});
|
||||
|
||||
wnd->EventTraceBarSeek.Subscribe([process2](const void * sender, const double & pos){
|
||||
process2->TrackBarSeek(pos);
|
||||
});
|
||||
|
||||
auto SThis2 = SThis;
|
||||
wnd->EventClosed.Subscribe([SThis2, process2](const void * sender, const bool & e){
|
||||
|
||||
auto SThis = SThis2;
|
||||
auto process = process2;
|
||||
SThis->DoLater([SThis, process](){
|
||||
auto iter = SThis->_processWndMap.find(process);
|
||||
assert(process);
|
||||
auto wnd = iter->second;
|
||||
SThis->_processWndMap.erase(process);
|
||||
SThis->_processIsUpdating.erase(process);
|
||||
if (SThis->_controlPanelList)
|
||||
{
|
||||
SThis->_controlPanelList->RemoveControlPanelWnd(wnd);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
SThis->_processWndMap.insert(make_pair(process, wnd));
|
||||
SThis->_processIsUpdating.insert(make_pair(process, false));
|
||||
|
||||
if (SThis->_controlPanelList)
|
||||
{
|
||||
SThis->_controlPanelList->AddControlPanelWnd(wnd);
|
||||
}
|
||||
TRACE1("Process Opened activated %d\n", process->Pid());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void ControlPanelDriver::RemoveProcess(std::shared_ptr<ProcessOpened> process)
|
||||
{
|
||||
auto SThis = dynamic_pointer_cast<ControlPanelDriver, AsyncObject>(shared_from_this());
|
||||
this->DoLater([SThis, process](){
|
||||
auto iter = SThis->_processWndMap.find(process);
|
||||
|
||||
if (iter == SThis->_processWndMap.end())
|
||||
{
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
auto wnd = iter->second;
|
||||
|
||||
HWND hWnd = wnd->m_hWnd;
|
||||
if (hWnd)
|
||||
::PostMessage(hWnd, WM_CLOSE, 0, 0);
|
||||
});
|
||||
}
|
||||
|
||||
void ControlPanelDriver::Update()
|
||||
{
|
||||
auto SThis = dynamic_pointer_cast<ControlPanelDriver, AsyncObject>(shared_from_this());
|
||||
this->DoLater([SThis](){
|
||||
for (auto iter = SThis->_processWndMap.begin(); iter != SThis->_processWndMap.end(); ++iter)
|
||||
{
|
||||
auto process = iter->first;
|
||||
auto wnd = iter->second;
|
||||
bool bProcessUpdating = SThis->_processIsUpdating.find(process)->second;
|
||||
if (bProcessUpdating)
|
||||
continue;
|
||||
|
||||
auto SThis2 = SThis;
|
||||
process->GenUpdateData([SThis2](Bitmap * bitmap, bool isRawDataBufInUse, shared_ptr<ProcessOpened> process){
|
||||
auto SThis3 = SThis2;
|
||||
SThis2->DoLater([SThis3, bitmap, isRawDataBufInUse, process](){
|
||||
auto iter = SThis3->_processWndMap.find(process);
|
||||
if (iter != SThis3->_processWndMap.end())
|
||||
{
|
||||
auto wnd = iter->second;
|
||||
wnd->SetBitmap(bitmap);
|
||||
wnd->EnableButton(isRawDataBufInUse);
|
||||
}
|
||||
|
||||
auto iterUpdate = SThis3->_processIsUpdating.find(process);
|
||||
if (iterUpdate != SThis3->_processIsUpdating.end())
|
||||
iterUpdate->second = false;
|
||||
});
|
||||
});
|
||||
}
|
||||
}, [](){});
|
||||
}
|
||||
|
||||
void ControlPanelDriver::Clear()
|
||||
{
|
||||
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include "AsyncObject.h"
|
||||
#include "ProcessOpened.h"
|
||||
#include "ControlPanelWnd.h"
|
||||
#include "ControlPanelList.h"
|
||||
|
||||
class ControlPanelDriver : public AsyncObject
|
||||
{
|
||||
public:
|
||||
~ControlPanelDriver();
|
||||
std::shared_ptr<CWnd> GetControlWnd();
|
||||
void AddProcessOpened(std::shared_ptr<ProcessOpened>);
|
||||
void RemoveProcess(std::shared_ptr<ProcessOpened>);
|
||||
void Update();
|
||||
void Clear();
|
||||
private:
|
||||
std::shared_ptr<ControlPanelList> _controlPanelList;
|
||||
std::map<std::shared_ptr<ProcessOpened>, std::shared_ptr<ControlPanelWnd> > _processWndMap;
|
||||
std::map<std::shared_ptr<ProcessOpened>, bool> _processIsUpdating;
|
||||
};
|
|
@ -0,0 +1,131 @@
|
|||
// ControlPanelList.cpp : implementation file
|
||||
//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include <algorithm>
|
||||
#include "DbgPlotViewer.h"
|
||||
#include "ControlPanelList.h"
|
||||
|
||||
|
||||
// ControlPanelList
|
||||
|
||||
IMPLEMENT_DYNAMIC(ControlPanelList, Invokable)
|
||||
|
||||
ControlPanelList::ControlPanelList()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
ControlPanelList::~ControlPanelList()
|
||||
{
|
||||
}
|
||||
|
||||
void ControlPanelList::AddControlPanelWnd(std::shared_ptr<ControlPanelWnd> wnd)
|
||||
{
|
||||
this->Invoke([this, wnd](bool close){
|
||||
|
||||
if (close)
|
||||
return;
|
||||
|
||||
if (m_hWnd == 0)
|
||||
return;
|
||||
|
||||
this->_controlPanelList.push_back(wnd);
|
||||
CRect rectDummy;
|
||||
rectDummy.SetRectEmpty();
|
||||
wnd->Create(NULL, NULL, WS_CHILD | WS_VISIBLE, rectDummy, this, 0);
|
||||
if (this->m_hWnd)
|
||||
this->AdjustLayout();
|
||||
});
|
||||
}
|
||||
|
||||
void ControlPanelList::RemoveControlPanelWnd(std::shared_ptr<ControlPanelWnd> wnd)
|
||||
{
|
||||
this->Invoke([this, wnd](bool close){
|
||||
|
||||
if (close)
|
||||
return;
|
||||
|
||||
auto iter = std::find(this->_controlPanelList.begin(), this->_controlPanelList.end(), wnd);
|
||||
assert(iter != this->_controlPanelList.end());
|
||||
this->_controlPanelList.erase(iter);
|
||||
if (this->m_hWnd)
|
||||
this->AdjustLayout();
|
||||
});
|
||||
}
|
||||
|
||||
void ControlPanelList::AdjustLayout()
|
||||
{
|
||||
CRect rect;
|
||||
this->GetClientRect(&rect);
|
||||
int width = rect.Width();
|
||||
|
||||
int y = 0;
|
||||
const int WND_HEIGHT= ControlPanelWnd::Height();
|
||||
const int MARGIN = 1;
|
||||
|
||||
for (
|
||||
auto iterWnd = _controlPanelList.begin();
|
||||
iterWnd != _controlPanelList.end();
|
||||
++iterWnd)
|
||||
{
|
||||
auto& wnd = *iterWnd;
|
||||
if (wnd->m_hWnd)
|
||||
{
|
||||
wnd->MoveWindow(0, y, width, WND_HEIGHT, 1);
|
||||
y += WND_HEIGHT + MARGIN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BEGIN_MESSAGE_MAP(ControlPanelList, Invokable)
|
||||
ON_WM_SIZE()
|
||||
ON_WM_PAINT()
|
||||
END_MESSAGE_MAP()
|
||||
|
||||
|
||||
// ControlPanelList message handlers
|
||||
|
||||
void ControlPanelList::OnSize(UINT nType, int cx, int cy)
|
||||
{
|
||||
Invokable::OnSize(nType, cx, cy);
|
||||
|
||||
// TODO: Add your message handler code here
|
||||
this->Invoke([this, cx](bool close){
|
||||
if (close)
|
||||
return;
|
||||
|
||||
if (this->m_hWnd)
|
||||
this->AdjustLayout();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void ControlPanelList::OnPaint()
|
||||
{
|
||||
CPaintDC dc(this); // device context for painting
|
||||
// TODO: Add your message handler code here
|
||||
// Do not call Invokable::OnPaint() for painting messages
|
||||
CBrush brush(RGB(0, 0, 0));
|
||||
CRect rect;
|
||||
GetClientRect(&rect);
|
||||
dc.FillRect(rect,&brush);
|
||||
}
|
||||
|
||||
|
||||
BOOL ControlPanelList::PreCreateWindow(CREATESTRUCT& cs)
|
||||
{
|
||||
// TODO: Add your specialized code here and/or call the base class
|
||||
|
||||
cs.style |= WS_CLIPCHILDREN;
|
||||
|
||||
return Invokable::PreCreateWindow(cs);
|
||||
}
|
||||
|
||||
|
||||
void ControlPanelList::PostNcDestroy()
|
||||
{
|
||||
// TODO: Add your specialized code here and/or call the base class
|
||||
|
||||
Invokable::PostNcDestroy();
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include "Invokable.h"
|
||||
#include "ControlPanelWnd.h"
|
||||
#include "Event.h"
|
||||
|
||||
// ControlPanelList
|
||||
|
||||
class ControlPanelList : public Invokable
|
||||
{
|
||||
DECLARE_DYNAMIC(ControlPanelList)
|
||||
|
||||
public:
|
||||
ControlPanelList();
|
||||
virtual ~ControlPanelList();
|
||||
|
||||
void AddControlPanelWnd(std::shared_ptr<ControlPanelWnd>);
|
||||
void RemoveControlPanelWnd(std::shared_ptr<ControlPanelWnd>);
|
||||
|
||||
private:
|
||||
void AdjustLayout();
|
||||
|
||||
private:
|
||||
std::list<std::shared_ptr<ControlPanelWnd> > _controlPanelList;
|
||||
|
||||
protected:
|
||||
DECLARE_MESSAGE_MAP()
|
||||
public:
|
||||
afx_msg void OnSize(UINT nType, int cx, int cy);
|
||||
afx_msg void OnPaint();
|
||||
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
|
||||
virtual void PostNcDestroy();
|
||||
};
|
||||
|
||||
|
|
@ -0,0 +1,446 @@
|
|||
// ControlPanelWnd.cpp : implementation file
|
||||
//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "DbgPlotViewer.h"
|
||||
#include "ControlPanelWnd.h"
|
||||
|
||||
|
||||
// ControlPanelWnd
|
||||
|
||||
IMPLEMENT_DYNAMIC(ControlPanelWnd, Invokable)
|
||||
|
||||
ControlPanelWnd::ControlPanelWnd(const CString & caption)
|
||||
{
|
||||
_captionWidth = 100;
|
||||
_readPos = 0.4f;
|
||||
_writePos = 0.55f;
|
||||
_caption = caption;
|
||||
_buttonIsPlayState = false;
|
||||
_bitmap = 0;
|
||||
_buttonEnabled = true;
|
||||
}
|
||||
|
||||
ControlPanelWnd::~ControlPanelWnd()
|
||||
{
|
||||
if (_bitmap)
|
||||
delete _bitmap;
|
||||
}
|
||||
|
||||
int ControlPanelWnd::Height()
|
||||
{
|
||||
return 30;
|
||||
}
|
||||
|
||||
int ControlPanelWnd::ButtonWidth()
|
||||
{
|
||||
return 28;
|
||||
}
|
||||
|
||||
|
||||
void ControlPanelWnd::DrawCaption(Graphics * g)
|
||||
{
|
||||
|
||||
SolidBrush fontBrush(Color(255, 150, 150, 150));
|
||||
StringFormat format;
|
||||
format.SetAlignment(StringAlignmentNear);
|
||||
//format.SetFormatFlags(StringFormatFlagsNoWrap);
|
||||
//format.SetTrimming(StringTrimmingEllipsisCharacter);
|
||||
Gdiplus::Font captionFont(L"Arial", 10);
|
||||
PointF pointF(5, 2);
|
||||
|
||||
CRect rectCaption;
|
||||
GetClientRect(&rectCaption);
|
||||
int top = rectCaption.top;
|
||||
int bottom = rectCaption.bottom;
|
||||
int middle = (top + bottom) / 2;
|
||||
|
||||
rectCaption.left = this->_captionLeft;
|
||||
rectCaption.right = this->_captionRight;
|
||||
|
||||
SolidBrush brushBk(Color(30, 30, 30));
|
||||
g->FillRectangle(&brushBk, rectCaption.left, rectCaption.top, rectCaption.right,rectCaption.bottom);
|
||||
|
||||
RectF rectName(
|
||||
(Gdiplus::REAL)this->_captionLeft,
|
||||
(Gdiplus::REAL)top,
|
||||
(Gdiplus::REAL)this->_captionRight,
|
||||
(Gdiplus::REAL)bottom );
|
||||
g->DrawString(_caption, -1, &captionFont, rectName, &format, &fontBrush);
|
||||
}
|
||||
|
||||
void ControlPanelWnd::DrawTrackBar(Graphics * g)
|
||||
{
|
||||
CRect rect;
|
||||
GetClientRect(&rect);
|
||||
if (_bitmap)
|
||||
{
|
||||
g->DrawImage(_bitmap, _trackBarLeft, rect.top, _trackBarRight - _trackBarLeft, rect.bottom - rect.top);
|
||||
}
|
||||
|
||||
//CRect rect;
|
||||
//GetClientRect(&rect);
|
||||
//rect.left = this->_trackBarLeft;
|
||||
//rect.right = this->_trackBarRight;
|
||||
|
||||
//float readRatio = this->_readPos;
|
||||
//float readPos = (rect.right - rect.left) * readRatio + rect.left;
|
||||
//Color colorReadDataPart(28,48,69);
|
||||
//SolidBrush brushReadDataPart(colorReadDataPart);
|
||||
//g->FillRectangle(
|
||||
// &brushReadDataPart,
|
||||
// float(rect.left),
|
||||
// float(rect.top),
|
||||
// readPos,
|
||||
// float(rect.bottom));
|
||||
|
||||
//float emptyStartPos = readPos;
|
||||
|
||||
//if (this->_readPos < this->_writePos)
|
||||
//{
|
||||
// float writeRatio = (float)this->_writePos;
|
||||
// float writePos = float((rect.right - rect.left) * writeRatio + rect.left);
|
||||
// Color colorWriteDataPart(100, 100, 100);
|
||||
// SolidBrush brushWriteDataPart(colorWriteDataPart);
|
||||
// g->FillRectangle(
|
||||
// &brushWriteDataPart,
|
||||
// readPos,
|
||||
// float(rect.top),
|
||||
// writePos,
|
||||
// float(rect.bottom));
|
||||
// emptyStartPos = writePos;
|
||||
//}
|
||||
|
||||
//SolidBrush brush(Color::Black);
|
||||
//g->FillRectangle(
|
||||
// &brush,
|
||||
// emptyStartPos,
|
||||
// float(rect.top),
|
||||
// float(rect.right),
|
||||
// float(rect.bottom));
|
||||
}
|
||||
|
||||
void ControlPanelWnd::AdjustLayout()
|
||||
{
|
||||
// calculate one by one
|
||||
/*
|
||||
|caption|trace bar|play button|single step button|
|
||||
*/
|
||||
|
||||
CRect rect;
|
||||
this->GetClientRect(&rect);
|
||||
int width = rect.Width();
|
||||
int height = rect.Height();
|
||||
|
||||
const int MARGIN = 1;
|
||||
const int BUTTON_WIDTH = ControlPanelWnd::ButtonWidth();
|
||||
|
||||
_captionLeft = 1;
|
||||
_captionRight = _captionLeft + _captionWidth;
|
||||
|
||||
int buttonWidthRequired = MARGIN * 3 + BUTTON_WIDTH * 2;
|
||||
if (_captionRight + buttonWidthRequired >= width) // layout buttons from left
|
||||
{
|
||||
_trackBarLeft = _trackBarRight = _captionRight;
|
||||
_playButtonLeft = _captionRight + MARGIN;
|
||||
_playButtonRight = _playButtonLeft + BUTTON_WIDTH;
|
||||
_singleStepButtonLeft = _playButtonRight + MARGIN;
|
||||
_singleStepButtonRight = _singleStepButtonLeft + BUTTON_WIDTH;
|
||||
}
|
||||
else // layout buttons from right
|
||||
{
|
||||
_singleStepButtonRight = width - MARGIN;
|
||||
_singleStepButtonLeft = _singleStepButtonRight - BUTTON_WIDTH;
|
||||
_playButtonRight = _singleStepButtonLeft - MARGIN;
|
||||
_playButtonLeft = _playButtonRight - BUTTON_WIDTH;
|
||||
_trackBarLeft = _captionRight + MARGIN;
|
||||
_trackBarRight = _playButtonLeft - MARGIN;
|
||||
assert(_trackBarRight >= _trackBarLeft);
|
||||
}
|
||||
|
||||
_playButton.MoveWindow(_playButtonLeft, 0, BUTTON_WIDTH, height, 1);
|
||||
_singleStepButton.MoveWindow(_singleStepButtonLeft, 0, BUTTON_WIDTH, height, 1);
|
||||
}
|
||||
|
||||
void ControlPanelWnd::SetCaptionWidth(int width)
|
||||
{
|
||||
this->Invoke([this, width](bool close){
|
||||
if (close) return;
|
||||
|
||||
this->_captionWidth = width;
|
||||
});
|
||||
}
|
||||
|
||||
void ControlPanelWnd::SetCaption(const CString & caption)
|
||||
{
|
||||
this->Invoke([this, caption](bool close){
|
||||
if (close) return;
|
||||
|
||||
this->_caption = caption;
|
||||
});
|
||||
}
|
||||
|
||||
void ControlPanelWnd::SetReadWritePos(float readPos, float writePos)
|
||||
{
|
||||
this->Invoke([this, readPos, writePos](bool close){
|
||||
if (close) return;
|
||||
|
||||
this->_readPos = readPos;
|
||||
this->_writePos = writePos;
|
||||
});
|
||||
}
|
||||
|
||||
void ControlPanelWnd::SetPlayPauseButtonState(bool bPlay)
|
||||
{
|
||||
this->Invoke([this, bPlay](bool close){
|
||||
if (close) return;
|
||||
|
||||
this->_buttonIsPlayState = bPlay;
|
||||
if (_playButton.m_hWnd)
|
||||
{
|
||||
if (bPlay)
|
||||
{
|
||||
_playButton.SetImage(IDB_BITMAP_CONTROL_PLAY, IDB_BITMAP_CONTROL_PLAY);
|
||||
}
|
||||
else
|
||||
{
|
||||
_playButton.SetImage(IDB_BITMAP_CONTROL_PAUSE, IDB_BITMAP_CONTROL_PAUSE);
|
||||
}
|
||||
|
||||
_playButton.Invalidate(TRUE);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void ControlPanelWnd::SetBitmap(Bitmap * bitmap)
|
||||
{
|
||||
this->Invoke([this, bitmap](bool close){
|
||||
if (close)
|
||||
{
|
||||
delete bitmap;
|
||||
return;
|
||||
}
|
||||
|
||||
if (_bitmap)
|
||||
delete _bitmap;
|
||||
if (this->m_hWnd)
|
||||
{
|
||||
_bitmap = bitmap;
|
||||
this->Invalidate();
|
||||
}
|
||||
else
|
||||
{
|
||||
delete bitmap;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void ControlPanelWnd::EnableButton(bool bEnable)
|
||||
{
|
||||
this->Invoke([this, bEnable](bool close){
|
||||
if (close) return;
|
||||
|
||||
if (_playButton.m_hWnd != 0)
|
||||
{
|
||||
if (_buttonEnabled != bEnable)
|
||||
{
|
||||
this->_playButton.EnableWindow(bEnable ? TRUE : FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
if (_singleStepButton.m_hWnd != 0)
|
||||
{
|
||||
if (_buttonEnabled != bEnable)
|
||||
{
|
||||
this->_singleStepButton.EnableWindow(bEnable ? TRUE : FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
_buttonEnabled = bEnable;
|
||||
});
|
||||
}
|
||||
|
||||
BEGIN_MESSAGE_MAP(ControlPanelWnd, Invokable)
|
||||
ON_WM_SIZE()
|
||||
ON_WM_CREATE()
|
||||
ON_WM_PAINT()
|
||||
ON_COMMAND(ControlPanelWnd::ID_PLAY_BUTTON, &ControlPanelWnd::OnPlayPauseButtonClicked)
|
||||
ON_COMMAND(ControlPanelWnd::ID_SINGLE_STEP_BUTTON, &ControlPanelWnd::OnSingleStepButtonClicked)
|
||||
ON_WM_MOUSEWHEEL()
|
||||
ON_WM_LBUTTONDOWN()
|
||||
ON_WM_MOUSEMOVE()
|
||||
END_MESSAGE_MAP()
|
||||
|
||||
|
||||
|
||||
// ControlPanelWnd message handlers
|
||||
|
||||
|
||||
|
||||
|
||||
void ControlPanelWnd::OnSize(UINT nType, int cx, int cy)
|
||||
{
|
||||
Invokable::OnSize(nType, cx, cy);
|
||||
|
||||
// TODO: Add your message handler code here
|
||||
this->Invoke([this](bool close){
|
||||
if (close) return;
|
||||
|
||||
if (this->m_hWnd == 0)
|
||||
return;
|
||||
|
||||
this->AdjustLayout();
|
||||
CRect rect;
|
||||
this->GetClientRect(&rect);
|
||||
rect.left = _trackBarLeft;
|
||||
rect.right = _trackBarRight;
|
||||
EventTraceBarSizeChanged.Raise(this, rect);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
int ControlPanelWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
|
||||
{
|
||||
if (Invokable::OnCreate(lpCreateStruct) == -1)
|
||||
return -1;
|
||||
|
||||
// TODO: Add your specialized creation code here
|
||||
CRect rectDummy;
|
||||
rectDummy.SetRectEmpty();
|
||||
|
||||
//_playButton.m_bTransparent = TRUE;
|
||||
_playButton.SetImage(IDB_BITMAP_CONTROL_PAUSE, IDB_BITMAP_CONTROL_PAUSE);
|
||||
|
||||
_playButton.Create(L"", BS_PUSHBUTTON | BS_OWNERDRAW | WS_VISIBLE | WS_CHILD,
|
||||
rectDummy, this, ID_PLAY_BUTTON);
|
||||
|
||||
_singleStepButton.SetImage(IDB_BITMAP_SINGLESTEP, IDB_BITMAP_SINGLESTEP);
|
||||
|
||||
_singleStepButton.Create(L"", BS_PUSHBUTTON | BS_OWNERDRAW | WS_VISIBLE | WS_CHILD,
|
||||
rectDummy, this, ID_SINGLE_STEP_BUTTON);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ControlPanelWnd::OnPaint()
|
||||
{
|
||||
CPaintDC dc(this); // device context for painting
|
||||
// TODO: Add your message handler code here
|
||||
// Do not call Invokable::OnPaint() for painting messages
|
||||
|
||||
//CBrush brush(RGB(0, 0, 0));
|
||||
CRect rect;
|
||||
GetClientRect(&rect);
|
||||
//dc.FillRect(rect,&brush);
|
||||
|
||||
Bitmap bmp(rect.right,rect.bottom);
|
||||
Graphics* memGraph = Graphics::FromImage(&bmp);
|
||||
|
||||
SolidBrush brushBg(Color::Black);
|
||||
memGraph->FillRectangle(
|
||||
&brushBg,
|
||||
rect.left,
|
||||
rect.top,
|
||||
rect.Width(),
|
||||
rect.Height()
|
||||
);
|
||||
|
||||
|
||||
this->DrawCaption(memGraph);
|
||||
this->DrawTrackBar(memGraph);
|
||||
|
||||
Graphics graphics(dc.m_hDC);
|
||||
graphics.DrawImage(&bmp,rect.left,rect.top,rect.right,rect.bottom);
|
||||
|
||||
delete memGraph;
|
||||
}
|
||||
|
||||
|
||||
BOOL ControlPanelWnd::PreCreateWindow(CREATESTRUCT& cs)
|
||||
{
|
||||
// TODO: Add your specialized code here and/or call the base class
|
||||
|
||||
cs.style |= WS_CLIPCHILDREN;
|
||||
|
||||
return Invokable::PreCreateWindow(cs);
|
||||
}
|
||||
|
||||
void ControlPanelWnd::OnPlayPauseButtonClicked()
|
||||
{
|
||||
EventPlayPause.Raise(this, _buttonIsPlayState);
|
||||
|
||||
//_playButton.SetWindowText(_buttonIsPlayState ? L"||" : L">");
|
||||
if (_playButton.m_hWnd)
|
||||
{
|
||||
if (_buttonIsPlayState)
|
||||
{
|
||||
_playButton.SetImage(IDB_BITMAP_CONTROL_PAUSE, IDB_BITMAP_CONTROL_PAUSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
_playButton.SetImage(IDB_BITMAP_CONTROL_PLAY, IDB_BITMAP_CONTROL_PLAY);
|
||||
}
|
||||
|
||||
_playButton.Invalidate(TRUE);
|
||||
|
||||
_buttonIsPlayState = !_buttonIsPlayState;
|
||||
}
|
||||
}
|
||||
|
||||
void ControlPanelWnd::OnSingleStepButtonClicked()
|
||||
{
|
||||
EventSingleStep.Raise(this, true);
|
||||
this->SetPlayPauseButtonState(true);
|
||||
}
|
||||
|
||||
void ControlPanelWnd::PostNcDestroy()
|
||||
{
|
||||
// TODO: Add your specialized code here and/or call the base class
|
||||
EventClosed.Raise(this, true);
|
||||
EventPlayPause.Reset();
|
||||
EventSingleStep.Reset();
|
||||
EventTraceBarSizeChanged.Reset();
|
||||
EventTraceBarWheel.Reset();
|
||||
EventTraceBarSeek.Reset();
|
||||
EventClosed.Reset();
|
||||
|
||||
Invokable::PostNcDestroy();
|
||||
}
|
||||
|
||||
|
||||
BOOL ControlPanelWnd::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
|
||||
{
|
||||
// TODO: Add your message handler code here and/or call default
|
||||
|
||||
EventTraceBarWheel.Raise(this, zDelta > 0);
|
||||
|
||||
return Invokable::OnMouseWheel(nFlags, zDelta, pt);
|
||||
}
|
||||
|
||||
|
||||
void ControlPanelWnd::OnLButtonDown(UINT nFlags, CPoint point)
|
||||
{
|
||||
// TODO: Add your message handler code here and/or call default
|
||||
|
||||
int width = _trackBarRight - _trackBarLeft;
|
||||
if (width > 0)
|
||||
{
|
||||
if (point.x >= _trackBarLeft &&
|
||||
point.y < _trackBarRight)
|
||||
{
|
||||
double pos = ((double)(point.x - _trackBarLeft)) / width;
|
||||
EventTraceBarSeek.Raise(this, pos);
|
||||
}
|
||||
}
|
||||
|
||||
Invokable::OnLButtonDown(nFlags, point);
|
||||
}
|
||||
|
||||
|
||||
void ControlPanelWnd::OnMouseMove(UINT nFlags, CPoint point)
|
||||
{
|
||||
// TODO: Add your message handler code here and/or call default
|
||||
SetFocus();
|
||||
|
||||
Invokable::OnMouseMove(nFlags, point);
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
#pragma once
|
||||
|
||||
#include "Invokable.h"
|
||||
#include "CustomButton.h"
|
||||
#include "Event.h"
|
||||
|
||||
// ControlPanelWnd
|
||||
|
||||
class ControlPanelWnd : public Invokable
|
||||
{
|
||||
DECLARE_DYNAMIC(ControlPanelWnd)
|
||||
|
||||
public:
|
||||
static int Height();
|
||||
static int ButtonWidth();
|
||||
|
||||
public:
|
||||
ControlPanelWnd(const CString &);
|
||||
virtual ~ControlPanelWnd();
|
||||
|
||||
void SetCaptionWidth(int width);
|
||||
void SetCaption(const CString & caption);
|
||||
void SetReadWritePos(float readPos, float writePos);
|
||||
void SetPlayPauseButtonState(bool bPlay);
|
||||
void SetBitmap(Bitmap * bitmap);
|
||||
void EnableButton(bool bEnable);
|
||||
|
||||
SoraDbgPlot::Event::Event<bool> EventClosed;
|
||||
SoraDbgPlot::Event::Event<bool> EventPlayPause;
|
||||
SoraDbgPlot::Event::Event<bool> EventSingleStep;
|
||||
SoraDbgPlot::Event::Event<CRect> EventTraceBarSizeChanged;
|
||||
SoraDbgPlot::Event::Event<bool> EventTraceBarWheel;
|
||||
SoraDbgPlot::Event::Event<double> EventTraceBarSeek;
|
||||
|
||||
private:
|
||||
void AdjustLayout();
|
||||
void DrawCaption(Graphics * g);
|
||||
void DrawTrackBar(Graphics * g);
|
||||
|
||||
private:
|
||||
bool _buttonEnabled;
|
||||
Bitmap * _bitmap;
|
||||
CString _caption;
|
||||
float _readPos;
|
||||
float _writePos;
|
||||
bool _buttonIsPlayState;
|
||||
|
||||
enum {
|
||||
ID_PLAY_BUTTON = 1,
|
||||
ID_SINGLE_STEP_BUTTON
|
||||
};
|
||||
|
||||
CFont _buttonFont;
|
||||
CustomButton _playButton;
|
||||
CustomButton _singleStepButton;
|
||||
int _captionWidth;
|
||||
|
||||
int _captionLeft;
|
||||
int _captionRight;
|
||||
int _trackBarLeft;
|
||||
int _trackBarRight;
|
||||
int _playButtonLeft;
|
||||
int _playButtonRight;
|
||||
int _singleStepButtonLeft;
|
||||
int _singleStepButtonRight;
|
||||
|
||||
protected:
|
||||
DECLARE_MESSAGE_MAP()
|
||||
public:
|
||||
afx_msg void OnSize(UINT nType, int cx, int cy);
|
||||
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
|
||||
afx_msg void OnPaint();
|
||||
afx_msg void OnPlayPauseButtonClicked();
|
||||
afx_msg void OnSingleStepButtonClicked();
|
||||
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
|
||||
virtual void PostNcDestroy();
|
||||
afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt);
|
||||
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
|
||||
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
|
||||
};
|
||||
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
#include "stdafx.h"
|
||||
#include <DbgHelp.h>
|
||||
#include "PathName.h"
|
||||
|
||||
#define ATOW2(x) L##x
|
||||
#define ATOW(x) ATOW2(x)
|
||||
|
||||
#define __WDATE__ ATOW(__DATE__)
|
||||
#define __WTIME__ ATOW(__TIME__)
|
||||
|
||||
const wchar_t * buildString = __WDATE__ __WTIME__;
|
||||
|
||||
static LONG WINAPI AppUnhandledExceptionFilter(
|
||||
_In_ struct _EXCEPTION_POINTERS *ExceptionInfo
|
||||
)
|
||||
{
|
||||
CString errMsg;
|
||||
|
||||
DWORD requiredSize = GetCurrentDirectory(0, NULL);
|
||||
if (requiredSize == 0) // error, just exit
|
||||
{
|
||||
errMsg.Format(L"DbgPlot Viewer has crashed.\n");
|
||||
::AfxMessageBox(errMsg);
|
||||
::OutputDebugString(L"DbgPlot Crash dump: error in querying directory 1\n");
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
wchar_t * currentPathBuffer = new wchar_t[requiredSize];
|
||||
DWORD pathLen = GetCurrentDirectory(requiredSize, currentPathBuffer);
|
||||
if (pathLen != requiredSize - 1) // error
|
||||
{
|
||||
delete [] currentPathBuffer;
|
||||
errMsg.Format(L"DbgPlot Viewer has crashed.\n");
|
||||
::AfxMessageBox(errMsg);
|
||||
::OutputDebugString(L"DbgPlot Crash dump: error in querying directory 2\n");
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
PathName pathName;
|
||||
pathName.Append(currentPathBuffer);
|
||||
delete [] currentPathBuffer;
|
||||
pathName.Append(L"\\");
|
||||
|
||||
pathName.AppendWithEscape(buildString, '_');
|
||||
FILETIME fileTime;
|
||||
::GetSystemTimeAsFileTime(&fileTime);
|
||||
CString time;
|
||||
time.Format(L"{%d%d}", fileTime.dwHighDateTime, fileTime.dwLowDateTime);
|
||||
pathName.AppendWithEscape(time, '_');
|
||||
pathName.Append(L".dmp");
|
||||
|
||||
HANDLE hFile = CreateFileW(
|
||||
(const wchar_t *)pathName,
|
||||
GENERIC_WRITE,
|
||||
0,
|
||||
NULL,
|
||||
CREATE_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
errMsg.Format(L"DbgPlot Viewer has crashed. Cannot create crash dump file in %s\n", (const wchar_t *)pathName);
|
||||
::AfxMessageBox(errMsg);
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
BOOL succ = ::MiniDumpWriteDump(
|
||||
GetCurrentProcess(),
|
||||
GetCurrentProcessId(),
|
||||
hFile,
|
||||
MiniDumpNormal,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
if (succ == TRUE)
|
||||
{
|
||||
errMsg.Format(L"DebugPlot Viewer has crashed. A crash dump file is saved at %s\n", (const wchar_t *)pathName);
|
||||
::AfxMessageBox(errMsg);
|
||||
}
|
||||
else
|
||||
{
|
||||
errMsg.Format(L"DebugPlot Viewer has crashed. Error happened in writing dump file to %s\n", (const wchar_t *)pathName);
|
||||
::AfxMessageBox(errMsg);
|
||||
}
|
||||
|
||||
CloseHandle(hFile);
|
||||
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
|
||||
void SetCrashDump()
|
||||
{
|
||||
::SetUnhandledExceptionFilter(AppUnhandledExceptionFilter);
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
#pragma once
|
||||
|
||||
void SetCrashDump();
|
|
@ -0,0 +1,30 @@
|
|||
// CustomButton.cpp : implementation file
|
||||
//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "DbgPlotViewer.h"
|
||||
#include "CustomButton.h"
|
||||
|
||||
|
||||
// CustomButton
|
||||
|
||||
IMPLEMENT_DYNAMIC(CustomButton, CMFCButton)
|
||||
|
||||
CustomButton::CustomButton()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CustomButton::~CustomButton()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
BEGIN_MESSAGE_MAP(CustomButton, CMFCButton)
|
||||
END_MESSAGE_MAP()
|
||||
|
||||
|
||||
|
||||
// CustomButton message handlers
|
||||
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
#pragma once
|
||||
|
||||
|
||||
// CustomButton
|
||||
|
||||
class CustomButton : public CMFCButton
|
||||
{
|
||||
DECLARE_DYNAMIC(CustomButton)
|
||||
|
||||
public:
|
||||
CustomButton();
|
||||
virtual ~CustomButton();
|
||||
|
||||
protected:
|
||||
DECLARE_MESSAGE_MAP()
|
||||
};
|
||||
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
#define VER_FILEDESCRIPTION_STR "DebugPlot Viewer"
|
||||
#define VER_INTERNALNAME_STR "DbgPlot.exe"
|
||||
#define VER_ORIGINALFILENAME_STR "DbgPlot.exe"
|
||||
|
||||
#include "Version.rc"
|
||||
|
|
@ -0,0 +1,675 @@
|
|||
|
||||
// DbgPlotViewer.cpp : Defines the class behaviors for the application.
|
||||
//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "afxwinappex.h"
|
||||
#include "afxdialogex.h"
|
||||
#include "DbgPlotViewer.h"
|
||||
#include "MainFrm.h"
|
||||
|
||||
#include "DbgPlotViewerDoc.h"
|
||||
#include "DbgPlotViewerView.h"
|
||||
|
||||
#include "Event.h"
|
||||
#include "TaskQueue.h"
|
||||
#include "SharedNameManagement.h"
|
||||
#include "CrashDump.h"
|
||||
|
||||
|
||||
using namespace std;
|
||||
using namespace SoraDbgPlot::SharedObj;
|
||||
using namespace SoraDbgPlot::Task;
|
||||
using namespace SoraDbgPlot::Event;
|
||||
|
||||
#ifdef _DEBUG
|
||||
#define new DEBUG_NEW
|
||||
#endif
|
||||
|
||||
// CDbgPlotViewerApp
|
||||
|
||||
BEGIN_MESSAGE_MAP(CDbgPlotViewerApp, CWinAppEx)
|
||||
ON_COMMAND(ID_APP_ABOUT, &CDbgPlotViewerApp::OnAppAbout)
|
||||
// Standard file based document commands
|
||||
ON_COMMAND(ID_FILE_NEW, &CWinAppEx::OnFileNew)
|
||||
ON_COMMAND(ID_FILE_OPEN, &CWinAppEx::OnFileOpen)
|
||||
// Standard print setup command
|
||||
ON_COMMAND(ID_FILE_PRINT_SETUP, &CWinAppEx::OnFilePrintSetup)
|
||||
END_MESSAGE_MAP()
|
||||
|
||||
|
||||
// CDbgPlotViewerApp construction
|
||||
|
||||
CDbgPlotViewerApp::CDbgPlotViewerApp()
|
||||
{
|
||||
m_bHiColorIcons = TRUE;
|
||||
|
||||
// support Restart Manager
|
||||
m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_ALL_ASPECTS;
|
||||
#ifdef _MANAGED
|
||||
// If the application is built using Common Language Runtime support (/clr):
|
||||
// 1) This additional setting is needed for Restart Manager support to work properly.
|
||||
// 2) In your project, you must add a reference to System.Windows.Forms in order to build.
|
||||
System::Windows::Forms::Application::SetUnhandledExceptionMode(System::Windows::Forms::UnhandledExceptionMode::ThrowException);
|
||||
#endif
|
||||
|
||||
// TODO: replace application ID string below with unique ID string; recommended
|
||||
// format for string is CompanyName.ProductName.SubProduct.VersionInformation
|
||||
SetAppID(_T("DbgPlotViewer.AppID.NoVersion"));
|
||||
|
||||
// TODO: add construction code here,
|
||||
// Place all significant initialization in InitInstance
|
||||
|
||||
#ifdef ENABLE_CRASH_DUMP
|
||||
_bEnableCrashDump = true;
|
||||
#else
|
||||
_bEnableCrashDump = false;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
// The one and only CDbgPlotViewerApp object
|
||||
|
||||
CDbgPlotViewerApp theApp;
|
||||
#define SHARED_SINGLE_INSTANCE_MUTEX_NAME L"|Sora|DebugPlot|single_instance_mutex"
|
||||
|
||||
static BOOL SetPrivilege(
|
||||
HANDLE hToken, // access token handle
|
||||
LPCTSTR lpszPrivilege, // name of privilege to enable/disable
|
||||
BOOL bEnablePrivilege // to enable or disable privilege
|
||||
)
|
||||
{
|
||||
TOKEN_PRIVILEGES tp;
|
||||
LUID luid;
|
||||
|
||||
if ( !LookupPrivilegeValue(
|
||||
NULL, // lookup privilege on local system
|
||||
lpszPrivilege, // privilege to lookup
|
||||
&luid ) ) // receives LUID of privilege
|
||||
{
|
||||
char msg[64];
|
||||
sprintf(msg, "LookupPrivilegeValue error: %u\n", GetLastError());
|
||||
OutputDebugStringA(msg);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
tp.PrivilegeCount = 1;
|
||||
tp.Privileges[0].Luid = luid;
|
||||
if (bEnablePrivilege)
|
||||
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
||||
else
|
||||
tp.Privileges[0].Attributes = 0;
|
||||
|
||||
// Enable the privilege or disable all privileges.
|
||||
|
||||
if ( !AdjustTokenPrivileges(
|
||||
hToken,
|
||||
FALSE,
|
||||
&tp,
|
||||
sizeof(TOKEN_PRIVILEGES),
|
||||
(PTOKEN_PRIVILEGES) NULL,
|
||||
(PDWORD) NULL) )
|
||||
{
|
||||
char msg[64];
|
||||
sprintf(msg, "AdjustTokenPrivileges error: %u\n", GetLastError());
|
||||
OutputDebugStringA(msg);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
|
||||
|
||||
{
|
||||
OutputDebugStringA("The token does not have the specified privilege. \n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL SetDebugPrivilege()
|
||||
{
|
||||
HANDLE hToken = NULL;
|
||||
BOOL succ = ::OpenProcessToken(::GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
|
||||
if (succ == TRUE)
|
||||
{
|
||||
BOOL succ = SetPrivilege(hToken, SE_DEBUG_NAME, TRUE);
|
||||
return succ;
|
||||
}
|
||||
else
|
||||
{
|
||||
::OutputDebugStringA("OpenProcessToken failed");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
// CDbgPlotViewerApp initialization
|
||||
|
||||
BOOL CDbgPlotViewerApp::InitInstance()
|
||||
{
|
||||
::OutputDebugString(L"DebugPlot Viewer started\n");
|
||||
|
||||
SECURITY_ATTRIBUTES sa;
|
||||
CreateDACLWithAllAccess(&sa);
|
||||
|
||||
HANDLE hMutex = CreateMutex(&sa, TRUE, SHARED_SINGLE_INSTANCE_MUTEX_NAME);
|
||||
if ( GetLastError() == ERROR_ALREADY_EXISTS )
|
||||
{
|
||||
::CloseHandle(hMutex);
|
||||
::AfxMessageBox(L"Instance already running");
|
||||
_bInitialized = false;
|
||||
LocalFree(sa.lpSecurityDescriptor);
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
_bInitialized = true;
|
||||
LocalFree(sa.lpSecurityDescriptor);
|
||||
}
|
||||
|
||||
if (SetDebugPrivilege() == FALSE)
|
||||
{
|
||||
::AfxMessageBox(L"Please run DebugPlot Viewer as administrator");
|
||||
_bInitialized = false;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
SetCrashDumpHandler();
|
||||
|
||||
ClearLog();
|
||||
InitAppObj();
|
||||
|
||||
// InitCommonControlsEx() is required on Windows XP if an application
|
||||
// manifest specifies use of ComCtl32.dll version 6 or later to enable
|
||||
// visual styles. Otherwise, any window creation will fail.
|
||||
INITCOMMONCONTROLSEX InitCtrls;
|
||||
InitCtrls.dwSize = sizeof(InitCtrls);
|
||||
// Set this to include all the common control classes you want to use
|
||||
// in your application.
|
||||
InitCtrls.dwICC = ICC_WIN95_CLASSES;
|
||||
InitCommonControlsEx(&InitCtrls);
|
||||
|
||||
CWinAppEx::InitInstance();
|
||||
|
||||
|
||||
// Initialize OLE libraries
|
||||
if (!AfxOleInit())
|
||||
{
|
||||
AfxMessageBox(IDP_OLE_INIT_FAILED);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
AfxEnableControlContainer();
|
||||
|
||||
EnableTaskbarInteraction(FALSE);
|
||||
|
||||
// AfxInitRichEdit2() is required to use RichEdit control
|
||||
// AfxInitRichEdit2();
|
||||
|
||||
// Standard initialization
|
||||
// If you are not using these features and wish to reduce the size
|
||||
// of your final executable, you should remove from the following
|
||||
// the specific initialization routines you do not need
|
||||
// Change the registry key under which our settings are stored
|
||||
// TODO: You should modify this string to be something appropriate
|
||||
// such as the name of your company or organization
|
||||
SetRegistryKey(_T("Sora DebugPlot Viewer v2.0"));
|
||||
LoadStdProfileSettings(4); // Load standard INI file options (including MRU)
|
||||
|
||||
|
||||
InitContextMenuManager();
|
||||
|
||||
InitKeyboardManager();
|
||||
|
||||
InitTooltipManager();
|
||||
CMFCToolTipInfo ttParams;
|
||||
ttParams.m_bVislManagerTheme = TRUE;
|
||||
theApp.GetTooltipManager()->SetTooltipParams(AFX_TOOLTIP_TYPE_ALL,
|
||||
RUNTIME_CLASS(CMFCToolTipCtrl), &ttParams);
|
||||
|
||||
// GDI+
|
||||
Gdiplus::GdiplusStartupInput gdiplusStartupInput;
|
||||
Gdiplus::GdiplusStartup(&_gdiplusToken, &gdiplusStartupInput, NULL);
|
||||
|
||||
CoInitialize(NULL);
|
||||
|
||||
// Register the application's document templates. Document templates
|
||||
// serve as the connection between documents, frame windows and views
|
||||
CSingleDocTemplate* pDocTemplate;
|
||||
pDocTemplate = new CSingleDocTemplate(
|
||||
IDR_MAINFRAME,
|
||||
RUNTIME_CLASS(CDbgPlotViewerDoc),
|
||||
RUNTIME_CLASS(CMainFrame), // main SDI frame window
|
||||
RUNTIME_CLASS(CDbgPlotViewerView));
|
||||
if (!pDocTemplate)
|
||||
return FALSE;
|
||||
AddDocTemplate(pDocTemplate);
|
||||
|
||||
|
||||
// Parse command line for standard shell commands, DDE, file open
|
||||
CCommandLineInfo cmdInfo;
|
||||
ParseCommandLine(cmdInfo);
|
||||
|
||||
|
||||
|
||||
// Dispatch commands specified on the command line. Will return FALSE if
|
||||
// app was launched with /RegServer, /Register, /Unregserver or /Unregister.
|
||||
if (!ProcessShellCommand(cmdInfo))
|
||||
return FALSE;
|
||||
|
||||
// The one and only window has been initialized, so show and update it
|
||||
m_pMainWnd->ShowWindow(SW_SHOW);
|
||||
m_pMainWnd->UpdateWindow();
|
||||
// call DragAcceptFiles only if there's a suffix
|
||||
// In an SDI app, this should occur after ProcessShellCommand
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int CDbgPlotViewerApp::ExitInstance()
|
||||
{
|
||||
//TODO: handle additional resources you may have added
|
||||
|
||||
if (_bInitialized)
|
||||
{
|
||||
CoUninitialize();
|
||||
|
||||
// GDI+
|
||||
Gdiplus::GdiplusShutdown(_gdiplusToken);
|
||||
|
||||
AfxOleTerm(FALSE);
|
||||
|
||||
DeiniteAppObj();
|
||||
}
|
||||
|
||||
return CWinAppEx::ExitInstance();
|
||||
}
|
||||
|
||||
// CDbgPlotViewerApp message handlers
|
||||
|
||||
|
||||
// CAboutDlg dialog used for App About
|
||||
|
||||
class CAboutDlg : public CDialogEx
|
||||
{
|
||||
public:
|
||||
CAboutDlg();
|
||||
|
||||
// Dialog Data
|
||||
enum { IDD = IDD_ABOUTBOX };
|
||||
|
||||
protected:
|
||||
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
|
||||
|
||||
// Implementation
|
||||
protected:
|
||||
DECLARE_MESSAGE_MAP()
|
||||
};
|
||||
|
||||
CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
|
||||
{
|
||||
}
|
||||
|
||||
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
|
||||
{
|
||||
CDialogEx::DoDataExchange(pDX);
|
||||
}
|
||||
|
||||
BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
|
||||
END_MESSAGE_MAP()
|
||||
|
||||
// App command to run the dialog
|
||||
void CDbgPlotViewerApp::OnAppAbout()
|
||||
{
|
||||
CAboutDlg aboutDlg;
|
||||
aboutDlg.DoModal();
|
||||
}
|
||||
|
||||
// CDbgPlotViewerApp customization load/save methods
|
||||
|
||||
void CDbgPlotViewerApp::PreLoadState()
|
||||
{
|
||||
BOOL bNameValid;
|
||||
CString strName;
|
||||
bNameValid = strName.LoadString(IDS_EDIT_MENU);
|
||||
ASSERT(bNameValid);
|
||||
//GetContextMenuManager()->AddMenu(strName, IDR_POPUP_EDIT);
|
||||
bNameValid = strName.LoadString(IDS_EXPLORER);
|
||||
ASSERT(bNameValid);
|
||||
//GetContextMenuManager()->AddMenu(strName, IDR_POPUP_EXPLORER);
|
||||
GetContextMenuManager()->AddMenu(strName, IDR_POPUP_CHANNEL_EXPLORER);
|
||||
GetContextMenuManager()->AddMenu(strName, IDR_POPUP_TEXT_CHANNEL);
|
||||
}
|
||||
|
||||
void CDbgPlotViewerApp::LoadCustomState()
|
||||
{
|
||||
}
|
||||
|
||||
void CDbgPlotViewerApp::SaveCustomState()
|
||||
{
|
||||
}
|
||||
|
||||
// CDbgPlotViewerApp message handlers
|
||||
|
||||
|
||||
bool CDbgPlotViewerApp::DeleteDirRecursive(const std::wstring& dir, bool bDir, bool bContent)
|
||||
{
|
||||
wstring directoryname = dir;
|
||||
if(dir.at(directoryname.size()-1) != '\\') directoryname += '\\';
|
||||
|
||||
if (bContent)
|
||||
{
|
||||
WIN32_FIND_DATAW fdata;
|
||||
HANDLE dhandle;
|
||||
//BUG 1: Adding a extra \ to the directory name..
|
||||
directoryname += L"*";
|
||||
dhandle = FindFirstFileW(directoryname.c_str(), &fdata);
|
||||
//BUG 2: Not checking for invalid file handle return from FindFirstFileA
|
||||
if( dhandle != INVALID_HANDLE_VALUE )
|
||||
{
|
||||
// Loop through all the files in the main directory and delete files & make a list of directories
|
||||
while(true)
|
||||
{
|
||||
if(FindNextFileW(dhandle, &fdata))
|
||||
{
|
||||
std::wstring filename = fdata.cFileName;
|
||||
if(filename.compare(L"..") != 0)
|
||||
{
|
||||
//BUG 3: caused by BUG 1 - Removing too many characters from string.. removing 1 instead of 2
|
||||
std::wstring filelocation = directoryname.substr(0, directoryname.size()-1) + filename;
|
||||
|
||||
// If we've encountered a directory then recall this function for that specific folder.
|
||||
|
||||
//BUG 4: not really a bug, but spurious function call - we know its a directory from FindData already, use it.
|
||||
if( (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
|
||||
DeleteFileW(filelocation.c_str());
|
||||
else
|
||||
DeleteDirRecursive(filelocation, true, true);
|
||||
}
|
||||
} else if(GetLastError() == ERROR_NO_MORE_FILES) break;
|
||||
}
|
||||
directoryname = directoryname.substr(0, directoryname.size()-2);
|
||||
//BUG 5: Not closing the FileFind with FindClose - OS keeps handles to directory open. MAIN BUG
|
||||
FindClose( dhandle );
|
||||
}
|
||||
}
|
||||
if (bDir)
|
||||
{
|
||||
HANDLE DirectoryHandle;
|
||||
DirectoryHandle = CreateFileW(directoryname.c_str(),
|
||||
FILE_LIST_DIRECTORY,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
|
||||
NULL);
|
||||
//BUG 6: Not checking CreateFileA for invalid handle return.
|
||||
if( DirectoryHandle != INVALID_HANDLE_VALUE )
|
||||
{
|
||||
|
||||
bool DeletionResult = (RemoveDirectoryW(directoryname.c_str()) != 0)?true:false;
|
||||
CloseHandle(DirectoryHandle);
|
||||
return DeletionResult;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CDbgPlotViewerApp::SetCrashDumpHandler()
|
||||
{
|
||||
if (_bEnableCrashDump)
|
||||
SetCrashDump();
|
||||
}
|
||||
|
||||
void CDbgPlotViewerApp::ClearLog()
|
||||
{
|
||||
DWORD requiredLen = ::GetCurrentDirectory(0, NULL);
|
||||
if (requiredLen == 0)
|
||||
return;
|
||||
|
||||
const wchar_t * dir = L"\\logs";
|
||||
|
||||
requiredLen += (wcslen(dir) + 1);
|
||||
|
||||
wchar_t * path = new wchar_t[requiredLen];
|
||||
DWORD ret = ::GetCurrentDirectory(requiredLen, path);
|
||||
|
||||
if (ret == 0)
|
||||
{
|
||||
delete [] path;
|
||||
return;
|
||||
}
|
||||
|
||||
wcscat(path, dir);
|
||||
DeleteDirRecursive(path, true, true);
|
||||
|
||||
if (path)
|
||||
delete [] path;
|
||||
}
|
||||
|
||||
void CDbgPlotViewerApp::InitAppObj()
|
||||
{
|
||||
_serialGen = make_shared<SoraDbgPlot::Common::SharedSerialNumGenerator>(
|
||||
SharedNameManager::GetSerialNumGeneratorName()
|
||||
);
|
||||
_taskQueue = make_shared<TaskQueue>();
|
||||
channelManager = make_shared<SharedChannelManager>();
|
||||
objLookup = make_shared<ObjLookup>();
|
||||
plotWindowOpenedContainer = make_shared<PlotWindowOpenedContainer>();
|
||||
plotOperationDriver = make_shared<PlotOperationDriver>();
|
||||
controlPanelDriver = make_shared<ControlPanelDriver>();
|
||||
playPauseController = make_shared<PlotWndPlayPauseController>();
|
||||
|
||||
RouteMessage_SharedObj();
|
||||
RouteMessage_TreeUpdate();
|
||||
RouteMessage_OpenOperation();
|
||||
RouteMessage_SaveLoad();
|
||||
RouteMessage_PlayPause();
|
||||
}
|
||||
|
||||
void CDbgPlotViewerApp::DeiniteAppObj()
|
||||
{
|
||||
|
||||
objLookup->Clear();
|
||||
channelManager->Clear();
|
||||
plotWindowOpenedContainer->Clear();
|
||||
|
||||
channelManager.reset();
|
||||
objLookup.reset();
|
||||
plotWindowOpenedContainer.reset();
|
||||
plotOperationDriver.reset();
|
||||
controlPanelDriver.reset();
|
||||
playPauseController.reset();
|
||||
currentObject.reset();
|
||||
_taskQueue.reset();
|
||||
|
||||
while(1)
|
||||
{
|
||||
int numQueue = TaskQueue::WaitAndClean(1000);
|
||||
|
||||
#ifdef _DEBUG
|
||||
//int numHandler = SoraDbgPlot::Event::EventHandlerCount();
|
||||
//TRACE0("Waiting for task queue tasks\n");
|
||||
//TRACE1("Task queue count: %d\n", numQueue);
|
||||
//TRACE1("Event handler unreleased: %d\n", numHandler);
|
||||
//TRACE1("Task num in queue: %d\n", SoraDbgPlot::Task::TaskQueue::MonitorTaskInQueue());
|
||||
//TRACE1("Task num to run: %d\n", SoraDbgPlot::Task::TaskQueue::MonitorTaskCntToRun());
|
||||
//TRACE1("Task num runnning: %d\n", SoraDbgPlot::Task::TaskQueue::MonitorTaskCntRunning());
|
||||
//TRACE1("Task queue op num: %d\n", SoraDbgPlot::Task::TaskQueue::MonitorTaskQueueOpCnt());
|
||||
#endif
|
||||
|
||||
if (numQueue == 0)
|
||||
break;
|
||||
}
|
||||
_serialGen.reset();
|
||||
|
||||
ClearLog();
|
||||
|
||||
::OutputDebugString(L"DebugPlot Viewer exited\n");
|
||||
}
|
||||
|
||||
void CDbgPlotViewerApp::RouteMessage_SaveLoad()
|
||||
{
|
||||
auto lu = objLookup;
|
||||
auto pl = plotWindowOpenedContainer;
|
||||
auto pod = theApp.plotOperationDriver;
|
||||
auto playPauseController = theApp.playPauseController;
|
||||
|
||||
lu->EventPlotWindowLoaded.Subscribe([pod](const void * sender, const ObjLookup::PlotWindowLoadedEvent & e){
|
||||
pod->AddPlotWnd(e._plotWnd);
|
||||
});
|
||||
|
||||
lu->EventPlotWindowLoaded.Subscribe([playPauseController](const void * sender, const ObjLookup::PlotWindowLoadedEvent & e){
|
||||
playPauseController->AddProcessPlotWnd(e._process, e._plotWnd);
|
||||
});
|
||||
|
||||
lu->EventPlotWindowLoaded.Subscribe([pl](const void * sender, const ObjLookup::PlotWindowLoadedEvent & e){
|
||||
pl->AddPlotWindow(e._plotWnd, e._rect);
|
||||
});
|
||||
|
||||
lu->EventChannelLoaded.Subscribe([pl](const void * sender, const ObjLookup::ChannelLoadedEvent & e){
|
||||
pl->AddChannel(e._plotWnd, e._channel, e._rect);
|
||||
});
|
||||
}
|
||||
|
||||
void CDbgPlotViewerApp::RouteMessage_OpenOperation()
|
||||
{
|
||||
auto lu = objLookup;
|
||||
auto cm = channelManager;
|
||||
auto pl = plotWindowOpenedContainer;
|
||||
auto pod = theApp.plotOperationDriver;
|
||||
auto playPauseController = theApp.playPauseController;
|
||||
|
||||
pl->EventCloseChannel.Subscribe([lu](const void * sender, const PlotWindowOpenedContainer::CloseChannelEvent & e){
|
||||
lu->CloseChannel(e._channel);
|
||||
});
|
||||
|
||||
pl->EventAddPlotWndRequest.Subscribe([lu, pl](const void * sender, const PlotWindowOpenedContainer::AddPlotWndParam & e){
|
||||
auto succ = make_shared<bool>();
|
||||
auto process = e._process;
|
||||
auto channel = e._channel;
|
||||
auto point = e._point;
|
||||
|
||||
auto pl2 = pl;
|
||||
lu->OpenChannel(channel, [pl2, process, channel, point](bool succ){
|
||||
if (succ)
|
||||
pl2->AddPlotWindow(process, channel, point);
|
||||
});
|
||||
});
|
||||
|
||||
pl->EventAddChannelRequest.Subscribe([lu, pl](const void * sender, const PlotWindowOpenedContainer::AddChannelRequestEvent & e){
|
||||
auto succ = make_shared<bool>();
|
||||
auto channel = e._channel;
|
||||
auto plotWnd = e._plotWnd;
|
||||
auto rect = e._rect;
|
||||
lu->CloseChannel(channel);
|
||||
|
||||
auto pl2 = pl;
|
||||
lu->OpenChannel(channel, [pl2, plotWnd, channel, rect](bool succ){
|
||||
pl2->AddChannel(plotWnd, channel, rect);
|
||||
});
|
||||
});
|
||||
|
||||
pl->EventClosePlotWnd.Subscribe([pod](const void * sender, const PlotWindowOpenedContainer::ClosePlotWndEvent & e){
|
||||
pod->RemovePlotWnd(e._plotWnd);
|
||||
});
|
||||
|
||||
pl->EventClosePlotWnd.Subscribe([lu](const void * sender, const PlotWindowOpenedContainer::ClosePlotWndEvent & e){
|
||||
lu->RemovePlotWnd(e._plotWnd);
|
||||
});
|
||||
|
||||
pl->EventClosePlotWnd.Subscribe([playPauseController](const void * sender, const PlotWindowOpenedContainer::ClosePlotWndEvent & e){
|
||||
playPauseController->RemovePlotWnd(e._plotWnd);
|
||||
});
|
||||
|
||||
pl->EventPlotWndAdded.Subscribe([pod](const void * sender, const PlotWindowOpenedContainer::PlotWndAddedParam & e){
|
||||
pod->AddPlotWnd(e._plotWnd);
|
||||
});
|
||||
|
||||
pl->EventPlotWndAdded.Subscribe([playPauseController](const void * sender, const PlotWindowOpenedContainer::PlotWndAddedParam & e){
|
||||
playPauseController->AddProcessPlotWnd(e._process, e._plotWnd);
|
||||
});
|
||||
|
||||
pl->EventPlotWndAdded.Subscribe([lu](const void * sender, const PlotWindowOpenedContainer::PlotWndAddedParam & e){
|
||||
lu->AddPlotWnd(e._plotWnd, e._process);
|
||||
});
|
||||
}
|
||||
|
||||
void CDbgPlotViewerApp::RouteMessage_TreeUpdate()
|
||||
{
|
||||
//auto lu = objLookup;
|
||||
|
||||
//lu->EventProcessChannelTreeChanged.Subscribe([](const void * sender, const ObjLookup::ProcessChannelTree & tree){
|
||||
// TRACE0("Ps-Ch tree changed\n");
|
||||
// for (auto iterPsChMap = tree.begin(); iterPsChMap != tree.end(); ++iterPsChMap)
|
||||
// {
|
||||
// auto process = iterPsChMap->first;
|
||||
// TRACE2("process [%d] [%s]\n", process->Pid(), process->Name().c_str());
|
||||
// auto channelMap = iterPsChMap->second;
|
||||
// for (auto iterChannel = channelMap.begin(); iterChannel != channelMap.end(); ++iterChannel)
|
||||
// {
|
||||
// TRACE2("channel [%d] [%s]\n", (*iterChannel)->Pid(), (*iterChannel)->Name().c_str());
|
||||
// }
|
||||
// }
|
||||
//});
|
||||
}
|
||||
|
||||
void CDbgPlotViewerApp::RouteMessage_SharedObj()
|
||||
{
|
||||
auto lu = objLookup;
|
||||
auto cm = channelManager;
|
||||
auto pl = plotWindowOpenedContainer;
|
||||
|
||||
cm->EventDiscoverdProcess.Subscribe([lu](const void * sender, const vector<shared_ptr<SharedProcess> > & vec){
|
||||
TRACE0("New shared process discoved\n");
|
||||
lu->AddSharedProcess(vec);
|
||||
});
|
||||
|
||||
cm->EventProcessClosed.Subscribe([lu](const void * sender, const vector<shared_ptr<SharedProcess> > & vec){
|
||||
TRACE0("Shared Process closed\n");
|
||||
lu->RemoveSharedProcess(vec);
|
||||
});
|
||||
|
||||
cm->EventDiscoverdChannel.Subscribe([lu](const void * sender, const vector<shared_ptr<SharedChannel> > & vec){
|
||||
TRACE0("New shared channel discovered\n");
|
||||
lu->AddSharedChannel(vec);
|
||||
});
|
||||
|
||||
cm->EventChannelClosed.Subscribe([lu](const void * sender, const vector<shared_ptr<SharedChannel> > & vec){
|
||||
TRACE0("Shared channel closed\n");
|
||||
lu->RemoveSharedChannel(vec);
|
||||
});
|
||||
|
||||
// control panel related
|
||||
|
||||
auto controlPanelDriver = theApp.controlPanelDriver;
|
||||
|
||||
lu->EventProcessOpenedAttatched.Subscribe([controlPanelDriver](const void * sender, const std::shared_ptr<ProcessOpened> & process){
|
||||
controlPanelDriver->AddProcessOpened(process);
|
||||
});
|
||||
|
||||
lu->EventProcessOpenedDeattatched.Subscribe([controlPanelDriver](const void * sender, const std::shared_ptr<ProcessOpened> & process){
|
||||
controlPanelDriver->RemoveProcess(process);
|
||||
});
|
||||
|
||||
lu->EventProcessOpenedAttatched.Subscribe([pl](const void * sender, const std::shared_ptr<ProcessOpened> & process){
|
||||
pl->PrcessAttatchDetatch(process, true);
|
||||
});
|
||||
|
||||
lu->EventProcessOpenedDeattatched.Subscribe([pl](const void * sender, const std::shared_ptr<ProcessOpened> & process){
|
||||
pl->PrcessAttatchDetatch(process, false);
|
||||
});
|
||||
}
|
||||
|
||||
void CDbgPlotViewerApp::RouteMessage_PlayPause()
|
||||
{
|
||||
auto theObjLookup = this->objLookup;
|
||||
auto thePlayPauseController = this->playPauseController;
|
||||
|
||||
theObjLookup->EventPauseProcess.Subscribe([thePlayPauseController](const void * sender, const std::shared_ptr<ProcessOpened> & process){
|
||||
thePlayPauseController->PauseProcess(process);
|
||||
});
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
|
||||
// DbgPlotViewer.h : main header file for the DbgPlotViewer application
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#ifndef __AFXWIN_H__
|
||||
#error "include 'stdafx.h' before including this file for PCH"
|
||||
#endif
|
||||
|
||||
#include "resource.h" // main symbols
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "SharedSerialNumGenerator.h"
|
||||
#include "SharedChannelManager.h"
|
||||
#include "GlobalObjLookup.h"
|
||||
#include "PlotWindowOpenedContainer.h"
|
||||
#include "PlotOperationDriver.h"
|
||||
#include "ControlPanelDriver.h"
|
||||
#include "PlotWndPlayPauseController.h"
|
||||
|
||||
// CDbgPlotViewerApp:
|
||||
// See DbgPlotViewer.cpp for the implementation of this class
|
||||
//
|
||||
|
||||
class CDbgPlotViewerApp : public CWinAppEx
|
||||
{
|
||||
public:
|
||||
CDbgPlotViewerApp();
|
||||
|
||||
|
||||
// Overrides
|
||||
public:
|
||||
virtual BOOL InitInstance();
|
||||
virtual int ExitInstance();
|
||||
|
||||
// Implementation
|
||||
BOOL m_bHiColorIcons;
|
||||
|
||||
virtual void PreLoadState();
|
||||
virtual void LoadCustomState();
|
||||
virtual void SaveCustomState();
|
||||
|
||||
afx_msg void OnAppAbout();
|
||||
DECLARE_MESSAGE_MAP()
|
||||
public:
|
||||
std::shared_ptr<SoraDbgPlot::SharedObj::SharedChannelManager> channelManager;
|
||||
std::shared_ptr<ObjLookup> objLookup;
|
||||
std::shared_ptr<PlotWindowOpenedContainer> plotWindowOpenedContainer;
|
||||
std::shared_ptr<PlotOperationDriver> plotOperationDriver;
|
||||
std::shared_ptr<PropObject> currentObject;
|
||||
std::shared_ptr<ControlPanelDriver> controlPanelDriver;
|
||||
std::shared_ptr<PlotWndPlayPauseController> playPauseController;
|
||||
|
||||
private:
|
||||
bool DeleteDirRecursive(const std::wstring &path, bool bDir, bool bContent);
|
||||
void ClearLog();
|
||||
void SetCrashDumpHandler();
|
||||
void InitAppObj();
|
||||
void DeiniteAppObj();
|
||||
void RouteMessage_SharedObj();
|
||||
void RouteMessage_TreeUpdate();
|
||||
void RouteMessage_OpenOperation();
|
||||
void RouteMessage_SaveLoad();
|
||||
void RouteMessage_PlayPause();
|
||||
|
||||
bool _bEnableCrashDump;
|
||||
|
||||
std::shared_ptr<SoraDbgPlot::Common::SharedSerialNumGenerator> _serialGen;
|
||||
|
||||
std::shared_ptr<SoraDbgPlot::Task::TaskQueue> _taskQueue;
|
||||
|
||||
bool _bInitialized;
|
||||
|
||||
private:
|
||||
ULONG_PTR _gdiplusToken; // GDI+
|
||||
};
|
||||
|
||||
extern CDbgPlotViewerApp theApp;
|
Двоичный файл не отображается.
|
@ -0,0 +1,302 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{19D199A8-1BF1-49E4-97F6-B4CB51F6F58B}</ProjectGuid>
|
||||
<SccProjectName>
|
||||
</SccProjectName>
|
||||
<SccAuxPath>
|
||||
</SccAuxPath>
|
||||
<SccLocalPath>
|
||||
</SccLocalPath>
|
||||
<SccProvider>
|
||||
</SccProvider>
|
||||
<RootNamespace>DbgPlotViewer</RootNamespace>
|
||||
<Keyword>MFCProj</Keyword>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<UseOfMfc>Dynamic</UseOfMfc>
|
||||
<PlatformToolset>v110</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<UseOfMfc>Dynamic</UseOfMfc>
|
||||
<PlatformToolset>v110</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<IncludePath>C:\Program Files %28x86%29\Visual Leak Detector\include;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>C:\Program Files %28x86%29\Visual Leak Detector\lib\Win32;$(LibraryPath)</LibraryPath>
|
||||
<TargetName>DbgPlot</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<TargetName>DbgPlot</TargetName>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_WINDOWS;_DEBUG;USER_MODE;DEBUG_INTERNAL_DATAFILTER;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>..\DebugPlotU;..\..\..\kernel\core\inc;..\Common;..\LibViewer</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<TreatWChar_tAsBuiltInType>false</TreatWChar_tAsBuiltInType>
|
||||
<CallingConvention>StdCall</CallingConvention>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>msxml6.lib;usora.lib;LibViewer.lib;Psapi.lib;Common.lib;DebugPlotU_Viewer.lib;DbgHelp.lib</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\Debug;..\..\..\target\ke\chk_wxp_x86\i386</AdditionalLibraryDirectories>
|
||||
<UACExecutionLevel>RequireAdministrator</UACExecutionLevel>
|
||||
</Link>
|
||||
<Midl>
|
||||
<MkTypLibCompatible>false</MkTypLibCompatible>
|
||||
<ValidateAllParameters>true</ValidateAllParameters>
|
||||
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</Midl>
|
||||
<ResourceCompile>
|
||||
<Culture>0x0409</Culture>
|
||||
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(IntDir);..\..\..\build;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ResourceCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;_WINDOWS;NDEBUG;USER_MODE;ENABLE_CRASH_DUMP;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>..\DebugPlotU;..\..\..\kernel\core\inc;..\Common;..\LibViewer</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<TreatWChar_tAsBuiltInType>false</TreatWChar_tAsBuiltInType>
|
||||
<CallingConvention>StdCall</CallingConvention>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>msxml6.lib;usora.lib;DebugPlotU_Viewer.lib;LibViewer.lib;Psapi.lib;DbgHelp.lib</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\Release;..\..\..\target\ke\fre_wxp_x86\i386</AdditionalLibraryDirectories>
|
||||
<UACExecutionLevel>RequireAdministrator</UACExecutionLevel>
|
||||
</Link>
|
||||
<Midl>
|
||||
<MkTypLibCompatible>false</MkTypLibCompatible>
|
||||
<ValidateAllParameters>true</ValidateAllParameters>
|
||||
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</Midl>
|
||||
<ResourceCompile>
|
||||
<Culture>0x0409</Culture>
|
||||
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(IntDir);..\..\..\build;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ResourceCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<None Include="ClassDiagram.cd" />
|
||||
<None Include="ClassDiagram1.cd" />
|
||||
<None Include="ReadMe.txt" />
|
||||
<None Include="res\autolayout.ico" />
|
||||
<None Include="res\bitmap1.bmp" />
|
||||
<None Include="res\bmp00001.bmp" />
|
||||
<None Include="res\channelExplorer.ico" />
|
||||
<None Include="res\channel_bmp.bmp" />
|
||||
<None Include="res\controlPanel.ico" />
|
||||
<None Include="res\DbgPlotViewer.ico" />
|
||||
<None Include="res\DbgPlotViewer.rc2" />
|
||||
<None Include="res\DbgPlotViewerDoc.ico" />
|
||||
<None Include="res\menuimages.bmp" />
|
||||
<None Include="res\menuimages_hc.bmp" />
|
||||
<None Include="res\pause32.bmp" />
|
||||
<None Include="res\properties.ico" />
|
||||
<None Include="res\run32.bmp" />
|
||||
<None Include="res\singlestep32.bmp" />
|
||||
<None Include="res\Toolbar.bmp" />
|
||||
<None Include="res\toolbar1.bmp" />
|
||||
<None Include="res\Toolbar256.bmp" />
|
||||
<None Include="UserImages.bmp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="AsyncObject.h" />
|
||||
<ClInclude Include="AutoLayoutSlider.h" />
|
||||
<ClInclude Include="BaseProperty.h" />
|
||||
<ClInclude Include="BitmapPlotWnd.h" />
|
||||
<ClInclude Include="ChannelAddable.h" />
|
||||
<ClInclude Include=".\ChannelProperty.h" />
|
||||
<ClInclude Include="ChannelOpened.h" />
|
||||
<ClInclude Include="ChannelOpenedDots.h" />
|
||||
<ClInclude Include="ChannelOpenedFixedLengthType.h" />
|
||||
<ClInclude Include="ChannelOpenedLine.h" />
|
||||
<ClInclude Include="ChannelOpenedLineType.h" />
|
||||
<ClInclude Include="ChannelOpenedLog.h" />
|
||||
<ClInclude Include="ChannelOpenedSpectrum.h" />
|
||||
<ClInclude Include="ChannelOpenedText.h" />
|
||||
<ClInclude Include="ChannelOpenedTextType.h" />
|
||||
<ClInclude Include="ChannelTreeCtrl.h" />
|
||||
<ClInclude Include=".\ViewerAppConst.h" />
|
||||
<ClInclude Include="ControlPanelDriver.h" />
|
||||
<ClInclude Include="ControlPanelList.h" />
|
||||
<ClInclude Include="ControlPanelWnd.h" />
|
||||
<ClInclude Include="CrashDump.h" />
|
||||
<ClInclude Include="CustomButton.h" />
|
||||
<ClInclude Include="DbgPlotViewer.h" />
|
||||
<ClInclude Include="DbgPlotViewerDoc.h" />
|
||||
<ClInclude Include="DbgPlotViewerView.h" />
|
||||
<ClInclude Include="DockableWndContainer.h" />
|
||||
<ClInclude Include="GlobalObjLookup.h" />
|
||||
<ClInclude Include=".\Targetable.h" />
|
||||
<ClInclude Include="GridAlg.h" />
|
||||
<ClInclude Include="HelperFunc.h" />
|
||||
<ClInclude Include="Invokable.h" />
|
||||
<ClInclude Include="BitmapTypeSettings.h" />
|
||||
<ClInclude Include="MainFrm.h" />
|
||||
<ClInclude Include=".\PropObject.h" />
|
||||
<ClInclude Include="PassiveTaskQueue.h" />
|
||||
<ClInclude Include="PlayControlWnd.h" />
|
||||
<ClInclude Include=".\PlotWindowOpenedContainer.h" />
|
||||
<ClInclude Include="PlotOperationDriver.h" />
|
||||
<ClInclude Include=".\PlotWindowLineTypeProperty.h" />
|
||||
<ClInclude Include="PlotWindowDotsProperty.h" />
|
||||
<ClInclude Include="PlotWindowOpened.h" />
|
||||
<ClInclude Include="PlotWindowOpenedBitmapType.h" />
|
||||
<ClInclude Include="PlotWindowOpenedDots.h" />
|
||||
<ClInclude Include="PlotWindowOpenedLine.h" />
|
||||
<ClInclude Include="PlotWindowOpenedLineType.h" />
|
||||
<ClInclude Include="PlotWindowOpenedLog.h" />
|
||||
<ClInclude Include="PlotWindowOpenedSpectrum.h" />
|
||||
<ClInclude Include="PlotWindowOpenedText.h" />
|
||||
<ClInclude Include="PlotWindowOpenedTextType.h" />
|
||||
<ClInclude Include="PlotWindowTextTypeProperty.h" />
|
||||
<ClInclude Include="PlotWnd.h" />
|
||||
<ClInclude Include="PlotWndContainer.h" />
|
||||
<ClInclude Include="PlotWndPlayPauseController.h" />
|
||||
<ClInclude Include="ProcessOpened.h" />
|
||||
<ClInclude Include="ReplayBufferTrackBar.h" />
|
||||
<ClInclude Include="Resource.h" />
|
||||
<ClInclude Include="Serializable.h" />
|
||||
<ClInclude Include="SettingsPlotWindow.h" />
|
||||
<ClInclude Include="stdafx.h" />
|
||||
<ClInclude Include="SubBitmapPlotWnd.h" />
|
||||
<ClInclude Include="SubPlotWnd.h" />
|
||||
<ClInclude Include="SubTextTypePlotWnd.h" />
|
||||
<ClInclude Include="targetver.h" />
|
||||
<ClInclude Include="TemplateProperty.h" />
|
||||
<ClInclude Include="TextPlayControlWnd.h" />
|
||||
<ClInclude Include="TextTypePlotWnd.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="AsyncObject.cpp" />
|
||||
<ClCompile Include="AutoLayoutSlider.cpp" />
|
||||
<ClCompile Include="BaseProperty.cpp" />
|
||||
<ClCompile Include="BitmapPlotWnd.cpp" />
|
||||
<ClCompile Include=".\ChannelProperty.cpp" />
|
||||
<ClCompile Include="ChannelAddable.cpp" />
|
||||
<ClCompile Include="ChannelOpened.cpp" />
|
||||
<ClCompile Include="ChannelOpenedDots.cpp" />
|
||||
<ClCompile Include="ChannelOpenedFixedLengthType.cpp" />
|
||||
<ClCompile Include="ChannelOpenedLine.cpp" />
|
||||
<ClCompile Include="ChannelOpenedLineType.cpp" />
|
||||
<ClCompile Include="ChannelOpenedLog.cpp" />
|
||||
<ClCompile Include="ChannelOpenedSpectrum.cpp" />
|
||||
<ClCompile Include="ChannelOpenedText.cpp" />
|
||||
<ClCompile Include="ChannelOpenedTextType.cpp" />
|
||||
<ClCompile Include="ChannelTreeCtrl.cpp" />
|
||||
<ClCompile Include=".\ViewerAppConst.cpp" />
|
||||
<ClCompile Include="ControlPanelDriver.cpp" />
|
||||
<ClCompile Include="ControlPanelList.cpp" />
|
||||
<ClCompile Include="ControlPanelWnd.cpp" />
|
||||
<ClCompile Include="CrashDump.cpp" />
|
||||
<ClCompile Include="CustomButton.cpp" />
|
||||
<ClCompile Include="DbgPlotViewer.cpp" />
|
||||
<ClCompile Include="DbgPlotViewerDoc.cpp" />
|
||||
<ClCompile Include="DbgPlotViewerView.cpp" />
|
||||
<ClCompile Include="DockableWndContainer.cpp" />
|
||||
<ClCompile Include="GlobalObjLookup.cpp" />
|
||||
<ClCompile Include="GridAlg.cpp" />
|
||||
<ClCompile Include="HelperFunc.cpp" />
|
||||
<ClCompile Include="Invokable.cpp" />
|
||||
<ClCompile Include="BitmapTypeSettings.cpp" />
|
||||
<ClCompile Include="MainFrm.cpp" />
|
||||
<ClCompile Include=".\PropObject.cpp" />
|
||||
<ClCompile Include="PlayControlWnd.cpp" />
|
||||
<ClCompile Include=".\PlotWindowOpenedContainer.cpp" />
|
||||
<ClCompile Include="PlotOperationDriver.cpp" />
|
||||
<ClCompile Include=".\PlotWindowLineTypeProperty.cpp" />
|
||||
<ClCompile Include="PlotWindowDotsProperty.cpp" />
|
||||
<ClCompile Include="PlotWindowOpened.cpp" />
|
||||
<ClCompile Include="PlotWindowOpenedBitmapType.cpp" />
|
||||
<ClCompile Include="PlotWindowOpenedDots.cpp" />
|
||||
<ClCompile Include="PlotWindowOpenedLine.cpp" />
|
||||
<ClCompile Include="PlotWindowOpenedLineType.cpp" />
|
||||
<ClCompile Include="PlotWindowOpenedLog.cpp" />
|
||||
<ClCompile Include="PlotWindowOpenedSpectrum.cpp" />
|
||||
<ClCompile Include="PlotWindowOpenedText.cpp" />
|
||||
<ClCompile Include="PlotWindowOpenedTextType.cpp" />
|
||||
<ClCompile Include="PlotWindowTextTypeProperty.cpp" />
|
||||
<ClCompile Include="PlotWnd.cpp" />
|
||||
<ClCompile Include="PlotWndContainer.cpp" />
|
||||
<ClCompile Include="PlotWndPlayPauseController.cpp" />
|
||||
<ClCompile Include="ProcessOpened.cpp" />
|
||||
<ClCompile Include="ReplayBufferTrackBar.cpp" />
|
||||
<ClCompile Include="SettingsPlotWindow.cpp" />
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SubBitmapPlotWnd.cpp" />
|
||||
<ClCompile Include="SubPlotWnd.cpp" />
|
||||
<ClCompile Include="SubTextTypePlotWnd.cpp" />
|
||||
<ClCompile Include="TemplateProperty.cpp" />
|
||||
<ClCompile Include="TextPlayControlWnd.cpp" />
|
||||
<ClCompile Include="TextTypePlotWnd.cpp" />
|
||||
<ClCompile Include="Vld.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="DbgPlotViewer.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Common\Common.vcxproj">
|
||||
<Project>{54730ad7-5b11-493b-adcc-8e4ec3c0204a}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\LibViewer\LibViewer.vcxproj">
|
||||
<Project>{6ae0ea97-eb5a-40e1-92d8-54532e208be1}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
<ProjectExtensions>
|
||||
<VisualStudio>
|
||||
<UserProperties RESOURCE_FILE="DbgPlotViewer.rc" />
|
||||
</VisualStudio>
|
||||
</ProjectExtensions>
|
||||
</Project>
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче