Enumerate Microsoft SQL database servers on the local network, using delphi

前端 未结 3 1948
-上瘾入骨i
-上瘾入骨i 2020-12-30 09:53

If I was using C# I could use the .net framework\'s SqlDataSourceEnumerator to discover and show a user a list of SQL Server instances on the network.

How can I do t

相关标签:
3条回答
  • 2020-12-30 09:56

    I use this code:

    uses ActiveX,
         ComObj,
         OleDB,
         DB,
         ADOInt,
         ADODB;
    
    procedure ListAvailableSQLServers(Names: TStringList);
    var
      RSCon: ADORecordsetConstruction;
      Rowset: IRowset;
      SourcesRowset: ISourcesRowset;
      SourcesRecordset: _Recordset;
      SourcesName, SourcesType: TField;
    
    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;
    
    begin
      SourcesRecordset :=
           PtCreateADOObject(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;
    
    0 讨论(0)
  • 2020-12-30 10:08

    You can use the NetServerEnum function , filtering by the SV_TYPE_SQLSERVER value in the servertype param, another option is use the SQLOLEDB Enumerator ADO object.

    0 讨论(0)
  • 2020-12-30 10:21

    To enumerate all available Microsoft SQL Servers, you can follow this excellent tutorial:

    Enumerating available SQL Servers. Retrieving databases on a SQL Server

    Included in Zarko's tutorial, there's a link to download the full source code (direct download) which can be useful to quickly test it and check if it fits your needs.

    Edit Zarko Gajic's main routine is:

    procedure ListAvailableSQLServers(Names : TStrings);
    var
      RSCon: ADORecordsetConstruction;
      Rowset: IRowset;
      SourcesRowset: ISourcesRowset;
      SourcesRecordset: _Recordset;
      SourcesName, SourcesType: TField;
    
        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;
    begin
      SourcesRecordset := PtCreateADOObject(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'); { do not localize }
        SourcesType := FieldByName('SOURCES_TYPE'); { do not localize }
        Names.BeginUpdate;
        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;
    

    I don't know what I can add without lamering what Zarko's explained.

    0 讨论(0)
提交回复
热议问题