用Borland C++Builder 6.0开发简单的多线程Web Service客户程序

 

Borland最新推出的C++Builder 6.0(以下简称BCB)Delphi/Kylix一样,有着强大的Web  Service处理能力,但现在关于如何用BCB创建和调用Web Service的资料并不多,现在我就示范一下如何使用BCB6.0实现一个简单的Web Service客户端,而且在我的例子中使用的是多线程的调用方式。由于自己使用BCB的时间非常短,开发经验还不足,所以本文仅当是抛砖引玉。如果文中有错误或可以改进的地方,还请大家多提意见。 

现在我们就开始。我们要调用的是大名鼎鼎的Dr.BobDelphi6写的一个自动获取DelphiCppBuilderKylixJbuilderBorland产品信息的Web Service,它的WSDLhttp://www.ebob42.com/cgi-bin/DrBobsClinic.exe/wsdl/IHeadline。你可以在www.xmethods.com上看到它以及更多Web Service的有关信息。 

1、首先创建一个新项目:File-New-Application,在Form1上分别放上MemoComboBoxButton控件,界面效果如下图如示。然后以默认名称保存单元和项目(你也可以给单元和项目分别命上有意义的名称)

 

2、设定ComboBox1的一些属性:我们要调用不同的产品信息,这个通过ComboBox1中的值来决定。打开它的Items属性编辑器,在其中输入下面的内容:

Delphi

C++Builder

JBuilder

Kylix

SOAP

Borcon

然后,把ComboBox1ItemIndex属性设为0,这样“Delphi”就成了默认值。 

3、现在就要通过WSDL Importer来导入Web Service的接口了。保持现有项目不变,再选择File-New-Other,在Web Service页中,点选WSDL Importer项,确定。在随后出现的向导中,在Location of WSDL file or URL中输入:http://www.ebob42.com/cgi-bin/DrBobsClinic.exe/wsdl/IHeadline,点击NextWSDL Importer就会自动获取有关的接口信息,产生的结果如下图所示:

点击Finish退出。以默认名称IheadLine.cpp把单元保存在项目目录之下。

4、现在,我们有了接口信息,就开始对它进行调用了。在前面我说过,要用多线程来调用。为什么要这样?在此之前,我一直在Delphi中进行Web Service调用,那时看的资料(包括李维老师写的书)都是用单线程的,但我在使用过程中发现效果并不理想。因为Web Service是非常消耗资源的,加上XML的封装、转换,服务端与客户端的数据处理,往往一个简单的调用会很费时间,而且客户端界面会像死掉了一样停滞一段时间。基于以上考虑,我想通过建立另一个线程来解决问题,通过新线程在后台进行调用和数据处理,最后把结果反应到主线程的VCL界面上来。这是我的考虑,当然也可能有不成熟的地方。

5、接下来就是创建一个新的线程。同样保持现有项目不变,点选File-New-Other,在New页中点选Thread Object项确定。在随后的对话框中输入该线程的类和名称。在我机器上的效果是这样的:

 

确定后,以GetNews.cpp来保存单元至同一目录下。

6、现在来具体编写新线程的代码。首先要明确的是,我们要在这一线程内用到刚才自动导入的接口信息,同时又要与主线程交换信息,所以请点击File-Include Unit Hdr…,在随后的对话框中把UnitGetNews两个头文件都选上,否则编译时会报错。

然后,在GetNews.h头文件中声明这样一个函数:

  void __fastcall ThreadGetNews();

你可以把它声明为GetNews类的私有函数。然后在GetNews.cpp文件中实现这一函数,代码如下:

//------------------------------------------------------------------------

void __fastcall TGetNews::ThreadGetNews()

{

  Form1->Button1->Enabled=false;  //目的是使新线程运行期间只有一个实例

  AnsiString s;

  switch (Form1->ComboBox1 ->ItemIndex)  /*通过ComboBox中的不同项目来决定要调用哪个函数*/

  {

    case 0:// delphi

      s=GetIHeadLine()->DelphiNews(0);

    break;

    case 1:// cppBuilder

      s=GetIHeadLine()->CBuilderNews(0);

    break;

    case 2: // JBuilder

      s=GetIHeadLine()->JBuilderNews(0);

    break;

    case 3: // Kylix

      s=GetIHeadLine()->KylixNews(0);

    break;

    case 4: // SOAP

      s=GetIHeadLine()->SOAPNews(0);

    break;

    case 5: // Borcon

      s=GetIHeadLine()->BorConNews(0);

    break;

    default:

      s="Invalide direction" ;

  }

  Form1->Memo1->Lines ->Clear();

  Form1->Memo1->Lines->Add(s);

  Form1->Button1 ->Enabled=true;  /*线程结束(不严格意义上说),让Button1可以再用*/

  s="";

}

//------------------------------------------------------------------------

注意:如果你上面忘了引用两个头文件,那么这一步编译肯定通不过。 

7、接着设定线程如何启动。首先请在GetNews.cpp中找到__fastcall TGetNews::TGetNews(bool CreateSuspended): TThread(CreateSuspended)的定义,然后在{}中加入:

Priority=tpNormal;

设定线程以正常优先级来运行。你也可以另外设定其它的优先级。

然后,在Execute()函数中加入代码,使之成为下面的样子:

//-----------------------------------------------------------------------

void __fastcall TGetNews::Execute()

{

  SetName();

  //---- Place thread code here ----

  //下面的代码是新加的

  FreeOnTerminate=true;

  if(!Terminated)

    Synchronize(ThreadGetNews);

}

//-----------------------------------------------------------------------

这样,关于新线程的设定就完成了。可以看出,一但主线程中创建了一个新线程的实例,并设置CreateSuspendedfalse时,新线程就会执行Execute()中的代码,如果线程没有结束,那么就会通过Synchronize来调用ThreadGetNews,通过该函数来调用Web Service并获得结果,实现对主线程VCL界面的更新。一但线程调用完成,就会自动回收资源。(因为我们设定了FreeOnTerminatetrue) 

8、现在,我们就可以在主线程中调用这个新线程了。切换到Form1,先加入对线程头文件的引用:#include "GetNews.h"(或者同样用上面的方法通过File菜单加入),然后在Button1OnClick事件中输入如下代码:

//-----------------------------------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)

{

   TGetNews *gNews=new TGetNews(false);

}

//----------------------------------------------------------------------

OK!大功即将告成。现在就可以编译项目了。运行后,在ComboBox中点选喜欢的主题,然后按Button,过一会Memo中就会有信息传回来了。在我的机器上是这样的:

 

当然,这里返回的是ASCII字符,在这个Web Service中,你也可以选择返回HTML格式,甚至是可以用在PDA上的WML。你可以在调用函数比如说DelphiNews(int)中设定,以上三种格式的参数值分别为0,1,2。为了方便起见,我在本示例中设为0 

不过,还有一点似乎是个问题,那就是运行这个程序时,新线程在后台进行Web Service调用,但主界面依然有点停滞,这和普通的多线程程序多少有点不一样,至于为什么还请大家一起给解决一下。我的mail是:[email protected]

你可能感兴趣的:(C++)