我正在寻找一种从64位Delphi应用程序在本地网络上枚举MS SQL Server的方法。到目前为止,我在32位上使用的方法工作正常,但包含在32位上不能编译的汇编代码。我似乎无法找到一种从64位客户端枚举服务器的方法。
我无法编译的代码是:
function PtCreateADOObject(const ClassID: TGUID): IUnknown;
var
Status: HResult;
FPUControlWord: Word;
begin
asm
FNSTCW FPUControlWord
end;
Status := CoCreateInstance(
CLASS_Recordset,
nil,
CLSCTX_INPROC_SERVER or CLSCTX_LOCAL_SERVER,
IUnknown,
Result);
asm
FNCLEX
FLDCW FPUControlWord
end;
OleCheck(Status);
end;
答案 0 :(得分:8)
导致您遇到麻烦的代码只是存储和恢复浮点控制状态。你可以用跨平台的方式编写它(好吧,支持x86和x64),如下所示:
type
TFPControlState = {$IFDEF CPUX86}Word{$ENDIF}{$IFDEF CPUX64}UInt32{$ENDIF};
function GetFPControlState: TFPControlState;
begin
{$IFDEF CPUX86}
Result := Get8087CW;
{$ENDIF}
{$IFDEF CPUX64}
Result := GetMXCSR;
{$ENDIF}
end;
procedure SetFPControlState(const Value: TFPControlState);
begin
{$IFDEF CPUX86}
Set8087CW(Value);
{$ENDIF}
{$IFDEF CPUX64}
SetMXCSR(Value);
{$ENDIF}
end;
这抽象出32位代码使用8087单元的16位控制状态,64位代码使用SSE单元的32位控制状态。
现在您的功能变为:
function PtCreateADOObject(const ClassID: TGUID): IUnknown;
var
Status: HResult;
FPControlState: TFPControlState;
begin
FPControlState := GetFPControlState;
Status := CoCreateInstance(
CLASS_Recordset,
nil,
CLSCTX_INPROC_SERVER or CLSCTX_LOCAL_SERVER,
IUnknown,
Result
);
SetFPControlState(FPControlState);
OleCheck(Status);
end;
这种方法有很多好处。最清楚的是:
答案 1 :(得分:0)
x64采用的here示例,现在它与x32 / x64系统兼容。
uses
ActiveX, ComObj, OleDB, DB, ADOInt, ADODB;
function CreateADOObject(const ClassID: TGUID): IUnknown;
var
Status: HResult;
{$IFDEF CPUX86}
FPUControlWord: Word;
{$ENDIF CPUX86}
begin
{$IFDEF CPUX86}
asm
FNSTCW FPUControlWord
end;
{$ENDIF CPUX86}
Status := CoCreateInstance(ClassID, nil, CLSCTX_INPROC_SERVER or
CLSCTX_LOCAL_SERVER, IUnknown, Result);
{$IFDEF CPUX86}
asm
FNCLEX
FLDCW FPUControlWord
end;
{$ENDIF CPUX86}
if (Status = REGDB_E_CLASSNOTREG) then
raise Exception.Create('error')
else
OleCheck(Status);
end;
procedure ListAvailableSQLServers(Names: TStringList);
var
RSCon: ADORecordsetConstruction;
Rowset: IRowset;
SourcesRowset: ISourcesRowset;
SourcesRecordset: _Recordset;
SourcesName, SourcesType: TField;
begin
SourcesRecordset := CreateADOObject(CLASS_Recordset) as _Recordset;
RSCon := SourcesRecordset as ADORecordsetConstruction;
SourcesRowset := CreateComObject(ProgIDToClassID('SQLOLEDB Enumerator')) as ISourcesRowset;
OleCheck(SourcesRowset.GetSourcesRowset(nil, IRowset, 0, nil, IUnknown(Rowset)));
RSCon.Rowset := RowSet;
with TADODataSet.Create(nil) do
try
Recordset := SourcesRecordset;
SourcesName := FieldByName('SOURCES_NAME');
SourcesType := FieldByName('SOURCES_TYPE');
Names.BeginUpdate;
Names.Clear;
try
while not EOF do
begin
if (SourcesType.AsInteger = DBSOURCETYPE_DATASOURCE) and
(SourcesName.AsString <> '')
then
Names.Add(SourcesName.AsString);
Next;
end;
finally
Names.EndUpdate;
end;
finally
Free;
end;
end;
procedure GetServer;
var
oItems: TStringList;
begin
oItems:= TStringList.Create;
try
ListAvailableSQLServers(oItems);
// To something with oItems
ShowMessage(oItems.Text);
finally
oItems.Free;
end;
end;