type TMessage is not a defined class with virtual function C++ builder sample - c++builder

Im trying to use embarcadero sample on useing android camera and geting an error:
"type TMessage is not a defined class with virtual function" on lines:
void __fastcall TForm1::DoMessageListener(const TObject *Sender, TMessage const *M) {
TMessageDidFinishTakingImageFromLibrary const *v = dynamic_cast<TMessageDidFinishTakingImageFromLibrary const *>(M);
if (v) {
Image1->Bitmap->Assign(v->Value);
}
}

In Delphi, TMessage works fine, but in C++Builder you must use TMessageBase instead:
void __fastcall TForm1::DoMessageListener(const TObject *Sender, TMessageBase const *M)
This is clearly stated in the documentation:
Sending and Receiving Messages Using the RTL:
The RTL only defines one type of message, TMessage. It is actually a template that you can use to create messages for specific types of values; for example: TMessage<int> or TMessage<UnicodeString>. You can also subclass TMessage to define your own message types or, if you are using FireMonkey, you can reuse the message types defined by the framework.
Note: For C++ projects use TMessageBase instead of TMessage.
System.Messaging.TMessage
TMessage represents the base class used for message purposes. It can be inherited in order to send custom messages.
Warning: For C++ projects, use TMessageBase instead.
System.Messaging.TMessageBase
Alias to System.Messaging.TMessage.
Use System.Messaging.TMessageBase for C++ projects instead of System.Messaging.TMessage.
This use of TMessageBase is also demonstrated in the documentation's System.Messaging (C++) example.

Related

Unresolved external linker error in C++Builder

I am new to C++ Builder. I am translating a Delphi project into C++. I have translated some of the Delphi code into C++ and it compiles fine in C++Builder, but I get an error:
Unresolved external ColorClasses::TColorList:: referenced from ...
when I use the TColorList constructor in my MainForm in this way:
ColorClasses::TColorList *cl;
cl = new ColorClasses::TColorList();
The TColorList constructor is defined as follows in file ColorClasses.cpp:
__fastcall ColorClasses::TColorList::TColorList() : TColorClass()
{
fcolor_list = new TList();
}
The TColorList class is declared as follows in file ColorClasses.h:
class DELPHICLASS TColorList;
class PASCALIMPLEMENTATION TColorList : public TColorClass
{
private:
TList* fcolor_list;
public:
__fastcall TColorList();
virtual __fastcall ~TColorList();
};
I have searched the StackOverflow site for similar questions relevant to C++Builder, but I can't find one specific to my problem.
The problem seems to resolve itself if I remove the keywords DELPHICLASS and PASCALIMPLEMENTATION.

using Helpintfs::IHelpSystem gives an error 'abstract class' in C++Builder

