Board index » cppbuilder » Using delphi interfaces in C++

Using delphi interfaces in C++


2006-08-11 04:40:32 PM
cppbuilder41
Hi all,
Still struggling with interfaces but this time they are declared and
defined in a Delphi file, I'm simply using the generated HPP file but am
getting acces violations or privileged instructions.
Here is what I did:
I dropped two components on my Form, namely a TROBinMessage and a
TROSuperTcpChannel. These classes implement a few interfaces, namely these:
TROBinMessage
IROBinMessage, IROStreamAccess
implemented in parent class, TROMessage
IUnknown, IROMessage, IROMessageCloneable, IROModuleInfo
TROSuperTCPChannel
IROTransport, IROTCPTransport, IROActiveEventChannel,
IROMultiThreadAwareChannel, IROAsyncTransportChannel,
IROActiveAsyncTransportChannel, IROTransportChannelEx
implemented in parent class, TROTransportChannel
IROTransportChannel, IROTransport, IROMetadataReader
In my C++ code, I want to use InitializeRequestMessage and Write defined
in IROMessage like this:
virtual void __fastcall InitializeRequestMessage(
const _di_IROTransport aTransport,
const AnsiString aLibraryName,
const AnsiString anInterfaceName,
const AnsiString aMessageName) = 0 ;
virtual void __fastcall Write(const AnsiString aName,
Typinfo::PTypeInfo aTypeInfo,
const void *Ptr,
TParamAttributes ExtraAttributes) = 0 ;
and so I wrote the following code in C++:
_di_IROMessage __Message = ROBinMessage1->operator IROMessage *();
_di_IROTransport __Transport =
ROSuperTcpChannel1->operator IROTransport *();
AnsiString __InterfaceName = "NewService";
int A = 1;
__Message->InitializeRequestMessage(__Transport,
"NewLibrary",
__InterfaceName,
"Sum");
__Message->Write("A", __GetintInfo, &A, TParamAttributes());
__GetintInfo is a #define that expands to a function call that returns
the type infos taken from a published property of type int.
When I run this code, I'm getting an access violation error on the call
to InitializeRequestMessage. I tried to trace it, it triggers the error
in System.pas apparently while creating the strings to pass to the
method (_LStrFromPChar and _LStrFromPCharLen).
I really don't understand what's wrong here and am even more puzzled
when the same code in Delphi works just fine:
var
__Message: IROMessage;
__Transport: IROTransport;
__InterfaceName: string;
A: Integer;
begin
if not ROSuperTcpChannel1.Connected then
ROSuperTcpChannel1.Active := true;
__Message := ROBinMessage1;
__Transport := ROSuperTcpChannel1;
__InterfaceName := 'NewService';
A := 1;
__Message.InitializeRequestMessage(__Transport, 'NewLibrary',
__InterfaceName, 'Sum');
__Message.Write('A', TypeInfo(Integer), A, []);
end;
Any help would be VERY much appreciated.
Cheers
Olivier
 
 

Re:Using delphi interfaces in C++

Any idea, anyone?
Do you need more details?
 

Re:Using delphi interfaces in C++

OBones wrote:
Quote
Any idea, anyone?
Do you need more details?
Ok, a bit more details then.
With the code I gave, there is this:
_di_IROMessage __Message = ROBinMessage1->operator IROMessage *();
_di_IROTransport __TransportChannel = ROSuperTcpChannel1->operator
IROTransport *();
which triggers an access violation on the InitializeRequestMessage call,
AV being about read of address 00000020.
Now, if I replace operator IROMessage*() with operator IROBinMessage*(),
I do not get the AV any longer, but the call to Write triggers a
EPrivilege ("privileged instruction") exception.
I have tried to replace operator IROTransport *() with
IROTransportChannel *(), IROTCPTransport *(), but to no avail, I always
get the EPrivilege exception.
First question is why using IROBinMessage *() avoids the AV?
Second question is what could trigger this EPrivilege exception?
Thanks in advance
Olivier
 

{smallsort}

Re:Using delphi interfaces in C++

OBones wrote:
Quote
First question is why using IROBinMessage *() avoids the AV?
I know nothing about IRO, sorry.
Quote
Second question is what could trigger this EPrivilege exception?
These are guesses, as I believe EPrivilege is a VCL item, and I don't
do VCL.
A) Executing Data.
Causes of that:
1) Executing the address of a function pointer instead of the contents
of the pointer.
2) Passing the incorrect number of parameters. This usually causes
access violations as the function tries to use values you didn't
intend. But if it survives long enough to return, it will return to
not-where-you called-from, which could well be a data area.
B) Writting data that the O/S has marked r/o.
Suggestion:
Debug your code.
Use the CPU View to see exactly what is placed in __Message
and __TransportChannel. And that it is what is expected.
 

Re:Using delphi interfaces in C++

OBones wrote:
Quote
When I run this code, I'm getting an access violation error on the call to
InitializeRequestMessage. I tried to trace it, it triggers the error in
System.pas apparently while creating the strings to pass to the method
(_LStrFromPChar and _LStrFromPCharLen).
Try this code instead: (Untested)
_di_IROMessage Message = ROBinMessage1;
_di_IROTransport Transport = ROSuperTcpChannel1;
AnsiString InterfaceName = "NewService";
int A = 1;
Message->InitializeRequestMessage( Transport, "NewLibrary", InterfaceName,
"Sum" );
Message->Write( "A", __GetintInfo, &A, TParamAttributes() );
And if that doesn't work, then try this: (Untested)
IROMessage *Message = NULL;
IROTransport *Transport = NULL;
if( SUCCEEDED( ROBinMessage1->QueryInterface( IID_IROMessage, &Message ) ) )
{
if( SUCCEEDED( ROSuperTcpChannel1->QueryInterface( IID_IROTransport,
&Transport ) ) )
{
AnsiString InterfaceName = "NewService";
int A = 1;
Message->InitializeRequestMessage( Transport, "NewLibrary",
InterfaceName, "Sum" );
Message->Write( "A", __GetintInfo, &A, TParamAttributes() );
Transport->Release();
}
Message->Release();
}
 

