|
|||||||||||||||||||||
|
|||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
OverviewThe Using the classAdd DetectDotNet.h and DetectDotNet.cpp to your project. #include "DetectDotNet.h" // . . . CDetectDotNet detect; vector<string> CLRVersions; cout << "Is .NET present : " << (detect.IsDotNetPresent() ? "Yes" : "No") << endl; TCHAR szPath[300]; cout << "Root Path : " << (detect.GetInstallRootPath(szPath, 299) ? szPath : "") << endl; cout << "Number of CLRs detected : " << (int)detect.EnumerateCLRVersions(CLRVersions) << endl; cout << "CLR versions available :-" << endl; for(vector<string>::iterator it = CLRVersions.begin(); it < CLRVersions.end(); it++) { cout << *it << endl; } cout << "Press any key..." << endl; getch(); Sample OutputIs .NET present : Yes Root Path : C:\WINDOWS\Microsoft.NET\Framework\ Number of CLRs detected : 2 CLR versions available :- 2.0.50215 1.1.4322 Press any key... Public Interface
ImplementationDetecting the .NET FrameworkThe extremely simple technique I use to detect whether the .NET Framework is
present on the system is to bool CDetectDotNet::IsDotNetPresent() { return m_bDotNetPresent; } bool CDetectDotNet::IsDotNetPresentInternal() { bool bRet = false; //Attempt to LoadLibrary "mscoree.dll" (the CLR EE shim) HMODULE hModule = LoadLibrary(_T("mscoree")); if(hModule) { //Okay - that worked, but just to ensure that this is //not a placeholder DLL shipped with some earlier OS versions, //we attempt to GetProcAddress "GetCORVersion". bRet = (GetProcAddress(hModule, "GetCORVersion") != NULL); FreeLibrary(hModule); } return bRet; } Enumerating CLR versionsHere's the mechanism I use to enumerate the available CLR versions on a system.
Note - You'll find STDAPI GetRequestedRuntimeInfo(
LPCWSTR pExe, LPCWSTR pwszVersion, LPCWSTR pConfigurationFile,
DWORD startupFlags, DWORD runtimeInfoFlags,
LPWSTR pDirectory, DWORD dwDirectory, DWORD *dwDirectoryLength,
LPWSTR pVersion, DWORD cchBuffer, DWORD* dwlength);
Here's a screenshot of my .NET installation root folder.
Notice the folder named "renamed", which is actually the installation folder
for "v2.0.50215". The call to Getting the root installation folderThis is extracted from the registry. HKEY_LOCAL_MACHINE
SOFTWARE
Microsoft
.NETFramework : InstallRoot (REG_SZ)
bool CDetectDotNet::GetInstallRootPath(TCHAR* szRootPath, DWORD dwBufferSize) { bool bRet = false; if(m_szInstallRootPath) { size_t siz = _tcslen(m_szInstallRootPath); if(dwBufferSize > siz) { _tcsncpy(szRootPath, m_szInstallRootPath, siz); szRootPath[siz] = NULL; bRet = true; } } return bRet; } bool CDetectDotNet::GetInstallRootPathInternal(TCHAR* szRootPath, DWORD dwBufferSize) { bool bRet = false; TCHAR szRegPath[] = _T("SOFTWARE\\Microsoft\\.NETFramework"); HKEY hKey = NULL; if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, szRegPath, 0, KEY_READ, &hKey) == ERROR_SUCCESS) { DWORD dwSize = dwBufferSize; if(RegQueryValueEx(hKey, _T("InstallRoot"), NULL, NULL, reinterpret_cast<LPBYTE>(szRootPath), &dwSize) == ERROR_SUCCESS) { bRet = (dwSize <= dwBufferSize); } RegCloseKey(hKey); } return bRet; } Getting the .NET version from the mscorlib assemblystring CDetectDotNet::GetVersionFromFolderName(string szFolderName) { string strRet = "<Version could not be extracted from mscorlib>"; TCHAR szRootPath[g_cPathSize]; if(GetInstallRootPath(szRootPath, g_cPathSize)) { USES_CONVERSION; string szFilepath = T2A(szRootPath); szFilepath += (szFolderName + "\\mscorlib.dll"); string s = GetDotNetVersion(A2CT(szFilepath.c_str())); if(s.size() > 0) strRet = s; } return strRet; } string CDetectDotNet::GetDotNetVersion(LPCTSTR szFolder) { string strRet = _T(""); LPVOID m_lpData = NULL; TCHAR buff[MAX_PATH + 1] = {0}; _tcsncpy(buff, szFolder, MAX_PATH); DWORD dwHandle = 0; DWORD dwVerInfoSize = GetFileVersionInfoSize(buff, &dwHandle); if(dwVerInfoSize != 0) //Success { m_lpData = malloc(dwVerInfoSize); if(GetFileVersionInfo(buff, dwHandle, dwVerInfoSize, m_lpData) == FALSE) { free(m_lpData); m_lpData = NULL; } else { UINT cbTranslate = 0; struct LANGANDCODEPAGE { WORD wLanguage; WORD wCodePage; } *lpTranslate; if(VerQueryValue(m_lpData,_T("\\VarFileInfo\\Translation"), (LPVOID*)&lpTranslate,&cbTranslate)) { int count = (int)(cbTranslate/sizeof(struct LANGANDCODEPAGE)); for(int i=0; i < count; i++ ) { TCHAR SubBlock[128]; HRESULT hr = StringCchPrintf(SubBlock, 127,_T("\\StringFileInfo\\%04x%04x\\%s"), lpTranslate[i].wLanguage, lpTranslate[i].wCodePage,_T("FileVersion")); if(SUCCEEDED(hr)) { UINT dwBytes = 0; TCHAR* lpBuffer; if(VerQueryValue(m_lpData, SubBlock, (LPVOID*)&lpBuffer, &dwBytes)) { USES_CONVERSION; strRet = T2A(lpBuffer); for(unsigned int x = 0, j = 0; j < strRet.size(); j++) { if(strRet[j] == '.') { if(++x == 3) { strRet.erase(j,strRet.size() - j); break; } } } break; } } } } } } return strRet; } Check if a specific .NET version existsbool CDetectDotNet::CheckForSpecificCLRVersionInternal(LPCWSTR pszVersion) { bool bRet = false; if( m_bDotNetPresent ) { UINT prevErrMode = SetErrorMode(SEM_FAILCRITICALERRORS); HMODULE hModule = LoadLibrary(_T("mscoree")); if(hModule) { FPGetRequestedRuntimeInfo pGetRequestedRuntimeInfo = reinterpret_cast<FPGetRequestedRuntimeInfo>( GetProcAddress(hModule, "GetRequestedRuntimeInfo")); if(pGetRequestedRuntimeInfo) { LPWSTR dirBuff = NULL; DWORD dwDir = 0; LPWSTR verBuff = NULL; DWORD dwVer = 0; pGetRequestedRuntimeInfo(NULL, pszVersion, NULL,0,0, dirBuff, dwDir, &dwDir, verBuff, dwVer, &dwVer); dirBuff = new WCHAR[dwDir + 1]; verBuff = new WCHAR[dwVer + 1]; HRESULT hr = pGetRequestedRuntimeInfo(NULL, pszVersion, NULL,0,0,dirBuff, dwDir, &dwDir,verBuff, dwVer, &dwVer); bRet = (hr == S_OK); delete[] verBuff; delete[] dirBuff; } FreeLibrary(hModule); } SetErrorMode(prevErrMode); } return bRet; } Get list of CLR versionssize_t CDetectDotNet::EnumerateCLRVersions(vector<string>& CLRVersions) { CLRVersions.clear(); USES_CONVERSION; vector<string> PossibleCLRVersions; EnumeratePossibleCLRVersionsInternal(PossibleCLRVersions); for(vector<string>::iterator it = PossibleCLRVersions.begin(); it < PossibleCLRVersions.end(); it++) { if(CheckForSpecificCLRVersionInternal(A2CW((*it).c_str()))) { CLRVersions.push_back(GetVersionFromFolderName(*it)); } } return CLRVersions.size(); } size_t CDetectDotNet::EnumeratePossibleCLRVersionsInternal(
vector<string>& PossibleCLRVersions)
{
PossibleCLRVersions.clear();
if(m_bDotNetPresent)
{
TCHAR szRootBuff[g_cPathSize];
if(GetInstallRootPath(szRootBuff, g_cPathSize))
{
WIN32_FIND_DATA finddata = {0};
_tcsncat(szRootBuff, _T("*"), 1);
HANDLE hFind = FindFirstFile(szRootBuff, &finddata);
if(hFind != INVALID_HANDLE_VALUE)
{
do
{
if( finddata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
{
PossibleCLRVersions.push_back(finddata.cFileName);
}
}while(FindNextFile(hFind, &finddata));
FindClose(hFind);
}
}
}
return PossibleCLRVersions.size();
}
Final notesI haven't tested this code out on every Windows or .NET version out there, so I cannot guarantee that it will work correctly all the time. But if it does not work for you, please let me know of it through the forum, and if you post an accurate problem description, I'll make efforts to implement a fix or a work-around. But you need to tell me, because if I don't know that a bug exists, I am not going to be able to fix it. Enjoy! History
| ||||||||||||||||||||