专注于互联网--专注于架构

最新标签
网站地图
文章索引
Rss订阅

首页 »DotNet » 反斜杠:.NET中的对引号和反斜杠 \\和一不同的解释规则 »正文

反斜杠:.NET中的对引号和反斜杠 \\和一不同的解释规则

来源: 发布时间:星期三, 2008年9月10日 浏览:40次 评论:0
最近发现在使用.NET开发的命令行工具的对引号和反斜杠\\和一般命令行程序有着不同的解释规则。 www. 举例来说,如果你在命令行下输入:
C:\\>tool“C:\\ProgramFiles\\”


实际上传入的参数是C:\\ProgramFiles”。其实这里不仔细看可能发现不了问题。在原来的命令行中,第一个双引号代表一个参数的开始/结束,后面\\”因为.NET的解释规则不同,代表实际的双引号,而非参数的开始/结束,因此最后的结果会多出一个双引号,并且缺少一个反斜杠。
内部,CLR使用CommandLineToArgvW来分析程序的命令行分离出各个参数,这个函数有着特殊的解释规则:
<!--[if!supportLists]-->1.<!--[endif]-->2n个反斜杠后面跟一个双引号代表n个反斜杠
<!--[if!supportLists]-->2.<!--[endif]-->2n+1个反斜杠后面跟一个双引号代表n个反斜杠加一个”
<!--[if!supportLists]-->3.<!--[endif]-->N个反斜杠后面不跟双引号直接代表n个反斜杠
这个规则比较绕,用例子的方式来解释就是:
命令行参数实际参数
“C:\\ProgramFiles\\”C:\\ProgramFiles”
“C:\\ProgramFiles\\\\”C:\\ProgramFiles\\
“C:\\ProgramFiles\\\\\\”C:\\ProgramFiles\\”

因此,正确的方式是第二个,也就是”C:\\ProgramFiles\\\\”。

事实上,CLR内部并没有直接调用CommandLineToArgvw,而是直接实现了一个有着同等功能的函数SegmentCommandLine。在Rotor的源代码中可以找到它的实现,位于sscli20\\clr\\src\\utilcode\\util.cpp。CLR的主函数_CorExeMain在执行主函数之前会调用CorCommandLine::SetArgvW,这个函数会调用SegmentCommandLine来分析命令行(经过简化):

//Setargvwfromcommandline
/*static*/
HRESULTCorCommandLine::SetArgvW(LPCWSTRlpCommandLine)
{


HRESULThr=S_OK;
if(!m_ArgvW){
//分析命令行
m_ArgvW=SegmentCommandLine(lpCommandLine,&m_NumArgs);

//CLR特有的命令行处理,主要是和ClickOnce有关的
if(m_ArgvW)
hr=ParseCor();
else
hr=E_OUTOFMEMORY;
}

returnhr;
}



真正在执行Main主函数的时候,ClassLoader::RunMain函数则会调用CorCommandLine::GetArgvW获得之前分析得到的参数列表,并创建对应的托管String数组并传递给Main(经过简化): [Page]
/*static*/
HRESULTClassLoader::RunMain(MethodDesc*pFD,
shortnumSkipArgs,
INT32*piRetVal,
PTRARRAYREF*stringArgs/*=NULL*/)
{

wzArgs=CorCommandLine::GetArgvW(&cCommandArgs);

//创建一个托管数组
StrArgArray=(PTRARRAYREF)AllocateObjectArray((cCommandArgs-numSkipArgs),g_pStringClass);

//创建对应的托管字符串并赋给托管数组的每个元素
for(arg=numSkipArgs;arg<cCommandArgs;arg++){
STRINGREFsref=COMString::NewString(wzArgs[arg]);
StrArgArray->SetAt(arg-numSkipArgs,(OBJECTREF)sref);
}

MethodDescCallSitethreadStart(pFD);//准备调用MethodDesc指向的主函数(EntryPoint)

ARG_SLOTstackVar=ObjToArgSlot(StrArgArray);//将数组元素转为函数参数

*piRetVal=(INT32)threadStart.Call_RetArgSlot(&stackVar);//调用主函数(EntryPoint)

returnhr;
}


而最关键的SegmentCommandLine函数代码则如下:

//---------------------------------------------------------------------
//Splitsacommandlineintoargc/argvlists,usingtheVC7parsingrules.

相关文章

读者评论

  • 共0条 分0页

发表评论

  • 昵称:
  • 内容: