Solved

Converting VB DLL referencing to Delphi (Porting VB App to Delphi) with 3rd party DLL

Posted on 2004-08-31
15
773 Views
Last Modified: 2012-05-05
Hi Experts

I have a wee bit of a problem which has now had me stumped for 2 days. I am convinced that am not following the correct procedures involved in referencing an external dll and as such I turn to you for help. As it is urgent and in the end it will be difficult to test the solution yourself I’ll be throwing 500 points at this.

The idea behind the VB program is to establish a session to a message queue via a SonicMQ DLL

The easiest way to do this would be for me to supply you with the VB code and the dll.

What I need out of this would be a working equivalent of the VB code for Delphi 6.

What I have done thus far and I do not know if this was indeed the correct thing to do is to import the dll via the type library and I am currently referencing the dll via the uses clause. However I am unable to instantiate the Session object

Please leave your e-mail address on this topic and I will mail you the VB source code and the relevant dll's once you have the code to the point where you need me to test it please send the Delphi code to me along with an instructions that i need to follow and I will provide full feed back on it.

Kind Regards
Ridey

0
Comment
Question by:Ridey
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 7
  • 6
  • 2
15 Comments
 
LVL 14

Expert Comment

by:Pierre Cornelius
ID: 11941612
Let me see if I can help

pc@lirok.com
0
 
LVL 17

Expert Comment

by:Wim ten Brink
ID: 11942032
Warning! It is against the policy of EE to handle problems by email instead of using the EE services. Basically, if you solve a problem through email and then award the points, no other EE member will be able to see the solution of this problem. Therefore, if possible post the VB code here or else find some webserver to where you can upload the DLL and VB code that is troubling you and post an URL to this page.
So please post the VB code here or somewhere where everyone can access it...

Btw. For all experts interested in answering this question. If you leave your email address here in this topic, chances are that the amount of spam you receive will increase a bit. Please be careful when you post your email address somewhere. I don't think Ridey will be spamming you all, but any spammer can write a webspider that is searching for email addresses on websites...
0
 
LVL 14

Expert Comment

by:Pierre Cornelius
ID: 11942080
Thanks Alex
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 1

Author Comment

by:Ridey
ID: 11942178
Hi Guys

Thanks for the info Alex

As i dont have anyware to upload the information, could someone be so kind as to help out in some web space. And also I am willing to take the spam in the mean time so mail me at ettienned@mbd.co.za

I know this is not the usual operation of EE and i understand why, thus you can rest assured that the accpeted answer will be posted her for everyone to learn from.

In the mean time here is the VB Code


Option Explicit

'Declare the user input variables.
Dim broker As String
Dim username As String
Dim password As String
Dim sendQueueName As String
Dim recvQueueName As String
Dim selector As String

'Declare the global messaging objects.
Dim ConnectionFactory As JMSCOMClientLib.CJMSQueueConnectionFactory
Dim Connection As JMSCOMClientLib.CJMSQueueConnection
Dim Session As JMSCOMClientLib.CJMSQueueSession
Dim SendQueue As JMSCOMClientLib.CJMSQueue
Dim RecvQueue As JMSCOMClientLib.CJMSQueue
Dim QueueSender As JMSCOMClientLib.CJMSQueueSender
Dim textMessage As JMSCOMClientLib.CJMSTextMessage

Dim WithEvents QueueReceiver As JMSCOMClientLib.CJMSQueueReceiver

Const PROP_NAME = "Department"
Private Sub QueueReceiver_onMessage(ByVal message As JMSCOMClientLib.CJMSMessage)
    Set textMessage = message
    tReceive.Text = "Got async Message: " & textMessage.GetText
End Sub

