65.9K
CodeProject 正在变化。 阅读更多。
Home

Visual Studio 2010 的 OpenGL 自定义向导

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.86/5 (6投票s)

2010年8月5日

CPOL

3分钟阅读

viewsIcon

62580

downloadIcon

2425

本文是关于“如何在 Visual Studio 2010 上制作 OpenGL 自定义向导?”的指南

OpenGL_Custom_Wizard_Project_2.png

OpenGL_Custom_Wizard.png

引言

本文介绍了使用 MFC 自定义向导在 Visual Studio 2010 中创建自定义向导和 OpenGL 自定义向导的方法。许多人对 Visual Studio 2010 中的自定义向导有疑问。本文解释了“如何在 Visual Studio 2010 中使用 OpenGL 创建自定义向导?”。

背景

之前在 "Visual Studio .NET 中 OpenGL 的自定义向导" 中,我解释了 Visual Studio 2003/2005 的自定义向导。 Visual Studio 2008 与 Visual Studio 2003/2005 之间没有区别。 Visual Studio 2010 环境与 Visual Studio 2008 非常相似。但是,Visual Studio 2010 环境非常多变。

首先,项目 XML 文件格式从 *.vcproj 变为 *.vcxproj。 其次,“项目属性”非常多变。

概述

您必须将源代码从 zip 文件复制到 Visual Studio 2010 文件夹。如果您将 Visual Studio 2010 安装到 *C* 盘,那么您的 Visual Studio 2010 路径是 *C:\Program Files\Microsoft Visual Studio 10.0*。

  1. 您可以在 *C:\Program Files\Microsoft Visual Studio 10.0\VC* 中找到 Visual C++ 文件夹。
  2. 将 zip 文件中的文件夹“vcprojects”和“VCwizards”复制到 VC。

然后,您就可以创建自定义向导了。

创建自定义向导

如果您了解自定义向导的创建过程,则必须使用“文件 > 新建 > 项目”菜单在 Visual Studio 2010 中创建一个自定义向导项目。 然后,您可以在 Visual C++ 项目列表中选择自定义向导项目。 最后,单击“完成”按钮。

Visual_C___Custom_Wizard.png

恭喜! 您已成功创建了您的第一个自定义向导文件。

Visual_Studio_2010.png

更改您的自定义向导文件

自定义向导文件由 HTML 文件、图像文件、杂项文件、脚本文件和模板文件组成。

首先,HTML 文件使用 HTML 标记创建向导主框架。 Visual Studio 2010 默认创建一个 *default.htm* 文件。 但是,此文件对您的 OpenGL 自定义向导没有用。 因此,您必须从解决方案资源管理器中删除 *default.htm* 文件。 接下来,源文件从本文 zip 文件导入 HTM 文件。

C:\Program Files\Microsoft Visual Studio 10.0\VC\VCWizards\AppWiz\
	OpenGL\Application\html\1033

html.png

其次,当 Visual Studio 2010 自定义向导创建默认自定义向导时,图像文件为空。 图像文件用于在您编辑自定义向导时创建图像屏幕。 OpenGL 向导图像文件用于帮助选择理解 Alpha、Fog、Perspective 等属性。 所有文件都使用 Visual Studio 2010 解决方案资源管理器插入到图像文件中。

C:\Program Files\Microsoft Visual Studio 
	10.0\VC\VCWizards\AppWiz\OpenGL\Application\images

image.png

第三,杂项文件是自定义向导属性的属性。 例如,样式文件是 HTML 上的向导样式。

 C:\Program Files\Microsoft Visual Studio 10.0\VC\VCWizards\1033\NewStyle.css

例如,在 HTM 上

