Watch, Follow, &
Connect with Us

For forums, blogs and more please visit our
Developer Tools Community.


Welcome, Guest
Guest Settings
Help

Thread: Debug Visualizers in C++


This question is answered.


Permlink Replies: 12 - Last Post: Sep 30, 2016 5:56 AM Last Post By: Jason DeBettenc...
Andrew Law

Posts: 74
Registered: 11/6/02
Debug Visualizers in C++  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Aug 10, 2016 10:45 AM
Hi,

At our company we're considering developing some visualizers for STL containers.

I'm looking at the example visualizer for std::string in Delphi, as a starting point, and am trying to port this to C++ initially, partly so as to try to fix it so that it works properly with the clang compilers (a colleague tells me he output is not that helpful any more), and also so that it could be used as a reference point for more exotic visualizers.

However, several aspects of the Delphi code leave me perplexed as to how to port them to C++. I know that Remy has posted example code for a C++ visualizer on these forums, but all links that I have seen to hat previous post are now dead, suggesting that the relevant post is lost due to the forums meltdown of a year or so back.

So, my question is, has anyone managed to develop a visualizer in C++, and if so, how does one deal with the Register() procedure which seems to feature some unusual casting (BorlandIDEServices as IOTADebuggerServices) , and how can I use the Supports() function in C++, and what is going in the initialization - finalization - end section at the tail end? This looks similar to registering a component on the tool palette but is clearly different. The documentation for visualizers does not explain any of the sample code so it's a bit of a trial and error process to work this out.

If anyone has a simple example cpp unit that they are willing to share with brief description of how to install it, I'd be very grateful.

Thanks in advance.
david hoke

Posts: 616
Registered: 2/9/07
Re: Debug Visualizers in C++
Helpful
Click to report abuse...   Click to reply to this thread Reply
  Posted: Aug 10, 2016 12:42 PM   in response to: Andrew Law in response to: Andrew Law
Andrew Law wrote:

However, several aspects of the Delphi code leave me perplexed as to
how to port them to C++. I know that Remy has posted example code for
a C++ visualizer on these forums, but all links that I have seen to
hat previous post are now dead, suggesting that the relevant post is
lost due to the forums meltdown of a year or so back.

maybe ????:
http://codeverge.com/embarcadero.cppbuilder.ide/c++-debugger-visualizer/1067965

or

http://www.codenewsfast.com/cnf/article/1374376472/permalink.art-ng1882q4880
Andrew Law

Posts: 74
Registered: 11/6/02
Re: Debug Visualizers in C++  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Aug 11, 2016 1:27 AM   in response to: david hoke in response to: david hoke
david hoke wrote:
Andrew Law wrote:

However, several aspects of the Delphi code leave me perplexed as to
how to port them to C++. I know that Remy has posted example code for
a C++ visualizer on these forums, but all links that I have seen to
hat previous post are now dead, suggesting that the relevant post is
lost due to the forums meltdown of a year or so back.

maybe ????:
http://codeverge.com/embarcadero.cppbuilder.ide/c++-debugger-visualizer/1067965

or

http://www.codenewsfast.com/cnf/article/1374376472/permalink.art-ng1882q4880

Thanks David, I hadn't found either of those copies of that post.

Ironically, Jon who asked the question in those posts in 2010 was then working for the same company as me!
Which makes me wonder if he didn't manage to pursue this much further.

However I now have a C++ version without all the terribly confusing (to someone like me) Delphi bits.

Thanks again,
Andy
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Debug Visualizers in C++  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Aug 10, 2016 12:48 PM   in response to: Andrew Law in response to: Andrew Law
Andrew wrote:

However, several aspects of the Delphi code leave me perplexed as to
how to port them to C++. I know that Remy has posted example code
for a C++ visualizer on these forums, but all links that I have seen to
hat previous post are now dead, suggesting that the relevant post is
lost due to the forums meltdown of a year or so back.

Did you check the archived messages at http://www.codenewsfast.com?

So, my question is, has anyone managed to develop a visualizer in C++

Yes.

and if so, how does one deal with the Register() procedure which seems
to feature some unusual casting (BorlandIDEServices as
IOTADebuggerServices)

