From 904804de28fbc4ace8d12540694390622a400031 Mon Sep 17 00:00:00 2001 From: Akash Mozumdar Date: Wed, 18 Jul 2018 16:18:43 -0400 Subject: [PATCH] refactor textthread --- gui/TextBuffer.cpp | 5 +- gui/TextBuffer.h | 2 +- gui/utility.cpp | 10 ++++ gui/utility.h | 2 + gui/window.cpp | 69 ++++++++-------------- vnr/texthook/host/hookman.cc | 15 +++-- vnr/texthook/host/hookman.h | 41 ++++--------- vnr/texthook/host/pipe.cc | 4 +- vnr/texthook/host/textthread.cc | 88 ++++++++++------------------ vnr/texthook/host/textthread.h | 35 ++++++------ vnr/texthook/host/textthread_p.h | 98 -------------------------------- 11 files changed, 106 insertions(+), 263 deletions(-) delete mode 100644 vnr/texthook/host/textthread_p.h diff --git a/gui/TextBuffer.cpp b/gui/TextBuffer.cpp index f819bd1..f3e21d1 100644 --- a/gui/TextBuffer.cpp +++ b/gui/TextBuffer.cpp @@ -23,11 +23,10 @@ TextBuffer::~TextBuffer() WaitForSingleObject(hThread.get(), 0); } -void TextBuffer::AddText(LPCWSTR str, int len, bool line) +void TextBuffer::AddText(std::wstring text, bool line) { CSLock lock(cs); - if (len > 0) - this->str.append(str, len); + this->str.append(text); line_break = line; } diff --git a/gui/TextBuffer.h b/gui/TextBuffer.h index 20bd63f..cb15837 100644 --- a/gui/TextBuffer.h +++ b/gui/TextBuffer.h @@ -9,7 +9,7 @@ public: TextBuffer(HWND edit); ~TextBuffer(); void Flush(); - void AddText(LPCWSTR str, int len, bool line); + void AddText(std::wstring text, bool line); void ClearBuffer(); bool Running() { return running; } private: diff --git a/gui/utility.cpp b/gui/utility.cpp index 402c446..a66d28f 100644 --- a/gui/utility.cpp +++ b/gui/utility.cpp @@ -292,3 +292,13 @@ int WC_MB(const wchar_t *wc, char* mb, int mb_length) { return WideCharToMultiByte(932, 0, wc, -1, mb, mb_length, NULL, NULL); } + +std::wstring GetEntryString(TextThread* thread) +{ + ThreadParameter tp = thread->GetThreadParameter(); + std::wstring buffer; + buffer.resize(200); + buffer.resize(swprintf(&buffer[0], L"%.4X:%.4d:0x%08X:0x%08X:0x%08X:", thread->Number(), tp.pid, tp.hook, tp.retn, tp.spl)); + buffer += man->GetHook(tp.pid, tp.hook).name; + return buffer; +} diff --git a/gui/utility.h b/gui/utility.h index 5c8a065..74ba36f 100644 --- a/gui/utility.h +++ b/gui/utility.h @@ -1,6 +1,7 @@ #pragma once #include "ITH.h" +#include "texthook/host/textthread.h" struct HookParam; struct ProcessRecord; @@ -56,6 +57,7 @@ HANDLE IthCreateFile(LPCWSTR name, DWORD option, DWORD share, DWORD disposition) int MB_WC(const char* mb, wchar_t* wc, int wc_length); int MB_WC_count(const char* mb, int mb_length); int WC_MB(const wchar_t *wc, char* mb, int mb_length); +std::wstring GetEntryString(TextThread * thread); bool Parse(const std::wstring& cmd, HookParam& hp); // http://jrdodds.blogs.com/blog/2004/08/raii_in_c.html diff --git a/gui/window.cpp b/gui/window.cpp index c01c36b..13cf223 100644 --- a/gui/window.cpp +++ b/gui/window.cpp @@ -347,16 +347,9 @@ void ClickButton(HWND hWnd, HWND h) } } -DWORD ThreadOutput(TextThread* thread, const BYTE* out, DWORD len, DWORD new_line) +void ThreadOutput(TextThread* thread, std::wstring output) { - if (len == 0) - return len; - DWORD status = thread->Status(); - if (status & CURRENT_SELECT) - { - texts->AddText((LPWSTR)out, len / 2, false); - } - return len; + if (thread->Status() & CURRENT_SELECT) texts->AddText(output, false); } bool GetHookParam(DWORD pid, DWORD hook_addr, HookParam& hp) @@ -367,28 +360,21 @@ bool GetHookParam(DWORD pid, DWORD hook_addr, HookParam& hp) return true; } -std::wstring GetEntryString(TextThread& thread) -{ - CHAR entry[512]; - thread.GetEntryString(entry, 512); - return toUnicodeString(entry); -} - -std::wstring CreateEntryWithLink(TextThread& thread, std::wstring& entry) +std::wstring CreateEntryWithLink(ThreadParameter tp, std::wstring& entry) { std::wstring entryWithLink = entry; - if (thread.PID() == 0) + if (tp.pid == 0) entryWithLink += L"ConsoleOutput"; HookParam hp = {}; - if (GetHookParam(thread.PID(), thread.Addr(), hp)) - entryWithLink += L" (" + GetCode(hp, thread.PID()) + L")"; + if (GetHookParam(tp.pid, tp.hook, hp)) + entryWithLink += L" (" + GetCode(hp, tp.hook) + L")"; return entryWithLink; } void AddToCombo(TextThread& thread, bool replace) { - std::wstring entry = GetEntryString(thread); - std::wstring entryWithLink = CreateEntryWithLink(thread, entry); + std::wstring entry = GetEntryString(&thread); + std::wstring entryWithLink = CreateEntryWithLink(thread.GetThreadParameter(), entry); int i = ComboBox_FindString(hwndCombo, -1, entry.c_str()); if (replace) { @@ -410,12 +396,10 @@ void AddToCombo(TextThread& thread, bool replace) void RemoveFromCombo(TextThread* thread) { - CHAR entry[512]; - thread->GetEntryString(entry, 512); - std::wstring unicodeEntry = toUnicodeString(entry); - if (thread->PID() == 0) - unicodeEntry += L"ConsoleOutput"; - int i = ComboBox_FindString(hwndCombo, 0, unicodeEntry.c_str()); + std::wstring entry = GetEntryString(thread); + if (thread->GetThreadParameter().pid == 0) + entry += L"ConsoleOutput"; + int i = ComboBox_FindString(hwndCombo, 0, entry.c_str()); if (i != CB_ERR) { if (ComboBox_DeleteString(hwndCombo, i) == CB_ERR) @@ -423,7 +407,7 @@ void RemoveFromCombo(TextThread* thread) } } -DWORD SetEditText(LPWSTR wc) +DWORD SetEditText(LPCWSTR wc) { DWORD line; Edit_SetText(hwndEdit, wc); @@ -435,21 +419,16 @@ DWORD SetEditText(LPWSTR wc) DWORD ThreadReset(TextThread* thread) { texts->ClearBuffer(); - man->SetCurrent(thread); - thread->LockVector(); + man->SetCurrent(thread);; - DWORD len = 0; - LPWSTR wc = (LPWSTR)thread->GetStore(&len); - len /= 2; - wc[len] = L'\0'; - SetEditText(wc); + std::wstring text = thread->GetStore(); + SetEditText(text.c_str()); WCHAR buffer[16]; std::swprintf(buffer, L"%04X", thread->Number()); DWORD tmp = ComboBox_FindString(hwndCombo, 0, buffer); if (tmp != CB_ERR) ComboBox_SetCurSel(hwndCombo, tmp); - thread->UnlockVector(); return 0; } @@ -463,20 +442,20 @@ bool IsUnicodeHook(const ProcessRecord& pr, DWORD hook); DWORD ThreadCreate(TextThread* thread) { - thread->RegisterOutputCallBack(ThreadOutput, 0); + thread->RegisterOutputCallBack(ThreadOutput); //thread->RegisterFilterCallBack(ThreadFilter, 0); AddToCombo(*thread, false); - const auto& tp = thread->GetThreadParameter(); - auto pr = man->GetProcessRecord(tp->pid); + auto tp = thread->GetThreadParameter(); + auto pr = man->GetProcessRecord(tp.pid); if (pr == NULL) return 0; - if (IsUnicodeHook(*pr, tp->hook)) + if (IsUnicodeHook(*pr, tp.hook)) thread->Status() |= USING_UNICODE; - auto pf = pfman->GetProfile(tp->pid); + auto pf = pfman->GetProfile(tp.pid); if (!pf) return 0; - const std::wstring& hook_name = GetHookNameByAddress(*pr, thread->GetThreadParameter()->hook); - auto thread_profile = pf->FindThread(thread->GetThreadParameter(), hook_name); + const std::wstring& hook_name = GetHookNameByAddress(*pr, thread->GetThreadParameter().hook); + auto thread_profile = pf->FindThread(&thread->GetThreadParameter(), hook_name); if (thread_profile != pf->Threads().end()) { (*thread_profile)->HookManagerIndex() = thread->Number(); @@ -579,7 +558,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) man->RegisterThreadRemoveCallback(ThreadRemove); man->RegisterThreadResetCallback(ThreadReset); TextThread* console = man->FindSingle(0); - console->RegisterOutputCallBack(ThreadOutput, NULL); + console->RegisterOutputCallBack(ThreadOutput); AddToCombo(*console, false); man->RegisterProcessAttachCallback(RegisterProcess); man->RegisterProcessDetachCallback(RemoveProcessList); diff --git a/vnr/texthook/host/hookman.cc b/vnr/texthook/host/hookman.cc index 8387310..2f3b227 100644 --- a/vnr/texthook/host/hookman.cc +++ b/vnr/texthook/host/hookman.cc @@ -18,7 +18,7 @@ #include "profile/pugixml.h" #include "profile/misc.h" -#define HM_LOCK CriticalSectionLocker d_locker(hmcs) // Synchronized scope for accessing private data +#define HM_LOCK CriticalSectionLocker locker(hmcs) // Synchronized scope for accessing private data HookManager::HookManager() : current(nullptr), @@ -27,12 +27,11 @@ HookManager::HookManager() : reset(nullptr), attach(nullptr), detach(nullptr), - hook(nullptr), new_thread_number(0), textThreadsByParams(), processRecordsByIds() { - TextThread* consoleTextThread = textThreadsByParams[{0, -1UL, -1UL, -1UL}] = new TextThread({ 0, -1UL, -1UL, -1UL }, new_thread_number++, splitDelay); + TextThread* consoleTextThread = textThreadsByParams[{ 0, -1UL, -1UL, -1UL }] = new TextThread({ 0, -1UL, -1UL, -1UL }, new_thread_number++, splitDelay); consoleTextThread->Status() |= USING_UNICODE; SetCurrent(consoleTextThread); @@ -79,7 +78,7 @@ void HookManager::RemoveSingleHook(DWORD pid, DWORD addr) std::vector removedThreads; for (auto i : textThreadsByParams) { - if (i.second->PID() == pid && i.second->Addr() == addr) + if (i.first.pid == pid && i.first.hook == addr) { if (remove) { @@ -102,7 +101,7 @@ void HookManager::RemoveProcessContext(DWORD pid) std::vector removedThreads; for (auto i : textThreadsByParams) { - if (i.second->PID() == pid) + if (i.first.hook == pid) { if (remove) { @@ -274,11 +273,11 @@ void HookManager::AddThreadsToProfile(Profile& pf, const ProcessRecord& pr, DWOR DWORD AddThreadToProfile(Profile& pf, const ProcessRecord& pr, TextThread* thread) { - const ThreadParameter* tp = thread->GetThreadParameter(); - std::wstring hook_name = GetHookNameByAddress(pr, tp->hook); + ThreadParameter tp = thread->GetThreadParameter(); + std::wstring hook_name = GetHookNameByAddress(pr, tp.hook); if (hook_name.empty()) return -1; - auto thread_profile = new ThreadProfile(hook_name, tp->retn, tp->spl, 0, 0, + auto thread_profile = new ThreadProfile(hook_name, tp.retn, tp.spl, 0, 0, THREAD_MASK_RETN | THREAD_MASK_SPLIT, L""); DWORD threads_size = pf.Threads().size(); int thread_profile_index = pf.AddThread(thread_ptr(thread_profile)); diff --git a/vnr/texthook/host/hookman.h b/vnr/texthook/host/hookman.h index 16cfc38..8a66c13 100644 --- a/vnr/texthook/host/hookman.h +++ b/vnr/texthook/host/hookman.h @@ -5,7 +5,7 @@ // Branch: ITH/HookManager.h, rev 133 #include "config.h" -#include "host/textthread.h" +#include "textthread.h" #include "winmutex/winmutex.h" #include #include @@ -16,9 +16,6 @@ namespace pugi { } class Profile; -enum { MAX_REGISTER = 0xf }; -enum { MAX_PREV_REPEAT_LENGTH = 0x20 }; - struct ProcessRecord { HANDLE process_handle; HANDLE hookman_mutex; @@ -33,7 +30,8 @@ struct Hook std::wstring name; }; -typedef DWORD (*ProcessEventCallback)(DWORD pid); +typedef DWORD(*ProcessEventCallback)(DWORD pid); +typedef DWORD(*ThreadEventCallback)(TextThread*); struct ThreadParameterHasher { @@ -67,27 +65,14 @@ public: HANDLE GetHostPipe(DWORD pid); - ThreadEventCallback RegisterThreadCreateCallback(ThreadEventCallback cf) - { return (ThreadEventCallback)_InterlockedExchange((long*)&create,(long)cf); } - - ThreadEventCallback RegisterThreadRemoveCallback(ThreadEventCallback cf) - { return (ThreadEventCallback)_InterlockedExchange((long*)&remove,(long)cf); } - - ThreadEventCallback RegisterThreadResetCallback(ThreadEventCallback cf) - { return (ThreadEventCallback)_InterlockedExchange((long*)&reset,(long)cf); } - - ThreadEventCallback RegisterAddRemoveLinkCallback(ThreadEventCallback cf) - { return (ThreadEventCallback)_InterlockedExchange((long*)&addRemoveLink, (long)cf); } - - ProcessEventCallback RegisterProcessAttachCallback(ProcessEventCallback cf) - { return (ProcessEventCallback)_InterlockedExchange((long*)&attach,(long)cf); } - - ProcessEventCallback RegisterProcessDetachCallback(ProcessEventCallback cf) - { return (ProcessEventCallback)_InterlockedExchange((long*)&detach,(long)cf); } + void RegisterThreadCreateCallback(ThreadEventCallback cf) { create = cf; } + void RegisterThreadRemoveCallback(ThreadEventCallback cf) { remove = cf; } + void RegisterThreadResetCallback(ThreadEventCallback cf) { reset = cf; } + void RegisterProcessAttachCallback(ProcessEventCallback cf) { attach = cf; } + void RegisterProcessDetachCallback(ProcessEventCallback cf) { detach = cf; } void SetSplitInterval(unsigned int splitDelay) { this->splitDelay = splitDelay; } - void OnThreadCreate(pugi::xml_node profile_node, TextThread* thread); void GetProfile(DWORD pid, pugi::xml_node profile_node); private: @@ -99,14 +84,12 @@ private: TextThread *current; ThreadEventCallback create, - remove, - reset, - addRemoveLink; + remove, + reset; ProcessEventCallback attach, - detach, - hook; + detach; WORD register_count, - new_thread_number; + new_thread_number; unsigned int splitDelay; diff --git a/vnr/texthook/host/pipe.cc b/vnr/texthook/host/pipe.cc index 14caf92..e6b4d61 100644 --- a/vnr/texthook/host/pipe.cc +++ b/vnr/texthook/host/pipe.cc @@ -66,9 +66,9 @@ DWORD WINAPI TextReceiver(LPVOID lpThreadParameter) { case HOST_NOTIFICATION_NEWHOOK: man->SetHook(processId, - ((HookParam*)(buffer + sizeof(DWORD) * 2))->address, + ((HookParam*)(buffer + sizeof(DWORD) * 2))->address, // Hook address { - *(HookParam*)(buffer + sizeof(DWORD) * 2), // Hook address + *(HookParam*)(buffer + sizeof(DWORD) * 2), // Hook parameter std::wstring(A2W( (const char*)buffer + sizeof(DWORD) * 2 + sizeof(HookParam) // Hook name )) diff --git a/vnr/texthook/host/textthread.cc b/vnr/texthook/host/textthread.cc index 4820d2e..5799f96 100644 --- a/vnr/texthook/host/textthread.cc +++ b/vnr/texthook/host/textthread.cc @@ -14,69 +14,46 @@ #include "vnrhook/include/types.h" #include #include "extensions/Extensions.h" +#include "winmutex/winmutex.h" extern HookManager* man; - -DWORD GetHookName(LPSTR str, DWORD pid, DWORD hook_addr, DWORD max) -{ - if (!pid) - return 0; - - DWORD len = 0; - max--; //for '\0' magic marker. - - //if (pid == 0) { - // len = wcslen(HookNameInitTable[0]); - // if (len >= max) - // len = max; - // memcpy(str, HookNameInitTable[0], len << 1); - // str[len] = 0; - // return len; - //} - - //::man->LockProcessHookman(pid); - ProcessRecord *pr = ::man->GetProcessRecord(pid); - if (!pr) - return 0; - WaitForSingleObject(pr->hookman_mutex, 0); - const OldHook *hks = (const OldHook *)pr->hookman_map; - for (int i = 0; i < MAX_HOOK; i++) - if (hks[i].Address() == hook_addr) { - len = hks[i].NameLength(); - if (len >= max) - len = max; - ReadProcessMemory(pr->process_handle, hks[i].Name(), str, len, &len); - if (str[len - 1] == 0) - len--; - else - str[len] = 0; - break; - } - - ReleaseMutex(pr->hookman_mutex); - //::man->UnlockProcessHookman(pid); - return len; -} - extern HWND dummyWindow; +#define TT_LOCK CriticalSectionLocker locker(ttCs) // Synchronized scope for accessing private data + TextThread::TextThread(ThreadParameter tp, unsigned int threadNumber, unsigned int splitDelay) : - thread_number(threadNumber), - splitDelay(splitDelay), - output(nullptr), - status(0), - tp(tp), - sentenceBuffer() + storage(), + sentenceBuffer(), + status(0), + threadNumber(threadNumber), + splitDelay(splitDelay), + output(nullptr), + tp(tp) { + InitializeCriticalSection(&ttCs); +} + +TextThread::~TextThread() +{ + TT_LOCK; + DeleteCriticalSection(&ttCs); } void TextThread::Reset() { - MyVector::Reset(); + TT_LOCK; + storage.clear(); +} + +std::wstring TextThread::GetStore() +{ + TT_LOCK; + return storage; } void TextThread::AddSentence() { + TT_LOCK; std::wstring sentence; if (status & USING_UNICODE) { @@ -94,13 +71,15 @@ void TextThread::AddSentence() void TextThread::AddSentence(std::wstring sentence) { + TT_LOCK; sentence.append(L"\r\n"); - if (output) output(this, (const BYTE*)sentence.c_str(), sentence.length() * 2, false); - AddToStore((const BYTE*)sentence.c_str(), sentence.length() * 2); + if (output) output(this, sentence); + storage.append(sentence); } void TextThread::AddText(const BYTE *con, int len) { + TT_LOCK; sentenceBuffer.insert(sentenceBuffer.end(), con, con+len); SetTimer(dummyWindow, (UINT_PTR)this, splitDelay, [](HWND hWnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) @@ -110,11 +89,4 @@ void TextThread::AddText(const BYTE *con, int len) }); } -void TextThread::GetEntryString(LPSTR buffer, DWORD max) -{ - int len = sprintf(buffer, "%.4X:%.4d:0x%08X:0x%08X:0x%08X:", - thread_number, tp. pid, tp.hook, tp.retn, tp.spl); - GetHookName(buffer + len, tp.pid, tp.hook, max - len); -} - // EOF diff --git a/vnr/texthook/host/textthread.h b/vnr/texthook/host/textthread.h index 064d3b6..95c316a 100644 --- a/vnr/texthook/host/textthread.h +++ b/vnr/texthook/host/textthread.h @@ -4,7 +4,8 @@ // 8/23/2013 jichi // Branch: ITH/TextThread.h, rev 120 -#include "host/textthread_p.h" +#include +#include "config.h" #include // require _InterlockedExchange #include #include @@ -25,41 +26,37 @@ struct ThreadParameter { #define CURRENT_SELECT 0x1000 class TextThread; -typedef DWORD (* ThreadOutputFilterCallback)(TextThread *,const BYTE *, DWORD, DWORD); -typedef DWORD (* ThreadEventCallback)(TextThread *); +typedef void(*ThreadOutputCallback)(TextThread*, std::wstring data); //extern DWORD split_time,repeat_count,global_filter,cyclic_remove; -class TextThread : public MyVector +class DLLEXPORT TextThread { public: TextThread(ThreadParameter tp, unsigned int threadNumber, unsigned int splitDelay); - - virtual void GetEntryString(LPSTR buffer, DWORD max); + ~TextThread(); void Reset(); - void AddText(const BYTE *con,int len); + void AddText(const BYTE *con, int len); void AddSentence(); void AddSentence(std::wstring sentence); - BYTE *GetStore(DWORD *len) { if (len) *len = used; return storage; } - DWORD PID() const { return tp.pid; } - DWORD Addr() const {return tp.hook; } + std::wstring GetStore(); DWORD &Status() { return status; } - WORD Number() const { return thread_number; } - ThreadParameter *GetThreadParameter() { return &tp; } + WORD Number() const { return threadNumber; } + ThreadParameter GetThreadParameter() { return tp; } //LPCWSTR GetComment() { return comment; } - ThreadOutputFilterCallback RegisterOutputCallBack(ThreadOutputFilterCallback cb, PVOID data) - { - return (ThreadOutputFilterCallback)_InterlockedExchange((long*)&output,(long)cb); - } + void RegisterOutputCallBack(ThreadOutputCallback cb) { output = cb; } private: - ThreadParameter tp; - ThreadOutputFilterCallback output; + CRITICAL_SECTION ttCs; + ThreadOutputCallback output; std::vector sentenceBuffer; - unsigned int thread_number; + std::wstring storage; + + ThreadParameter tp; + unsigned int threadNumber; unsigned int splitDelay; DWORD status; }; diff --git a/vnr/texthook/host/textthread_p.h b/vnr/texthook/host/textthread_p.h deleted file mode 100644 index f1512a0..0000000 --- a/vnr/texthook/host/textthread_p.h +++ /dev/null @@ -1,98 +0,0 @@ -#pragma once -// textthread_p.h -// 8/14/2013 jichi -// Branch: ITH/main_template.h, rev 66 - -#include - -template -class MyVector -{ -public: - void LockVector() { EnterCriticalSection(&cs_store); } - void UnlockVector() { LeaveCriticalSection(&cs_store); } - MyVector() : size(default_size), used(0) - { - InitializeCriticalSection(&cs_store); - storage = new T[size]; - // jichi 9/21/2013: zero memory - // This would cause trouble if T is not an atomic type - ::memset(storage, 0, sizeof(T) * size); - } - - virtual ~MyVector() - { - if (storage) - delete[] storage; - DeleteCriticalSection(&cs_store); - storage = 0; - } -protected: - - void Reset() - { - EnterCriticalSection(&cs_store); - for (int i = 0; i < used; i++) { - //Release(storage[i]); - storage[i] = T(); - } - used = 0; - LeaveCriticalSection(&cs_store); - } - void Remove(int index) - { - if (index>=used) - return; - //Release(storage[index]); - for (int i = index; i < used; i++) - storage[i] = storage[i+1]; - used--; - } - void ClearMemory(int offset, int clear_size) - { - if (clear_size < 0) - return; - EnterCriticalSection(&cs_store); - if (offset+clear_size <= size) - ::memset(storage+offset, 0, clear_size * sizeof(T)); // jichi 11/30/2013: This is the original code of ITH - LeaveCriticalSection(&cs_store); - //else __asm int 3 - } - int AddToStore(const T *con,int amount) - { - if (amount <= 0 || con == 0) - return 0; - int status = 0; - EnterCriticalSection(&cs_store); - if (amount + used + 2 >= size) { - while (amount + used + 2 >= size) - size<<=1; - T *temp; - if (size * sizeof(T) < 0x1000000) { - temp = new T[size]; - if (size > used) - ::memset(temp, 0, (size - used) * sizeof(T)); // jichi 9/25/2013: zero memory - memcpy(temp, storage, used * sizeof(T)); - } else { - size = default_size; - temp = new T[size]; - ::memset(temp, 0, sizeof(T) * size); // jichi 9/25/2013: zero memory - used = 0; - status = 1; - } - delete[] storage; - storage = temp; - } - memcpy(storage+used, con, amount * sizeof(T)); - used += amount; - LeaveCriticalSection(&cs_store); - return status; - } - - CRITICAL_SECTION cs_store; - int size, - used; - T *storage; -}; - -// EOF