Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to enumerate MSSQL Servers from a 64-bit client app?

I'm looking for a way of enumerating MS SQL Servers on the local network from a 64-bit Delphi application. The method I've used thus far on 32-bit works fine but contains assembly code which won't compile on 32-bit. I can't seem to find a way of enumerating servers from a 64-bit client.

The code that I cannot compile is this:

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;
like image 562
Toby Groves Avatar asked Feb 12 '23 15:02

Toby Groves


1 Answers

The code that is causing you trouble simply stores and restores the floating point control state. You can write that in a cross-platform way (well, supporting x86 and x64) like this:

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;

This abstracts away the fact that the 32 bit code uses the 8087 unit with its 16 bit control state, and the 64 bit code uses the SSE unit with its 32 bit control state.

Now your function becomes:

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;

There are a number of benefits to this approach. Most clearly:

  1. You avoid using assembler code altogether.
  2. You use the standard RTL units for manipulating the floating point control state.
  3. You keep the conditional code confined to low-level routines. High level routines can remain ignorant of that detail and you can re-use this approach in different places at the high level without polluting it with conditionals.
like image 130
David Heffernan Avatar answered Feb 15 '23 05:02

David Heffernan