<HEAD>
<TITLE>'OpenGL Wizard'</TITLE>
<META NAME="vs_targetSchema" CONTENT="http://schemas.microsoft.com/intellisense/ie5">
<LINK ID="LINKURL" REL="stylesheet" HREF="../../../../../1033/NewStyles.css">
<!--  -->
<!-- The SYMBOL tag is used to set the default values for the user-defined symbols.-->
<!--  -->
<SYMBOL NAME='WIZARD_DIALOG_TITLE' TYPE=text VALUE='OpenGL Wizard'></SYMBOL>
<SYMBOL NAME='SAMPLE_CHECKBOX' TYPE=checkbox VALUE=true></SYMBOL>
<SYMBOL NAME='SAMPLE_RADIO_OPTION1' TYPE=checkbox VALUE=true></SYMBOL>
<SYMBOL NAME='SAMPLE_RADIO_OPTION2' TYPE=checkbox VALUE=false></SYMBOL>
<SYMBOL NAME='SAMPLE_LISTBOX' TYPE=select-one VALUE='option1'></SYMBOL>
<SYMBOL NAME='SOURCE_FILTER' TYPE=text VALUE='txt'></SYMBOL>
<SYMBOL NAME='APP_TYPE_SUMMARY' TYPE=text VALUE='//TODO: Application summary'></SYMBOL>
</HEAD>

*.vsdir 扩展名文件是您在 Visual Studio 中创建一个新项目时的自定义向导文件路径。

C:\Program Files\Microsoft Visual Studio 10.0\VC\vcprojects\OpenGL\OpenGL_Wizard.vsdir

*vsdir* 文件内容

. ..\OpenGL_Wizard.vsz|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|
	#2000|100|#2001|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|0|4096|#1154

*.vsz 扩展名文件是一个属性文件,您的自定义向导脚本在其中定义。

C:\Program Files\Microsoft Visual Studio 10.0\VC\vcprojects\OpenGL_Wizard.vsz

*vsz* 文件内容

VSWIZARD 7.0
Wizard=VsWizard.VsWizardEngine.10.0
Param="WIZARD_NAME = Application"
Param="RELATIVE_PATH = VCWizards\AppWiz\OpenGL"
Param="CONSOLE_TYPE_ONLY = false"
Param="WIZARD_ID = 103"

*Template.inf* 文件是自定义向导的文件列表。 此 INF 扩展名文件对于来自模板文件信息的新项目非常重要。

C:\Program Files\Microsoft Visual Studio 10.0\VC\VCWizards\
	AppWiz\OpenGL\Application\templates\1033.Template.inf

*Template.inf* 文件内容

readme.txt
sample.txt
stdafx.h
stdafx.cpp
OpenGLView.h
OpenGLView.cpp
OpenGLDoc.h
OpenGLDoc.cpp
OpenGL.h
OpenGL.cpp
MainFrm.h
MainFrm.cpp
OpenGL.rc
targetver.h
Res/OpenGL.ico
Res/OpenGL.rc2
Res/OpenGLDoc.ico
Res/Toolbar.bmp
Res/OpenGL.manifest
Resource.h
earth.bmp

misellaneous.png

编辑自定义向导脚本文件

*C:\Program Files\Microsoft Visual Studio 10.0\VC\VCWizards\AppWiz\OpenGL\Application\scripts\1033\default.js* 文件非常~ 非常~ 非常~ 重要。 此文件在 Visual Studio 2003/2005/2008 和 Visual Studio 2010 之间相似。 但是,脚本文件是不同的项目扩展名、目标 .NET Framework 版本以及 Visual Studio 2010 上的附加配置属性。 但其他的与 Visual Studio 2003/2005/2008 中相同。

function OnFinish(selProj, selObj)
{
 try
 {
  var strProjectPath = wizard.FindSymbol('PROJECT_PATH');
  var strProjectName = wizard.FindSymbol('PROJECT_NAME');

  selProj = CreateCustomProject(strProjectName, strProjectPath);
  AddConfig(selProj, strProjectName);
  AddFilters(selProj);

  var InfFile = CreateCustomInfFile();
  AddFilesToCustomProj(selProj, strProjectName, strProjectPath, InfFile);
  PchSettings(selProj);
  InfFile.Delete();

  selProj.Object.Save();
 }
 catch(e)
 {
  if (e.description.length != 0)
   SetErrorInfo(e);
  return e.number
 }
}

