Binh Ly 與 Deborah Pate 分別提供兩種傳遞 RecordSet 的方法:
一. Binh Ly 提供的方法
Something like this should work:
In Server:
func TFoo.GetRS: OleVariant;
var
rs: _Recordset;
begin
rs := CoRecordset.Create;
rs.CursorLocation := adUseClient;
rs.Open (..., adLockBatchOptimistic { if you want modifiable rs }, ... );
rs._Set_ActiveConnection (nil);
Result := rs;
end;
In Client:
var
Foo: IFoo;
rs: _Recordset;
begin
Foo := CoFoo.Create;
rs := IUnknown (Foo.GetRS) as _Recordset;
end;
have fun
--
Binh Ly
http://www.techvanguards.com
二. Deborah Pate 提供的方法
<>
Well, that's an easy way, when the components are overkill.
If you use the New...|ActiveX wizards to create an ActiveX
library and then create an automation object, you can
easily add a method or a property of _Recordset type. Just
select the library - the first line in the left hand window
pane - in the Type Library Editor, and on the right you'll
see a Uses tab. Select it, then right-click in that window
and select Show all libraries. Now make sure that
"Microsoft ActiveX Data Objects Recordset 2.5" is checked,
and you'll be able to specify _recordset interfaces for
your own interfaces' properties and method parameters.
For example, I just created an automation object, and added
a Recordset property to it using the Type Library Editor,
so that the interface looked like this:
IRecordsetProvider = interface(IDispatch)
['{CB8CDFA1-C536-11D4-8481-E82B82956957}']
function Get_Recordset: _Recordset; safecall;
procedure Set_Recordset(const Value: _Recordset);
safecall;
property Recordset: _Recordset read Get_Recordset
write Set_Recordset;
end;
In the corresponding TRecordSetProvider class, I added an
FRecordset private field. I had to put Ador_TLB in the uses
clause (the file had been generated for me automatically).
Then I filled in the methods to assign and retrieve the
recordset property, e.g.
function TRecordsetProvider.Get_Recordset: _Recordset;
begin
Result := FRecordset;
end;
The only thing left to do was to create the recordset. I
did that in an overridden Initialize method - you can't use
constructors with COM objects, because they're created
through class factories, so you do resource creation in
Initialize. Here's a little example:
procedure TRecordsetProvider.Initialize;
begin
inherited;
FRecordset :=
CreateComObject(CLASS_Recordset) as _Recordset;
FRecordset.CursorLocation := adUseClient;
{ Create the recordset's fields }
FRecordset.Fields.Append('FirstName', adBSTR,
0, adFldUnspecified, EmptyParam);
FRecordset.Fields.Append('Surname', adBSTR, 0,
adFldUnspecified, EmptyParam);
FRecordset.Fields.Append('EmailAddress', adBSTR,
0, adFldUnspecified, EmptyParam);
FRecordset.Open(EmptyParam, EmptyParam,
adOpenUnspecified, adLockUnspecified, 1);
{ Add a record }
FRecordset.AddNew(
VarArrayOf([Widestring('FirstName'),
Widestring('Surname'),
Widestring('EmailAddress')]),
VarArrayOf([Widestring('Deborah'),
Widestring('Pate'),
Widestring('dpate@hotmail.com')]));
FRecordset.Update(EmptyParam, EmptyParam);
end;
I'm very new to ADO myself, so I don't cite this as an
example of good code by any means. But it seems to work, at
least. :) I can call this automation object from a client
Delphi application like this:
var
RS: OleVariant;
begin
RS :=
CreateOleObject('DebsComplessADO.RecordsetProvider');
Caption := RS.Recordset.Fields['FirstName'].Value;
and it should work with the equivalent VB code without
difficulty.
--
Deborah Pate (TeamB)
http://delphi-jedi.org
Sorry, no email please.
               (
geocities.com/huanlin_tsai)