Solved

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

Posted on 2004-08-31
15
762 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
  • 7
  • 6
  • 2
15 Comments
 
LVL 14

Expert Comment

by:Pierre Cornelius
Comment Utility
Let me see if I can help

pc@lirok.com
0
 
LVL 17

Expert Comment

by:Wim ten Brink
Comment Utility
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
Comment Utility
Thanks Alex
0
 
LVL 1

Author Comment

by:Ridey
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 1

Author Comment

by:Ridey
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
0
 
LVL 1

Author Comment

by:Ridey
Comment Utility
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
Comment Utility
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
Comment Utility
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

Threat Intelligence Starter Resources

Integrating threat intelligence can be challenging, and not all companies are ready. These resources can help you build awareness and prepare for defense.

Join & Write a Comment

Suggested Solutions

Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
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…
This video shows how to remove a single email address from the Outlook 2010 Auto Suggestion memory. NOTE: For Outlook 2016 and 2013 perform the exact same steps. Open a new email: Click the New email button in Outlook. Start typing the address: …
This video explains how to create simple products associated to Magento configurable product and offers fast way of their generation with Store Manager for Magento tool.

763 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

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now