I've searching a long time, but i couldn't find answer.
Is there any way to determine framework and service pack .NET installed on PC, without access to registry in C#?
I can use registry keys, but i have to do this without access to registry.
I read something about directories in C:\Windows\Microsoft .NET, but there, I only found framework version, nothing about SP. But I need framework and Service Pack.
Can somebody help me?
Regards, Greg
string clrVersion = System.Environment.Version.ToString();
string dotNetVersion = Assembly
.GetExecutingAssembly()
.GetReferencedAssemblies()
.Where(x => x.Name == "mscorlib").First().Version.ToString();
you could use WMI to get a list of all the installed software filtering the result to achieve your goal
public static class MyClass
{
public static void Main()
{
ManagementObjectSearcher mos = new ManagementObjectSearcher("SELECT * FROM Win32_Product");
foreach (ManagementObject mo in mos.Get())
{
Console.WriteLine(mo["Name"]);
}
}
}
I think it's possible to ask the WMI.
Query for all Win32_Product elements and look for the Name Property contains "Microsoft .NET Framework"
ServicePack information is also provided by WMI.. But I don't know exactly where.
You can do this:
System.Environment.Version.ToString()
(CLR Version only)
or this
from MSDN blog on Updated sample .NET Framework detection code that does more in-depth checking
or this
No registry access. Borrowed from this blog.
using System;
using System.IO;
using System.Security;
using System.Text.RegularExpressions;
namespace YourNameSpace
{
public class SystemInfo
{
private const string FRAMEWORK_PATH = "\\Microsoft.NET\\Framework";
private const string WINDIR1 = "windir";
private const string WINDIR2 = "SystemRoot";
public static string FrameworkVersion
{
get
{
try
{
return getHighestVersion(NetFrameworkInstallationPath);
}
catch (SecurityException)
{
return "Unknown";
}
}
}
private static string getHighestVersion(string installationPath)
{
string[] versions = Directory.GetDirectories(installationPath, "v*");
string version = "Unknown";
for (int i = versions.Length - 1; i >= 0; i--)
{
version = extractVersion(versions[i]);
if (isNumber(version))
return version;
}
return version;
}
private static string extractVersion(string directory)
{
int startIndex = directory.LastIndexOf("\\") + 2;
return directory.Substring(startIndex, directory.Length - startIndex);
}
private static bool isNumber(string str)
{
return new Regex(#"^[0-9]+\.?[0-9]*$").IsMatch(str);
}
public static string NetFrameworkInstallationPath
{
get { return WindowsPath + FRAMEWORK_PATH; }
}
public static string WindowsPath
{
get
{
string winDir = Environment.GetEnvironmentVariable(WINDIR1);
if (String.IsNullOrEmpty(winDir))
winDir = Environment.GetEnvironmentVariable(WINDIR2);
return winDir;
}
}
}
}
Here is an improved example that includes service packs,
string path = System.Environment.SystemDirectory;
path = path.Substring( 0, path.LastIndexOf('\\') );
path = Path.Combine( path, "Microsoft.NET" );
// C:\WINDOWS\Microsoft.NET\
string[] versions = new string[]{
"Framework\\v1.0.3705",
"Framework64\\v1.0.3705",
"Framework\\v1.1.4322",
"Framework64\\v1.1.4322",
"Framework\\v2.0.50727",
"Framework64\\v2.0.50727",
"Framework\\v3.0",
"Framework64\\v3.0",
"Framework\\v3.5",
"Framework64\\v3.5",
"Framework\\v3.5\\Microsoft .NET Framework 3.5 SP1",
"Framework64\\v3.5\\Microsoft .NET Framework 3.5 SP1",
"Framework\\v4.0",
"Framework64\\v4.0"
};
foreach( string version in versions )
{
string versionPath = Path.Combine( path, version );
DirectoryInfo dir = new DirectoryInfo( versionPath );
if( dir.Exists )
{
Response.Output.Write( "{0}<br/>", version );
}
}
The problem is that you will have to keep up with the versions as they come out.
You can use the MSI API functions to get a list of all installed products and then check whether the required .NET Framework version is installed.
Just don't tell you boss that these functions will read from the Registry.
Here's the code:
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
class Program
{
[DllImport("msi.dll", SetLastError = true)]
static extern int MsiEnumProducts(int iProductIndex, StringBuilder lpProductBuf);
[DllImport("msi.dll", CharSet = CharSet.Unicode)]
static extern Int32 MsiGetProductInfo(string product, string property, [Out] StringBuilder valueBuf, ref Int32 len);
public const int ERROR_SUCCESS = 0;
public const int ERROR_MORE_DATA = 234;
public const int ERROR_NO_MORE_ITEMS = 259;
static void Main(string[] args)
{
int index = 0;
StringBuilder sb = new StringBuilder(39);
while (MsiEnumProducts(index++, sb) == 0)
{
var productCode = sb.ToString();
var product = new Product(productCode);
Console.WriteLine(product);
}
}
class Product
{
public string ProductCode { get; set; }
public string ProductName { get; set; }
public string ProductVersion { get; set; }
public Product(string productCode)
{
this.ProductCode = productCode;
this.ProductName = GetProperty(productCode, "InstalledProductName");
this.ProductVersion = GetProperty(productCode, "VersionString");
}
public override string ToString()
{
return this.ProductCode + " - Name: " + this.ProductName + ", Version: " + this.ProductVersion;
}
static string GetProperty(string productCode, string name)
{
int size = 0;
int ret = MsiGetProductInfo(productCode, name, null, ref size); if (ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA)
{
StringBuilder buffer = new StringBuilder(++size);
ret = MsiGetProductInfo(productCode, name, buffer, ref size);
if (ret == ERROR_SUCCESS)
return buffer.ToString();
}
throw new System.ComponentModel.Win32Exception(ret);
}
}
}
This page may be of use:
http://blogs.msdn.com/b/astebner/archive/2009/06/16/9763379.aspx
Although the registry bit is irrelevant to you, the checking using mscoree.dll may be of help - its just that I cant access skydrive from work hence cant look through the code.
Ill see if i find something else.
Related
In old school Excel Interop, I can use the following code to generate an absolute address and use it inside a formula:
range.Formula = $"=sum({myRange.Address[false, true]})";
What is the EPPlus equivalent of this line, to get an absolute address (with an absolute row and/or column on demand)?
For an approach, that uses only EPPlus methods, there are static methods like ExcelCellBase.GetAddress (with a couple of overloads) that return absolute addresses:
public abstract class ExcelCellBase
{
public static string GetAddress(
int Row,
int Column,
bool Absolute
);
public static string GetAddress(
int Row,
bool AbsoluteRow,
int Column,
bool AbsoluteCol
);
public static string GetAddress(
int FromRow,
int FromColumn,
int ToRow,
int ToColumn,
bool FixedFromRow,
bool FixedFromColumn,
bool FixedToRow,
bool FixedToColumn
);
/* ... and others, see comments */
}
An extension method could be as easy as this one:
public static class EpPlusExtensions
{
public static string GetAddress(
this ExcelRangeBase range,
bool absoluteRow = false,
bool absoluteColumn = false)
{
return ExcelCellBase.GetAddress(
range.Start.Row,
range.Start.Column,
range.End.Row,
range.End.Column,
absoluteRow,
absoluteColumn,
absoluteRow,
absoluteColumn);
}
}
Well, there isn't a built in method, but you can do the following:
string GetAddress(ExcelRange rgn, bool absoluteRow, bool absoluteColumn,bool includeSheetName=false)
{
string address = rgn.Address;
if (absoluteColumn)
{
address = Regex.Replace(address, #"\b([A-Z])", #"$$$1");
}
if (absoluteRow)
{
address = Regex.Replace(address, #"([0-9]+)", #"$$$1");
}
if (includeSheetName)
{
address = $"'{rgn.Worksheet.Name}'!{address}";
}
return address;
}
Or as an extension method, so you can use like interop:
public static class EpplusExtensions
{
public static string Address(this ExcelRange rgn, bool absoluteRow, bool absoluteColumn, bool includeSheetName=false)
{
string address = rgn.Address;
if (absoluteColumn)
{
address = Regex.Replace(address, #"\b([A-Z])", #"$$$1");
}
if (absoluteRow)
{
address = Regex.Replace(address, #"([0-9]+)", #"$$$1");
}
if (includeSheetName)
{
address = $"'{rgn.Worksheet.Name}'!{address}";
}
return address;
}
}
Usage:
using (var ep = new ExcelPackage(new FileInfo(file)))
{
var sh = ep.Workbook.Worksheets.First();
ExcelRange myRange = sh.Cells[1, 1, 26, 36];
var absoluteColumn = myRange.Address(false, true);
var absoluteRow = myRange.Address(true, false);
var absolute = myRange.Address(true, true);
var relative = myRange.Address(false, false);
var withSheetName = myRange.Address(true, true, true);
}
I am attempting to use a managed code action in an InstallShield suite project.
I followed their example in hopes it wouldn't be a big deal.
http://helpnet.flexerasoftware.com/installshield21helplib/helplibrary/SteActionManagedCd.htm
Ideally, I want to have my .dll method to change an install shield property when the action is executed. When I test out the installer to see if the property changed, I get the default value I set.
Maybe I am doing it wrong, any suggestions would be greatly appreciated.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using Microsoft.Web.Administration;
namespace IISHelp
{
[Guid("BAFAEAED-08C6-4679-B94E-487A4D89DE63")]
[TypeLibType(4288)]
public interface ISuiteExtension
{
[DispId(1)]
string get_Attribute(string bstrName);
[DispId(2)]
void LogInfo(string bstr);
[DispId(3)]
string get_Property(string bstrName);
[DispId(3)]
void set_Property(string bstrName, string bstrValue);
[DispId(4)]
string FormatProperty(string bstrValue);
[DispId(5)]
string ResolveString(string bstrStringId);
}
public class Help
{
const UInt32 ERROR_INSTALL_FAILURE = 1603;
const UInt32 ERROR_SUCCESS = 0;
ISuiteExtension GetExtensionFromDispatch(object pDispatch)
{
if (Marshal.IsComObject(pDispatch) == false)
throw new ContextMarshalException("Invalid dispatch object passed to CLR method");
return (ISuiteExtension)pDispatch;
}
public UInt32 IsUniqueName(object pDispatch)
{
try
{
List<string> currentVirtualDirectories = GetApplicationNames();
ISuiteExtension suiteExtension = GetExtensionFromDispatch(pDispatch);
var name = suiteExtension.get_Property("APPLICATION_NAME");
suiteExtension.set_Property("IS_UNIQUE_APPLICATION_NAME", (!currentVirtualDirectories.Contains(name)).ToString());
}
catch (System.ContextMarshalException)
{
return ERROR_INSTALL_FAILURE;
}
return ERROR_SUCCESS;
}
public List<string> GetApplicationNames()
{
List<string> currentVirtualDirectories = new List<string>();
ServerManager mgr = new ServerManager();
foreach (Site s in mgr.Sites)
{
foreach (Application app in s.Applications)
{
currentVirtualDirectories.Add(app.Path.Replace('/', ' ').Trim());
}
}
return currentVirtualDirectories.Where(s => !string.IsNullOrWhiteSpace(s)).Distinct().ToList();
}
}
}
Is there any way to force closed any instance of a specific file on Server 2012?
For arguments sake, call the link to the file D:\Shares\Shared\Sharedfile.exe
I have C# code which copies the latest version of a program into this directory, which often has people using the program during the day. Closing open file handles and replacing the file has worked well, because it just means next time the user opens the program they have all the latest changes.
However it gets a little monotonous doing this from computer management on the server, so I was wondering if there was a way to do it from C# code?
I tried this but it doesn't have the right overloads that I need. Perhaps is there something in the File class I could use?
EDIT The C# code to close the file will NOT be running on the host server.
[DllImport("Netapi32.dll", SetLastError=true, CharSet = CharSet.Unicode)]
public static extern int NetFileClose(string servername, int id);
You can wrap the NetFileClose API, which also requires wrapping the NetFileEnum API. Something like this:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
struct FILE_INFO_3 {
public int fi3_id;
public int fi3_permissions;
public int fi3_num_locks;
public string fi3_pathname;
public string fi3_username;
}
static class NativeMethods {
[DllImport("netapi32.dll", CharSet = CharSet.Unicode)]
public extern static int NetFileEnum(
string servername,
string basepath,
string username,
int level,
out IntPtr bufptr,
int prefmaxlen,
out int entriesread,
out int totalentries,
ref IntPtr resume_handle
);
[DllImport("netapi32.dll", CharSet = CharSet.Unicode)]
public extern static int NetFileClose(string servername, int fileid);
[DllImport("netapi32.dll")]
public extern static int NetApiBufferFree(IntPtr buffer);
}
Pretty ugly signatures, right? Let's wrap a little managed love around it.
class RemoteFile {
public RemoteFile(string serverName, int id, string path, string userName) {
ServerName = serverName;
Id = id;
Path = path;
UserName = userName;
}
public string ServerName { get; }
public int Id { get; }
public string Path { get; }
public string UserName { get; }
public void Close() {
int result = NativeMethods.NetFileClose(ServerName, Id);
if (result != 0) {
// handle error decently, omitted for laziness
throw new Exception($"Error: {result}");
}
}
}
IEnumerable<RemoteFile> EnumRemoteFiles(string serverName, string basePath = null) {
int entriesRead;
int totalEntries;
IntPtr resumeHandle = IntPtr.Zero;
IntPtr fileEntriesPtr = IntPtr.Zero;
try {
int result = NativeMethods.NetFileEnum(
servername: serverName,
basepath: basePath,
username: null,
level: 3,
bufptr: out fileEntriesPtr,
prefmaxlen: -1,
entriesread: out entriesRead,
totalentries: out totalEntries,
resume_handle: ref resumeHandle
);
if (result != 0) {
// handle error decently, omitted for laziness
throw new Exception($"Error: {result}");
}
for (int i = 0; i != entriesRead; ++i) {
FILE_INFO_3 fileInfo = (FILE_INFO_3) Marshal.PtrToStructure(
fileEntriesPtr + i * Marshal.SizeOf(typeof(FILE_INFO_3)),
typeof(FILE_INFO_3)
);
yield return new RemoteFile(
serverName,
fileInfo.fi3_id,
fileInfo.fi3_pathname,
fileInfo.fi3_username
);
}
} finally {
if (fileEntriesPtr != IntPtr.Zero) {
NativeMethods.NetApiBufferFree(fileEntriesPtr);
}
}
}
And now closing a particular file is easy: close all open instances of it.
foreach (var file in EnumRemoteFiles(server, path)) {
Console.WriteLine($"Closing {file.Path} at {file.ServerName} (opened by {file.UserName})");
file.Close();
}
Please note that this code is not quite production ready, in particular, the error handling sucks. Also, in my tests, it appears file paths can be subject to some mangling, depending on exactly how they're opened (like a file appearing as C:\\Path\File, with an extra backslash after the drive root) so you may want to do normalization before validating the name. Still, this covers the ground.
My app is running on a computer that is joined to an Active Directory domain. Is there a way to get that domain's DNS name using WinAPI methods? I want something that will work even if there are no DNS servers or Domain Controllers available.
Right now, the only way I can find is through the Domain property of the Win32_ComputerSystem WMI class:
using System.Management;
public class WMIUtility
{
public static ManagementScope GetDefaultScope(string computerName)
{
ConnectionOptions connectionOptions = new ConnectionOptions();
connectionOptions.Authentication = AuthenticationLevel.PacketPrivacy;
connectionOptions.Impersonation = ImpersonationLevel.Impersonate;
string path = string.Format("\\\\{0}\\root\\cimv2", computerName);
return new ManagementScope(path, connectionOptions);
}
public static ManagementObject GetComputerSystem(string computerName)
{
string path = string.Format("Win32_ComputerSystem.Name='{0}'", computerName);
return new ManagementObject(
GetDefaultScope(computerName),
new ManagementPath(path),
new ObjectGetOptions()
);
}
public static string GetDNSDomainName(string computerName)
{
using (ManagementObject computerSystem = GetComputerSystem(computerName))
{
object isInDomain = computerSystem.Properties["PartOfDomain"].Value;
if (isInDomain == null) return null;
if(!(bool)isInDomain) return null;
return computerSystem.Properties["Domain"].Value.ToString();
}
}
}
The only thing I can find in WinAPI is the NetGetJoinInformation method, which returns the NetBIOS domain name:
using System.Runtime.InteropServices;
public class PInvoke
{
public const int NERR_SUCCESS = 0;
public enum NETSETUP_JOIN_STATUS
{
NetSetupUnknownStatus = 0,
NetSetupUnjoined,
NetSetupWorkgroupName,
NetSetupDomainName
}
[DllImport("netapi32.dll", CharSet = CharSet.Unicode)]
protected static extern int NetGetJoinInformation(string lpServer, out IntPtr lpNameBuffer, out NETSETUP_JOIN_STATUS BufferType);
[DllImport("netapi32.dll", SetLastError = true)]
protected static extern int NetApiBufferFree(IntPtr Buffer);
public static NETSETUP_JOIN_STATUS GetComputerJoinInfo(string computerName, out string name)
{
IntPtr pBuffer;
NETSETUP_JOIN_STATUS type;
int lastError = NetGetJoinInformation(computerName, out pBuffer, out type);
if(lastError != NERR_SUCCESS)
{
throw new System.ComponentModel.Win32Exception(lastError);
}
try
{
if(pBuffer == IntPtr.Zero)
{
name = null;
}
else
{
switch(type)
{
case NETSETUP_JOIN_STATUS.NetSetupUnknownStatus:
case NETSETUP_JOIN_STATUS.NetSetupUnjoined:
{
name = null;
break;
}
default:
{
name = Marshal.PtrToStringUni(pBuffer);
break;
}
}
}
return type;
}
finally
{
if(pBuffer != IntPtr.Zero)
{
NetApiBufferFree(pBuffer);
}
}
}
}
I think what you are looking for is GetComputerNameEx with ComputerNameDnsDomain as first parameter. But it's possible that you want one of the other types there. Still, GetComputerNameEx is the function you are looking for from how I understand the question.
PInvoke details here.
You raise a fair point in your comment, so sure, in this case LsaQueryInformationPolicy with PolicyDnsDomainInformation may be the better way to get the DNS name of the domain of which the computer is a member.
But it is a special case and your question didn't mention any such special cases. This should only ever be the case when the primary DNS suffix has been set and differs from the DNS domain name of which the machine is a member. For all practical purposes GetComputerNameEx will do exactly what you want.
I am evaluating Winnovative's PdfToText library and have run into something that concerns me.
Everything runs fine and I am able to extract the text content from a small 20k or less pdf immediately if I am running a console application. However, if I call the same code from the NUnit gui running it takes 15-25 seconds (I've verified it's PdfToText by putting a breakpoint on the line that extracts the text and hitting F10 to see how long it takes to advance to the next line).
This concerns me because I'm not sure where to lay blame since I don't know the cause. Is there a problem with NUnit or PdfToText? All I want to do is extract the text from a pdf, but 20 seconds is completely unreasonable if I'm going to see this behavior under certain conditions. If it's just when running NUnit, that's acceptable, but otherwise I'll have to look elsewhere.
It's easier to demonstrate the problem using a complete VS Solution (2010), so here's the link to make it easier to setup and run (no need to download NUnit or PdfToText or even a sample pdf):
http://dl.dropbox.com/u/273037/PdfToTextProblem.zip (You may have to change the reference to PdfToText to use the x86 dll if you're running on a 32-bit machine).
Just hit F5 and the NUnit Gui runner will load.
I'm not tied to this library, if you have suggestions, I've tried iTextSharp (way too expensive for 2 lines of code), and looked at Aspose (I didn't try it, but the SaaS license is $11k). But they either lack the required functionality or are way too expensive.
(comment turned into answer)
How complex are your PDFs? The 4.1.6 version of iText allows for a closed sourced solution. Although 4.1.6 doesn't directly have a text extractor it isn't too terribly hard to write one using the PdfReader and GetPageContent().
Below is the code I used to extract the text from the PDF using iTextSharp v4.1.6. If it seems overly verbose, it's related to how I'm using it and the flexibility required.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using iTextSharp.text.pdf;
namespace ClassLibrary1
{
public class PdfToken
{
private PdfToken(int type, string value)
{
Type = type;
Value = value;
}
public static PdfToken Create(PRTokeniser tokenizer)
{
return new PdfToken(tokenizer.TokenType, tokenizer.StringValue);
}
public int Type { get; private set; }
public string Value { get; private set; }
public bool IsOperand
{
get
{
return Type == PRTokeniser.TK_OTHER;
}
}
}
public class PdfOperation
{
public PdfOperation(PdfToken operationToken, IEnumerable<PdfToken> arguments)
{
Name = operationToken.Value;
Arguments = arguments;
}
public string Name { get; private set; }
public IEnumerable<PdfToken> Arguments { get; private set; }
}
public interface IPdfParsingStrategy
{
void Execute(PdfOperation op);
}
public class PlainTextParsingStrategy : IPdfParsingStrategy
{
StringBuilder text = new StringBuilder();
public PlainTextParsingStrategy()
{
}
public String GetText()
{
return text.ToString();
}
#region IPdfParsingStrategy Members
public void Execute(PdfOperation op)
{
// see Adobe PDF specs for additional operations
switch (op.Name)
{
case "TJ":
PrintText(op);
break;
case "Tm":
SetMatrix(op);
break;
case "Tf":
SetFont(op);
break;
case "S":
PrintSection(op);
break;
case "G":
case "g":
case "rg":
SetColor(op);
break;
}
}
#endregion
bool newSection = false;
private void PrintSection(PdfOperation op)
{
text.AppendLine("------------------------------------------------------------");
newSection = true;
}
private void PrintNewline(PdfOperation op)
{
text.AppendLine();
}
private void PrintText(PdfOperation op)
{
if (newSection)
{
newSection = false;
StringBuilder header = new StringBuilder();
PrintText(op, header);
}
PrintText(op, text);
}
private static void PrintText(PdfOperation op, StringBuilder text)
{
foreach (PdfToken t in op.Arguments)
{
switch (t.Type)
{
case PRTokeniser.TK_STRING:
text.Append(t.Value);
break;
case PRTokeniser.TK_NUMBER:
text.Append(" ");
break;
}
}
}
String lastFont = String.Empty;
String lastFontSize = String.Empty;
private void SetFont(PdfOperation op)
{
var args = op.Arguments.ToList();
string font = args[0].Value;
string size = args[1].Value;
//if (font != lastFont || size != lastFontSize)
// text.AppendLine();
lastFont = font;
lastFontSize = size;
}
String lastX = String.Empty;
String lastY = String.Empty;
private void SetMatrix(PdfOperation op)
{
var args = op.Arguments.ToList();
string x = args[4].Value;
string y = args[5].Value;
if (lastY != y)
text.AppendLine();
else if (lastX != x)
text.Append(" ");
lastX = x;
lastY = y;
}
String lastColor = String.Empty;
private void SetColor(PdfOperation op)
{
lastColor = PrintCommand(op).Replace(" ", "_");
}
private static string PrintCommand(PdfOperation op)
{
StringBuilder text = new StringBuilder();
foreach (PdfToken t in op.Arguments)
text.AppendFormat("{0} ", t.Value);
text.Append(op.Name);
return text.ToString();
}
}
}
And here's how I call it:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using iTextSharp.text.pdf;
namespace ClassLibrary1
{
public class PdfExtractor
{
public static string GetText(byte[] pdfBuffer)
{
PlainTextParsingStrategy strategy = new PlainTextParsingStrategy();
ParsePdf(pdfBuffer, strategy);
return strategy.GetText();
}
private static void ParsePdf(byte[] pdf, IPdfParsingStrategy strategy)
{
PdfReader reader = new PdfReader(pdf);
for (int i = 1; i <= reader.NumberOfPages; i++)
{
byte[] page = reader.GetPageContent(i);
if (page != null)
{
PRTokeniser tokenizer = new PRTokeniser(page);
List<PdfToken> parameters = new List<PdfToken>();
while (tokenizer.NextToken())
{
var token = PdfToken.Create(tokenizer);
if (token.IsOperand)
{
strategy.Execute(new PdfOperation(token, parameters));
parameters.Clear();
}
else
{
parameters.Add(token);
}
}
}
}
}
}
}