function CreateCustomProject(strProjectName, strProjectPath)
{
 try
 {
  var strProjTemplatePath = wizard.FindSymbol('PROJECT_TEMPLATE_PATH');
  var strProjTemplate = '';
  strProjTemplate = strProjTemplatePath + '\\default.vcxproj';

  var Solution = dte.Solution;
  var strSolutionName = "";
  if (wizard.FindSymbol("CLOSE_SOLUTION"))
  {
   Solution.Close();
   strSolutionName = wizard.FindSymbol("VS_SOLUTION_NAME");
   if (strSolutionName.length)
   {
    var strSolutionPath = strProjectPath.substr
	(0, strProjectPath.length - strProjectName.length);
    Solution.Create(strSolutionPath, strSolutionName);
   }
  }

  var strProjectNameWithExt = '';
  strProjectNameWithExt = strProjectName + '.vcxproj';

  var oTarget = wizard.FindSymbol("TARGET");
  var prj;
  if (wizard.FindSymbol("WIZARD_TYPE") == vsWizardAddSubProject)  // vsWizardAddSubProject
  {
   var prjItem = oTarget.AddFromTemplate(strProjTemplate, strProjectNameWithExt);
   prj = prjItem.SubProject;
  }
  else
  {
   prj = oTarget.AddFromTemplate(strProjTemplate, strProjectPath, strProjectNameWithExt);
  }
  var fxtarget = wizard.FindSymbol("TARGET_FRAMEWORK_VERSION");
  if (fxtarget != null && fxtarget != "")
  {
      fxtarget = fxtarget.split('.', 2);
      if (fxtarget.length == 2)
   prj.Object.TargetFrameworkVersion = parseInt(fxtarget[0]) * 
				0x10000 + parseInt(fxtarget[1])
  }
  return prj;
 }
 catch(e)
 {
  throw e;
 }
}

function AddFilters(proj)
{
 try
 {
     // Add the folders to your project
     var group;
        
     group = proj.Object.AddFilter('Source Files');
        group.Filter = 'cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx';

     group = proj.Object.AddFilter('Header Files');
     group.Filter = 'h;hpp;hxx;hm;inl;inc;xsd';

     group = proj.Object.AddFilter('Resource Files');
     group.Filter = 'rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;
			jpe;resx;tiff;tif;png;wav';
 }
 catch(e)
 {
  throw e;
 }
}