Private Sub bConnect_Click()
    On Error Resume Next
   
    'Set the user input variables.
    broker = tURL.Text
    username = tUsername.Text
    password = tPassword.Text
    sendQueueName = tSendQueue.Text
    recvQueueName = tRecvQueue.Text
    'selector = tSelector.Text
   
    If Len(tSelector.Text) = 0 Then
        selector = ""
    Else
        selector = PROP_NAME & " = '" & tSelector.Text & "'"
    End If
   
    ' Make a connection
    Set ConnectionFactory = CreateObject("JMSCOMClient.JMSQueueConnectionFactory.1")
    If Err.Number <> 0 Then
        MsgBox ("Error creating ConnectionFactory # " & CStr(Err.Number) & " " & Err.Description)
        Err.Clear
        Exit Sub
    End If

    ' Make the connection factory, setting the broker, username,and password
    Call ConnectionFactory.initialize5(broker, username, password)
    If Err.Number <> 0 Then
        MsgBox ("Error initializing ConnectionFactory # " & CStr(Err.Number) & " " & Err.Description)
        Err.Clear
        Exit Sub
    End If

    ' Establish a connection
    Set Connection = ConnectionFactory.createQueueConnection
    If Err.Number <> 0 Then
        MsgBox ("Error creating Connection # " & CStr(Err.Number) & " " & Err.Description)
        Err.Clear
        Exit Sub
    End If

    ' Establish a session
    Set Session = Connection.createQueueSession(False, JMSCOMClientLib.JMSCOM_DeliveryMode_NON_PERSISTENT)
    If Err.Number <> 0 Then
        MsgBox ("Error creating Session# " & CStr(Err.Number) & " " & Err.Description)
        Err.Clear
        Exit Sub
    End If

    ' Create a queue.  If sender and receiver use the same queue this app will
    ' talk to itself.  If they use different queues then a sender and receiver
    ' will have to be started.
    Set SendQueue = Session.createQueue(sendQueueName)
    If Err.Number <> 0 Then
        MsgBox ("Error creating Send Queue# " & CStr(Err.Number) & " " & Err.Description)
        Err.Clear
        Exit Sub
    End If

    Set QueueSender = Session.createSender(SendQueue)
    If Err.Number <> 0 Then
        MsgBox ("Error creating Sender# " & CStr(Err.Number) & " " & Err.Description)
        Err.Clear
        Exit Sub
    End If

    ' Create the other queue
    Set RecvQueue = Session.createQueue(recvQueueName)
    If Err.Number <> 0 Then
        MsgBox ("Error creating Recv Queue# " & CStr(Err.Number) & " " & Err.Description)
        Err.Clear
        Exit Sub
    End If
   
    If selector <> "" Then
        Set QueueReceiver = Session.createReceiver2(RecvQueue, selector)
        If Err.Number <> 0 Then
            MsgBox ("Error creating Receiver# " & CStr(Err.Number) & " " & Err.Description)
            Err.Clear
            Exit Sub
        End If
    Else
        Set QueueReceiver = Session.createReceiver(RecvQueue)
        If Err.Number <> 0 Then
            MsgBox ("Error creating Receiver# " & CStr(Err.Number) & " " & Err.Description)
            Err.Clear
            Exit Sub
        End If
    End If

    ' Set QueueReceiverEv = New JMSCOMClientLib.CJMSQueueReceiver
    Call QueueReceiver.setMessageListener2
   
    ' Start the connection.  Messages will not be received until this is done
    Call Connection.start
    If Err.Number <> 0 Then
        MsgBox ("Error starting Connection# " & CStr(Err.Number) & " " & Err.Description)
        Err.Clear
        Exit Sub
    End If
   
    ' If all goes well let the user start sending and receiving messages
    bSend.Enabled = True

End Sub

Private Sub bExit_Click()
    Call QueueSender.Close
    Call QueueReceiver.Close
    Call Session.Close
    Call Connection.Close
    End
End Sub


Private Sub bSend_Click()
    Dim message As JMSCOMClientLib.CJMSTextMessage
   
    On Error Resume Next
   
    ' Create a text message
    Set message = Session.createTextMessage()
    If Err.Number <> 0 Then
        MsgBox ("Error creating text message# " & CStr(Err.Number) & " " & Err.Description)
        Err.Clear
        Exit Sub
    End If
   
    If Len(tSelector.Text) > 0 Then
        Call message.setStringProperty(PROP_NAME, tSelector.Text)
    End If
   
    message.SetText (tSend.Text)
    If Err.Number <> 0 Then
        MsgBox ("Error setting text # " & CStr(Err.Number) & " " & Err.Description)
        Err.Clear
        Exit Sub
    End If
   
    ' Send it
    Call QueueSender.send2(message, JMSCOMClientLib.JMSCOM_DeliveryMode_PERSISTENT, 4, 120000)
    If Err.Number <> 0 Then
        MsgBox ("Error sending message # " & CStr(Err.Number) & " " & Err.Description)
        Err.Clear
        Exit Sub
    End If
   
End Sub

0
 
LVL 17

Expert Comment

by:Wim ten Brink
ID: 11943025
For webspace you could visit http://geocities.yahoo.com/ps/learn2/HowItWorks4_Free.html and get a free website. You'll need a Yahoo ID for this but those are created reasonable easy too.

Now, your VB code seems to call an ActiveX control or a COM object. Those DLL's aren't imported normally but by using the "Import Type Library" option under the Project menu. Then Delphi will generate a nice COM wrapper around your DLL which you can then use to call it. Quite simple, actually. But you're doing this already. Well done.

Now, to create a Session object, you probably have to call something like:

var Session: ISession;
begin
  Session := CoSession.Create;

And then it's instantiated. The same for ConnectionFactory. Use 'ConnectionFactory := CoConnectionFactory.Create;' to create it.
Chances are, though, that the imported type library doesn't have these CoXxxx methods though. So it might be useful to post that code somewhere too. (E.g. in this topic.)
0
 
LVL 1

Author Comment

by:Ridey
ID: 11949768
Hi Alex

This is what i have so far I have marked the line i have an error on


procedure TForm1.btnConnectClick(Sender: TObject);
var
   // Variable Declarations
   sURL                 :  String;
   sUser                :  String;
   sPswd                :  String;
   sSendQ               :  String;
   sReceiveQ            :  String;
   sSelector            :  String;

   // Com Client Declarations
   ConnectionFactory    :  JMSCOMCLIENTLib_TLB.CJMSQueueConnectionFactory;
   Connection           :  JMSCOMCLIENTLib_TLB.CJMSQueueConnection;
   Session              :  JMSCOMCLIENTLib_TLB.CJMSQueueSession;
   SendQueue            :  JMSCOMCLIENTLib_TLB.CJMSQueue;
   RecvQueue            :  JMSCOMCLIENTLib_TLB.CJMSQueue;
   QueueSender          :  JMSCOMCLIENTLib_TLB.CJMSQueueSender;
   textMessage          :  JMSCOMCLIENTLib_TLB.CJMSTextMessage;

begin
   if bConnected then
   begin
   end else
   begin
      sURL := edtBroker.Text;
      sUser := edtUser.Text;
      sPswd := edtPassword.Text;
      sSendQ := edtSendQ.Text;
      sReceiveQ := edtReceiveQ.Text;
      sSelector := edtSelector.Text;
   end;

   If Length(sSelector) <> 0 Then
   begin
      sSelector := '';
   end else
   begin
      sSelector := PROP_NAME + ' = ' + Char(0039) + sSelector + Char(0039);
   End;

   // ' Make a connection
   ConnectionFactory := JMSCOMCLIENTLib_TLB.CoCJMSQueueConnectionFactory.Create;
  //JMSQueueConnectionFactory.1)

   //' Make the connection factory, setting the broker, username,and password
   ConnectionFactory.initialize5(sURL, sUser, sPswd);

   //' Establish a connection
   Connection := ConnectionFactory.createQueueConnection;

   //' Establish a session
   Session := Connection.createQueueSession; ----- This session can not be established, error = Undeclared Identifier "createQueueSession"


0
 
LVL 17

Expert Comment

by:Wim ten Brink
ID: 11950214
Check the source of the unit JMSCOMCLIENTLib_TLB and find the type definition of CJMSQueueConnection. It seems this type doesn't know the createQueueSession. Or maybe it has a slightly different name.
0
 
LVL 1

Author Comment

by:Ridey
ID: 11951516
Your right Alex it is not there it does not even seem to exist under a different name.

Now is it possible that Delphi does not expose all the functionality from the DLL that i require and that VB does expose all function procedures and variables that is required ?

If so is there any way that i can correct the problem ?

I am busy setting up the download area and will then place all the files there.
0
 
LVL 17

Expert Comment