I am using C++Builder and working with sample Delphi code for calling a new help file system called eViewer. When I convert the Delphi Procedure below the variable IHelpSystem is giving the error: variable type 'System::Helpintfs::IHelpSystem' is an abstract class. The error text is below. How can I use the variable IHelpSystem and the function GetHelpSystem in C++Builder?
//Original Delphi
procedure TFrmHelpViewerMain.btnShowTopicClick(Sender: TObject);
var
HelpSystem: IHelpSystem;
begin
GetHelpSystem(HelpSystem);
if assigned(HelpSystem) then
HelpSystem.ShowTopicHelp('topic3', Application.HelpFile);
end;
//My C++Builder code
#include <System.HelpIntfs.hpp>
void __fastcall TForm99::btnShowTopicClick(TObject *Sender)
{
IHelpSystem HelpSystem; //<< Error Here
GetHelpSystem(HelpSystem);
if( Assigned(HelpSystem) ){
HelpSystem->ShowTopicHelp("topic3", Application->HelpFile);
}
}
[bcc64 Error] CBtest_Unit1.cpp(97): variable type 'System::Helpintfs::IHelpSystem' is an abstract class
unknwn.h(114): unimplemented pure virtual method 'QueryInterface' in 'IHelpSystem'
unknwn.h(118): unimplemented pure virtual method 'AddRef' in 'IHelpSystem'
unknwn.h(120): unimplemented pure virtual method 'Release' in 'IHelpSystem'
System.HelpIntfs.hpp(66): unimplemented pure virtual method 'ShowHelp' in 'IHelpSystem'
System.HelpIntfs.hpp(67): unimplemented pure virtual method 'ShowContextHelp' in 'IHelpSystem'
System.HelpIntfs.hpp(68): unimplemented pure virtual method 'ShowTableOfContents' in 'IHelpSystem'
System.HelpIntfs.hpp(69): unimplemented pure virtual method 'ShowTopicHelp' in 'IHelpSystem'
System.HelpIntfs.hpp(70): unimplemented pure virtual method 'AssignHelpSelector' in 'IHelpSystem'
System.HelpIntfs.hpp(71): unimplemented pure virtual method 'Hook' in 'IHelpSystem'
Here are the help pages from the Embaradero website that discuss IHelpSystem.
IHelpSystem
HelpIntfs.GetHelpSystem
As the error message says, IHelpSystem is an abstract class (it has pure virtual methods that are implemented in derived classes), and as such you can't instantiate it directly, like you are trying to do in your C++ code:
IHelpSystem HelpSystem;
You can declare variables of this type only by pointer (IHelpSystem*) or reference (IHelpSystem&). And indeed, the C++ equivalent of the Delphi statement:
var HelpSystem: IHelpSystem;
is:
IHelpSystem* HelpSystem;
But, since IHelpSystem is a Delphi-based interface, you actually need to use the _di_IHelpSystem wrapper type (which is an alias for DelphiInterface<IHelpSystem>), which is what GetHelpSystem() actually outputs in C++:
extern DELPHI_PACKAGE bool __fastcall GetHelpSystem(/* out */ _di_IHelpSystem &System)/* overload */;
Try this instead:
#include <System.HelpIntfs.hpp>
void __fastcall TForm99::btnShowTopicClick(TObject *Sender)
{
_di_IHelpSystem HelpSystem;
GetHelpSystem(HelpSystem);
if (HelpSystem)
HelpSystem->ShowTopicHelp(_D("topic3"), Application->HelpFile);
}

How to convert C# code that uses Shell COM to F#?

I have the following C# method:
private static bool IsLink(string shortcutFilename)
{
var pathOnly = Path.GetDirectoryName(shortcutFilename);
var filenameOnly = Path.GetFileName(shortcutFilename);
var shell = new Shell32.Shell();
var folder = shell.NameSpace(pathOnly);
var folderItem = folder.ParseName(filenameOnly);
return folderItem != null && folderItem.IsLink;
}
I have tried converting this to F# as:
let private isLink filename =
let pathOnly = Path.GetDirectoryName(filename)
let filenameOnly = Path.GetFileName(filename)
let shell = new Shell32.Shell()
let folder = shell.NameSpace(pathOnly)
let folderItem = folder.ParseName(filenameOnly)
folderItem <> null && folderItem.IsLink
It however reports an error for the let shell = new Shell32.Shell() line, saying that new cannot be used on interface types.
Have I just made a silly syntactic mistake, or is there extra work needed to access COM from F#?
I don't know enough about the F# compiler but your comments makes it obvious enough. The C# and VB.NET compilers have a fair amount of explicit support for COM built-in. Note that your statement uses the new operator on an interface type, Shell32.Shell in the interop library looks like this:
[ComImport]
[Guid("286E6F1B-7113-4355-9562-96B7E9D64C54")]
[CoClass(typeof(ShellClass))]
public interface Shell : IShellDispatch6 {}
IShellDispatch6 is the real interface type, you can also see the IShellDispatch through IShellDispatch5 interfaces. That's versioning across the past 20 years at work, COM interface definitions are immutable since changing them almost always causes an undiagnosable hard crash at runtime.
The [CoClass] attribute is the important one for this story, that's what the C# compiler goes looking for you use new on a [ComImport] interface type. Tells it to create the object by creating an instance of Shell32.ShellClass instance and obtain the Shell interface. What the F# compiler doesn't do.
ShellClass is a fake class, it is auto-generated by the type library importer. COM never exposes concrete classes, it uses a hyper-pure interface-based programming paradigm. Objects are always created by an object factory, CoCreateInstance() is the workhorse for that. Itself a convenience function, the real work is done by the universal IClassFactory interface, hyper-pure style. Every COM coclass implements its CreateInstance() method.
The type library importer makes ShellClass look like this:
[ComImport]
[TypeLibType(TypeLibTypeFlags.FCanCreate)]
[ClassInterface(ClassInterfaceType.None)]
[Guid("13709620-C279-11CE-A49E-444553540000")]
public class ShellClass : IShellDispatch6, Shell {
// Methods
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime), DispId(0x60040000)]
public virtual extern void AddToRecent([In, MarshalAs(UnmanagedType.Struct)] object varFile, [In, Optional, MarshalAs(UnmanagedType.BStr)] string bstrCategory);
// Etc, many more methods...
}
Lots of fire and movement, none of it should ever be used. The only thing that really matters is the [Guid] attribute, that provides the CLSID that CoCreateInstance() needs. It also needs the IID, the [Guid] of the interface, provided by the interface declaration.
So the workaround in F# is to create the Shell32.ShellClass object, just like the C# compiler does implicitly. While technically you can keep the reference in a ShellClass variable, you should strongly favor the interface type instead. The COM way, the pure way, it avoids this kind of problem. Ultimately it is the CLR that gets the job done, it recognizes the [ClassInterface] attribute on the ShellClass class declaration in its new operator implementation. The more explicit way in .NET is to use Type.GetTypeFromCLSID() and Activator.CreateInstance(), handy when you only have the Guid of the coclass.

How do I construct this Delphi class in C++Builder?

What is the C++ equivalent of this code
ImageEnView1.IEBitmap.VirtualBitmapProvider := TIESlippyMap.Create();
I get a compile error
[bcc32 Error] Unit1.cpp(12907): E2285 Could not find a match for 'TIESlippyMap::TIESlippyMap()'
on my code
ImageEnview1->IEBitmap->VirtualBitmapProvider = new TIESlippyMap();
ImageEnView1->IEBitmap->VirtualBitmapProvider = new TIESlippyMap();
Update: You are trying to call this constructor:
constructor Create(provider:TIESlippyMapProvider = iesmpMapQuest; const cachePath:string = '');
The compiler error you are getting means that the C++ compiler cannot find a constructor that has no parameters, or at least a constructor with parameters that all have default values assigned to them. Depending on which C++Builder version you are using, it is likely that the Delphi compiler included with it is not emitting the default parameter values when generating the C++ .hpp file for the class. Older Delphi compiler versions did not do that correctly, but newer versions do. In which case, it sounds like you are using an affected version, so you will have to fill in those parameter values explicitly:
ImageEnView1->IEBitmap->VirtualBitmapProvider = new TIESlippyMap(iesmpMapQuest, "");
Or else edit the .hpp file to include the default values correctly:
class TIESlippyMap : public ...
{
...
public:
__fastcall TIESlippyMap(TIESlippyMapProvider provider = iesmpMapQuest, const String cachePath = "");
...
};

System::IDisposable woes

public ref class ScriptEditor : public Form
{
public:
typedef map<UInt32, ScriptEditor^> AlMap;
static AlMap AllocationMap;
Form^ EditorForm;
RichTextBox^ EditorBox;
StatusBar^ EditorStatusBar;
StatusBarPanel^ StatusBarLineNo;
void Destroy() { EditorForm->Close(); }
ScriptEditor(unsigned int PosX, unsigned int PosY);
};
The above code throws an Error C2039: '{dtor}' : is not a member of 'System::IDisposable'. I'm quite lost after having looked into articles that explain how the CLR manages memory. Any advice on getting rid of it would be appreciated. My first dabble in C+++/CLI isn't going too well.
You are not getting a very good error message. But the problem is that the STL map<> template class is only suitable for unmanaged types. It requires an element type to have a destructor, managed types don't have one. In the C++/CLI language, destructors are simulated with the IDisposable interface, that's the source of the confusing error message you see.
If you really want to use STL, you can with the STL/CLR implementation, available in VS2008. It is however pretty widely ignored as it basically combines the disadvantages of STL (expensive value semantics) with those of managed code (no default value semantics on reference types). This web page compares it to the native .NET collection classes, stark results to put it mildly.
The appropriate collection class to use here is System::Collections::Generic::Dictionary<>

Resources