function AddConfig(proj, strProjectName)
{
 try
 {
  var config = proj.Object.Configurations('Debug');
  config.CharacterSet = charSetMBCS;
  config.useOfMfc = useOfMfc.useMfcDynamic;

  var CLTool = config.Tools('VCCLCompilerTool');
  // TODO: Add compiler settings

  CLTool.DebugInformationFormat = debugEnabled; 
  CLTool.DebugInformationFormat = debugOption.debugEditAndContinue;
  CLTool.SuppressStartupBanner = true; 
  CLTool.RuntimeLibrary = runtimeLibraryOption.rtMultiThreadedDebugDLL; 
  CLTool.WarningLevel = warningLevelOption.warningLevel_3; 
  CLTool.Optimization = optimizeOption.optimizeDisabled;
  CLTool.MinimalRebuild = true;
  CLTool.DebugInformationFormat = debugOption.debugEditAndContinue;
  CLTool.PreprocessorDefinitions = "WIN32;_WINDOWS;_DEBUG";
  CLTool.UsePrecompiledHeader = pchOption.pchGenerateAuto; 

  var LinkTool = config.Tools('VCLinkerTool');
  // TODO: Add linker settings

  LinkTool.ProgramDatabaseFile = "$(OutDir)/$(ProjectName).pdb"; 
  LinkTool.GenerateDebugInformation = true;
  LinkTool.LinkIncremental = linkIncrementalYes; 
  LinkTool.OutputFile = "$(OutDir)/$(ProjectName).exe";
  LinkTool.SuppressStartupBanner=true;  // nologo
  LinkTool.AdditionalDependencies="opengl32.lib glu32.lib glut32.lib";
  LinkTool.SubSystem = subSystemOption.subSystemWindows;

  var MIDLTool = config.Tools('VCMIDLTool');
  MIDLTool.PreprocessorDefinitions = '_DEBUG';
  MIDLTool.MkTypLibCompatible = 'false';
  MIDLTool.ValidateParameters = 'false';

  var ResourceTool = config.Tools('VCResourceCompilerTool');  
  // TODO: Add Resource Compiler settings  
  ResourceTool.Culture = enumResourceLangID.rcEnglishUS;  
  ResourceTool.PreprocessorDefinitions = "_DEBUG";  
  ResourceTool.ResourceOutputFileName = "$(IntDir)/$(InputName).res"  

  config = proj.Object.Configurations('Release');
  config.CharacterSet = charSetMBCS; 
  config.useOfMfc = useOfMfc.useMfcDynamic;
  
  var CLTool = config.Tools('VCCLCompilerTool');
  // TODO: Add compiler settings

  CLTool.DebugInformationFormat = debugEnabled; 
  CLTool.DebugInformationFormat = debugOption.debugEnabled; 
  CLTool.SuppressStartupBanner = true; 
  CLTool.RuntimeLibrary = runtimeLibraryOption.rtMultiThreadedDLL; 
  CLTool.WarningLevel = warningLevelOption.warningLevel_3; 
  CLTool.Optimization = optimizeOption.optimizeMaximizeSpeed;
  CLTool.MinimalRebuild = true;
  CLTool.PreprocessorDefinitions = "WIN32;_WINDOWS;NDEBUG";
  CLTool.UsePrecompiledHeader = pchOption.pchGenerateAuto; 

  var LinkTool = config.Tools('VCLinkerTool');
  // TODO: Add linker settings

  LinkTool.ProgramDatabaseFile = "$(OutDir)/$(ProjectName).pdb"; 
  LinkTool.GenerateDebugInformation = true;
  LinkTool.LinkIncremental = linkIncrementalYes; 
  LinkTool.OutputFile = "$(OutDir)/$(ProjectName).exe";
  LinkTool.SuppressStartupBanner=true;  // nologo
  LinkTool.AdditionalDependencies="opengl32.lib glu32.lib glut32.lib";
  LinkTool.SubSystem = subSystemOption.subSystemWindows; 
  
  var MIDLTool = config.Tools('VCMIDLTool');
  MIDLTool.PreprocessorDefinitions = 'NDEBUG';
  MIDLTool.MkTypLibCompatible = 'false';
  MIDLTool.ValidateParameters = 'false';
  
  var ResourceTool = config.Tools('VCResourceCompilerTool');
  // TODO: Add Resource Compiler settings
  ResourceTool.Culture = enumResourceLangID.rcEnglishUS;
  ResourceTool.PreprocessorDefinitions = "";
  ResourceTool.ResourceOutputFileName = "$(IntDir)/$(InputName).res"
 }
 catch(e)
 {
  throw e;
 }
}

function PchSettings(proj)
{
 // TODO: specify pch settings
}

function DelFile(fso, strWizTempFile)
{
 try
 {
  if (fso.FileExists(strWizTempFile))
  {
   var tmpFile = fso.GetFile(strWizTempFile);
   tmpFile.Delete();
  }
 }
 catch(e)
 {
  throw e;
 }
}

