İyi günler. Muharrem Hocam bir kaç dakika erken davranmış

. Açıkçası bir zamanlar SQL Server listesini Registry üzerinden okumaya çalıştım ama sistemde hem x86, hem de x64 bit sql yüklü ise iki defa registry okuma yapmak gerekmektedir. Bu durum yukarıdaki
R.GetValueNames kodlaması için de geçerli maalesef. Zira bu platform farkından doğan registry kayıtları birbirinden bağımsız olarak erişilmektedir ve her SQL Server kendi platformuna göre registry değeri oluşturmaktadır. Ayrıca
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server anahtarında bulunan
InstalledInstances değeri string değil, multistring tipinde olduğu için bu bilgiyi string olarak ele almadan yorumlamak gerekmektedir. Bir zamanlar aşağıdaki yöntemle SQL Listesini alıyordum
Kod: Tümünü seç
uses Registry;
procedure GetInstanceNames(const Names:TStrings;Server:String='';BosSatirEkle:Boolean=True;const x64mu:Boolean=False);
const KEY_WOW64_64KEY=$0100;
var
Info: TRegDataInfo;
Bilgi:PByteArray;
S:PChar;
i:Integer;
Duzgun:Boolean;
RegParam:Cardinal;
begin //S:='?';
Server:=Trim(Server);
if SameText(Server,'(local)') or SameText(Server,'.') then Server:='';
if x64mu then RegParam:=KEY_READ OR KEY_WOW64_64KEY else RegParam:=KEY_READ;
with TRegistry.Create(RegParam) do try
RootKey:=HKEY_LOCAL_MACHINE;
if Trim(Server)<>'' then
if not RegistryConnect(Server) then Application.MessageBox(PChar(Format('%s sunucusu okunamıyor',[Server])),'Hata',MB_ICONERROR);
//RegistryConnect(Sunucu);
OpenKey('SOFTWARE\Microsoft\Microsoft SQL Server',False);
Bilgi:=nil;
if GetDataInfo('InstalledInstances', Info) then try
Bilgi:=AllocMem(Info.DataSize);
ReadBinaryData('InstalledInstances',Bilgi^,Info.DataSize);
Names.BeginUpdate;
Names.Clear;
//if Length(S)<-1 then ShowMessage(S);
S:=@(Bilgi^);
//if Length(S)<-1 then ShowMessage(S);
repeat
//if Trim(S)='' then Break ya da
if SameText('MSSQLSERVER',S) then Names.Add('') else begin
i:=Length(S)-1; Duzgun:=True;
while Duzgun and (i>0) do begin
Duzgun:=(S[i]>#31);
Dec(i);
end;
if Duzgun then Names.Add(S);
end;
S:=Pointer(Integer(S)+Length(S)+1)
until (S='') or (S[1]=#0);
finally
Names.EndUpdate;
if Assigned(Bilgi) then FreeMem(Bilgi);
end;
finally
Free;
end;
end;
Bu fonksiyonu aşağıdaki gibi 32 bit ve 64 bit sql isimlerini alabilmek için 2 kere çağırmak gerekiyor.
Kod: Tümünü seç
GetInstanceNames(ListBox1.Items,'',True,False);//<-x86 sql ler
GetInstanceNames(ListBox2.Items,'',True,True);//<-x64 sql ler
Ama bir zaman sonra SQL Server listesini hizmetler listesinden elde edilebileceği fikrine kapıldım ve gördüğüm kadarı ile bu hizmet eğer
instancename'e sahip değilse
MSSQLSERVER adını alıyor ama bir
instancename varsa
MSSQL$INSTANCENAME gibi bir hizmet oluşturmakta. Bu mantıkla aşağıdaki gibi başka bir fonksiyon kullandım ve şu an onu kullanmaktayım.
Kod: Tümünü seç
uses StrUtils, WinSvc;
function GetSQLServiceList(sMachine:string;dwServiceType,dwServiceState:DWord;slServicesList:TStrings):Boolean;
const
cnMaxServices = 4096;
SERVICE_KERNEL_DRIVER = $00000001;
SERVICE_FILE_SYSTEM_DRIVER = $00000002;
SERVICE_ADAPTER = $00000004;
SERVICE_RECOGNIZER_DRIVER = $00000008;
SERVICE_DRIVER =
(SERVICE_KERNEL_DRIVER or
SERVICE_FILE_SYSTEM_DRIVER or
SERVICE_RECOGNIZER_DRIVER);
SERVICE_WIN32_OWN_PROCESS = $00000010;
SERVICE_WIN32_SHARE_PROCESS = $00000020;
SERVICE_WIN32 =
(SERVICE_WIN32_OWN_PROCESS or
SERVICE_WIN32_SHARE_PROCESS);
SERVICE_INTERACTIVE_PROCESS = $00000100;
SERVICE_TYPE_ALL =
(SERVICE_WIN32 or
SERVICE_ADAPTER or
SERVICE_DRIVER or
SERVICE_INTERACTIVE_PROCESS);
type
TSvcA = array[0..cnMaxServices] of TEnumServiceStatus;
PSvcA = ^TSvcA;
var
j:integer;
schm:SC_Handle;
nBytesNeeded,nServices,nResumeHandle : DWord;
ssa : PSvcA;
DefaultSQL:Boolean;//MSSQLSERVER varsa true
procedure isSQLService(ServiceName:String);
const
MSSQLSERVER='MSSQLSERVER'; //LenMSSQLSERVER=11;
MSSQL='MSSQL$'; LenMSSQL=6;
//MSSQL$SQL2008,MSSQL$SQL2012
begin
if SameText(ServiceName,MSSQLSERVER) then DefaultSQL:=True
else if SameText(MSSQL,LeftStr(ServiceName,LenMSSQL)) then begin
Delete(ServiceName,1,LenMSSQL);
slServicesList.Add(ServiceName);
end;
end;
begin
Result := False;
DefaultSQL:=False;
slServicesList.Clear;
schm := OpenSCManager(PChar(sMachine),nil,SC_MANAGER_ALL_ACCESS);
if(schm > 0)then begin
nResumeHandle := 0;
New(ssa);
EnumServicesStatus(schm,dwServiceType,dwServiceState,ssa^[0],SizeOf(ssa^),
nBytesNeeded,nServices,nResumeHandle );
for j := 0 to nServices-1 do begin
//slServicesList.Add(StrPas(ssa^[j].lpServiceName{lpDisplayName{} ) );
isSQLService(ssa^[j].lpServiceName);
end;
if DefaultSQL then slServicesList.Insert(0,'');//default olan sql en üste...
Result := True;
Dispose(ssa);
// close service control
// manager handle
CloseServiceHandle(schm);
end;
end;
Bu foksyionu da aşağıdaki gibi kullandığımda sistemde yüklü olan bütün sql server
instancename listesini elde edebildim.
Kod: Tümünü seç
GetSQLServiceList('',SERVICE_WIN32,SERVICE_STATE_ALL,ListBox1.Items);
İyi çalışmalar.