9.3. Win32App 客户端编程模型

以下以 Delphi 语言为例子,描述在应用中将如何使用该客户端。编写该例子的程序之前,已经先将 %APUSIC_MQ_HOME%\client\win32appclient 目录中的 AMQClientWin32SpecDLL.dll 和 MQCClientlib.dll 两个文件拷贝到 Delphi 创建的工程的目录中。

必须先在 Delphi 语言中对即将调用到的DLL中的函数作出定义。例如:

  function AMQCreateConnection4(host:pchar; port:integer; user:pchar; password:pchar; connHandle:pinteger):pchar;stdcall;
  external 'AMQClientWin32SpecDLL.dll';
  function AMQCreateSession(connectionHandle:integer; transacted:integer; acknowledgeMode:integer; sessionHandle_out:pinteger):pchar;stdcall;
  external 'AMQClientWin32SpecDLL.dll';
  function AMQCloseConnection(connectionHandle:integer):pchar;stdcall;
  external 'AMQClientWin32SpecDLL.dll';
  function AMQCreateTopic(sessionHandle:integer; topicName:pchar; topicHandle_out:pinteger):pchar;stdcall;
  external 'AMQClientWin32SpecDLL.dll';
  function AMQCreateQueue(sessionHandle:integer; queueName:pchar; queueHandle_out:pinteger):pchar;stdcall;
  external 'AMQClientWin32SpecDLL.dll';
  function AMQCreateProducer(sessionHandle:integer; destinationHandle:integer; messageProducerHandle_out:pinteger):pchar;stdcall;
  external 'AMQClientWin32SpecDLL.dll';
  function AMQCreateTextMessage2(sessionHandle:integer; text:pchar; textMessageHandle_out:pinteger):pchar;stdcall;
  external 'AMQClientWin32SpecDLL.dll';
  function AMQSetMessageBooleanProperty(messageHandle:integer; name:pchar; value:integer):pchar;stdcall;
  external 'AMQClientWin32SpecDLL.dll';
  function AMQSetMessageStringProperty(messageHandle:integer; name:pchar; value:pchar):pchar;stdcall;
  external 'AMQClientWin32SpecDLL.dll';
  function AMQSendMessage1(messageProducerHandle:integer; messageHandle:integer):pchar;stdcall;
  external 'AMQClientWin32SpecDLL.dll';
  function AMQSendMessage3(messageProducerHandle:integer; destinationHandle:integer; messageHandle:integer):pchar;stdcall;
  external 'AMQClientWin32SpecDLL.dll';
  function AMQGetMessageText(textMessageHandle:integer; text_out:ppchar):pchar;stdcall;
  external 'AMQClientWin32SpecDLL.dll';
  function AMQGetMessageStringProperty(messageHandle:integer; name:pchar; property_out:ppchar):pchar;stdcall;
  external 'AMQClientWin32SpecDLL.dll';
  function AMQSetMessageText(textMessageHandle:integer; text:pchar):pchar;stdcall;
  external 'AMQClientWin32SpecDLL.dll';
  function AMQCloseMessageProducer(messageProducerHandle:integer):pchar;stdcall;
  external 'AMQClientWin32SpecDLL.dll';
  function AMQCloseSession(sessionHandle:integer):pchar;stdcall;
  external 'AMQClientWin32SpecDLL.dll';
  function AMQClearMessageProperties(messageHandle:integer):pchar;stdcall;
  external 'AMQClientWin32SpecDLL.dll';
  function AMQClearMessageBody(messageHandle:integer):pchar;stdcall;
  external 'AMQClientWin32SpecDLL.dll';
  function AMQCreateConsumer1(sessionHandle:integer; destinationHandle:integer; messageConsumerHandle_out:pinteger):pchar;stdcall;
  external 'AMQClientWin32SpecDLL.dll';
  function AMQCreateConsumer2(sessionHandle:integer; destinationHandle:integer; messageSelector:pchar; messageConsumerHandle_out:pinteger):pchar;stdcall;
  external 'AMQClientWin32SpecDLL.dll';
  function AMQCloseMessageConsumer(messageConsumerHandle:integer):pchar;stdcall;
  external 'AMQClientWin32SpecDLL.dll';
  function AMQReceiveMessage1(messageConsumerHandle:integer; messageHandle_out:pinteger):pchar;stdcall;
  external 'AMQClientWin32SpecDLL.dll';
  function AMQReceiveMessage2(messageConsumerHandle:integer; timeout:int64; messageHandle_out:pinteger):pchar;stdcall;
  external 'AMQClientWin32SpecDLL.dll';
  function AMQIsTextMessage(messageHandle:integer; isTextMessage_out:pinteger):pchar;stdcall;
  external 'AMQClientWin32SpecDLL.dll';
  function AMQStartConnection(connectionHandle:integer):pchar;stdcall;
  external 'AMQClientWin32SpecDLL.dll';
  function AMQGetMessageID(messageHandle:integer; messageID_out:ppchar):pchar;stdcall;
  external 'AMQClientWin32SpecDLL.dll';
  function AMQSetMessageReplyTo(messageHandle:integer; destinationHandle:integer):pchar;stdcall;
  external 'AMQClientWin32SpecDLL.dll';

以下的程序示例了如何使用 DLL 中的函数发送消息到 AMQ 服务器。

//检查函数调用结果的函数
procedure check(ret:pchar);
begin
  if ret <> NIL then
  begin
    ShowMessage(ret);
    halt(0);
  end;
end;

procedure TAMQSampleForm.SendButtonClick(Sender: TObject);
var
  //声明用于保存创建出来的资源的句柄
  session : Integer;
  queue : Integer;
  replyQueue : Integer;
  topic : Integer;
  producer : Integer;
  textMessage : Integer;
  text : pchar;
  conn : Integer;
  msgID : pchar;

begin

  //创建一个到服务器的连接,一个到服务器的连接可以在多个线程和多个Session中复用。
  check(AMQCreateConnection4(host, port, user, password, @conn));
  //创建一个Session,用于和服务器会话,进行消息的发送和接收
  check(AMQCreateSession(conn, 0, 1, @session));
  //创建一个testQueue队列的句柄
  check(AMQCreateQueue(session, 'testQueue', @queue));
  //创建一个testTopic主题的句柄,演示如何创建主题,但是这里没有使用
  //该创建出来的句柄
  check(AMQCreateTopic(session, 'testTopic', @topic));
  //创建一个消息生产者,用于发送消息到 testQueue队列
  check(AMQCreateProducer(session, queue, @producer));
  text := pchar(sendedTextMemo.Text);
  //用text的值创建一个TextMessage
  check(AMQCreateTextMessage2(session, text, @textMessage));
  //打开消息的跟踪消息传递时的消息路由路径的功能
  check(AMQSetMessageBooleanProperty(textMessage, 'JMSXDebugRouting', 1));
  //演示如何设置一个消息的String属性
  check(AMQSetMessageStringProperty(textMessage, 'SampleStringPropertyKey', 'SampleStringPropertyValue'));
  //演示如何重新设置一个TextMessage的文本内容
  check(AMQSetMessageText(textMessage, text));
  //将消息通过生产者发送出去
  check(AMQSendMessage3(producer, queue, textMessage));
  //演示得到消息的消息ID,要发送消息之后才能得到。
  check(AMQGetMessageID(textMessage, @msgID));

  //关闭消息生产者
  AMQCloseMessageProducer(producer);
  //关闭Session
  AMQCloseSession(session);
  //关闭连接
  AMQCloseConnection(conn);

end;


以下的程序示例了如何使用 DLL 中的函数从 AMQ 服务器中接收消息。

//检查函数调用结果的函数
procedure check(ret:pchar);
begin
  if ret <> NIL then
  begin
    ShowMessage(ret);
    halt(0);
  end;
end;

procedure TReceiveSampleForm.receiveButtonClick(Sender: TObject);
var
   //声明用于保存创建出来的资源的句柄
   session : Integer;
   queue : Integer;
   consumer : Integer;
   textMessage : Integer;
   isTextMessage : Integer;
   text : pchar;
   msgID : pchar;
   routingTract : pchar;
   replyQueue : Integer;
   producer : Integer;
   conn : Integer;

begin

  //创建一个到服务器的连接,一个到服务器的连接可以在多个线程和多个Session中复用。
  check(AMQCreateConnection4(host, port, user, password, @conn));
  //创建一个Session,用于和服务器会话,进行消息的发送和接收
  check(AMQCreateSession(conn, 0, 1, @session));
  //创建一个testQueue队列的句柄
  check(AMQCreateQueue(session, 'testQueue', @queue));
  //创建一个消息消费者,用于从testQueue队列接收消息
  check(AMQCreateConsumer1(session, queue, @consumer));
  //启动连接,准备好接收消息,可以开始接收了
  check(AMQStartConnection(conn));
  //接收一个消息到textMessage的句柄中
  check(AMQReceiveMessage1(consumer, @textMessage));
  //判断该接收到的消息是否是 TextMessage 类型
  check(AMQIsTextMessage(textMessage, @isTextMessage));

  if isTextMessage = 1 then
  begin
    //取得该TextMessage中的内容
    check(AMQGetMessageText(textMessage, @text));
    //取得该TextMessage的消息传递时的路由路径
    check(AMQGetMessageStringProperty(textMessage, 'JMSXRoutingTrack', @routingTract));
    receivedMsgMemo.Lines.Add('消息内容为:');
    receivedMsgMemo.Lines.Add('');
    receivedMsgMemo.Lines.Add(text);
    receivedMsgMemo.Lines.Add('');
    receivedMsgMemo.Lines.Add('消息传递时的消息路由路径为:');
    receivedMsgMemo.Lines.Add(routingTract);
    
    //演示得到消息的回执消息的回复目的地
    check(AMQGetMessageReplyTo(textMessage, @replyQueue));
    //演示得到消息的ID
    check(AMQGetMessageID(textMessage, @msgID));
    
    //创建一个消息生产者,用于发送回执消息
    check(AMQCreateProducer(session, replyQueue, @producer));
    check(AMQCreateTextMessage2(session, 'receive ok', @textMessage));
    //设置回执消息的关联消息ID,消息发送端根据关联消息ID来收取回执消息
    check(AMQSetMessageCorrelationID(textMessage, msgID));
    //发送回执消息
    check(AMQSendMessage3(producer, replyQueue, textMessage));
    //关闭消息生产者
    AMQCloseMessageProducer(producer);

  end;

  //关闭消息消费者
  AMQCloseMessageConsumer(consumer);
  //关闭 Session 
  AMQCloseSession(session);
  //关闭连接
  AMQCloseConnection(conn);

end;