有没有办法在vs2012中的命令行中包含项目?
我问的原因是因为每当我使用其他IDE(如ST3)或从Photoshop等保存文件时,包含我添加到项目文件夹中的任何新文件都非常令人沮丧。
我正在使用Grunt进行大量的缩小,连接,在我的角度脚本上运行ngmin等。有一个grunt-shell插件允许grunt任务运行shell命令(我已经用它来解锁锁定TFS的文件)。所以我想我可以创建一个任务,为我添加的任何新文件(通过用grunt-watch观看某个文件夹)为我做项目中的包含。
答案 0 :(得分:6)
这是使用PowerShell的解决方案。它有点长,但我保证它有效。我测试了很多。
首先,简单的部分。以下是从命令提示符运行脚本的方法。
powershell -File C:\AddExistingItem.ps1 -solutionPath "C:\Test.sln" -projectName "TestAddItem" -item "C:\Test.txt"
现在可怕的部分,AddExistingItem.ps1:
param([String]$solutionPath, [String]$projectName, [String]$item)
#BEGIN: section can be removed if executing from within a PowerShell window
$source = @"
namespace EnvDteUtils
{
using System;
using System.Runtime.InteropServices;
public class MessageFilter : IOleMessageFilter
{
//
// Class containing the IOleMessageFilter
// thread error-handling functions.
// Start the filter.
public static void Register()
{
IOleMessageFilter newFilter = new MessageFilter();
IOleMessageFilter oldFilter = null;
CoRegisterMessageFilter(newFilter, out oldFilter);
}
// Done with the filter, close it.
public static void Revoke()
{
IOleMessageFilter oldFilter = null;
CoRegisterMessageFilter(null, out oldFilter);
}
//
// IOleMessageFilter functions.
// Handle incoming thread requests.
int IOleMessageFilter.HandleInComingCall(int dwCallType,
System.IntPtr hTaskCaller, int dwTickCount, System.IntPtr
lpInterfaceInfo)
{
//Return the flag SERVERCALL_ISHANDLED.
return 0;
}
// Thread call was rejected, so try again.
int IOleMessageFilter.RetryRejectedCall(System.IntPtr
hTaskCallee, int dwTickCount, int dwRejectType)
{
if (dwRejectType == 2)
// flag = SERVERCALL_RETRYLATER.
{
// Retry the thread call immediately if return >=0 &
// <100.
return 99;
}
// Too busy; cancel call.
return -1;
}
int IOleMessageFilter.MessagePending(System.IntPtr hTaskCallee,
int dwTickCount, int dwPendingType)
{
//Return the flag PENDINGMSG_WAITDEFPROCESS.
return 2;
}
// Implement the IOleMessageFilter interface.
[DllImport("Ole32.dll")]
private static extern int
CoRegisterMessageFilter(IOleMessageFilter newFilter, out
IOleMessageFilter oldFilter);
}
[ComImport(), Guid("00000016-0000-0000-C000-000000000046"),
InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
interface IOleMessageFilter
{
[PreserveSig]
int HandleInComingCall(
int dwCallType,
IntPtr hTaskCaller,
int dwTickCount,
IntPtr lpInterfaceInfo);
[PreserveSig]
int RetryRejectedCall(
IntPtr hTaskCallee,
int dwTickCount,
int dwRejectType);
[PreserveSig]
int MessagePending(
IntPtr hTaskCallee,
int dwTickCount,
int dwPendingType);
}
}
"@
Add-Type -TypeDefinition $source
[EnvDTEUtils.MessageFilter]::Register()
#END: section can be removed if executing from within a PowerShell window
$IDE = New-Object -ComObject VisualStudio.DTE
$IDE.Solution.Open("$solutionPath")
$project = $IDE.Solution.Projects | ? { $_.Name -eq "$projectName" }
$project.ProjectItems.AddFromFile("$item") | Out-Null
$project.Save()
$IDE.Quit()
#BEGIN: section can be removed if executing from within a PowerShell window
[EnvDTEUtils.MessageFilter]::Revoke()
#END: section can be removed if executing from within a PowerShell window
95%的代码只允许您从命令提示符运行。如果您直接在PowerShell中编写和运行代码,则可以将其删除并直接转到$IDE = New-Object -ComObject VisualStudio.DTE
。
Here是一篇博文,解释了为什么需要这些可怕的东西 here是同一件事的另一个,但在C#中。
另一件值得注意的事情。我尝试使用EnvDTE程序集,就像在.net中一样,但我一直收到COM注册错误。一旦我开始使用COM对象直接一切正常。我对COM的了解不够充分猜测为什么会这样。
编辑
如果在尝试从命令提示符运行脚本时收到此错误:
然后你需要先运行它(你应该只需要运行一次。)
powershell -command "Set-ExecutionPolicy -ExecutionPolicy RemoteSigned"
Here是对该命令正在做什么的一个很好的,深入的解释。
答案 1 :(得分:4)
您可以手动编辑项目文件以添加文件。
项目文件具有基于xml的格式,您可以编辑它。尝试使用grunt-text-replace进行编辑。
您可以替换
</Project>
与
<ItemGroup>
<Compile Include="PythonProjectFactory.cs" />
</ItemGroup>
</Project>
答案 2 :(得分:3)
你可以创建一个小的exe来为你处理这个问题:
using System.IO;
using Microsoft.Build.Evaluation;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.VersionControl.Client;
namespace AddTfsItem
{
class Program
{
static void Main(string[] args)
{
var projectFile = args[0];
var projectDirectory = Path.GetDirectoryName(projectFile);
var sourceFile = args[1];
var itemType = args.Length > 2 ? args[2] : "Compile";
var workspaceInfo = Workstation.Current.GetLocalWorkspaceInfo(projectFile);
using (var server = new TfsTeamProjectCollection(workspaceInfo.ServerUri))
{
var workspace = workspaceInfo.GetWorkspace(server);
workspace.PendEdit(projectFile);
using (var projectCollection = new ProjectCollection())
{
var project = new Project(projectFile, null, null, projectCollection);
project.AddItem(itemType, sourceFile);
project.Save();
}
workspace.PendAdd(Path.Combine(projectDirectory, sourceFile));
}
}
}
}
C:\ Projects \ Test的结构:
用法:AddTfsItem.exe C:\Projects\Test\Test.csproj SomeFolder\Tester.cs
注意该文件必须是相对于.csproj文件的。
答案 3 :(得分:2)
我知道这不是完整的解决方案,我还没有测试过,但它可能有所帮助。
首先,我搜索了一个Powershell解决方案并发现了这个问题:
他们使用EnvDTE包含Visual Studio core automation的对象和成员的COM库。
我找不到任何资源如何使用它,除非来自CodeProject Exporing EnvDTE。
Project project;
//path is a list of folders from the root of the project.
public void AddFromFile(List<string> path, string file) {
ProjectItems pi = project.ProjectItems;
for (int i = 0; i < path.Count; i++) {
pi = pi.Item(path[i]).ProjectItems;
}
pi.AddFromFile(file);
}
//path is a list of folders from the root of the project.
public void AddFolder(string NewFolder, List<string> path) {
ProjectItems pi = project.ProjectItems;
for (int i = 0; i < path.Count; i++) {
pi = pi.Item(path[i]).ProjectItems;
}
pi.AddFolder(NewFolder,
EnvDTE.Constants.vsProjectItemKindPhysicalFolder);
}
//path is a list of folders from the root of the project.
public void DeleteFileOrFolder(List<string> path, string item) {
ProjectItems pi = project.ProjectItems;
for (int i = 0; i < path.Count; i++) {
pi = pi.Item(path[i]).ProjectItems;
}
pi.Item(item).Delete();
}
因为您想使用Grunt来自动执行任务。您可以查看Edge - .NET for Node.js。
require('edge');
...
var fileAdder = edge.func(/*
using EnvDTE;
using EnvDTE80;
using EnvDTE90;
using EnvDTE100;
using VSLangProj;
using VsLangProj80;
using VsLangProj90;
using VsLangProj100;
async (dynamic input) => {
// The C# code for adding the File to the project
}
*/);
grunt.registerTask('addFileVS',
'Adds new files to Visual Studio Project',
function (solutionname, projectname, filename){
var input = {
solution: solutionname,
project: projectname,
file: filename
};
fileAdder(input, function(error, results {...}));
});
答案 4 :(得分:0)
您还可以针对项目文件运行powershell脚本。我们长期使用它。
<强> AddContentToProject.ps1 强>
# Calling convension:
# AddContentToProject.PS1 "Mycsproj.csproj", "MyFolder/MyFile.txt"
param([String]$path, [String]$include)
$proj = [xml](Get-Content $path)
[System.Console]::WriteLine("")
[System.Console]::WriteLine("AddItemToProject {0} on {1}", $include, $path)
# Create the following hierarchy
# <Content Include='{0}'>
# </Content>
$xmlns = "http://schemas.microsoft.com/developer/msbuild/2003"
$itemGroup = $proj.CreateElement("ItemGroup", $xmlns);
$proj.Project.AppendChild($itemGroup);
$contentNode = $proj.CreateElement("Content", $xmlns);
$contentNode.SetAttribute("Include", $include);
$itemGroup.AppendChild($contentNode)
$proj.Save($path)
然后使用powershell
运行它.\AddContentToProject.ps1 "Mycsproj.csproj" "MyFolder/MyFile.txt"
或者从命令提示符
powershell -noexit "& ""C:\my_path\AddContentToProject.ps1"""