⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ch06.htm

📁 好书《C++ Builder高级编程技术》
💻 HTM
📖 第 1 页 / 共 3 页
字号:
  end;

Here is the same interface as it would be declared 
inside a C++ project:

class IDBClass : public IUnknown

{

public:

   STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID*) PURE;

   STDMETHOD_(ULONG,AddRef)  (THIS) PURE;

   STDMETHOD_(ULONG,Release) (THIS) PURE;

   // Interface

   STDMETHOD_(VOID, 
Open) (THIS) PURE;

   STDMETHOD_(VOID, Close) (THIS) PURE;

   STDMETHOD_(VOID, SetDatabaseName) (THIS_ LPSTR Name) PURE;

   STDMETHOD_(VOID, SetTableName) (THIS_ LPSTR Name) PURE;

   STDMETHOD_(VOID, GetStrField) (THIS_ LPSTR FieldName, LPSTR 
Value)

     PURE;

   STDMETHOD_(VOID, GetIntField) (THIS_ LPSTR FieldName, int * Value)

     PURE;

   STDMETHOD_(VOID, GetClassName) (THIS_ LPSTR Name) PURE;

   STDMETHOD_(VOID,  Next) (THIS) PURE;

   STDMETHOD_(VOID,  Prior) (THIS) PURE;

   
STDMETHOD_(VOID,  First) (THIS) PURE;

   STDMETHOD_(VOID,  Last) (THIS) PURE;

   STDMETHOD_(BOOL,  EOF) (THIS) PURE;

};

</FONT></PRE>
<P>This code is shown on the CD that accompanies this book in the program called
ComTable. Given the preceding 
definition, you could write the following C++ code
to use the Delphi object in C++:</P>
<PRE><FONT COLOR="#0066FF">#pragma argsused

void Window1_OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags)

{

  char CR[2] 
=&quot;\r&quot;;

  HRESULT hr;

  PIDBClass P;

  LPSTR S, Temp;

  CoInitialize(NULL);

  hr = CoCreateInstance(CLSID_IDBClass, NULL, CLSCTX_INPROC_SERVER,

                         IID_IUnknown, (VOID**) &amp;P);

  if (SUCCEEDED(hr))

  {

    S = 
(char *)malloc(1000);

    Temp = (LPSTR)malloc(100);

    P-&gt;SetDatabaseName(&quot;DBDEMOS&quot;);

    P-&gt;SetTableName(&quot;COUNTRY&quot;);

    P-&gt;Open();

    strcpy(S, &quot;Countries and their capitals: &quot;);

    strcat(S, CR);

    
strcat(S, CR);

    while (!P-&gt;EOF())

    {

      P-&gt;GetStrField(&quot;NAME&quot;, Temp);

      strcat(S, Temp);

      strcat(S, &quot;: &quot;);

      P-&gt;GetStrField(&quot;CAPITAL&quot;, Temp);

      strcat(S, Temp);

      strcat(S, 
CR);

      P-&gt;Next();

    }

    MessageBox(hwnd, S, &quot;COUNTRY TABLE&quot;, MB_OK);

    P-&gt;Release();

    free(S);

    free(Temp);

  }

}