Re:Using delphi interfaces in C++

Jonathan Benedicto wrote:
Quote
Try this code instead: (Untested)

_di_IROMessage Message = ROBinMessage1;
_di_IROTransport Transport = ROSuperTcpChannel1;
That does not compile, hence the reason why I explicitly used the operators.
Quote
And if that doesn't work, then try this: (Untested)

IROMessage *Message = NULL;
IROTransport *Transport = NULL;

if( SUCCEEDED( ROBinMessage1->QueryInterface( IID_IROMessage, &Message ) ) )
{
QueryInterface is not public, thus, not accessible. And the hpp file
generated from the .pas file does not contain an IID declaration.
Anyway, I tried this code:
class TMyROBinMessage: public TROBinMessage
{
public:
virtual HRESULT __stdcall QueryInterface(const GUID &IID, void *Obj)
{return TROBinMessage::QueryInterface(IID, Obj); };
};
class TMyROSuperTcpChannel: public TROSuperTcpChannel
{
public:
virtual HRESULT __stdcall QueryInterface(const GUID &IID, void *Obj)
{return TROSuperTcpChannel::QueryInterface(IID, Obj); };
};
void __fastcall TForm1::btnTestClick(TObject *Sender)
{
IROMessage* __Message = NULL;
IROTransport* __Transport = NULL;
AnsiString __InterfaceName = "NewService";
int A = 1;
if( SUCCEEDED(reinterpret_cast<TMyROBinMessage*>(ROBinMessage1)->
QueryInterface(
Sysutils::StringToGUID(
"{092FB8BE-5FC4-48CB-BB50-623465168B98}"),
&__Message ) ) )
{
if( SUCCEEDED(
reinterpret_cast<TMyROSuperTcpChannel*>(ROSuperTcpChannel1)->
QueryInterface(
Sysutils::StringToGUID(
"{56FA09B9-FFC8-4432-80E3-BF78E5E7DF33}"),
&__Transport ) ) )
{
__Message->InitializeRequestMessage( __Transport, "NewLibrary",
__InterfaceName, "Sum" );
__Message->Write( "A", __GetintInfo, &A, TParamAttributes() );
__Transport->Release();
}
__Message->Release();
}
}
And this code works. But it's not practical at all. I mean what's the
point of the IXXXX operators if I can't use them?
--
Olivier Sannier
JVCL Coordinator
jvcl.sf.net/
Find more about me on LinkedIn:
https://www.linkedin.com/in/obones
 

Re:Using delphi interfaces in C++

OBones wrote:
Quote
And this code works. But it's not practical at all. I mean what's the
point of the IXXXX operators if I can't use them?
Please try this code, it should use those operators:
_di_IROMessage Message = ( IROMessage* )( ROBinMessage1 );
_di_IROTransport Transport = ( IROTransport* )( ROSuperTcpChannel1 );
AnsiString InterfaceName = "NewService";
int A = 1;
Message->InitializeRequestMessage( Transport, "NewLibrary", InterfaceName,
"Sum" );
Message->Write( "A", __GetintInfo, &A, TParamAttributes() );
HTH
Jonathan
 

Re:Using delphi interfaces in C++

Jonathan Benedicto wrote:
Quote
OBones wrote:
>And this code works. But it's not practical at all. I mean what's the
>point of the IXXXX operators if I can't use them?

Please try this code, it should use those operators:
<SNIP>
Thanks, it does indeed call the operators, but it gives an AV on the
very first assignment. If I replace the _di_IXXX types for the two
variables by direct IXXX pointers, I get the AV on the call to
InitializeRequestMessage.
{*word*81}.
 

Re:Using delphi interfaces in C++

OBones wrote:
Quote
Thanks, it does indeed call the operators, but it gives an AV on the very
first assignment. If I replace the _di_IXXX types for the two variables by
direct IXXX pointers, I get the AV on the call to
InitializeRequestMessage.
I suspect that there could be a bug in those operator's code. You might just
have to go the QueryInterface method.
Jonathan
 

Re:Using delphi interfaces in C++

Jonathan Benedicto wrote:
Quote
OBones wrote:

>Thanks, it does indeed call the operators, but it gives an AV on the very
>first assignment. If I replace the _di_IXXX types for the two variables by
>direct IXXX pointers, I get the AV on the call to
>InitializeRequestMessage.


I suspect that there could be a bug in those operator's code. You might just
have to go the QueryInterface method.
Well, there sure is a bug.
Via the QueryInterface calls, I get different pointers than via the
operators. One is off by 8 bytes, the other by 4. To actually get the
appropriate pointer values, I need to call these operators:
IROModuleInfo* ModInfo = ROBinMessage1->operator IROModuleInfo* ();
IROMetadataReader* meta = ROSuperTcpChannel1->
operator IROMetadataReader* ();
That's really crazy.
--
Olivier Sannier
JVCL Coordinator
jvcl.sf.net/
Find more about me on LinkedIn:
https://www.linkedin.com/in/obones