by:Wim ten Brink
ID: 11952675
I  know ther can be some problems with Delphi importing some type libraries, especially type libraries for components created with VB. It might be possible that Delphi just doesn't recognise this method as such, thus the import wizards might ignore it. I'm not sure exactly about what could be the problem here.

Does the method CJMSQueueConnection exist as part of some other object in the type library unit?

I found some information on http://www.sonicsoftware.com/developer/documentation/docs/sonicmq_com_v60.pdf that might be useful for you but assume you already know this. Unfortunately it doesn't mention anything about Delphi here...
0
 
LVL 1

Author Comment

by:Ridey
ID: 11952923
Yeah I have had a look at the documentation that Sonic Provides unfortunatelly it is not very comprehensive with regards to their COM Component, and the only real documentation that is worth anything is the VB Sample code.

These are the referneces to createQueueSession in JMSCOMCLIENTLib_TLB

// *********************************************************************//
// Interface: IJMSQueueConnection
// Flags:     (4416) Dual OleAutomation Dispatchable
// GUID:      {E2ACC010-8DB7-4F4D-9D83-C39EE9BAC48F}
// *********************************************************************//
  IJMSQueueConnection = interface(IJMSConnection)
    ['{E2ACC010-8DB7-4F4D-9D83-C39EE9BAC48F}']
    function  createQueueSession(transactedVar: Integer; acknowledgeMode: SYSINT): IJMSSession; safecall;
  end;


// *********************************************************************//
// DispIntf:  IJMSQueueConnectionDisp
// Flags:     (4416) Dual OleAutomation Dispatchable
// GUID:      {E2ACC010-8DB7-4F4D-9D83-C39EE9BAC48F}
// *********************************************************************//
  IJMSQueueConnectionDisp = dispinterface
    ['{E2ACC010-8DB7-4F4D-9D83-C39EE9BAC48F}']
    function  createQueueSession(transactedVar: Integer; acknowledgeMode: SYSINT): IJMSSession; dispid 301;
    procedure start; dispid 201;
    procedure stop; dispid 202;
    procedure close; dispid 203;
    function  getClientID: WideString; dispid 204;
    procedure setClientID(const param: WideString); dispid 205;
    function  getMetaData: IJMSConnectionMetaData; dispid 208;
    procedure setExceptionListener(const pIUnknown: IUnknown); dispid 209;
    procedure setExceptionListener2; dispid 210;
    procedure resetExceptionListener; dispid 211;
    procedure setPingInterval(interval: Integer); dispid 212;
    function  equals(const obj: IJMSMessage): Integer; dispid 101;
    function  clone: IJMSMessage; dispid 102;
    function  toString: WideString; dispid 103;
  end;

// *********************************************************************//
// OLE Server Proxy class declaration
// Server Object    : TCJMSConnection
// Help String      : JMSConnection Class
// Default Interface: IJMSQueueConnection
// Def. Intf. DISP? : No
// Event   Interface: IJMSExceptionListener
// TypeFlags        : (2) CanCreate
// *********************************************************************//
{$IFDEF LIVE_SERVER_AT_DESIGN_TIME}
  TCJMSConnectionProperties= class;
{$ENDIF}
  TCJMSConnection = class(TOleServer)
  private
    FOnonException: TCJMSConnectiononException;
    FIntf:        IJMSQueueConnection;
{$IFDEF LIVE_SERVER_AT_DESIGN_TIME}
    FProps:       TCJMSConnectionProperties;
    function      GetServerProperties: TCJMSConnectionProperties;
{$ENDIF}
    function      GetDefaultInterface: IJMSQueueConnection;
  protected
    procedure InitServerData; override;
    procedure InvokeEvent(DispID: TDispID; var Params: TVariantArray); override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor  Destroy; override;
    procedure Connect; override;
    procedure ConnectTo(svrIntf: IJMSQueueConnection);
    procedure Disconnect; override;
    function  equals(const obj: IJMSMessage): Integer;
    function  clone: IJMSMessage;
    function  toString: WideString;
    procedure start;
    procedure stop;
    procedure close;
    function  getClientID: WideString;
    procedure setClientID(const param: WideString);
    function  getMetaData: IJMSConnectionMetaData;
    procedure setExceptionListener(const pIUnknown: IUnknown);
    procedure setExceptionListener2;
    procedure resetExceptionListener;
    procedure setPingInterval(interval: Integer);
    function  createQueueSession(transactedVar: Integer; acknowledgeMode: SYSINT): IJMSSession;
    property  DefaultInterface: IJMSQueueConnection read GetDefaultInterface;
  published
{$IFDEF LIVE_SERVER_AT_DESIGN_TIME}
    property Server: TCJMSConnectionProperties read GetServerProperties;
{$ENDIF}
    property OnonException: TCJMSConnectiononException read FOnonException write FOnonException;
  end;