The 'as' operator is just a wrapper for the QueryInterface() method, raising
an exception if it fails.

and how can I use the Supports() function in C++

The same way you do in Delphi. It is not a hard function to use.

But either way, Supports() is just another wrapper for QueryInterface().

and what is going in the initialization - finalization - end
section at the tail end?

What is unclear about it?

This looks similar to registering a component on the tool palette but is
clearly different.

Not really. They just

--
Remy Lebeau (TeamB)
Andrew Law

Posts: 74
Registered: 11/6/02
Re: Debug Visualizers in C++  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Aug 11, 2016 1:37 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Remy Lebeau (TeamB) wrote:
Andrew wrote:

Did you check the archived messages at http://www.codenewsfast.com?

No I didn't because I was not aware of that site before. I've tried it now and found a poorly displayed copy of the same thread that David has linked to above.

So, my question is, has anyone managed to develop a visualizer in C++

Yes.

Great to hear but not exactly helpful, unfortunately.

and how can I use the Supports() function in C++

The same way you do in Delphi. It is not a hard function to use.

I don't use Delphi at all, hence my question. If I understood Delphi then I would have been able to translate this into C++ for myself.

It seems that there is a big assumption amongst users (and the makers) of RAD Studio in general that of course we all use Delphi, regardless of whether we use C++ or not. This is not true, at least not in my company. We use C++ exclusively in our own code, irrespective of the fact that we are linking to Delphi RTL and VCL code underneath.

and what is going in the initialization - finalization - end
section at the tail end?

What is unclear about it?

Everything, since I am not a Delphi programmer. I can convert recognisable Pascal code, since I did use Turbo Pascal in the early 1990s, but those final three lines mean nothing to me.

Thanks to David for providing a link to one of Remy's previous helpful answers, and thanks Remy for your previous help to my then-colleague Jon.
Andrew Law

Posts: 74
Registered: 11/6/02
Re: Debug Visualizers in C++  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Aug 11, 2016 1:52 AM   in response to: Andrew Law in response to: Andrew Law
Dear all,

Attempting to compile the C++ version of the std::string visualizer previously posted (untested,I fully recognise) by Remy, I'm finding the following compiler error: The line:

if( Supports(BorlandIDEServices, IID_IOTADebuggerServices, (void*)&DebugSvcs) )

gives the following error:

[C++ Error] E2014 Member is ambiguous: 'IInterface::Supports<T>' and 'IInterface::Supports<T>'
[C++ Error] E2285 Could not find a match for 'IInterface::Supports<T>(_di_IBorlandIDEServices,const _GUID,void *)'

and later on I encounter:

[C++ Error] RemyStdString.cpp(193, 79): E2352 Cannot create instance of abstract class 'TStdStringTimeVisualizer'
[C++ Error] RemyStdString.cpp(193, 79): E2353 Class 'TStdStringTimeVisualizer' is abstract because of '__stdcall IUnknown::QueryInterface(const _GUID &,void * *) = 0'

Given Remy's explanation that Supports() is a wrapper for QueryInterface, I suspect that these two issues are linked. But the first error message has me stumped because it looks as though the two alternatives suggested in the error message are one and the same.

Right-clicking on "Supports" and choosing "Find Declaration" takes me straight to line 264 in sysmac.h (using BCB 2010 at the moment). The call to Supports() passes in three parameters, as it was doing in the Delphi example, but the declaration for Supports() in sysmac.h only seems to accept one parameter.

Thanks in advance if anyone can help a "bear of very little brain".
Andrew Law

Posts: 74
Registered: 11/6/02
Re: Debug Visualizers in C++  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Aug 11, 2016 2:40 AM   in response to: Andrew Law in response to: Andrew Law
Andrew Law wrote:
Dear all,

if( Supports(BorlandIDEServices, IID_IOTADebuggerServices, (void*)&DebugSvcs) )

Mystery solved - this should be SysUtils::Supports to pick up the correct version of the function.

[C++ Error] E2352 Cannot create instance of abstract class 'TStdStringTimeVisualizer'
[C++ Error] E2353 Class 'TStdStringTimeVisualizer' is abstract because of '__stdcall IUnknown::QueryInterface(const _GUID &,void * *) = 0'

