While coding a simple game engine framework, I encountered a strange error using std::wcout to log messages during shutdown and destruction of objects. The output is truncated and the app does not terminate, but yet throws no exceptions. I suspect some object is being destroyed before the message is completely displayed.
Here is the output when the app goes through a "normal" shutdown sequence.
Here is WinMain -
using namespace sge;
extern BaseApp *SGEApp;
LRESULT CALLBACK NullWinProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
return DefWindowProc(hwnd, message, wParam, lParam);
}
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR lpszCmdLine, int nCmdShow)
{
#if defined(_DEBUG) | !defined(NDEBUG)
SGE_LEAK_CHECK;
SGE_LEAK_CHECK_BREAK(0);
#endif
/////////////////////
// TODO: move this block of code to a console object
if (!GetConsoleWindow()) {
AllocConsole();
FILE *pCout;
FILE *pCerr;
FILE *pCin;
freopen_s(&pCout, "CONOUT$", "w", stdout);
freopen_s(&pCerr, "CONOUT$", "w", stderr);
freopen_s(&pCin, "CONIN$", "r", stdin);
std::wcout.clear();
std::wcerr.clear();
std::wcin.clear();
SetConsoleTitle(L"Framework Console");
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED);
}
SetThreadAffinityMask(GetCurrentThread(), 1);
bool bRun(true);
MSG msg;
if (!SGEApp->initialize())
return -1;
while (bRun) {
while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
if (GetAsyncKeyState(VK_PAUSE) || msg.message == WM_QUIT)
bRun = false;
SGEApp->update();
SGEApp->draw();
}
delete SGEApp;
FreeConsole();
return int(0);
}
Application objects -
#pragma once
#ifndef _APP_H
#define _APP_H
#ifndef SGE_BASEAPP_H
#include "Application/OpenglApp.h"
#endif
using namespace sge;
class app : public OpenglApp
{
public:
app();
~app();
};
#include "App.h"
BaseApp *SGEApp = new app();
app::app()
{
}
app::~app()
{
}
#pragma once
#ifndef SGE_BASEAPP_H
#define SGE_BASEAPP_H
#ifndef SGE_LOGGER_H
#include "Core/Logger/Logger.h"
#endif
namespace sge
{
class BaseApp
{
public:
BaseApp();
virtual ~BaseApp();
virtual bool initialize();
virtual bool shutDown();
virtual void update();
virtual void draw();
virtual Logger *getLogger() const { return app_logger; }
protected:
Logger *app_logger;
};
} // namespace sge
#endif // !SGE_BASEAPP_H
#include "BaseApp.h"
namespace sge
{
BaseApp::BaseApp()
{
}
BaseApp::~BaseApp()
{
}
bool BaseApp::initialize()
{
return bool(false);
}
bool BaseApp::shutDown()
{
return bool(false);
}
void BaseApp::update()
{
}
void BaseApp::draw()
{
}
} // namespace sge
#pragma once
#ifndef SGE_OPENGLAPP_H
#define SGE_OPENGLAPP_H
#ifndef SGE_BASEAPP_H
#include "BaseApp.h"
#endif
namespace sge
{
class OpenglApp : public BaseApp
{
public:
OpenglApp();
virtual ~OpenglApp();
virtual bool initialize();
virtual bool shutDown();
virtual void update();
virtual void draw();
};
} // namespace sge
#endif // SGE_OPENGLAPP_H
#include "Application/OpenglApp.h"
namespace sge
{
OpenglApp::OpenglApp()
{
}
OpenglApp::~OpenglApp()
{
shutDown();
app_logger->writeLogFile();
delete app_logger;
}
bool OpenglApp::initialize()
{
app_logger = new Logger();
app_logger->log(SGEString(L"Begin initialization."), LOG_TRACE);
app_logger->log(SGEString(L"Initialization succeeded."), LOG_TRACE);
return bool(true);
}
bool OpenglApp::shutDown()
{
SGEString msg();
app_logger->log(SGEString(L"Begin shutdown."), LOG_TRACE);
app_logger->log(SGEString(L"Shutdown succeeded."), LOG_TRACE);
return bool(true);
}
void OpenglApp::update()
{
}
void OpenglApp::draw()
{
}
} // namespace sge
If I comment the two log() calls in the shutDown() method above, everything works fine.
This is the logger class -
#pragma once
#ifndef SGE_LOGGER_H
#define SGE_LOGGER_H
#ifndef _VECTOR_
#include <vector>
#endif
#ifndef _FSTREAM_
#include <fstream>
#endif
#ifndef SGE_TYPES_H
#include "Common/SGE_Types.h"
#endif
namespace sge
{
const SGEString DEFAULT_LOGFILE(L"Scavenger.log");
enum SGELogLevel : uint32 {
LOG_ERROR = 0x0001,
LOG_WARN = 0x0002,
LOG_INFO = 0x0004,
LOG_TRACE = 0x0008,
LOG_DEBUG = 0x0010,
LOG_CODE = 0x0020,
};
struct SGELogData {
SGELogData(uint32 severity, SGEString msg)
: level(severity)
, message(msg)
{}
uint32 level;
SGEString message;
};
class Logger
{
public:
Logger();
Logger(uint32 loglevel);
~Logger();
bool initialize();
bool shutdown();
void log(SGEString message, uint32 level = LOG_ERROR);
void log(uint32 level = 0xffff);
void setLogFile(SGEString filespec, bool flush = false);
bool writeLogFile(uint32 level = 0xffff);
protected:
SGEString logger_filespec;
uint32 logger_loglevel;
std::vector<SGELogData> logger_logs;
};
} // namespace sge
#endif // !SGE_LOGGER_H
#include "Logger.h"
namespace sge
{
Logger::Logger()
: logger_loglevel(0xffff)
, logger_filespec(L"")
{
}
Logger::Logger(uint32 loglevel)
: logger_loglevel(loglevel)
, logger_filespec(L"")
{
}
Logger::~Logger()
{
shutdown();
}
bool Logger::initialize()
{
return bool(true);
}
bool Logger::shutdown()
{
logger_logs.clear();
return bool(true);
}
void Logger::log(SGEString message, uint32 level)
{
SGEStringstream msg;
SGEString prefix;
if (!logger_loglevel & level)
return;
prefix = L"";
if(level & LOG_CODE)
prefix = L"**CODE :";
if(level & LOG_DEBUG)
prefix = L"**DEBUG:";
if(level & LOG_TRACE)
prefix = L"**TRACE:";
if(level & LOG_INFO)
prefix = L"**INFO :";
if(level & LOG_WARN)
prefix = L"**WARN :";
if(level & LOG_ERROR)
prefix = L"**ERROR:";
msg << prefix << L" " << message;
logger_logs.push_back(SGELogData(level, message));
std::wcout << msg.str().c_str() << std::endl;
}
void Logger::log(uint32 level)
{
if (!logger_loglevel & level)
return;
for (auto i : logger_logs) {
if (level & i.level) {
uint32 l(level & i.level);
SGEStringstream msg;
SGEString prefix;
if (l & LOG_CODE)
prefix = L"**CODE :";
if (l & LOG_DEBUG)
prefix = L"**DEBUG:";
if (l & LOG_TRACE)
prefix = L"**TRACE:";
if (l & LOG_INFO)
prefix = L"**INFO :";
if (l & LOG_WARN)
prefix = L"**WARN :";
if (l & LOG_ERROR)
prefix = L"**ERROR:";
msg << prefix << L" " << i.message;
std::wcout << msg.str() << std::endl;
}
}
}
void Logger::setLogFile(SGEString filespec, bool flush)
{
if (flush)
writeLogFile();
logger_filespec = filespec;
}
bool Logger::writeLogFile(uint32 level)
{
bool result(false);
if (logger_filespec.empty())
logger_filespec = DEFAULT_LOGFILE;
std::wofstream file(logger_filespec, std::ios::in | std::ios::out | std::ios::trunc);
if (!file) {
log(SGEString(L"Unable to create log file!", LOG_ERROR));
return result;
}
file << L"==================================================" << std::endl;
file << L"Scavenger Log created: " << __DATE__ << " " << __TIME__ << std::endl;
file << L"Logger log level: 0x" << std::hex << logger_loglevel << " ";
file << L" File log level : 0x" << std::hex << level << std::endl;
file << L"==================================================" << std::endl;
for (auto i : logger_logs) {
if (level & i.level) {
uint32 l(level & i.level);
//SGEStringstream msg;
SGEString prefix;
if (l & LOG_CODE)
prefix = L"**CODE :";
if (l & LOG_DEBUG)
prefix = L"**DEBUG:";
if (l & LOG_TRACE)
prefix = L"**TRACE:";
if (l & LOG_INFO)
prefix = L"**INFO :";
if (l & LOG_WARN)
prefix = L"**WARN :";
if (l & LOG_ERROR)
prefix = L"**ERROR:";
file << prefix.c_str() << L" " << i.message.c_str() << std::endl;
}
}
file.close();
return bool(true);
}
} // namespace sge
And a snippet for certain defined objects I use-
typedef std::wstring SGEString;
typedef std::wstringstream SGEStringstream;
typedef std::wostream SGECout;
I am using MSVC 2015 Community Edition. When I single step through the shutdown, all messages are displayed and the application exits normally. It only fails when running normally. Any help would be appreciated.
Related
I am trying to detect how many instances of a application person is running. Did he open my application once? Twice? Thrice?
I tried to detect it by checking it's instances by process names, but in windows it is pointles - people might change .exe name and it won't count towards final number.
How would I proceed then? I thought about searching it by className (HWND?) rather by processName, but how would I do it?
This is the code I am using for detecting by process name:
int Platform::getMulticlientCount(const std::string& ProcessName)
{
PROCESSENTRY32 pe32 = { sizeof(PROCESSENTRY32) };
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
const char *cstr = ProcessName.c_str();
int counter = 0;
if (Process32First(hSnapshot, &pe32))
{
do
{
if (_tcsicmp(pe32.szExeFile, cstr) == 0)
{
counter++;
}
} while (Process32Next(hSnapshot, &pe32));
}
CloseHandle(hSnapshot);
return counter;
}
The instance of the Remy:
static int counter;
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
char classname[MAX_PATH] = { 0 };
GetClassNameA(hwnd,classname, MAX_PATH);
if (_tcsicmp(classname, (char*)lParam) == 0)
counter++;
return true;
}
int Platform::getMulticlientCount(const std::string& ClassName)
{
counter = 0;
const char *cstr = ClassName.c_str();
EnumWindows(EnumWindowsProc, (LPARAM)cstr);
return counter;
}
If you also need to get the instance, in EnumWindowsProc:
HINSTANCE instance = (HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE);
If you also need to get the processId, in EnumWindowsProc:
DWORD pid;
GetWindowThreadProcessId(hwnd, &pid);
Here is an example code that counts the instances that are running. While the application count the instances it self it does not matter if the binary is renamed. I used a file to keep the example simple but registry would work too. The only thing that is missing is a global mutex to protect the file against concurrent access. HTH
#include <iostream>
#include <thread>
#include <fstream>
#include <Windows.h>
class GlobalCounter
{
public:
GlobalCounter(const std::string& id)
: _id(id)
{
const auto filename = "C:\\users\\twollgam\\" + id + ".counter";
if (GlobalFindAtomA(id.c_str()) == 0)
{
std::ofstream(filename) << 1;
std::cout << "I am the first instance." << std::endl;
}
else
{
auto counter = 0;
std::ifstream(filename) >> counter;
++counter;
std::ofstream(filename) << counter;
std::cout << "I am the " << counter << " instance." << std::endl;
}
_atom = GlobalAddAtomA(id.c_str());
}
~GlobalCounter()
{
const auto filename = "C:\\users\\twollgam\\" + _id + ".counter";
auto counter = 0;
std::ifstream(filename) >> counter;
--counter;
std::ofstream(filename) << counter;
GlobalDeleteAtom(_atom);
}
private:
const std::string _id;
ATOM _atom;
};
int main()
{
const auto globalCounter = GlobalCounter("test");
std::cout << "Hello World!\n";
std::this_thread::sleep_for(std::chrono::seconds(30));
return 0;
}
I'm trying to make a program that gets a process name, finds it's ID,
and then finds the language with the function GetKeyboardLayout.
Although I'm having difficulties and it seem not to work.
It finds the processID although the language that return is always 00000000.
That is my code :
#include <iostream>
#include <windows.h>
#include <string>
#include <tlhelp32.h>
DWORD FindProcessId(LPCTSTR ProcessName);
int main() {
HKL currentKBLayout;
DWORD processID;
LPCTSTR processName = "chrome.exe";
while (true) {
processID = FindProcessId(processName);
if (processID == 0); // TODO: pause system for 5 seconds
else {
currentKBLayout = GetKeyboardLayout(processID);
std::cout << processID << " | "<< currentKBLayout << std::endl;
}
}
system("pause");
return 0;
}
DWORD FindProcessId(LPCTSTR ProcessName)
{
PROCESSENTRY32 pt;
HANDLE hsnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
pt.dwSize = sizeof(PROCESSENTRY32);
if (Process32First(hsnap, &pt)) { // must call this first
do {
if (!lstrcmpi(pt.szExeFile, ProcessName)) {
CloseHandle(hsnap);
return pt.th32ProcessID;
}
} while (Process32Next(hsnap, &pt));
}
CloseHandle(hsnap); // close handle on failure
return 0;
}
I agree with Remys comment about using a simpler way to get the keyboard layout for the processes if that's all you need. If you however are interested in adding more information to your current approach using snapshots, this could be a way to start. It takes a snapshot of all processes and threads. Each Process has a vector of Thread objects. Adding Thread objects to each Process is done via an unordered_map<processId, Process>. To get a unique set of keyboard layouts for each process (since each thread may in theory have its own), an unordered_set<HKL> is used.
#include "pch.h"
#include <iostream>
#include <string>
#include <vector>
#include <unordered_set>
#include <unordered_map>
#include <windows.h>
#include <tlhelp32.h>
struct Thread {
DWORD m_id;
HKL m_keyboard_layout;
Thread(DWORD Id) :
m_id(Id), m_keyboard_layout(GetKeyboardLayout(m_id))
{}
};
struct Process {
std::vector<Thread> m_threads;
DWORD m_id;
std::wstring m_exefile;
Process() = default;
Process(DWORD Id, std::wstring Name) :
m_id(Id), m_exefile(Name)
{}
// get a unique set of HKL:s from all the threads in the process
std::unordered_set<HKL> GetKeyboardLayouts() const {
std::unordered_set<HKL> rv;
for (auto& t : m_threads) {
if(t.m_keyboard_layout) // does it have a keyboard layout?
rv.emplace(t.m_keyboard_layout);
}
return rv;
}
// if you'd like to iterate over the individual threads
std::vector<Thread>::iterator begin() { return m_threads.begin(); }
std::vector<Thread>::iterator end() { return m_threads.end(); }
};
class Snapshot {
HANDLE hSnap;
std::unordered_map<DWORD, Process> m_processes;
void GetProcesses() {
PROCESSENTRY32 pt;
pt.dwSize = sizeof(pt);
if (Process32First(hSnap, &pt)) { // must call this first
do {
m_processes[pt.th32ProcessID] = Process(pt.th32ProcessID, pt.szExeFile);
} while (Process32Next(hSnap, &pt));
}
}
void GetThreads() {
THREADENTRY32 pt;
pt.dwSize = sizeof(pt);
if (Thread32First(hSnap, &pt)) { // must call this first
do {
m_processes[pt.th32OwnerProcessID].m_threads.emplace_back(pt.th32ThreadID);
} while (Thread32Next(hSnap, &pt));
}
}
void Populate() {
GetProcesses();
GetThreads();
}
public:
Snapshot() :
hSnap(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD, 0)),
m_processes()
{
// TODO: make this exception better
if (hSnap == INVALID_HANDLE_VALUE) throw GetLastError();
Populate();
CloseHandle(hSnap);
}
std::unordered_map<DWORD, Process>::iterator begin() { return m_processes.begin(); }
std::unordered_map<DWORD, Process>::iterator end() { return m_processes.end(); }
};
int main() {
Snapshot snap;
// show processes with keyboard layouts
for (const auto& m : snap) { // std::pair m.first = processId, m.second = Process
const Process& p = m.second;
auto layouts = p.GetKeyboardLayouts();
if (layouts.size()) { // only show processes with keyboard layouts
std::wcout << p.m_id << L" " << p.m_exefile << L"\n";
for (const auto& l : layouts) {
std::wcout << L" layout " << l << L"\n";
}
}
}
return 0;
}
This is a subsequent question to my fist one, asking how to register a custom CodeInsight manager to the IDE with C++Builder.
I switched my code to Remy Lebeau's version with the #pragma startup and #pragma exitdirectives.
What now happens when I try to use it (see my code below) is this:
With CodeGuard set to active:
I hit F9 -> Project compiles well (except for [TLIB Warning] Warning: library was too large for page size, rebuilt with page size 32)
A second instance of bds.exe starts (because i set it as the host app)
In the 2nd instance I try to install my package wich results in the following error:
I deactivate CodeGuard in the project debugging settings and try it again and now it seems to work, as I can see a sequence of MessageBoxes:
TMyCodeInsightSymbolList::TMyCodeInsightSymbolList
TMyCodeInsightManager::TMyCodeInsightManager
TMyCodeInsightManager::GetIDString
TMyCodeInsightManager::GetIDString
TMyCodeInsightManager::GetIDString
TMyCodeInsightManager::GetIDString
TMyCodeInsightManager::GetIDString
Now I create a new VCL Forms Application in the debugging instance and enter
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
this->|
}
in TForm1's constructor.
The resulting MessageBoxes:
TMyCodeInsightManager::HandlesFile
TMyCodeInsightManager::GetEnabled
TMyCodeInsightManager::AllowCodeInsight
TMyCodeInsightManager::EditorTokenValidChars
TMyCodeInsightManager::PreValidateCodeInsight
TMyCodeInsightManager::EditorTokenValidChars
TMyCodeInsightManager::InvokeCodeCompletion
TMyCodeInsightManager::GetSymbolList
TMyCodeInsightSymbolList::GetCount
TMyCodeInsightSymbolList::~TMyCodeInsightSymbolList
TMyCodeInsightManager::GetSymbolList
Error:
It drives me crazy...so what the heck am I doing wrong here?
{...}
Furthermore, in the IDE setting in the 2nd instance at Editor Options -> CodeInsight I see my new entry in the ComboBox Source file type but when I select it, there's an out of range error, so I think the IDE is missing some registry entries for my completion manager or stuff. Am I right?
Now, here's my code:
my_completion.cpp
#pragma hdrstop
#pragma package(smart_init)
#include "my_codeinsight_manager.h"
static int FCodeManagerIndex = -1;
void DoRegister()
{
_di_IOTACodeInsightServices CIS;
if (BorlandIDEServices->Supports(CIS))
FCodeManagerIndex = CIS->AddCodeInsightManager(new TMyCodeInsightManager);
}
#pragma startup DoRegister
void DoUnregister()
{
_di_IOTACodeInsightServices CIS;
if ((FCodeManagerIndex != -1) && BorlandIDEServices->Supports(CIS))
CIS->RemoveCodeInsightManager(FCodeManagerIndex);
}
#pragma exit DoUnregister
#pragma argsused
extern "C" int _libmain(unsigned long reason)
{
return 1;
}
my_codeinsight_manager.h
#ifndef my_codeinsight_managerH
#define my_codeinsight_managerH
//---------------------------------------------------------------------------
#include <memory>
#include <System.SysUtils.hpp>
#include <ToolsAPI.hpp>
#include "my_codeinsight_symbollist.h"
//---------------------------------------------------------------------------
class TMyCodeInsightManager : public TCppInterfacedObject<IOTANotifier, IOTACodeInsightManager>
{
public:
TMyCodeInsightManager();
virtual __fastcall ~TMyCodeInsightManager();
String __fastcall GetName();
String __fastcall GetIDString();
bool __fastcall GetEnabled();
void __fastcall SetEnabled(bool AValue) ;
TSysCharSet __fastcall EditorTokenValidChars(bool APreValidating);
void __fastcall AllowCodeInsight(bool& Allow, const WideChar AKey);
bool __fastcall PreValidateCodeInsight(const String AStr);
bool __fastcall IsViewerBrowsable(int AIndex);
bool __fastcall GetMultiSelect();
void __fastcall GetSymbolList(_di_IOTACodeInsightSymbolList& ASymbolList);
void __fastcall OnEditorKey(WideChar AKey, bool& ACloseViewer, bool& AAccept);
bool __fastcall HandlesFile(const String AFileName);
String __fastcall GetLongestItem();
void __fastcall GetParameterList(_di_IOTACodeInsightParameterList& AParameterList);
void __fastcall GetCodeInsightType(WideChar AChar, int AElement, TOTACodeInsightType& ACodeInsightType, TOTAInvokeType& AInvokeType);
bool __fastcall InvokeCodeCompletion(TOTAInvokeType AHowInvoked, String& AStr);
bool __fastcall InvokeParameterCodeInsight(TOTAInvokeType AHowInvoked, int& ASelectedIndex);
void __fastcall ParameterCodeInsightAnchorPos(TOTAEditPos& AEdPos);
int __fastcall ParameterCodeInsightParamIndex(const TOTAEditPos& AEdPos);
String __fastcall GetHintText(int AHintLine, int AHintCol);
String __fastcall GetOptionSetName();
bool __fastcall GotoDefinition(String& AFileName, int& ALineNum, int AIndex=0xFFFFFFFF);
void __fastcall Done(bool AAccepted, bool& ADisplayParams);
__property String Name = {read=GetName};
__property bool MultiSelect = {read=GetMultiSelect};
__property bool Enabled = {read=GetEnabled, write=SetEnabled};
/* IOTANotifier */
void __fastcall AfterSave() {}
void __fastcall BeforeSave() {}
void __fastcall Destroyed() {}
void __fastcall Modified() {}
private:
std::unique_ptr<TMyCodeInsightSymbolList> FSymbolList;
TSysCharSet FSysCharSet;
};
my_codeinsight_manager.cpp
#include <vcl.h>
#pragma hdrstop
#include "my_codeinsight_manager.h"
// ---------------------------------------------------------------------------
#pragma package(smart_init)
TMyCodeInsightManager::TMyCodeInsightManager()
: FSymbolList(std::unique_ptr<TMyCodeInsightSymbolList>(new TMyCodeInsightSymbolList))
{
FSysCharSet = TSysCharSet() << 'A' << 'B' << 'C' << 'D' << 'E' << 'F' << 'G' << 'H' << 'I' << 'J' << 'K'
<< 'L' << 'M' << 'N' << 'O' << 'P' << 'Q' << 'R' << 'S' << 'T' << 'U' << 'V' << 'W'
<< 'X' << 'Y' << 'Z'
<< 'a' << 'b' << 'c' << 'd' << 'e' << 'f' << 'g' << 'h' << 'i' << 'j' << 'k' << 'l'
<< 'm' << 'n' << 'o' << 'p' << 'q' << 'r' << 's' << 't' << 'u' << 'v' << 'w' << 'x'
<< 'y' << 'z'
<< '0' << '1' << '2' << '3' << '4' << '5' << '6' << '7' << '8' << '9'
<< '+' << '-' << '*' << '/' << '^' << '\\' << '(' << ')' << '[' << ']' << '{' << '}'
<< '=' << '!' << '<' << '>' << '\'' << '\"' << '$' << ',' << ';' << ':' << '5' << '!'
<< '&' << '?' << '_' << '#' << '#'
<< 0x08 << 0x09 << 0x0B << 0x0C << 0x0D;
ShowMessage(L"TMyCodeInsightManager::TMyCodeInsightManager");
}
//---------------------------------------------------------------------------
__fastcall TMyCodeInsightManager::~TMyCodeInsightManager()
{
ShowMessage(L"TMyCodeInsightManager::~TMyCodeInsightManager");
}
//---------------------------------------------------------------------------
String __fastcall TMyCodeInsightManager::GetName()
{
ShowMessage(L"TMyCodeInsightManager::GetName");
return L"MyCodeInsightLanguage";
}
//----------------------------------------------------------------------------
String __fastcall TMyCodeInsightManager::GetIDString()
{
ShowMessage(L"TMyCodeInsightManager::GetIDString");
return L"My.CodeInsight";
}
//----------------------------------------------------------------------------
bool __fastcall TMyCodeInsightManager::GetEnabled()
{
ShowMessage(L"TMyCodeInsightManager::GetEnabled");
return true;
}
//----------------------------------------------------------------------------
void __fastcall TMyCodeInsightManager::SetEnabled(bool AValue)
{
ShowMessage(L"TMyCodeInsightManager::SetEnabled");
}
//----------------------------------------------------------------------------
TSysCharSet __fastcall TMyCodeInsightManager::EditorTokenValidChars(bool APreValidating)
{
ShowMessage(L"TMyCodeInsightManager::EditorTokenValidChars");
return FSysCharSet;
}
//----------------------------------------------------------------------------
void __fastcall TMyCodeInsightManager::AllowCodeInsight(bool& AAllow, const WideChar AKey)
{
ShowMessage(L"TMyCodeInsightManager::AllowCodeInsight");
AAllow = true;
}
//----------------------------------------------------------------------------
bool __fastcall TMyCodeInsightManager::PreValidateCodeInsight(const String AStr)
{
ShowMessage(L"TMyCodeInsightManager::PreValidateCodeInsight");
return true;
}
//----------------------------------------------------------------------------
bool __fastcall TMyCodeInsightManager::IsViewerBrowsable(int AIndex)
{
ShowMessage(L"TMyCodeInsightManager::IsViewerBrowsable");
return true; // # TO DO #
}
//----------------------------------------------------------------------------
bool __fastcall TMyCodeInsightManager::GetMultiSelect()
{
ShowMessage(L"TMyCodeInsightManager::GetMultiSelect");
return false;
}
//----------------------------------------------------------------------------
void __fastcall TMyCodeInsightManager::GetSymbolList(_di_IOTACodeInsightSymbolList& ASymbolList)
{
ASymbolList = FSymbolList.get();
ShowMessage(L"TMyCodeInsightManager::GetSymbolList");
}
//----------------------------------------------------------------------------
void __fastcall TMyCodeInsightManager::OnEditorKey(WideChar AKey, bool& ACloseViewer, bool& AAccept)
{
ACloseViewer = true;
AAccept = false;
ShowMessage(L"TMyCodeInsightManager::OnEditorKey");
}
//----------------------------------------------------------------------------
bool __fastcall TMyCodeInsightManager::HandlesFile(const String AFileName)
{
ShowMessage(L"TMyCodeInsightManager::HandlesFile");
String FileExt = ExtractFileExt(AFileName);
if ( (FileExt == L".c")
|| (FileExt == L".cpp")
|| (FileExt == L".h")
|| (FileExt == L".hpp")
|| (FileExt == L".cc")
|| (FileExt == L".cp")
|| (FileExt == L".cxx") )
{
return true;
}
else
{
return false;
}
}
//----------------------------------------------------------------------------
String __fastcall TMyCodeInsightManager::GetLongestItem()
{
ShowMessage(L"TMyCodeInsightManager::GetLongestItem");
return String(L"dddddddddddddddddddddd");
}
//----------------------------------------------------------------------------
void __fastcall TMyCodeInsightManager::GetParameterList(_di_IOTACodeInsightParameterList& AParameterList)
{
AParameterList = NULL;
ShowMessage(L"TMyCodeInsightManager::GetParameterList");
}
//----------------------------------------------------------------------------
void __fastcall TMyCodeInsightManager::GetCodeInsightType(WideChar AChar, int AElement, TOTACodeInsightType& ACodeInsightType, TOTAInvokeType& AInvokeType)
{
AInvokeType = itManual;
if ( (AElement != atString) && (AChar != 0x0001) && (AElement == atComment) )
{
switch (AChar)
{
case 0x0000:
ACodeInsightType = citCodeInsight;
break;
case 0x0001:
ACodeInsightType = citParameterCodeInsight;
break;
case 0x0002:
ACodeInsightType = citBrowseCodeInsight;
break;
case 0x0003:
ACodeInsightType = citHintCodeInsight;
break;
case L'.':
ACodeInsightType = citCodeInsight;
AInvokeType = itTimer;
break;
case L'(':
ACodeInsightType = citParameterCodeInsight;
AInvokeType = itTimer;
break;
default:
ACodeInsightType = citNone;
}
}
ShowMessage(L"TMyCodeInsightManager::GetCodeInsightType");
}
//----------------------------------------------------------------------------
bool __fastcall TMyCodeInsightManager::InvokeCodeCompletion(TOTAInvokeType AHowInvoked, String& AStr)
{
switch (AHowInvoked)
{
case itAuto:
break;
case itManual:
break;
case itTimer:
break;
}
AStr = L"IAmASymbolText";
return true;
}
//----------------------------------------------------------------------------
bool __fastcall TMyCodeInsightManager::InvokeParameterCodeInsight(TOTAInvokeType AHowInvoked, int& ASelectedIndex)
{
switch (AHowInvoked)
{
case itAuto:
break;
case itManual:
break;
case itTimer:
break;
}
ShowMessage(L"TMyCodeInsightManager::OnvokeParameterCodeInsight");
return true; // # TO DO #
}
//----------------------------------------------------------------------------
void __fastcall TMyCodeInsightManager::ParameterCodeInsightAnchorPos(TOTAEditPos& AEdPos)
{
ShowMessage(L"TMyCodeInsightManager::ParameterCodeInsightAnchorPos");
}
//----------------------------------------------------------------------------
int __fastcall TMyCodeInsightManager::ParameterCodeInsightParamIndex(const TOTAEditPos& AEdPos)
{
ShowMessage(L"TMyCodeInsightManager::ParameterCodeInsightParamIndex");
return 0;
}
//----------------------------------------------------------------------------
String __fastcall TMyCodeInsightManager::GetHintText(int AHintLine, int AHintCol)
{
ShowMessage(L"TMyCodeInsightManager::GetHintText");
return L"NoHint";
}
//----------------------------------------------------------------------------
String __fastcall TMyCodeInsightManager::GetOptionSetName()
{
ShowMessage(L"TMyCodeInsightManager::GetOptionSetName");
return L"MyCodeInsight";
}
//---------------------------------------------------------------------------
bool __fastcall TMyCodeInsightManager::GotoDefinition(String &AFileName, int& ALineNum, int AIndex)
{
ShowMessage(L"TMyCodeInsightManager::GotoDefinition");
return true;
}
//----------------------------------------------------------------------------
void __fastcall TMyCodeInsightManager::Done(bool AAccepted, bool& ADisplayParams)
{
ShowMessage(L"TMyCodeInsightManager::Done");
}
//----------------------------------------------------------------------------
my_codeinsight_symbollist.h
#ifndef my_codeinsight_symbollistH
#define my_codeinsight_symbollistH
//---------------------------------------------------------------------------
#include <vector>
#include <algorithm>
#include <System.SysUtils.hpp>
#include <ToolsAPI.hpp>
//---------------------------------------------------------------------------
class TMySymbolList
{
public:
TMySymbolList(const String AText=L"", const String AType=L"", const String AClass=L"", const bool AIsReadWrite=false, const bool AIsAbstract=false, const TOTAViewerSymbolFlags AFlag=vsfUnknown, const TOTAViewerVisibilityFlags AVisibilityFlag=vvfPrivate, TOTAProcDispatchFlags AProcDispatchFlag=pdfNone)
: FText(AText),
FType(AType),
FClass(AClass),
FFlag(AFlag),
FVisibilityFlag(AVisibilityFlag),
FProcDispatchFlag(AProcDispatchFlag)
{}
__property String Text = {read=FText, write=FText}; // i.e. 'Form1'
__property String Type = {read=FType, write=FType}; // i.e. 'TForm1'
__property String Class = {read=FClass, write=FClass}; // i.e. 'var', 'function', 'type', etc.
__property bool IsReadWrite = {read=FIsReadWrite, write=FIsReadWrite};
__property bool IsAbstract = {read=FIsAbstract, write=FIsAbstract};
__property TOTAViewerSymbolFlags Flag = {read=FFlag, write=FFlag};
__property TOTAViewerVisibilityFlags VisibilityFlag = {read=FVisibilityFlag, write=FVisibilityFlag};
__property TOTAProcDispatchFlags ProcDispatchFlag = {read=FProcDispatchFlag, write=FProcDispatchFlag};
private:
String FText;
String FType;
String FClass;
bool FIsReadWrite;
bool FIsAbstract;
TOTAViewerSymbolFlags FFlag;
TOTAViewerVisibilityFlags FVisibilityFlag;
TOTAProcDispatchFlags FProcDispatchFlag;
};
//---------------------------------------------------------------------------
class TMyCodeInsightSymbolList : public TCppInterfacedObject<IOTACodeInsightSymbolList>
{
public:
TMyCodeInsightSymbolList();
virtual __fastcall ~TMyCodeInsightSymbolList();
void __fastcall Clear(void);
int __fastcall GetCount(void);
bool __fastcall GetSymbolIsReadWrite(int AIndex);
bool __fastcall GetSymbolIsAbstract(int AIndex);
TOTAViewerSymbolFlags __fastcall GetViewerSymbolFlags(int AIndex);
int __fastcall GetViewerVisibilityFlags(int AIndex);
TOTAProcDispatchFlags __fastcall GetProcDispatchFlags(int AIndex);
void __fastcall SetSortOrder(const TOTASortOrder AValue);
TOTASortOrder __fastcall GetSortOrder(void);
int __fastcall FindIdent(const String AIdent);
bool __fastcall FindSymIndex(const String AIdent, int& AIndex);
void __fastcall SetFilter(const String AFilterText);
String __fastcall GetSymbolText(int AIndex);
String __fastcall GetSymbolTypeText(int AIndex);
String __fastcall GetSymbolClassText(int AIndex);
__property String SymbolClassText[int Index] = {read=GetSymbolClassText};
__property String SymbolTypeText[int Index] = {read=GetSymbolTypeText};
__property String SymbolText[int Index] = {read=GetSymbolText};
__property TOTAViewerSymbolFlags SymbolFlags[int i] = {read=GetViewerSymbolFlags};
__property int SymbolVisibility[int Index] = {read=GetViewerVisibilityFlags};
__property bool SymbolIsAbstract[int Index] = {read=GetSymbolIsAbstract};
__property bool SymbolIsReadWrite[int Index] = {read=GetSymbolIsReadWrite};
__property TOTAProcDispatchFlags FuncDispatchFlags[int Index] = {read=GetProcDispatchFlags};
__property TOTASortOrder SortOrder = {read=GetSortOrder, write=SetSortOrder};
__property int Count = {read=GetCount};
private:
static bool SymbolTextCompare(const TMySymbolList& AX, const TMySymbolList& AY);
std::vector<TMySymbolList> FSymbols;
TOTASortOrder FSortOrder;
};
//---------------------------------------------------------------------------
#endif
my_codeinsight_symbollist.cpp
#include <vcl.h>
#pragma hdrstop
#include "my_codeinsight_symbollist.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
// Constructor
TMyCodeInsightSymbolList::TMyCodeInsightSymbolList()
: FSortOrder(soAlpha)
{
TMySymbol S;
S.Text = L"IAmASymbolText";
S.Type = L"IAmASymbolType";
S.Class = L"IAmASymbolClass";
S.Flag = vsfFunction;
S.VisibilityFlag = vvfPublic;
FSymbols.push_back(S);
FSymbols.push_back(S);
FSymbols.push_back(S);
#ifdef _DEBUG
ShowMessage(L"TMyCodeInsightSymbolList::TMyCodeInsightSymbolList");
#endif
}
//---------------------------------------------------------------------------
// Destructor
__fastcall TMyCodeInsightSymbolList::~TMyCodeInsightSymbolList()
{
#ifdef _DEBUG
ShowMessage(L"TMyCodeInsightSymbolList::~TMyCodeInsightSymbolList");
#endif
}
//---------------------------------------------------------------------------
// Implementor should clear its symbol list
void __fastcall TMyCodeInsightSymbolList::Clear(void)
{
FSymbols.clear();
#ifdef _DEBUG
ShowMessage(L"TMyCodeInsightSymbolList::Clear");
#endif
}
//----------------------------------------------------------------------------
// Returns the count of the symbols in the list - may be modified by setting a filter
int __fastcall TMyCodeInsightSymbolList::GetCount(void)
{
#ifdef _DEBUG
ShowMessage(L"TMyCodeInsightSymbolList::GetCount");
#endif
return static_cast<int>(FSymbols.size());
}
//----------------------------------------------------------------------------
// Returns whether the symbol is able to be read from and written to
bool __fastcall TMyCodeInsightSymbolList::GetSymbolIsReadWrite(int AIndex)
{
#ifdef _DEBUG
ShowMessage(L"TMyCodeInsightSymbolList::GetSymbolIsReadWrite");
#endif
if (AIndex < static_cast<int>(FSymbols.size()))
return FSymbols[AIndex].IsReadWrite;
else
return false;
}
//----------------------------------------------------------------------------
// Returns whether the symbols is abstract. Viewer draws these in the 'need to implement' color
bool __fastcall TMyCodeInsightSymbolList::GetSymbolIsAbstract(int AIndex)
{
#ifdef _DEBUG
ShowMessage(L"TMyCodeInsightSymbolList::GetSymbolIsAbstract");
#endif
if (AIndex < static_cast<int>(FSymbols.size()))
return FSymbols[AIndex].IsAbstract;
else
return false;
}
//----------------------------------------------------------------------------
// Return the symbol flags for the item at index 'AIndex'. AIndex is the index in the filtered list
TOTAViewerSymbolFlags __fastcall TMyCodeInsightSymbolList::GetViewerSymbolFlags(int AIndex)
{
#ifdef _DEBUG
ShowMessage(L"TMyCodeInsightSymbolList::GetViewerSymbolFlags");
#endif
if (AIndex < static_cast<int>(FSymbols.size()))
return FSymbols[AIndex].Flag;
else
return vsfUnknown;
}
//----------------------------------------------------------------------------
// Return the visibility flags for the item at index 'AIndex'. AIndex is the index in the filtered list
int __fastcall TMyCodeInsightSymbolList::GetViewerVisibilityFlags(int AIndex)
{
#ifdef _DEBUG
ShowMessage(L"TMyCodeInsightSymbolList::GetViewerVisibilityFlags");
#endif
if (AIndex < static_cast<int>(FSymbols.size()))
return FSymbols[AIndex].VisibilityFlag;
else
return vvfPrivate; // # TO DO #
}
//----------------------------------------------------------------------------
// Return the procedure flags for the item at index 'AIndex'. AIndex is the index in the filtered list
TOTAProcDispatchFlags __fastcall TMyCodeInsightSymbolList::GetProcDispatchFlags(int AIndex)
{
#ifdef _DEBUG
ShowMessage(L"TMyCodeInsightSymbolList::GetProcDispatchFlags");
#endif
if (AIndex < static_cast<int>(FSymbols.size()))
return FSymbols[AIndex].ProcDispatchFlag;
else
return pdfNone;
}
//----------------------------------------------------------------------------
// The list was requested to be sorted by 'AValue'
void __fastcall TMyCodeInsightSymbolList::SetSortOrder(const TOTASortOrder AValue)
{
#ifdef _DEBUG
ShowMessage(L"TMyCodeInsightSymbolList::SetSortOrder");
#endif
FSortOrder = AValue;
// Sort order is alphabetically
if (FSortOrder == soAlpha)
{
// Sort Symbol vector alphabetically
std::sort(FSymbols.begin(), FSymbols.end(), SymbolTextCompare);
}
// Sort order is by scope
else if (FSortOrder == soScope)
{
// Sort Symbol vector by scope
// # TO DO #
}
}
//----------------------------------------------------------------------------
// Returns the sort order of the list
TOTASortOrder __fastcall TMyCodeInsightSymbolList::GetSortOrder(void)
{
#ifdef _DEBUG
ShowMessage(L"TMyCodeInsightSymbolList::GetSortOrder");
#endif
return FSortOrder;
}
//----------------------------------------------------------------------------
// Given an identifier, return the index of the closest partial match
int __fastcall TMyCodeInsightSymbolList::FindIdent(const String AIdent)
{
#ifdef _DEBUG
ShowMessage(L"TMyCodeInsightSymbolList::FindIdent");
#endif
return 0; // # TO DO # We're not searching at the moment
}
//----------------------------------------------------------------------------
// Given an identifier, find the 'Index' of an exact match in the list and return true. Otherwise return false
bool __fastcall TMyCodeInsightSymbolList::FindSymIndex(const String AIdent, int& AIndex)
{
#ifdef _DEBUG
ShowMessage(L"TMyCodeInsightSymbolList::FindSymIndex");
#endif
return false; // # TO DO # We aren't matching at the moment
}
//----------------------------------------------------------------------------
// Set the lists filter to 'FilterText'. It is up to the implementor to determine how to filter or if they even want to filter
void __fastcall TMyCodeInsightSymbolList::SetFilter(const String AFilterText)
{
#ifdef _DEBUG
ShowMessage(L"TMyCodeInsightSymbolList::SetFilter");
#endif
// # TO DO # : We don't filter at the moment
}
//----------------------------------------------------------------------------
// Return the symbol text for item 'AIndex'. i.e. Form1
String __fastcall TMyCodeInsightSymbolList::GetSymbolText(int AIndex)
{
#ifdef _DEBUG
ShowMessage(L"TMyCodeInsightSymbolList::GetSymbolText");
#endif
if (AIndex < static_cast<int>(FSymbols.size()))
return FSymbols[AIndex].Text;
else
return L"";
}
//----------------------------------------------------------------------------
// Return the symbol type text for item 'AIndex'. i.e. TForm1
String __fastcall TMyCodeInsightSymbolList::GetSymbolTypeText(int AIndex)
{
#ifdef _DEBUG
ShowMessage(L"TMyCodeInsightSymbolList::GetSymbolTypeText");
#endif
if (AIndex < static_cast<int>(FSymbols.size()))
return FSymbols[AIndex].Type;
else
return L"";
}
//----------------------------------------------------------------------------
// Return the symbol class text for item 'AIndex'. i.e. 'var', 'function', 'type', etc
String __fastcall TMyCodeInsightSymbolList::GetSymbolClassText(int AIndex)
{
#ifdef _DEBUG
ShowMessage(L"TMyCodeInsightSymbolList::GetSymbolClassText");
#endif
if (AIndex < static_cast<int>(FSymbols.size()))
return FSymbols[AIndex].Class;
else
return L"";
}
//----------------------------------------------------------------------------
// Returns true, if AX.Text's position is alphabetically before AY.Text's
bool TMyCodeInsightSymbolList::SymbolTextCompare(const TMySymbol& AX, const TMySymbol& AY)
{
#ifdef _DEBUG
ShowMessage(L"TMyCodeInsightSymbolList::SymbolTextCompare");
#endif
return (AnsiCompareStr(AX.Text, AY.Text) == -1);
}
//---------------------------------------------------------------------------
i solved couple of my redefinition problems but still have one:
Error 2 error LNK2005: "class ConsoleCommandHandler commandHandler" (?commandHandler##3VConsoleCommandHandler##A) already defined in IRC.obj C:\Users\Łukasz\Desktop\IRCClient-master\Magic.obj
Here are the .h files
magic.h
#ifndef Magic_h
#define Magic_h
#include <iostream>
#include <signal.h>
#include <cstdlib>
#include <map>
#include <algorithm>
#include "src\Thread.h"
#include "src\IRCClient.h"
void signalHandler(int signal);
class ConsoleCommandHandler
{
public:
bool AddCommand(std::string name, int argCount, void(*handler)(std::string /*params*/, IRCClient* /*client*/));
void ParseCommand(std::string command, IRCClient* client);
private:
struct CommandEntry
{
int argCount;
void(*handler)(std::string /*arguments*/, IRCClient* /*client*/);
};
std::map<std::string, CommandEntry> _commands;
};
ConsoleCommandHandler commandHandler;
void msgCommand(std::string arguments, IRCClient* client);
void joinCommand(std::string channel, IRCClient* client);
void partCommand(std::string channel, IRCClient* client);
void ctcpCommand(std::string arguments, IRCClient* client);
ThreadReturn inputThread(void* client);
#endif
magic.cpp
#include "Magic.h"
void signalHandler(int signal)
{
volatile bool running;
running = false;
};
bool ConsoleCommandHandler::AddCommand(std::string name, int argCount, void(*handler)(std::string /*params*/, IRCClient* /*client*/))
{
CommandEntry entry;
entry.argCount = argCount;
entry.handler = handler;
std::transform(name.begin(), name.end(), name.begin(), towlower);
_commands.insert(std::pair<std::string, CommandEntry>(name, entry));
return true;
}
void ConsoleCommandHandler::ParseCommand(std::string command, IRCClient* client)
{
if (_commands.empty())
{
std::cout << "No commands available." << std::endl;
return;
}
if (command[0] == '/')
command = command.substr(1); // Remove the slash
std::string name = command.substr(0, command.find(" "));
std::string args = command.substr(command.find(" ") + 1);
int argCount = std::count(args.begin(), args.end(), ' ');
std::transform(name.begin(), name.end(), name.begin(), towlower);
std::map<std::string, CommandEntry>::const_iterator itr = _commands.find(name);
if (itr == _commands.end())
{
std::cout << "Command not found." << std::endl;
return;
}
if (++argCount < itr->second.argCount)
{
std::cout << "Insuficient arguments." << std::endl;
return;
}
(*(itr->second.handler))(args, client);
}
struct CommandEntry
{
int argCount;
void(*handler)(std::string /*arguments*/, IRCClient* /*client*/);
};
std::map<std::string, CommandEntry> _commands;
void msgCommand(std::string arguments, IRCClient* client)
{
std::string to = arguments.substr(0, arguments.find(" "));
std::string text = arguments.substr(arguments.find(" ") + 1);
std::cout << "To " + to + ": " + text << std::endl;
client->SendIRC("PRIVMSG " + to + " :" + text);
};
void joinCommand(std::string channel, IRCClient* client)
{
if (channel[0] != '#')
channel = "#" + channel;
client->SendIRC("JOIN " + channel);
}
void partCommand(std::string channel, IRCClient* client)
{
if (channel[0] != '#')
channel = "#" + channel;
client->SendIRC("PART " + channel);
}
void ctcpCommand(std::string arguments, IRCClient* client)
{
std::string to = arguments.substr(0, arguments.find(" "));
std::string text = arguments.substr(arguments.find(" ") + 1);
std::transform(text.begin(), text.end(), text.begin(), towupper);
client->SendIRC("PRIVMSG " + to + " :\001" + text + "\001");
}
ThreadReturn inputThread(void* client)
{
std::string command;
commandHandler.AddCommand("msg", 2, &msgCommand);
commandHandler.AddCommand("join", 1, &joinCommand);
commandHandler.AddCommand("part", 1, &partCommand);
commandHandler.AddCommand("ctcp", 2, &ctcpCommand);
while (true)
{
getline(std::cin, command);
if (command == "")
continue;
if (command[0] == '/')
commandHandler.ParseCommand(command, (IRCClient*)client);
else
((IRCClient*)client)->SendIRC(command);
if (command == "quit")
break;
}
#ifdef _WIN32
_endthread();
#else
pthread_exit(NULL);
#endif
}
irc.h
#pragma once
#include <iostream>
#include <signal.h>
#include <cstdlib>
#include <map>
#include <algorithm>
#include "Magic.h"
#include <msclr/marshal.h>
#include <msclr/marshal_cppstd.h>
#using <mscorlib.dll>
namespace IRCclient {
using namespace System;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;
using namespace System::IO;
using namespace System::Runtime::InteropServices;
using namespace msclr::interop;
/// <summary>
/// Summary for MyForm
/// </summary>
private: System::Void connect_button_Click(System::Object^ sender, System::EventArgs^ e)
{
if ((server_box->Text == "") || (port_box->Text == "") || (username_box->Text == "") || (channel_box->Text == ""))
{
MessageBox::Show("Wypełnij wszystkie pola", "Puste pola", MessageBoxButtons::OK, MessageBoxIcon::Warning);
server_box->Focus();
}
else
{
String^ host_string = server_box->Text;
char* host = (char*)(void*)Marshal::StringToHGlobalAnsi(host_string);
String^ port_string = port_box->Text;
int port;
//String^ port_string = port.ToString();
String^ nick_string = username_box->Text;
std::string nick(marshal_as<std::string>(nick_string));
std::string user = "test";
IRCClient client;
volatile bool running;
Thread thread;
thread.Start(&inputThread, &client);
if (client.InitSocket())
{
content_box->Text = "Socket initialized. Connecting..." + "\r\n";
if (client.Connect(host, port))
{
content_box->Text = "Connected. Loggin in..." + "\r\n";
if (client.Login(nick, user))
{
content_box->Text = "Logged." + "\r\n";
running = true;
signal(SIGINT, signalHandler);
while (client.Connected() && running)
client.ReceiveData();
}
if (client.Connected())
client.Disconnect();
content_box->Text = "Disconnected." + "\r\n";
}
}
}
};
};
};
In the Magic.h file make this change:
extern ConsoleCommandHandler commandHandler;
Then in the Magic.cpp file add this code:
ConsoleCommandHandler commandHandler;
Otherwise both Magic.obj and IRC.obj will end up with ConsoleCommandHandler commandHandler because the header will reserve it twice, once in each obj file.
i searched for an answer but couldnt find it. im working on threads. i have a thread class and 3 subclass of it. when i call one of these 3 subclass i have to create a thread in thread class and use their main(since threads main is pure virtual abstract) but the problem is before it call the Create Thread function(c'tor of thread) it calls those sub-mains.
thread.h
#ifndef _THREAD_H_
#define _THREAD_H_
#include <string>
#include <Windows.h>
#include <iosfwd>
#include "Mutex.h"
#include "SynchronizedArray.h"
#include "SynchronizedCounter.h"
std::string message = "";
class Thread{
private:
HANDLE hThread;
int idThread;
protected:
SynchronizedArray *arr;
int size;
SynchronizedCounter *counter;
public:
Thread(DWORD funct){ //creates a thread by calling subclasses main functions appropriately
hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) funct, NULL, 0, (LPDWORD)&idThread);
}
virtual DWORD WINAPI main(void*) = 0; // pure virtual abstract class
void suspend(){ //suspent the thread
SuspendThread(hThread);
}
void resume(){// retume the thread
ResumeThread(hThread);
}
void terminate(){ // terminates the thread
TerminateThread(hThread,0);
}
void join(){ // joins the thread
Mutex mut;
mut.lock();
}
static void sleep(int sec){ //wrapper of sleep by sec
Sleep(sec*1000);
}
};
#endif
1 of 3 inherited class of Thread as example (all of them do the same)
PrintThread.h
#ifndef _PRINTINGTHREAD_H_
#define _PRINTINGTHREAD_H_
#include "SynchronizedArray.h"
#include "SynchronizedCounter.h"
#include "Thread.h"
#include <iostream>
#include "SortingThread.h"
#include "CountingThread.h"
#include <string>
#include <Windows.h>
extern CountingThread counterThread1;
extern CountingThread counterThread2;
extern SortingThread sortingThread1;
extern SortingThread sortingThread2;
class PrintingThread:public Thread{
private:
char temp;
public:
PrintingThread() :Thread(main(&temp)){
}
DWORD WINAPI main(void* param)
{
std::cout << "Please enter an operation ('showcounter1','showcounter2','showarray1','showarray2' or 'quit')" << std::endl;
std::cin >> message;
while (message != "quit")
{
if (message == "showcounter1")
{
std::cout << counterThread1<<std::endl;
}
else if (message == "showcounter2")
{
std::cout << counterThread2 << std::endl;
}
else if (message == "showarray1")
{
std::cout << sortingThread1 << std::endl;
}
else if (message == "showarray2")
{
std::cout << sortingThread2 << std::endl;
}
else {
std::cout << "Invalid operation";
}
std::cout << "Please enter an operation ('show counter 1','show counter 2','show array 1','show array 2' or 'quit')" << std::endl;
std::cin >> message;
}
return 0;
}
};
#endif
Why its calling mains before it calls the c'tor of thread.
Your PrintingThread constructor initializer list is actually calling PrintingThread::main and passing the result of that to the Thread constructor. That means that the CreateThread call is receiving a DWORD (in this case, 0) as its function argument.
You need to change your class design to actually pass the function pointer and context argument around, e.g.:
Thread(DWORD funct){
hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) funct, NULL, 0, (LPDWORD)&idThread);
should be:
Thread(LPTHREAD_START_ROUTINE funct, LPVOID arg) {
hThread = CreateThread(NULL, 0, funct, arg, 0, (LPDWORD)&idThread);
(The fact that you had to cast funct should have been a giant red flag.)
Likewise, the subclass constructors will change from:
PrintingThread() :Thread(main(&temp)){
to:
PrintingThread(): Thread(main, &temp) {
Note that your code will still have other issues, like the fact that the thread functions should be static (so you can't try to access member functions).
you need to do something more like this instead:
thread.h:
#ifndef _THREAD_H_
#define _THREAD_H_
#include <string>
#include <Windows.h>
#include <iosfwd>
#include "Mutex.h"
#include "SynchronizedArray.h"
#include "SynchronizedCounter.h"
class Thread
{
private:
HANDLE hThread;
DWORD idThread;
void *pParam;
static DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
Thread *pThis = (Thread*) lpParameter;
return pThis->main(pThis->pParam);
}
protected:
SynchronizedArray *arr;
int size;
SynchronizedCounter *counter;
public:
Thread(void *aParam)
{
//creates a thread by calling subclasses main functions appropriately
pParam = aParam;
hThread = CreateThread(NULL, 0, &ThreadProc, this, 0, &idThread);
}
virtual DWORD main(void*) = 0; // pure virtual abstract class
void suspend()
{
//suspent the thread
SuspendThread(hThread);
}
void resume()
{
// resume the thread
ResumeThread(hThread);
}
void terminate()
{
// terminates the thread
TerminateThread(hThread, 0);
}
void join()
{
// joins the thread
Mutex mut;
mut.lock();
}
static void sleep(int sec)
{
//wrapper of sleep by sec
Sleep(sec*1000);
}
};
#endif
PrintThread.h:
include <iostream>
#include "SortingThread.h"
#include "CountingThread.h"
#include <string>
#include <Windows.h>
extern CountingThread counterThread1;
extern CountingThread counterThread2;
extern SortingThread sortingThread1;
extern SortingThread sortingThread2;
class PrintingThread : public Thread
{
private:
char temp;
public:
PrintingThread() : Thread(&temp)
{
}
virtual DWORD main(void* param)
{
std::string message;
do
{
std::cout << "Please enter an operation ('showcounter1','showcounter2','showarray1','showarray2' or 'quit')" << std::endl;
std::cin >> message;
if (message == "quit")
{
break;
}
if (message == "showcounter1")
{
std::cout << counterThread1 << std::endl;
}
else if (message == "showcounter2")
{
std::cout << counterThread2 << std::endl;
}
else if (message == "showarray1")
{
std::cout << sortingThread1 << std::endl;
}
else if (message == "showarray2")
{
std::cout << sortingThread2 << std::endl;
}
else
{
std::cout << "Invalid operation";
}
}
while (true);
return 0;
}
};
#endif