function  TCJMSConnection.createQueueSession(transactedVar: Integer; acknowledgeMode: SYSINT): IJMSSession;
begin
  Result := DefaultInterface.createQueueSession(transactedVar, acknowledgeMode);
end;
0
 
LVL 17

Accepted Solution

by:
Wim ten Brink earned 500 total points
ID: 11954390
This is the part you need:

  IJMSQueueConnection = interface(IJMSConnection)
    ['{E2ACC010-8DB7-4F4D-9D83-C39EE9BAC48F}']
    function  createQueueSession(transactedVar: Integer; acknowledgeMode: SYSINT): IJMSSession; safecall;
  end;

Why? Because it has the createQueueSession method you're looking for. But you defined Connection as JMSCOMCLIENTLib_TLB.CJMSQueueConnection and I think you should change it in:
  Connection: IJMSQueueConnection ;

(You can remobve the 'JMSCOMCLIENTLib_TLB.' since you already told Delphi to use the JMSCOMCLIENTLib_TLB so it knows where to find it, unless you redefine those types in your own code. This applied for every place where you used this.)

Actually, you might prefer this var definition:
var
  ConnectionFactory: IJMSQueueConnectionFactory;
  Connection: IJMSQueueConnection;
  Session: IJMSQueueSession;
  SendQueue: IJMSQueue;
  RecvQueue: IJMSQueue;
  QueueSender: IJMSQueueSender;
  textMessage: IJMSTextMessage;

Btw. I've noticed you imported the type library WITH component wrappers for every interface. (TCJMSConnection in this case.) Actually, in general those component wrappers are only useful for ActiveX controls, not for all type libraries. (It's an option you can turn off while importing a type library.)
0
 
LVL 1

Author Comment

by:Ridey
ID: 11962173
0
 
LVL 1

Author Comment

by:Ridey
ID: 11962213
Hi Alex

I have tried your suggested var definition. Here is the result

"Incompatible types IJMSConnection and IJMSQueueConnection"

The error occurs on
   //' Establish a connection
   Connection := ConnectionFactory.createQueueConnection;

I have been to the point where the code compiles but i then get an access violation when trying to create the connection object, I'll try and get to that point again ( I have changed it in the mean time ) and then post it here.

Kind Regards
Ridey
0
 
LVL 17

Expert Comment

by:Wim ten Brink
ID: 11974002
Maybe you need to do a typecast around it... Something like:

if Succeeded(ConnectionFactory.createQueueConnection.QueryInterface(IJMSQueueConnection, Connection)) then begin
  // You're connected.
end;

The queued connection is related to the normal connection interface. Normally you'd get the normal connection interface but by using QueryInterface you specifically ask for the queued connection. And if it fails, then it fails.
0
 
LVL 1

Author Comment

by:Ridey
ID: 13283863
Hi Alex

Thanks for all your help in this, I have not been able to get my application to work yet, but in the mean time the focus has changed from using this product to plain and simple sockets, Thanks for all your help in this regard


Ridey
0

Featured Post

Announcing the Most Valuable Experts of 2016

MVEs are more concerned with the satisfaction of those they help than with the considerable points they can earn. They are the types of people you feel privileged to call colleagues. Join us in honoring this amazing group of Experts.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
Do you want to know how to make a graph with Microsoft Access? First, create a query with the data for the chart. Then make a blank form and add a chart control. This video also shows how to change what data is displayed on the graph as well as form…
Visualize your data even better in Access queries. Given a date and a value, this lesson shows how to compare that value with the previous value, calculate the difference, and display a circle if the value is the same, an up triangle if it increased…
Suggested Courses
Course of the Month11 days, 15 hours left to enroll

623 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question