Also solved, through correct declaration of QueryInterface(), AddRef(), and Release() methods.

My final unresolved external link error for "BorlandIDEServices" has been solved by adding "DesignIDE.bpi" to the required section of the project. My C++ string visualiser now installs. So now to test it...

Thanks.

Edited by: Andrew Law on Aug 11, 2016 3:04 AM

Edited by: Andrew Law on Aug 11, 2016 3:07 AM

Edited by: Andrew Law on Aug 11, 2016 3:22 AM
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Debug Visualizers in C++
Correct
Click to report abuse...   Click to reply to this thread Reply
  Posted: Aug 11, 2016 9:03 AM   in response to: Andrew Law in response to: Andrew Law
Andrew wrote:

[C++ Error] RemyStdString.cpp(193, 79): E2352 Cannot create instance
of abstract class 'TStdStringTimeVisualizer'

[C++ Error] RemyStdString.cpp(193, 79): E2353 Class
'TStdStringTimeVisualizer' is abstract because of '__stdcall
IUnknown::QueryInterface(const _GUID &,void * *) = 0'

http://docwiki.embarcadero.com/RADStudio/en/Inheritance_and_Interfaces#IUnknown_and_IInterface

http://docwiki.embarcadero.com/RADStudio/en/Inheritance_and_Interfaces#Creating_classes_that_support_IUnknown

--
Remy Lebeau (TeamB)
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Debug Visualizers in C++  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Aug 11, 2016 9:00 AM   in response to: Andrew Law in response to: Andrew Law
Andrew wrote;

It seems that there is a big assumption amongst users (and the makers)
of RAD Studio in general that of course we all use Delphi, regardless
of whether we use C++ or not. This is not true, at least not in my
company. We use C++ exclusively in our own code, irrespective of the
fact that we are linking to Delphi RTL and VCL code underneath.

Anyone who uses C++Builder should take the time to learn at least a basic
understanding of Delphi, since the RTL/VCL is written in Delphi, and so has
performance and behavioral effects on C++Builder VCL projects.

Everything, since I am not a Delphi programmer. I can convert
recognisable Pascal code, since I did use Turbo Pascal in the early
1990s, but those final three lines mean nothing to me.

What "final three lines"? The initialization and finalization sections?

http://docwiki.embarcadero.com/RADStudio/en/Programs_and_Units_(Delphi)#The_Initialization_Section
http://docwiki.embarcadero.com/RADStudio/en/Programs_and_Units_(Delphi)#The_Finalization_Section

--
Remy Lebeau (TeamB)
Andrew Law

Posts: 74
Registered: 11/6/02
Re: Debug Visualizers in C++  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Aug 11, 2016 9:49 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Remy Lebeau (TeamB) wrote:
Andrew wrote;

Anyone who uses C++Builder should take the time to learn at least a basic
understanding of Delphi, since the RTL/VCL is written in Delphi, and so has
performance and behavioral effects on C++Builder VCL projects.

Fair enough I accept that and I do read the Delphi forums as well as the C++ ones, but I would have called installation of 3rd party components or similar I would class as beyond "basic". I often have a hard enough time persuading some of my colleagues that we shouldn't ditch Builder for MSVC (with all the pain and upheaval that would entail) without the possibility of them needing to familiarise themselves with Delphi as well. New clang Win32 is the key to keeping us on Builder, and the reports that the visualisers behave worse under clang than under bcc32.exe was not good news when I heard it.

What "final three lines"? The initialization and finalization sections?

Yes, the ones I was trying to explain before that I didn't recognise.


Thanks for pointing me in the right direction, it's appreciated - but I still wouldn't have managed to convert that to C++ without some help. Thanks to you and David, I now have a working visualiser that does what I want under bcc32 but behaves differently (i.e. worse) under bcc32c, just like the default std::string visualiser. This means I'm free to try to make it work better under clang.
david hoke

Posts: 616
Registered: 2/9/07
Re: Debug Visualizers in C++  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Aug 11, 2016 10:24 AM   in response to: Andrew Law in response to: Andrew Law
Andrew Law wrote:

