I am attempting to programmatically add a test project to a solution. However when the code below executes I receive a File IO exception on the line "vhaSolution.GetProjectTemplate("TestProject.zip", "Csharp")". The error indicates that "he language specified is not supported by any of the installed packages". Does anyone have any idea what could be causing this?
public enum TestProjectType
{
Unit,
Acceptance,
Integration
}
public static void CreateTestProject(string fullyQualifiedSolutionFileName,string projectName,TestProjectType testProjectType)
{
#region Argument Validation
if (String.IsNullOrEmpty(fullyQualifiedSolutionFileName) || String.IsNullOrEmpty(fullyQualifiedSolutionFileName.Trim()))
{
throw new ArgumentNullException("fullyQualifiedSolutionFileName", "The solution file location is required.");
}
if (String.IsNullOrEmpty(projectName) || String.IsNullOrEmpty(projectName.Trim()))
{
throw new ArgumentNullException("projectName", "The project name is required.");
}
if (!File.Exists(fullyQualifiedSolutionFileName))
{
throw new ArgumentException(String.Format("The file {0} specified does not exist.", fullyQualifiedSolutionFileName));
}
if (testProjectType == null) testProjectType = TestProjectType.Unit;
#endregion
System.Type vsType = System.Type.GetTypeFromProgID("VisualStudio.DTE.8.0");
Object vs = System.Activator.CreateInstance(vsType, true);
EnvDTE80.DTE2 dte8Obj = (EnvDTE80.DTE2)vs;
Solution2 vhaSolution = (Solution2)dte8Obj.Solution;
vhaSolution.Open(fullyQualifiedSolutionFileName);
//TODO: Externalize company name
string cmpnyName = "Vha";
string testProjectName = String.Format("{0}.{1}.{2}{3}",cmpnyName,projectName,testProjectType.ToString(),"Test");
string testTemplateLocation = vhaSolution.GetProjectTemplate("TestProject.zip", "CSharp");
FileInfo rootSolutionFolder = new FileInfo(fullyQualifiedSolutionFileName);
//TODO: Externalize test directory name
string testDirName = String.Format("{0}\\{1}\\{2}\\{3}",rootSolutionFolder.DirectoryName,"test",testProjectType.ToString(),testProjectName);
if (!Directory.Exists(testDirName))
{
//may throw an exception if the dir can't be created...
Directory.CreateDirectory(testDirName);
}
Project vhaTestProj = vhaSolution.AddFromTemplate(testTemplateLocation,testDirName,testProjectName + ".proj",false);
vhaTestProj.Save(String.Format("{0}\\{1}.proj",testDirName , testProjectName));
}
I figured it out. I need to use the prog ID VisualStudio.DTE.9.0 so that it would point to the correct registry location for VS 2008.
Related
I have an visual studio 2015 extension which reads files from a DB and creates a solution and project from a template. The files are then added as ProjectItems to the project (type VSProject2).
I would like to save the files in a folder, together with the csproj and sln file so that one can open it later without the extension.
However, the folder which contains the files in the solution window, is empty on disk.
So I'm confused. I've tried to save the projectItems, but it still doesn't end up in die folder on disk.
I add the folder with variable name "foldername" to the project. Let's make it TimeAndAttendance. So on disk a folder TempProject is created and in that, a folder TimeAndAttendance. I would like the csproj file and the source files (added as ProjectItems) to be saved in that folder.
public void CreateSolution()
{
// This function creates a solution and adds a Visual C# Class library project to it.
try
{
Solution2 soln = (Solution2)visualStudioInstance.Solution;
String csTemplatePath;
Project projCS = null;
parameterWindowEventsList = new Dictionary<EnvDTE.Window, WindowEvents>();
String csPrjPath = Path.Combine(Config.Cluster.WorkingPath, "TempProject");
if (Directory.Exists(csPrjPath))
{
DirectoryInfo di = new DirectoryInfo(csPrjPath);
foreach (var dir in di.GetDirectories())
{
dir.Attributes = FileAttributes.Normal;
FileInfo fi = new FileInfo(dir.FullName);
fi.IsReadOnly = false;
dir.Delete(true);
}
di.Attributes = FileAttributes.Normal;
di.Delete(true);
}
csTemplatePath = soln.GetProjectTemplate("TAEngineTemplate.zip", "CSharp");
// Create a new C# Class Library project using the template obtained above.
soln.AddFromTemplate(csTemplatePath, csPrjPath, "TAEngineProject", false);
foreach (Project p in soln.Projects)
{
if (String.Compare(p.Name, "TAEngineProject") == 0)
{
projCS = p;
break;
}
}
System.Windows.Forms.Application.DoEvents();
if (projCS != null)
{
taEngineProject = projCS.Object as VSProject2;
}
taEngineProject.References.Add(Path.Combine(Config.Engine.EngineBinPath, "Engines.TimeAndAttendance.dll"));
taEngineProject.References.Add("System.Data.DLL");
taEngineProject.References.Add("System.Xml.DLL");
taEngineProject.References.Add("System.Core.dll");
taEngineProject.Project.ProjectItems.AddFolder(folderName);
taEngineProject.Project.Save(null);
}
catch (SystemException ex)
{
log.Error("Problem with creating solution. " + ex);
}
}
The last line
taEngineProject.Project.Save(null);
doesn't seem to do anything.
The following is where I load a source file as a ProjectItem. Any improvement on how to do it without the try-catch functionality is also welcome. I inherited this code and just shook my head the first time I saw it, but I don't know how to improve it either. :-(
public ProjectItem LoadAsProjectItem(string sourcePath)
{
if (taEngineProject != null)
{
string filename = sourcePath.Substring(sourcePath.LastIndexOf("\\") + 1);
ProjectItem retItem;
ProjectItem projFolderItem = taEngineProject.Project.ProjectItems.Item(folderName);
try
{
retItem = projFolderItem.ProjectItems.Item(filename);
}
catch (Exception)
{
retItem = projFolderItem.ProjectItems.AddFromFile(sourcePath);
}
return retItem;
}
return null;
}
i want to find out that mspaint shortcut exist in desktop or no? if its exist, user score is 7 else its 0. i use this code:
string path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
if (Directory.Exist (path + #"\mspaint.exe"))
{
Controller.ExamController.AddExam(1, n, 7, time, Session.currentUserId);
}
else
{
Controller.ExamController.AddExam(1, n, 0, time, Session.currentUserId);
}
but anyway the result is "0".but this code works for directory and folders and return 7.
also i try "File.Exist" but it has same problem.
How can i check a shortcut of specific program exist in desktop or no?
if (questionNumber == 2)
{
string path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
var list = Directory.EnumerateFiles(path);
foreach (var v in list)
{
var extension = Path.GetExtension(v);
if (extension.Equals(".lnk", StringComparison.InvariantCultureIgnoreCase))
{
WshShell shell = new WshShell();
IWshShortcut link = (IWshShortcut)shell.CreateShortcut(v);
if (Path.GetFileName(link.TargetPath).Equals("mspaint.exe", StringComparison.InvariantCultureIgnoreCase))
{
Controller.ExamController.AddExam(1, n, 7, time, Session.currentUserId);
}
else
{
Controller.ExamController.AddExam(1, n, 0, time, Session.currentUserId);
}
}
}
}
when i use this, its ok, but it returns 0 for not exist and return both of 0 and 7 for exist
Shortcut is just another type of files, as MSDN says:
When the user creates a shortcut to an object by choosing the Create
Shortcut command from the object's shortcut menu, Windows stores the
information it needs to access the object in a link file—a binary file
that has the .lnk file name extension.
It mean that you should refer exactly to shortcut: with exact name and .lnk extension.
You need to check shortcut for example like this:
File.Exist(Path.Combine(path, "Paint.lnk"))
But in my opinion right solution is to get all shortcuts from desktop and examine target path for each one for mspaint.exe path.
For reading shortcut information read this SO post: Get target of shortcut folder
This needs explicit coding and you cannot look for names of the file in deskTop since it can be changed to anything because its just a short cut,
Include the COM addin reference Windows Script Host Object Model - Interop.IWshRuntimeLibrary
using IWshRuntimeLibrary;
public string test()
{
string path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
var list = Directory.EnumerateFiles(path);
foreach(var v in list)
{
var extension = Path.GetExtension(v);
if (extension.Equals(".lnk", StringComparison.InvariantCultureIgnoreCase))
{
WshShell shell = new WshShell();
IWshShortcut link = (IWshShortcut) shell.CreateShortcut(v);
if (Path.GetFileName(link.TargetPath).Equals("mspaint.exe", StringComparison.InvariantCultureIgnoreCase))
{
return link.TargetPath;
}
}
}
return null;
}
A Shortcut is a special kind of file
A shortcut is a special kind of file. It contains data which points to a location (for example mspaint.exe), but that doesn't mean it needs to be named the same as the exe it's pointing to. For example, it can have a name of "HappyPaint.lnk" and point to "mspaint.exe".
Reading Shortcut Destination
Therefore you need to look for all "*.lnk" files on the desktop and read their destination paths. Here's how you can go about it:
First, add a reference to Microsoft Shell Controls And Automation:
Second, add some code along the lines of:
string desktopDirectoryPath = Environment.GetFolderPath(
Environment.SpecialFolder.DesktopDirectory);
string msPaintPath = Environment.ExpandEnvironmentVariables(
#"%windir%\system32\mspaint.exe");
// add reference to COM --> Microsoft Shell controls and Automation
Shell shell = new Shell();
Folder folder = shell.NameSpace(desktopDirectoryPath);
var shortcutFilePaths = Directory.GetFiles(desktopDirectoryPath, "*.lnk");
bool msPaintShortcutExists = false;
foreach (string shortcutFilePath in shortcutFilePaths)
{
FolderItem folderItem = folder.ParseName(Path.GetFileName(shortcutFilePath));
Shell32.ShellLinkObject link = (Shell32.ShellLinkObject) folderItem.GetLink;
var shortcutDestination = Environment.ExpandEnvironmentVariables(link.Path);
if (string.Compare(
msPaintPath, shortcutDestination, StringComparison.OrdinalIgnoreCase) == 0)
{
msPaintShortcutExists = true;
break;
}
}
if (msPaintShortcutExists)
{
Controller.ExamController.AddExam(1, n, 7, time, Session.currentUserId);
}
else
{
Controller.ExamController.AddExam(1, n, 0, time, Session.currentUserId);
}
Needs to be run in an STAThread
Note: In case an InvalidCastException with a message
Unable to cast COM object of type 'System.__ComObject' to interface type 'Shell32.Shell'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{286E6F1B-7113-4355-9562-96B7E9D64C54}' failed due to the following error: No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE)).
occurs on new Shell(); you're not running the code in an STAThread but it needs to be run in an STAThread. An easy work around is to add the following method:
private static void ExecuteInStaThread(Action a)
{
var thread = new Thread(() => a());
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
if (!thread.Join(TimeSpan.FromSeconds(30)))
{
thread.Abort();
}
}
and wrap the code in a call to it:
ExecuteInStaThread(() =>
{
string desktopDirectoryPath = ...
...
});
I need to check if the current user has write permissions inside the path. Here an example:
string save_path = #"C:\Windows\somefolder";
string my_dir = Path.DirectorySeparatorChar + "foobar";
//check if specific path are valid
if (!Directory.Exists(save_path)) { return; }
if (Directory.Exists(save_path + my_dir)) { return; }
if (canWriteOnPath(save_path)) {
Directory.CreateDirectory(save_path + my_dir);
} else {
//You are not allowed to save here OR not are launching this application as "administrator"
Directory.CreateDirectory(#"C:\Users\contoso\Documents\foobar");
}
solved in this question:
CurrentUserSecurity cus = new CurrentUserSecurity();
bool flag = cus.HasAccess(new DirectoryInfo(#"C:\Windows"), FileSystemRights.Write);
if (flag) {
//yes create that folder
Directory.CreateDirectory(Path.Combine(save_path, my_dir));
} else {
//NO YOU CANT
Directory.CreateDirectory(#"C:\Users\contoso\Documents\foobar");
}
The robust method would be to Try to create the directory and Catch any resulting exception.
The documentation for Directory.CreateDirectory lists the possible exceptions: IOException, UnauthorizedAccessException, ArgumentException, ArgumentNullException, PathTooLongException, DirectoryNotFoundException.
Although unlikely, it is possible that the permissions changed between your code checking that access is allowed and actually trying to create the directory.
I have a ClickOnce Publish Name that is different from the assembly name. For discussion purposes, it is "App 6.0". I set it in the Properties for my project. Is there any way to get this value from inside the program?
Add a reference to Microsoft.Build.Tasks.v4.0.dll, then run this:
if (null != AppDomain.CurrentDomain.ActivationContext)
{
DeployManifest manifest;
using (MemoryStream stream = new MemoryStream(AppDomain.CurrentDomain.ActivationContext.DeploymentManifestBytes))
{
manifest = (DeployManifest)ManifestReader.ReadManifest("Deployment", stream, true);
}
// manifest.Product has the name you want
}
else
{
// not deployed
}
The DeployManifest can also provide other useful info from your manifest, like Publisher or SupportUrl.
The answer can be found in ClickOnce Run at Startup. Essentially, you use InPlaceHostingManager to get the ClickOnce manifest and read it. It bugs me that it is an asynchronous method, but this is the only thing that has worked thus far. Simplifications are much appreciated. See the webpage for a description of DeploymentDescription.
var inPlaceHostingManager = new InPlaceHostingManager(ApplicationDeployment.CurrentDeployment.UpdateLocation, false);
inPlaceHostingManager.GetManifestCompleted += ((sender, e) =>
{
try
{
var deploymentDescription = new DeploymentDescription(e.DeploymentManifest);
string productName = deploymentDescription.Product;
***DoSomethingToYour(productName);***
// - use this later -
//var commandBuilder = new StartMenuCommandBuilder(deploymentDescription);
//string startMenuCommand = commandBuilder.Command;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + Environment.NewLine + ex.StackTrace);
}
});
ApplicationDeployment.UpdatedApplicationFullName Property
How can I get the location of the tnsnames.ora file by code, in a machine with the Oracle client installed?
Is there a windows registry key indicating the location of this file?
Some years ago I had the same problem.
Back then I had to support Oracle 9 and 10 so the code only takes care of those versions, but maybe it saves you from some research.
The idea is to:
search the registry to determine the oracle client version
try to find the ORACLE_HOME
finally get the tnsnames from HOME
public enum OracleVersion
{
Oracle9,
Oracle10,
Oracle0
};
private OracleVersion GetOracleVersion()
{
RegistryKey rgkLM = Registry.LocalMachine;
RegistryKey rgkAllHome = rgkLM.OpenSubKey(#"SOFTWARE\ORACLE\ALL_HOMES");
/*
* 10g Installationen don't have an ALL_HOMES key
* Try to find HOME at SOFTWARE\ORACLE\
* 10g homes start with KEY_
*/
string[] okeys = rgkLM.OpenSubKey(#"SOFTWARE\ORACLE").GetSubKeyNames();
foreach (string okey in okeys)
{
if (okey.StartsWith("KEY_"))
return OracleVersion.Oracle10;
}
if (rgkAllHome != null)
{
string strLastHome = "";
object objLastHome = rgkAllHome.GetValue("LAST_HOME");
strLastHome = objLastHome.ToString();
RegistryKey rgkActualHome = Registry.LocalMachine.OpenSubKey(#"SOFTWARE\ORACLE\HOME" + strLastHome);
string strOraHome = "";
object objOraHome = rgkActualHome.GetValue("ORACLE_HOME");
string strOracleHome = strOraHome = objOraHome.ToString();
return OracleVersion.Oracle9;
}
return OracleVersion.Oracle0;
}
private string GetOracleHome()
{
RegistryKey rgkLM = Registry.LocalMachine;
RegistryKey rgkAllHome = rgkLM.OpenSubKey(#"SOFTWARE\ORACLE\ALL_HOMES");
OracleVersion ov = this.GetOracleVersion();
switch(ov)
{
case OracleVersion.Oracle10:
{
string[] okeys = rgkLM.OpenSubKey(#"SOFTWARE\ORACLE").GetSubKeyNames();
foreach (string okey in okeys)
{
if (okey.StartsWith("KEY_"))
{
return rgkLM.OpenSubKey(#"SOFTWARE\ORACLE\" + okey).GetValue("ORACLE_HOME") as string;
}
}
throw new Exception("No Oracle Home found");
}
case OracleVersion.Oracle9:
{
string strLastHome = "";
object objLastHome = rgkAllHome.GetValue("LAST_HOME");
strLastHome = objLastHome.ToString();
RegistryKey rgkActualHome = Registry.LocalMachine.OpenSubKey(#"SOFTWARE\ORACLE\HOME" + strLastHome);
string strOraHome = "";
object objOraHome = rgkActualHome.GetValue("ORACLE_HOME");
string strOracleHome = strOraHome = objOraHome.ToString();
return strOraHome;
}
default:
{
throw new Exception("No supported Oracle Installation found");
}
}
}
public string GetTNSNAMESORAFilePath()
{
string strOracleHome = GetOracleHome();
if (strOracleHome != "")
{
string strTNSNAMESORAFilePath = strOracleHome + #"\NETWORK\ADMIN\TNSNAMES.ORA";
if (File.Exists(strTNSNAMESORAFilePath))
{
return strTNSNAMESORAFilePath;
}
else
{
strTNSNAMESORAFilePath = strOracleHome + #"\NET80\ADMIN\TNSNAMES.ORA";
if (File.Exists(strTNSNAMESORAFilePath))
{
return strTNSNAMESORAFilePath;
}
else
{
throw new SystemException("Could not find tnsnames.ora");
}
}
}
else
{
throw new SystemException("Could not determine ORAHOME");
}
}
On Windows, the most likely locations are either %ORACLE_HOME%/network/admin or %TNS_ADMIN% (or the TNS_ADMIN registry setting). These two cover almost every installation.
Of course it is possible to have a working Oracle client without this file. Oracle has bewildering array of networking options, and there are plenty of ways to achieve a working setup with using TNSNAMES. Depending on what you are trying to achieve here, your first port of call might be the sqlnet.ora file, which is also found in %ORACLE_HOME%/network/admin. This should contain a line that looks something like this:
NAMES.DIRECTORY_PATH= (LDAP, TNSNAMES, HOSTNAME)
TNSNAMES means it will use the TNSNAMES.ora file (second in this case). LDAP and HOSTNAME are alternate ways of resolving the database. If there is no TNSNAMES the TNSNAMES.ora file will be ignored if it exists in the right place.
In C# / .NET this should get you the environment variables:
Environment.GetEnvironmentVariable("ORACLE_HOME");
Environment.GetEnvironmentVariable("TNS_ADMIN");
List<string> logicalDrives = Directory.GetLogicalDrives().ToList();
List<string> result = new List<string>();
foreach (string drive in logicalDrives)
{
Console.WriteLine("Searching " + drive);
DriveInfo di = new DriveInfo(drive);
if(di.IsReady)
result = Directory.GetFiles(drive, "tnsnames.ora", SearchOption.AllDirectories).ToList();
if (0 < result.Count) return;
}
foreach (string file in result) { Console.WriteLine(result); }
According to the net that depends on the version of Oracle and the working directory of the SQL*Plus process. This first link tells you the environment variable that specifies the base path for some versions (7, 8, 9i) of Oracle. If you use a different one, I'm sure there's a similar way to get to the system directory.
If you spread versions of these files all over the place though and rely on the "look for a local tnsnames.ora first" behaviour of the client, then I guess you're out of luck.
I'm not a C# or a Windows guy for that matter so hopefully this helps. The tnsnames.ora file should be located in:
ORACLE_HOME\network\admin
If an alternate location has been specified, it should be available via the TNS_ADMIN registry key.
See this link for more information on how Oracle handles tns names on Windows.