</FONT></PRE>
<P>This code is found on disk in the program called CRunTable. Clearly this 
technique
takes a bit of work, but it is not overly difficult. If you understand something
about COM objects, it provides a viable method for sharing code between Delphi and
C++.</P>
<P>In the <TT>ComTable</TT> directory on the CD that accompanies 
this book, you will
find two sample programs: one called ComTable and the other called CRunTable. ComTable
is a Delphi DLL that contains the COM object shown earlier in this section of the
chapter. You can compile this program with Delphi 2.0 or with 
the command-line version
of the Delphi compiler called <TT>DCC32.EXE</TT> that ships with C++Builder.</P>
<P>In the same directory as the source for ComTable, you will find a file called
<TT>Win32.reg</TT>, which can be used to register ComTable with 
the system. In this
file you will find an entry called <TT>InProcServer</TT> that will have a path to
<TT>ComTable.dll</TT> hardcoded into it. You will have to edit this path to point
to the place on your system where <TT>ComTable.dll</TT> resides. 
You can load the
<TT>Win32.reg</TT> program into the Windows utility called <TT>RegEdit.exe</TT> or
go to a DOS window, change to the <TT>ComTable</TT> directory, and type <TT>START
WIN32.REG</TT>.</P>
<P>After compiling and registering ComTable, you 
can use BCB to compile and run CRunTable.
Click once with the left mouse button on the surface of this application to load
the Delphi COM object. CRunTable happens to be a Windows API program rather than
a standard BCB RAD program, but the core code 
that launches the COM object also works
in a standard BCB program. An sample BCB program of this type called BCBRunTable
can be found on the CD that accompanies this book.</P>
<P>The code found in ComTable provides a good example of how to construct a 
simple
COM object. Unfortunately, there isn't enough room in this book to discuss this topic
in any depth. If you want to learn more about this subject, read my book Delphi 2
Unleashed (published by Sams), or go to <A 
HREF="javascript:if(confirm('http://www.microsoft.com/  \n\nThis file was not retrieved by Teleport Pro, because it is addressed on a domain or path outside the boundaries set for its Starting Address.  \n\nDo you want to open it from the server?'))window.location='http://www.microsoft.com/'" tppabs="http://www.microsoft.com/"><TT>www.microsoft.com</TT></A>
and download the COM specification, which turns out to be a surprisingly readable
document.
<H4><A NAME="Heading20"></A><FONT COLOR="#000077">Using DLLs to Link Delphi Code
in to 
C++Builder</FONT></H4>
<P>C ++Builder can easily access a Delphi DLL containing functions and procedures.
If you want to access a Delphi object implemented inside a DLL from C++Builder, you
should read the following section called &quot;Mapping 
Virtual Method Tables.&quot;</P>
<P>If you have a Delphi DLL that you can call from inside a Delphi 2.01 project,
you do not need to change it at all to call it from inside C++Builder. To get started,
take the Delphi unit that lists the methods in 
your DLL and add it to your C++ project.
C++Builder will automatically compile the unit and generate a C++ header file. In
particular, you should link the unit using the techniques described previously in
the section called &quot;Ground Rules for 
Linking Delphi Code in to C++Builder.&quot;</P>
<P>You will not be able to access data declared in your DLL without first calling
a function or procedure. This same limitation applies to all DLLs, regardless of
the language used to implement them.</P>

<P>DLLs are useful when you have a large project that you want to divide into several
modules. By placing code in DLLs, you can divide your projects into several binary
files that can be loaded in and out of memory at will.
<H4><A 
NAME="Heading21"></A><FONT COLOR="#000077">Mapping Virtual Method Tables</FONT></H4>
<P>Delphi objects stored in a DLL are normally out of reach of Ebony projects. However,
there is a way to get at them by matching the VMT of the Delphi object to the 
VMT
of a virtual abstract, or &quot;PURE,&quot; C++ object.</P>
<P>An example of this type of program is found on the CD that accompanies this book
in the directory called <TT>ObjectsInDLL</TT>. The code for this project is described
in the remainder 
of this section of the chapter. To run the program, use Delphi or
the copy of <TT>DCC32.exe</TT> that ships with BCB to compile <TT>ObjectLib.dpr</TT>:</P>
<PRE><FONT COLOR="#0066FF">dcc32 -b ObjectLib.dpr

</FONT></PRE>
<P>Then load the GetObject 
project into BCB and compile and run the program. After
the program is launched, you can press the button in the BCB program in order to
call one of the methods in the Object Pascal DLL.</P>
<P>Consider the following Delphi declaration:</P>
<PRE><FONT 
COLOR="#0066FF">TMyObject = class

  function AddOne(i: Integer): Integer; virtual; stdcall;

  function AddTwo(i: Integer): Integer; virtual; stdcall;

end;

</FONT></PRE>
<P>A virtual abstract version of the same object could be declared in C++ like 
this:</P>
<PRE><FONT COLOR="#0066FF">class __declspec(pascalimplementation) TMyObject: public TObject

{

public:

  virtual _stdcall int AddOne(int i) = 0;

  virtual _stdcall int AddTwo(int i) = 0;

};

</FONT></PRE>
<P>To match up the VMT of the 
C++ object to the VMT of the Pascal object, all you
need to do is retrieve a pointer to the object from the DLL. One way to do this is
to export a function from the DLL that is designed for this explicit purpose:</P>
<PRE><FONT 
COLOR="#0066FF">function CreateObject(ID: Integer; var Obj): Boolean;

var

  M: TMyObject;

begin

  if ID = ID_MyObject then begin

    M := TMyObject.Create;

    Result := True

  end else begin

    M := nil;

    Result := False

  end;

  
Pointer(Obj) := M;

end;