help. Thanks to you and David, I now have a working visualiser that
does what I want under bcc32 but behaves differently (i.e. worse)
under bcc32c, just like the default std::string visualiser. This
means I'm free to try to make it work better under clang.

Consider posting what you have, since that now compiles and runs, and
is thus a step beyond what Remy originally posted.

I realize you generally spoke of what you did to reach that stage, but
it would be much easier for others if you could now provide what was
not previously provided for you... :)

and would also have it again, at least for a while, in these groups,
where people might generally search first, as you did...
Andrew Law

Posts: 74
Registered: 11/6/02
Re: Debug Visualizers in C++  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Aug 11, 2016 2:38 PM   in response to: david hoke in response to: david hoke
david hoke wrote:

Consider posting what you have, since that now compiles and runs, and
is thus a step beyond what Remy originally posted.

Because invited to do so, I will certainly look at doing so, tomorrow. It's late in the UK now.

Thanks.
Jason DeBettenc...

Posts: 1
Registered: 8/2/08
Re: Debug Visualizers in C++  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Sep 30, 2016 5:56 AM   in response to: Andrew Law in response to: Andrew Law
Andrew Law wrote:
david hoke wrote:

Consider posting what you have, since that now compiles and runs, and
is thus a step beyond what Remy originally posted.

Because invited to do so, I will certainly look at doing so, tomorrow. It's late in the UK now.

Thanks.

Here's my version of Remy's code (Thanks Remy!). I've built and installed it under Berlin Update 1 -- works well. My steps were, create new project type of Package, Add designide.bpi to required list. Create a new unit, Mystdstringvisualizer.cpp -- name required as Remy noted. Paste in this code in cpp file and build. Then right-click on the bpl node in the project manager and pick install. You should see it under Tools->Options->Debugger Options->Visualizers

#include <vcl.h>
#pragma hdrstop

#include <Classes.hpp>
#include <Forms.hpp>
#include <SysUtils.hpp>
#include <ToolsAPI.hpp>

#pragma package(smart_init)

const String sStdStringVisualizerName =
"Remy std::string and std::wstring Visualizer for C++";
const String sStdStringVisualizerDescription =
"Remy Displays the actual string value for std::string and std::wstring instances";

class TStdStringTimeVisualizer : public TInterfacedObject,
// public IOTADebuggerVisualizer,
public IOTADebuggerVisualizerValueReplacer,
public IOTAThreadNotifier {
private:
int FNotifierIndex;
bool FCompleted;
String FDeferredResult;

public:
// IOTADebuggerVisualizer
int __fastcall GetSupportedTypeCount();
void __fastcall GetSupportedType(int Index, String &TypeName,
bool &AllDescendants);
String __fastcall GetVisualizerIdentifier();
String __fastcall GetVisualizerName();
String __fastcall GetVisualizerDescription();

// IOTADebuggerVisualizerValueReplacer
String __fastcall GetReplacementValue(const String Expression,
const String TypeName, const String EvalResult);

// IOTAThreadNotifier
void __fastcall EvaluteComplete(const String ExprStr,
const String ResultStr, bool CanModify, Cardinal ResultAddress,
Cardinal ResultSize, int ReturnCode);
void __fastcall ModifyComplete(const String ExprStr, const String ResultStr,
int ReturnCode);
void __fastcall ThreadNotify(TOTANotifyReason Reason);
void __fastcall AfterSave();
void __fastcall BeforeSave();
void __fastcall Destroyed();
void __fastcall Modified();

// IUnknown
HRESULT __stdcall QueryInterface(REFIID riid, void** ppv) {
return TInterfacedObject::QueryInterface(riid, (void*)ppv);
}

ULONG __stdcall AddRef() {
return TInterfacedObject::_AddRef();
}

ULONG __stdcall Release() {
return TInterfacedObject::_Release();
}
};

const String StdStringVisualizerTypes[2] = {
"std::basic_string<char, std::char_traits<char>, std::allocator<char> >",
"std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> >"};

// TStdStringTimeVisualizer

void __fastcall TStdStringTimeVisualizer::AfterSave() {
// don't care about this notification
}

void __fastcall TStdStringTimeVisualizer::BeforeSave() {
// don't care about this notification
}

