Time slip through our fingers!

三千山

    路漫漫其修远兮,吾将上下而求索

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

一、   需求

网上讲VS(以下VS均特指VS2005)自定义模板的不少,不过大部分都是讲C#或者Web开发的,什么export template的,都不适合C++工程,由于MS的确是减弱了对C++的支持,(这点没有人否认吧?)所以在VS中C++总是被遗忘在那个没有人理睬的角落,所以现在很多人宁愿还用着C++与MFC最辉煌的版本VC6.0,哪怕那个版本的C++这么不符合标准。。。。。既然MS不关心C++使用者,那就只有自己奋发图强啰,还好再怎么样,没有了VS,我们总还是有VIM+G+++GDB/Emacs的,没有了MFC我们还有Qt,GTK+的,何况个人用 Eclipse在Linux下做Qt程序的感觉也不错,闲话不说了,看看正题。

自定义工程模板是用途很大的,当你有一个简单的模板用于开发的时候,没有VS内部的支持时,你有两种办法,其一你将原有整个工程拷贝一份,然后改工程名,改名不说,要进VSS,还得改工程的GUID(不懂的就算了),其二是新建一个工程,然后一个一个添加文件,假如有自己的目录结构的时候,还得重新控制目录结构,工程大时也是异常麻烦,其实这些用上了VS自定义模板,一切都可以很简单,就像你进行Win32 SDK,MFC开发MS给你的模板一样。

 

二、   解决办法

1.新建文件

奥秘在Microsoft Visual Studio 8\VC\vcprojectitems中(Microsoft Visual Studio 8根据你安装目录而定)

新建的C++文件,主要是newc++file.cpp这个文件,目前是空的,你将其改成什么样,那就是什么样,比如,我需要在每个文件的头部添加 一大串的GPL说明,(不是我想,这是FSF规定的),那么就直接在此文件添加我的文件头即可,以后用add->add new item->C++ files时,就都会自动带着文件头出来了。。。更好用的是,我现在将此文件转为UTF8+Unix换行格式,那么以后新建的文件都是如此了。。。呵呵, 此谓之一劳永逸。

新建的头文件是hfile.h这个文件,如上更改,一劳永逸。事实上,我将上面的文件复制一份,重命名为hfile.h^^

普通文本文件由于常做Readme用,也改了。是text.txt这个文件。

 

2.授人以鱼不如授人以渔

这当然不是一个一个文件试出来的,也不是猜出来的,授人以鱼不如授人以渔,这里告诉大家怎么去自己摸索。上述三个文件有个共同特点,那就是可以通过右键 add->new item,那么我首先查看的就是new item了,这里,我的Visual C++下的下面有UI,Code,Data,Resource,Web,Utility,Property Sheets7个选项,与Microsoft Visual Studio 8\VC\vcprojectitems下面的7个目录及目录名一一对应,很明显了,这些选项由此7个目录中的内容控制的,首先看Code目录,一个 code.vsdir的文件,打开一看

..\NewC++File.cpp|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1075|10|#1076|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|9031|4096|#1077

..\HFile.h|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1078|15|#1079|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|9030|4096|#1080

..\IDLFile.idl|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1084|20|#1085|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|9035|4096|#1086

..\DEFFile.vsz|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1087|35|#1088|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|9036|4096|#1089

..\addmc++componentclass.vsz|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1236|85|#1237|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|9563|4096|#1238

..\installer.vsz|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1245|85|#1246|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|9564|4096|#1247

咋一看,乱码?2进制文件?的确像,再仔细看看,前面的一部分,那不就是菜单中有的Items项?一一对应的。再仔细看,发现其实前面的字符串都是 一个目录,指向父目录下的各个文件,其中前面两个就是.. \NewC++File.cpp,.. \HFile.h两个文件,那就是上一节中我发现的两个文件,对应新添加的C++文件和头文件。vsdir后面的东西是更详细的说明,长串的{}是 GUID,#xxx是通过ID来表示资源。但是这里我们不去详细了解了,想要详细了解的参看MSDN这里,同理,文本文件在Utility目录下的 VCUtilityItems.vsdir制定的,我就不多说了。

3. 自定义工程模板

新建工程中有个Custom Wizard选项,我将其命名为Win32OpenGLWizard。建立以后是一个完整的Wizard工程,天哪,一看,真复杂,我仅仅想建立一个简单 的C++工程嘛,至于这样复杂吗?很显然,MS设计VS的自定义模板的时候就是给其他软件开发商用的,根本没有考虑过个人使用-_-!因为其中包含了 HTML,CSS,JS….并不是每个人都是做网页的**。。。。作为用C++的我们,就知道想办法摸索摸索罗,符合我们的要求就好。要将引导框设计的多么完美我个人是没有什么希望了。所以建立Win32OpenGLWizard工程时,用户的UI选择就不需要了吧,直接通过名字就好。

首先利用刚才新建的Wizard去建立一个工程,(会出现在New Project的Wizard下,实际的文件放在 Microsoft Visual Studio 8\VC\vcprojects中)发现我们主要关注的是Template Files下的两个文件,那就是生成后工程会包含的文件。尝试一下。