function CreateCustomInfFile()
{
 try
 {
  var fso, TemplatesFolder, TemplateFiles, strTemplate;
  fso = new ActiveXObject('Scripting.FileSystemObject');

  var TemporaryFolder = 2;
  var tfolder = fso.GetSpecialFolder(TemporaryFolder);
  var strTempFolder = tfolder.Drive + '\\' + tfolder.Name;

  var strWizTempFile = strTempFolder + "\\" + fso.GetTempName();

  var strTemplatePath = wizard.FindSymbol('TEMPLATES_PATH');
  var strInfFile = strTemplatePath + '\\Templates.inf';
  wizard.RenderTemplate(strInfFile, strWizTempFile);

  var WizTempFile = fso.GetFile(strWizTempFile);
  return WizTempFile;
 }
 catch(e)
 {
  throw e;
 }
}

function GetTargetName(strName, strProjectName)
{
 try
 {
  // TODO: set the name of the rendered file based on the template filename
  var strTarget = strName;
  var strProjectName = wizard.FindSymbol('PROJECT_NAME');

  if (strName == 'readme.txt')
   strTarget = 'ReadMe.txt';

  if (strName == 'sample.txt')
   strTarget = 'Sample.txt';
   
  if (strName == 'stdafx.cpp')
   strTarget =  'stdafx.cpp';
 
  if (strName == 'stdafx.h')
   strTarget =  'stdafx.h'; 

  if (strName == 'OpenGL.h')
   strTarget =  strProjectName + '.h';  
   
  if (strName == 'OpenGL.cpp')
   strTarget =  strProjectName + '.cpp';  

  if (strName == 'MainFrm.h')
   strTarget =  'MainFrm.h';  
   
  if (strName == 'MainFrm.cpp')
   strTarget =  'MainFrm.cpp';    

  if (strName == 'OpenGLView.h')
   strTarget =  strProjectName + 'View.h';  
   
  if (strName == 'OpenGLView.cpp')
   strTarget =  strProjectName + 'View.cpp';   

  if (strName == 'OpenGLDoc.h')
   strTarget =  strProjectName + 'Doc.h';  
   
  if (strName == 'OpenGLDoc.cpp')
   strTarget =  strProjectName + 'Doc.cpp';   

  if (strName == 'OpenGL.rc')
   strTarget =  strProjectName + '.rc';

  if (strName == 'resource.h')
   strTarget =  'Resource.h';  
   
  if (strName == 'Res/OpenGL.ico')
   strTarget =  'Res/' + strProjectName + '.ico';     

  if (strName == 'earth.bmp')
   strTarget =  'earth.bmp';     

  if (strName == 'Res/OpenGL.rc2')
   strTarget =  'Res/' + strProjectName + '.rc2';
   
  if (strName == 'Res/OpenGLDoc.ico')
   strTarget =  'Res/' + strProjectName + 'Doc.ico';     
      
  if (strName == 'Res/OpenGL.manifest')
   strTarget =  'Res/' + strProjectName + '.manifest';       
  
  return strTarget; 
 }
 catch(e)
 {
  throw e;
 }
}

function AddFilesToCustomProj(proj, strProjectName, strProjectPath, InfFile)
{
 try
 {
  var projItems = proj.ProjectItems

  var strTemplatePath = wizard.FindSymbol('TEMPLATES_PATH');

  var strTpl = '';
  var strName = '';

  var strTextStream = InfFile.OpenAsTextStream(1, -2);
  while (!strTextStream.AtEndOfStream)
  {
   strTpl = strTextStream.ReadLine();
   if (strTpl != '')
   {
    strName = strTpl;
    var strTarget = GetTargetName(strName, strProjectName);
    var strTemplate = strTemplatePath + '\\' + strTpl;
    var strFile = strProjectPath + '\\' + strTarget;

    var bCopyOnly = false;  //"true" will only copy the file 
	// from strTemplate to strTarget without rendering/adding to the project
    var strExt = strName.substr(strName.lastIndexOf("."));
    if(strExt==".bmp" || strExt==".ico" || strExt==".gif" || 
			strExt==".rtf" || strExt==".css")
     bCopyOnly = true;
    wizard.RenderTemplate(strTemplate, strFile, bCopyOnly);
    proj.Object.AddFile(strFile);
   }
  }
  strTextStream.Close();
 }
 catch(e)
 {
  throw e;
 }
}

Visual Studio 向导插入

最后,如果您创建自定义向导项目,则必须构建此项目。 但是,如果您不创建自定义向导,则应将自定义向导插入到 Visual Studio 2010 向导列表。 *C:\Program Files\Microsoft Visual Studio 10.0\VC\vcprojects\vc.svdir* 文件是 Visual Studio 2010 的列表。 您必须更改 OpenGL 自定义向导文件的自定义向导安装路径。

ATL|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1041|10
vcNET|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1040|20
General|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1044|30
MFC|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1042|40
SmartDevice|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1045|50
Win32|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1043|60
Win32Console.vsz|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1204|10|
	#1205|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|0|4096|#1154
MFCAppWiz.vsz|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1161|20|
	#1162|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|0|4096|#1154
Win32Wiz.vsz|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1171|30|
	#1172|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|0|4096|#1154
EmptyProj.vsz|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1279|40|
	#1280|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|0|4096|#1154
ATLWiz.vsz|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1155|50|#1156|
	{1B027A40-8F43-11D0-8D11-00A0C91BC942}|0|4096|#1154
MFCDLLWiz.vsz|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1163|60|#1164|
	{1B027A40-8F43-11D0-8D11-00A0C91BC942}|0|4096|#1154
MC++WinApp.vsz|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1221|70|#1222|
	{1B027A40-8F43-11D0-8D11-00A0C91BC942}|0|4096|FormApp
MC++AppWiz.vsz|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1173|80|#1174|
	{1B027A40-8F43-11D0-8D11-00A0C91BC942}|0|4096|#1154
MC++EmptyProj.vsz|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1177|90|#1178|
	{1B027A40-8F43-11D0-8D11-00A0C91BC942}|0|4096|#1154
MakefileAppWiz.vsz|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1183|100|#1184|
	{1B027A40-8F43-11D0-8D11-00A0C91BC942}|0|4096|#1154
MFCCtlWiz.vsz|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1165|100|#1166|
	{1B027A40-8F43-11D0-8D11-00A0C91BC942}|0|4096|#1154
MC++ClassLib.vsz|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1175|100|#1176|
	{1B027A40-8F43-11D0-8D11-00A0C91BC942}|0|4096|#1154
MC++WinCtrlLib.vsz|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1243|100|#1244|
	{1B027A40-8F43-11D0-8D11-00A0C91BC942}|0|4096|#1154
SDWin32Wiz.vsz|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1404|100|#1405|
	{1B027A40-8F43-11D0-8D11-00A0C91BC942}|0|4096|#1154
SDATLWiz.vsz|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1400|100|#1401|
	{1B027A40-8F43-11D0-8D11-00A0C91BC942}|0|4096|#1154
SDMFCAppWiz.vsz|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1402|100|#1403|
	{1B027A40-8F43-11D0-8D11-00A0C91BC942}|0|4096|#1154
SDMFCCtlWiz.vsz|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1406|100|#1407|
	{1B027A40-8F43-11D0-8D11-00A0C91BC942}|0|4096|#1154
SDMFCDLLWiz.vsz|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1408|100|#1409|
	{1B027A40-8F43-11D0-8D11-00A0C91BC942}|0|4096|#1154
OpenGL_Wizard.vsz|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#2000|100|
	#2001|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|0|4096|#1154

兴趣点和历史记录

如果您想要详细说明,则必须查看我之前关于“Visual Studio .NET 中 OpenGL 的自定义向导”的文章。

© . All rights reserved.