void __fastcall TStdStringTimeVisualizer::Destroyed() {
// don't care about this notification
}

void __fastcall TStdStringTimeVisualizer::Modified() {
// don't care about this notification
}

void __fastcall TStdStringTimeVisualizer::ModifyComplete(const String ExprStr,
const String ResultStr, int ReturnCode) {
// don't care about this notification
}

void __fastcall TStdStringTimeVisualizer::EvaluteComplete(const String ExprStr,
const String ResultStr, bool CanModify, Cardinal ResultAddress,
Cardinal ResultSize, int ReturnCode) {
FCompleted = true;
if (ReturnCode == 0)
FDeferredResult = ResultStr;
}

void __fastcall TStdStringTimeVisualizer::ThreadNotify(TOTANotifyReason Reason)
{
// don't care about this notification
}

String __fastcall TStdStringTimeVisualizer::GetReplacementValue
(const String Expression, const String TypeName, const String EvalResult) {
_di_IOTAProcess CurProcess;
_di_IOTAThread CurThread;
Char ResultStr[4096];
bool CanModify;
unsigned __int64 ResultAddr;
unsigned int ResultSize;
unsigned int ResultVal;
TOTAEvaluateResult EvalRes;
_di_IOTADebuggerServices DebugSvcs;

String Result = EvalResult;
if (::Supports(BorlandIDEServices, IID_IOTADebuggerServices,
(void*)&DebugSvcs))
CurProcess = DebugSvcs->CurrentProcess;
if (CurProcess) {
CurThread = CurProcess->CurrentThread;
if (CurThread) {
EvalRes = CurThread->Evaluate(Expression + "._Myptr()",
ResultStr,
4096,
CanModify,
eseAll,
"",
ResultAddr,
ResultSize,
ResultVal,
"",
0);

switch (EvalRes) {
case erOK: {
Result = ResultStr;
break;
}
case erDeferred: {
FCompleted = false;
FDeferredResult = "";
FNotifierIndex = CurThread->AddNotifier(this);
while (!FCompleted)
DebugSvcs->ProcessDebugEvents();
CurThread->RemoveNotifier(FNotifierIndex);
FNotifierIndex = -1;
if (FDeferredResult != "")
Result = FDeferredResult;
else
Result = EvalResult;
break;
}
case erBusy: {
DebugSvcs->ProcessDebugEvents();
Result = GetReplacementValue(Expression, TypeName,
EvalResult);
break;
}
}
}
}

return Result;
}

int __fastcall TStdStringTimeVisualizer::GetSupportedTypeCount() {
return 2;
}

void __fastcall TStdStringTimeVisualizer::GetSupportedType(int Index,
String &TypeName, bool &AllDescendants) {
AllDescendants = false;
TypeName = StdStringVisualizerTypes[Index];
}

String __fastcall TStdStringTimeVisualizer::GetVisualizerDescription() {
return sStdStringVisualizerDescription;
}

String __fastcall TStdStringTimeVisualizer::GetVisualizerIdentifier() {
return ClassName();
}

String __fastcall TStdStringTimeVisualizer::GetVisualizerName() {
return sStdStringVisualizerName;
}

_di_IOTADebuggerVisualizer StdStringVis;

namespace Mystdstringvisualizer {
void __fastcall PACKAGE Register() {

StdStringVis = (IOTADebuggerVisualizer *) new TStdStringTimeVisualizer();

_di_IOTADebuggerServices DebuggerServices;
if (::Supports(BorlandIDEServices, IID_IOTADebuggerServices,
(void*)&DebuggerServices))
DebuggerServices->RegisterDebugVisualizer(StdStringVis);
}
}

void RemoveVisualizer() {
_di_IOTADebuggerServices DebuggerServices;
if (::Supports(BorlandIDEServices, IID_IOTADebuggerServices,
(void*)&DebuggerServices))
DebuggerServices->UnregisterDebugVisualizer(StdStringVis);
StdStringVis = NULL;
}

#pragma exit RemoveVisualizer

Legend
Helpful Answer (5 pts)
Correct Answer (10 pts)

Server Response from: ETNAJIVE02