You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
338 lines
8.3 KiB
338 lines
8.3 KiB
// ***************************************************************************
|
|
// Copyright (C) 2000- Microsoft Corporation.
|
|
// @File: sqlenum.cpp
|
|
//
|
|
// PURPOSE:
|
|
//
|
|
// Enumerate the sqlservers available on the local node.
|
|
//
|
|
// NOTES:
|
|
//
|
|
//
|
|
// HISTORY:
|
|
//
|
|
// @Version: Whistler/Shiloh
|
|
// 76910 SRS 08/08/01 Rollforward from VSS snapshot
|
|
// 68228 12/05/00 ntsnap work
|
|
// 68067 srs 11/06/00 ntsnap fix
|
|
// 67026 srs 10/05/00 Server enumeration bugs
|
|
//
|
|
//
|
|
// @EndHeader@
|
|
// ***************************************************************************
|
|
|
|
#ifdef HIDE_WARNINGS
|
|
#pragma warning( disable : 4786)
|
|
#endif
|
|
|
|
#include <stdafx.h>
|
|
#include <clogmsg.h>
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// Standard foo for file name aliasing. This code block must be after
|
|
// all includes of VSS header files.
|
|
//
|
|
#ifdef VSS_FILE_ALIAS
|
|
#undef VSS_FILE_ALIAS
|
|
#endif
|
|
#define VSS_FILE_ALIAS "SQLENUMC"
|
|
//
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
//------------------------------------------------------------------------
|
|
// Determine if the given service name is for a sql server instance.
|
|
// If so, return TRUE, the version (7,8,9) and the name of the server
|
|
// The servername is the name used to connect to the server.
|
|
// This will always be of the form: <ComputerName> [\<NamedInstanceName>]
|
|
// On a cluster, the ComputerName is a virtual server name.
|
|
//
|
|
BOOL // TRUE if the service is a sqlserver instance
|
|
IsSQL (
|
|
PCWSTR pServiceName, // in: name of a service
|
|
UINT* pVersion, // out: version of the sql instance
|
|
WString& serverName) // out: servername to use to connect to instance
|
|
{
|
|
BOOL isDefault = FALSE;
|
|
PCWSTR pInstanceName = NULL;
|
|
|
|
if (_wcsicmp (pServiceName, L"MSSQLSERVER") != 0)
|
|
{
|
|
if (_wcsnicmp (pServiceName, L"MSSQL$", 6) != 0)
|
|
{
|
|
return FALSE;
|
|
}
|
|
// we have a named instance
|
|
//
|
|
pInstanceName = pServiceName+6;
|
|
isDefault = FALSE;
|
|
}
|
|
else
|
|
{
|
|
// default instance.... pInstanceName remains null...
|
|
isDefault = TRUE;
|
|
}
|
|
|
|
WString rootKey = L"Software\\Microsoft\\";
|
|
|
|
if (isDefault)
|
|
{
|
|
rootKey += L"MSSQLServer";
|
|
}
|
|
else
|
|
{
|
|
rootKey += L"Microsoft SQL Server\\" + WString (pInstanceName);
|
|
}
|
|
|
|
// First determine the "machinename".
|
|
// when clustered, we pull the the virtual server name from the registry.
|
|
//
|
|
BOOL isClustered = FALSE;
|
|
WString keyName = rootKey + L"\\Cluster";
|
|
HKEY regHandle;
|
|
|
|
if (RegOpenKeyExW (
|
|
HKEY_LOCAL_MACHINE,
|
|
keyName.c_str (),
|
|
0, KEY_QUERY_VALUE, ®Handle) == ERROR_SUCCESS)
|
|
{
|
|
#define MAX_CLUSTER_NAME 256
|
|
DWORD keytype;
|
|
WCHAR clusterName [MAX_CLUSTER_NAME+1];
|
|
DWORD valueLen = sizeof (clusterName)- sizeof(WCHAR);
|
|
|
|
clusterName[MAX_CLUSTER_NAME] = L'\0';
|
|
if (RegQueryValueExW (
|
|
regHandle, L"ClusterName",
|
|
NULL, &keytype, (LPBYTE) clusterName,
|
|
&valueLen) == ERROR_SUCCESS &&
|
|
keytype == REG_SZ)
|
|
{
|
|
isClustered = TRUE;
|
|
serverName = WString(clusterName);
|
|
}
|
|
|
|
RegCloseKey (regHandle);
|
|
}
|
|
|
|
if (!isClustered)
|
|
{
|
|
WCHAR compName [MAX_COMPUTERNAME_LENGTH + 2];
|
|
DWORD nameLen = MAX_COMPUTERNAME_LENGTH + 1;
|
|
if (!GetComputerNameW (compName, &nameLen))
|
|
{
|
|
// In the unlikely event that this fails,
|
|
// let's just use '.'
|
|
//
|
|
compName [0] = L'.';
|
|
compName [1] = 0;
|
|
}
|
|
|
|
|
|
serverName = compName;
|
|
}
|
|
|
|
// For named instances, append the instance name to the "machine" name.
|
|
//
|
|
if (!isDefault)
|
|
{
|
|
serverName += L"\\" + WString (pInstanceName);
|
|
}
|
|
|
|
*pVersion = 9; // assume post sql2000 if we can't tell
|
|
|
|
keyName = rootKey + L"\\MSSQLServer\\CurrentVersion";
|
|
|
|
if (RegOpenKeyExW (
|
|
HKEY_LOCAL_MACHINE,
|
|
keyName.c_str (),
|
|
0, KEY_QUERY_VALUE, ®Handle) == ERROR_SUCCESS)
|
|
{
|
|
DWORD keytype;
|
|
const bufferSize = 20;
|
|
WCHAR versionString [bufferSize+1];
|
|
DWORD valueLen = sizeof (versionString) - sizeof(WCHAR);
|
|
|
|
versionString[bufferSize] = L'\0';
|
|
if (RegQueryValueExW (
|
|
regHandle, L"CurrentVersion",
|
|
NULL, &keytype, (LPBYTE) versionString,
|
|
&valueLen) == ERROR_SUCCESS &&
|
|
keytype == REG_SZ)
|
|
{
|
|
swscanf (versionString, L"%d", pVersion);
|
|
}
|
|
|
|
RegCloseKey (regHandle);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------
|
|
// Build the list of servers on the current machine.
|
|
// Throws exception if any errors occur.
|
|
//
|
|
StringVector*
|
|
EnumerateServers ()
|
|
{
|
|
CVssFunctionTracer ft(VSSDBG_SQLLIB, L"EnumerateServers");
|
|
|
|
RETCODE rc;
|
|
BYTE* pBuf = NULL;
|
|
std::auto_ptr<StringVector> serverList (new StringVector);
|
|
SC_HANDLE hSCManager = NULL;
|
|
|
|
BOOL restrict2000 = FALSE;
|
|
|
|
// Read a registry key to see if we should avoid sql versions
|
|
// beyond SQL2000.
|
|
//
|
|
{
|
|
CVssRegistryKey restrictKey (KEY_QUERY_VALUE);
|
|
|
|
if (restrictKey.Open (HKEY_LOCAL_MACHINE, x_wszVssCASettingsPath))
|
|
{
|
|
DWORD val;
|
|
if (restrictKey.GetValue (L"MSDEVersionChecking", val, FALSE))
|
|
{
|
|
if (val != 0)
|
|
{
|
|
restrict2000 = TRUE;
|
|
ft.Trace(VSSDBG_SQLLIB, L"Restricting Enumeration - MSDE writer will skip every SQL version newer than 2000");
|
|
}
|
|
}
|
|
restrictKey.Close ();
|
|
}
|
|
}
|
|
|
|
try
|
|
{
|
|
// open SCM
|
|
//
|
|
hSCManager = OpenSCManagerW (NULL, NULL,
|
|
SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_CONNECT);
|
|
|
|
if (hSCManager == NULL )
|
|
ft.TranslateWin32Error(VSSDBG_SQLLIB, L"OpenSCManager(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_CONNECT)");
|
|
|
|
|
|
LPENUM_SERVICE_STATUSW pServStat;
|
|
DWORD bytesNeeded;
|
|
DWORD sizeOfBuffer;
|
|
DWORD entriesReturned;
|
|
DWORD resumeHandle = 0;
|
|
DWORD status;
|
|
|
|
EnumServicesStatusW (hSCManager,
|
|
SERVICE_WIN32,
|
|
SERVICE_ACTIVE,
|
|
NULL,
|
|
0,
|
|
&bytesNeeded,
|
|
&entriesReturned,
|
|
&resumeHandle);
|
|
status = GetLastError ();
|
|
if (status != ERROR_MORE_DATA)
|
|
ft.TranslateWin32Error(VSSDBG_SQLLIB, L"EnumServicesStatus(SERVICE_WIN32, SERVICE_STATE_ALL, ...)");
|
|
|
|
sizeOfBuffer = bytesNeeded;
|
|
pBuf = new BYTE [sizeOfBuffer]; // "new" will throw on err
|
|
|
|
BOOL moreExpected = FALSE;
|
|
do
|
|
{
|
|
pServStat = (LPENUM_SERVICE_STATUSW)pBuf;
|
|
|
|
moreExpected = FALSE;
|
|
if (!EnumServicesStatusW (hSCManager,
|
|
SERVICE_WIN32,
|
|
SERVICE_ACTIVE,
|
|
pServStat,
|
|
sizeOfBuffer,
|
|
&bytesNeeded,
|
|
&entriesReturned,
|
|
&resumeHandle))
|
|
{
|
|
status = GetLastError ();
|
|
if (status != ERROR_MORE_DATA)
|
|
ft.TranslateWin32Error(VSSDBG_SQLLIB, L"EnumServicesStatus(SERVICE_WIN32, SERVICE_STATE_ALL, ...)");
|
|
|
|
moreExpected = TRUE;
|
|
}
|
|
|
|
while (entriesReturned-- > 0)
|
|
{
|
|
UINT version = 0;
|
|
WString serverName;
|
|
|
|
// We only need the running servers.
|
|
//
|
|
if (pServStat->ServiceStatus.dwCurrentState == SERVICE_RUNNING)
|
|
{
|
|
if (IsSQL (pServStat->lpServiceName, &version, serverName))
|
|
{
|
|
ft.Trace(VSSDBG_SQLLIB, L"Service: %s Server: %s. Version=%d\n",
|
|
pServStat->lpServiceName, serverName.c_str (), version);
|
|
|
|
if (version >= 7)
|
|
{
|
|
if (version < 9 || !restrict2000)
|
|
{
|
|
serverList->push_back (serverName);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
pServStat++;
|
|
}
|
|
}
|
|
while (moreExpected);
|
|
|
|
|
|
if (pBuf)
|
|
{
|
|
delete [] pBuf;
|
|
}
|
|
|
|
if (hSCManager)
|
|
{
|
|
CloseServiceHandle (hSCManager);
|
|
}
|
|
}
|
|
catch (HRESULT)
|
|
{
|
|
if (pBuf)
|
|
{
|
|
delete [] pBuf;
|
|
}
|
|
|
|
if (hSCManager)
|
|
{
|
|
CloseServiceHandle (hSCManager);
|
|
}
|
|
|
|
throw;
|
|
}
|
|
catch (std::exception)
|
|
{
|
|
if (pBuf)
|
|
{
|
|
delete [] pBuf;
|
|
}
|
|
|
|
if (hSCManager)
|
|
{
|
|
CloseServiceHandle (hSCManager);
|
|
}
|
|
|
|
throw;
|
|
}
|
|
|
|
return serverList.release();
|
|
}
|
|
|
|
|