在template Files下添加main.cpp,修改Readme.txt,实际操作时请将文件添加到\Templates\1033目录下面去,并且手动修改Templates.inf添加进main.cpp。新建工程后果然可行--(在我的vs2005里成功了一次,以后就在用类似的模板建立工程时就出现了添加文件的错误,试了一下vs2008中也是一样,而且在三台电脑上做同样的测试都以失败告终)。

4. 修改自定义工程模板

有个问题是Readme.txt在Source File目录下,而main.cpp跑到Source Files外面去了。作为半个完美主义者,虽然工程已经能编译通过,但是还是有点不爽,我希望进一步改进,那么下一步看看Source Files是哪里规定的罗,在default.js中可以看到

 1 function AddFilters(proj)
2
3 {
4
5 try
6
7 {
8
9 // Add the folders to your project
10
11 var strSrcFilter = wizard.FindSymbol('SOURCE_FILTER');
12
13 var group = proj.Object.AddFilter('Source Files');
14
15 group.Filter = strSrcFilter;
16
17 }
18
19 catch(e)
20
21 {
22
23 throw e;
24
25 }
26
27 }



此函数,已经明白一半了,此函数不就是寻找匹配的过滤文字,然后将其加入Source Files中去嘛。就看SOURCE_FILTER是什么symbol了

这里分两种情况:

无wizard UI

假如没有添加Wizards UI可以在添加的wizard工程下看到一个vsz文件,我这里如下:

 

VSWIZARD 7.0

Wizard=VsWizard.VsWizardEngine.9.0

Param="WIZARD_NAME = Win32OpenGL"

Param="ABSOLUTE_PATH = D:\MyDocument\Visual Studio 2008\WizardTemplate\Win32OpenGL\Win32OpenGL"

Param="FALLBACK_LCID = 1033"

Param="WIZARD_UI = FALSE"

Param="SOURCE_FILTER = txt"



这就是一个简单的类INI文件,详细信息可以参考MSDN这里。我们关心的自然是SOURCE_FILTER参数,改成cpp,竟然没有效果,好像就是这个样子,怎么改也没有效果,目前没有效果的原因不明(google、baidu都没找到)。但是虽然不知道此js 的wizard.FindSymbol的实现方法,但是我们还是可以用暴力解决!呵呵,将上述js函数改成如下形式:

 1 function AddFilters(proj)
2
3 {
4
5 try
6
7 {
8
9 // Add the folders to your project
10
11 //var strSrcFilter = wizard.FindSymbol('SOURCE_FILTER');
12
13 var strSrcFilter = 'cpp';
14
15 var group = proj.Object.AddFilter('Source Files');
16
17 group.Filter = strSrcFilter;
18
19 }
20
21 catch(e)
22
23 {
24
25 throw e;
26
27 }
28
29 }



就好了。我得意的笑啊,我得意的笑^^对于MS奇怪的失灵,有的时候暴力也是必须的。

有wizard UI

假如添加了UI,MS就要考虑你在wizard UI中改变此Symbo的可能了,会在HTML\1033\default.htm这个UI管理文件下看到

<SYMBOL NAME='SOURCE_FILTER' TYPE=text VALUE='txt'></SYMBOL>

改之

<SYMBOL NAME='SOURCE_FILTER' TYPE=cpp VALUE='cpp'></SYMBOL>

有效。

再次创建工程,cpp文件已经在Source Files中了,ReadMe.txt也死出去了,以后再需要头文件什么的也一样处理就好了。

5.接近完美

好了吗?已经很好了,但是作为3/4个完美主义者,我还有有点想改的地方,那就是我平时建工程,很简单的工程主文件与工程名一直,这样万一哪天想全部拷贝到一起管理也方便,但是按上述方式文件将全部是main.cpp,解决之,电脑上没有咋程序员解决不了的事情。

看上述js脚本,如下函数:

 1 function GetTargetName(strName, strProjectName)
2
3 {
4
5 try
6
7 {
8
9 // TODO: set the name of the rendered file based on the template filename
10
11 var strTarget = strName;
12
13 if (strName == 'readme.txt')
14
15 strTarget = 'ReadMe.txt';
16
17 if (strName == 'sample.txt')
18
19 strTarget = 'Sample.txt';
20
21 return strTarget;
22
23 }
24
25 catch(e)
26
27 {
28
29 throw e;
30
31 }
32
33 }



再看看它的使用,就知道此处就是我们需要修改的地方,实际上MS已经考虑了这样的情况了,我们不需要暴力^^改成如下内容:

 1 function GetTargetName(strName, strProjectName)
2
3 {
4
5 try
6
7 {
8
9 // TODO: set the name of the rendered file based on the template filename
10
11 var strTarget = strName;
12
13 if (strName == 'readme.txt')
14
15 strTarget = 'ReadMe.txt';
16
17 if (strName == 'main.cpp')
18
19 strTarget = strProjectName + ".cpp";
20
21 return strTarget;
22
23 }
24
25 catch(e)
26
27 {
28
29 throw e;
30
31 }
32
33 }



测试,OK!

三、修改工程的信息

Miscellaneous Files下有个default.vcproj改成自己的工程文件(my.vcproj),用模板建立的工程居然没有自己定义的工程信息,我滴个去。我找找找,在筛选器Script Files下的脚本文件default.js中发现

 1 function CreateCustomProject(strProjectName, strProjectPath)
2
3 {
4
5 try
6
7 {
8
9 var strProjTemplatePath = wizard.FindSymbol('PROJECT_TEMPLATE_PATH');
10
11 var strProjTemplate = '';
12
13 strProjTemplate = strProjTemplatePath + '\\default.vcproj';//在这里修改工程文件名为你该了后的工程名my.vcproj
14
15
16
17 var Solution = dte.Solution;
18
19 var strSolutionName = "";
20
21 if (wizard.FindSymbol("CLOSE_SOLUTION"))
22
23 {
24
25 Solution.Close();
26
27 strSolutionName = wizard.FindSymbol("VS_SOLUTION_NAME");
28
29 if (strSolutionName.length)
30
31 {
32
33 var strSolutionPath = strProjectPath.substr(0, strProjectPath.length - strProjectName.length);
34
35 Solution.Create(strSolutionPath, strSolutionName);
36
37 }
38
39 }
40
41
42
43 var strProjectNameWithExt = '';
44
45 strProjectNameWithExt = strProjectName + '.vcproj';
46
47
48
49 var oTarget = wizard.FindSymbol("TARGET");
50
51 var prj;
52
53 if (wizard.FindSymbol("WIZARD_TYPE") == vsWizardAddSubProject) // vsWizardAddSubProject
54
55 {
56
57 var prjItem = oTarget.AddFromTemplate(strProjTemplate, strProjectNameWithExt);
58
59 prj = prjItem.SubProject;
60
61 }
62
63 else
64
65 {
66
67 prj = oTarget.AddFromTemplate(strProjTemplate, strProjectPath, strProjectNameWithExt);
68
69 }
70
71 return prj;
72
73 }
74
75 catch(e)
76
77 {
78
79 throw e;
80
81 }
82
83 }



发现是一如既往的不行,那就是工程文件没放对地方,接着找,我发现Microsoft Visual Studio 8\VC\VCWizards下有个defaul.vcproj文件而且内容和我的模板工程中的是一致的,我就把自己的工程文件拷进去人后再用模板建工程,呵呵这下貌似一切正常了,可是发现如果自己的工程文件中设置的输出文件的输出位置和中间文件的输出位置始终都是$(ConfigurationName)这个应该是控制脚本的问题,果然在脚本文件default.js中找到了如下

 1 function AddConfig(proj, strProjectName)
2
3 {
4
5 try
6
7 {
8
9 var config = proj.Object.Configurations('Debug');
10
11 config.IntermediateDirectory = '$(ConfigurationName)';//注释掉
12
13 config.OutputDirectory = '$(ConfigurationName)';// 注释掉
14
15
16
17 var CLTool = config.Tools('VCCLCompilerTool');
18
19 // TODO: Add compiler settings
20
21
22
23 var LinkTool = config.Tools('VCLinkerTool');
24
25 // TODO: Add linker settings
26
27
28
29 config = proj.Object.Configurations('Release');
30
31 config.IntermediateDirectory = '$(ConfigurationName)';//注释掉
32
33 config.OutputDirectory = '$(ConfigurationName)';//注释掉
34
35
36
37 var CLTool = config.Tools('VCCLCompilerTool');
38
39 // TODO: Add compiler settings
40
41
42
43 var LinkTool = config.Tools('VCLinkerTool');
44
45 // TODO: Add linker settings
46
47 }
48
49 catch(e)
50
51 {
52
53 throw e;
54
55 }
56
57 }



原来MS也够暴力的,把四行注释掉后一切都正常了。

四、后记

到此自己建立的模板总算可以将就着用了,可是如果在Readme.txt添加中文的话新建在我的机器上用模板建立的工程中这些中文会是乱码这个没有搞明白;还有就是不能给工程添加默认的文件,这个肯定是可以添加的但是现在出现添加不上的情况还没有找到解决的办法。其他的就基本没有什么问题了,凑合用吧。以后再仔细研究。

此过程发狂的得不到MSDN满篇.Net的帮助,又难领悟广大C#网民的旁敲侧击,独自在VS的漆黑中摸索,逢JS大山则开路,逢HTML大石则劈之,屡次撞壁,失败数回,叹MS之弃cpper至此,捶胸顿足,奋发自强,吐血三升,乃作此文,以兹纪念。

 

此文部分摘自雨夜水之精灵的百度空间,连接地址http://hi.baidu.com/419836321/blog/item/2a9615221450e94aad34deba.html

posted on 2012-03-22 20:21  xueye9  阅读(716)  评论(0)    收藏  举报
@Baldwin