exports

  CreateObject name `CreateObject';

</FONT></PRE>
<P>You can call this method from the Ebony project with the following code:</P>
<PRE><FONT COLOR="#0066FF">typedef Boolean (_stdcall *LPCreateObject)(int ID, void 
*obj);

void __fastcall TForm1::Button1Click(TObject *Sender)

{

  TMyObject *MyObject;

  LPCreateObject CreateObject;

  HANDLE hlib = LoadLibrary(&quot;OBJECTLIB.DLL&quot;);

  CreateObject = (LPCreateObject)GetProcAddress(hlib, 
&quot;CreateObject&quot;);

  if (CreateObject(1, &amp;MyObject))

  {

    int i = MyObject-&gt;AddOne(1);

    ShowMessage((AnsiString)i);

  }

  FreeLibrary(hlib);

}

</FONT></PRE>
<P>The code shown here first declares a pointer to a function 
with the same signature
as the <TT>CreateObject</TT> routine in the DLL. It then calls the standard Windows
API functions <TT>LoadLibrary</TT> and <TT>GetProcAddress</TT> in order to retrieve
a pointer to <TT>CreateObject</TT>. If the call succeeds, 
you can call <TT>CreateObject</TT>,
return the address of the object you want to call, and then call one of its methods.</P>
<P>Notice that all the methods in the Pascal object are declared virtual. This is
necessary because you want to match up the 
VMTs, or Virtual Method Tables, of the
two declarations. If the methods weren't declared virtual, there would be no Virtual
Method Table and the ploy would not work. You can declare nonvirtual methods in your
object if you want, but you will not be 
able to call these methods from C++.</P>
<P>Note also that the order of the methods you declare is very important. The names
of the methods you want to call are not important to the C++ implementation; all
that matters is the order in which the 
methods are declared.</P>
<P>You can use this same technique, or one like it, to export any object from a Delphi
DLL into a C++Builder or Borland C++ project. You do not have to use <TT>GetProcAddress</TT>
and <TT>LoadLibrary</TT>, but could instead 
import a Delphi unit that exports <TT>CreateObject</TT>
directly into your C++Builder project. However, I use <TT>GetProcAddress</TT> in
this example because it forces you to imagine the exact steps necessary to make this
process work. In other words, 
it forces you to think about the addresses that are
being shared between the DLL and the BCB project.
<H3><A NAME="Heading22"></A><FONT COLOR="#000077">Summary</FONT></H3>
<P>In this chapter you have learned that C++Builder has an unprecedented 
capability
to access the code from its sister product, Delphi. As a rule, you can simply link
Delphi code directly into your C++Builder projects without any additional work on
your part. It is no harder to link Object Pascal code into C++Builder than 
it would
be to link Object Pascal code into a Delphi project!</P>

<P>The types of code that can be shared between Delphi and C++Builder include forms,
components, ActiveX controls, and simple methods and functions. You can simply link
this code 
directly into your projects without any extra work.</P>

<P>This chapter also examined using OLE or DLLs to share code between C++Builder
and Delphi. OLE can be useful if you want to share code with not only C++Builder,
but also with other, 
non-Borland environments such as Word, Visual Basic, or Excel.
DLLs are a great way to share code if memory management issues are significant. In
particular, you can load and unload DLLs from memory during the life of your project.</P>
<P 
ALIGN="CENTER"><A HREF="index-3.htm" tppabs="http://pbs.mcp.com/ebooks/0672310228/index.htm"><IMG SRC="toc.gif" tppabs="http://pbs.mcp.com/ebooks/0672310228/buttonart/toc.gif" WIDTH="41" HEIGHT="41"
ALIGN="BOTTOM" ALT="TOC" BORDER="0" NAME="toc8"></A><A HREF="ch05.htm" tppabs="http://pbs.mcp.com/ebooks/0672310228/ch05.htm"><IMG SRC="back-1.gif" tppabs="http://pbs.mcp.com/ebooks/0672310228/buttonart/back.gif"
WIDTH="41" HEIGHT="41" ALIGN="BOTTOM" ALT="BACK" BORDER="0" 
NAME="toc6"></A><A HREF="ch07.htm" tppabs="http://pbs.mcp.com/ebooks/0672310228/ch07.htm"><IMG
SRC="forward.gif" tppabs="http://pbs.mcp.com/ebooks/0672310228/buttonart/forward.gif" WIDTH="41" HEIGHT="41" ALIGN="BOTTOM" ALT="FORWARD" BORDER="0"
NAME="toc7"></A><BR>
</P>

<P ALIGN="CENTER"><BR>
<FONT COLOR="#000000">&copy;</FONT><A 
HREF="copy.htm" tppabs="http://pbs.mcp.com/ebooks/0672310228/copy.htm">Copyright</A><FONT COLOR="#000000">,
Macmillan Computer Publishing. All rights reserved.</FONT>

</BODY>

</HTML>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -