Category Archives: Win32 Programming

System.Runtime.InteropServices.ExternalException: Cannot execute a program. The command being executed was “C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\csc.exe” /noconfig /fullpaths @”C:\WINDOWS\TEMP\bld_39642\thr_114\seps7hdv.cmdline”.

上上周收到了一个bug说我们的tools在执行的时候出现了这样的错误: System.Runtime.InteropServices.ExternalException: Cannot execute a program. The command being executed was "C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\csc.exe" /noconfig /fullpaths @"C:\WINDOWS\TEMP\bld_39642\thr_114\seps7hdv.cmdline". 仔细看了一下,出错的程序师一个dotnet程序,但是程序里面从来没有调用csc的内容啊。这个程序是在一个很复杂的tools chain中被调用的。更奇怪的是,如果自己直接运行这个程序,配合正确的参数,却不会出现这个问题。只有当从tools chain中调用时,才会这样。而且只在xp和2k3上出现,vista和seven都没有问题。 拿到bug时有点儿天狗吃月无处下口的感觉,就去网上搜了一下,看到很多link,但是都没有实质内容,有一个倒是说到了可能是security的问题,但是那个只有在asp。net上才出现,我的又不是asp应用,应该没有关系。 虽然没有解决方案,但是调用csc原因倒是有人提及:如果使用Xml Serialization的话,DotNEt runtime会在运行时生成一小段code,并调用csc编译。这一小段code就是需要的XmlSerialization的代码。 有了这个原因,我就试着从根本上解决这个问题,据说有个SGen的tool可以生成对应的XmlSerialization dll,这样runtime就不会动态编译了,东西我倒是生成了,然后runtime死活就是不理我的东西,唉,也不知道是路径不对,文件名不对,还是version不对,process monitor也没有帮助,dotnet还是不熟啊,什么这方面的工具也没有。 没办法,要赶进度,只好另外寻找突破口。既然单独运行没问题,那就肯定是两种运行模式有些内容不一样,会是什么呢?我的第一反应就是环境变量!的确,通过插入一些脚本,我导出了从tool chain运行的时候的环境变量,跟单独运行果然差别很大啊。可是我怎么看,也看不出那个环境变量与这个是相关的。实在没办法,就把所有的导出的环境变量再导入当前环境,然后单独运行,果然出错,同样的错误,然后我就开始二分法,一半一半的去掉不同的变量,做了两步忽然意识到自己傻逼了,忘了环境变量数目的影响了。 网上一查,xp系列的环境变量限制是32k,vista和windows 7 的是64k。按这样说,我应该也能在vista上重现的,果然,在加了无数垃圾环境变量之后,出了同样的错误,还是vista先进,这次的错误信息明确的指出来环境变量块超过64k无法创建新进程!靠! 最后的总结,这个错误的原因嘛,就如它的提示信息所说,无法创建新进程,至于为什么无法创建嘛,原因很多了,安全是一个,环境变量是一个,你要把可执行程序删了,那也会出现同样的错误 Advertisements

Posted in Win32 Programming | Leave a comment

Windows 7的VirtualStore

这两天在windows 7上调一个bug,过程中出现了一个很有意思的事情。我的bug需要存一个文件到C:\Program Files\Zune\下面去。因为文件是另外一个程序的附件,我就直接右键,选择另存为,然后选择这个地址。一切正常,文件保存了,而且程序确实读到了这个文件。 然而后来因为别的问题,我打开了C:\Program Files\Zune目录,却惊奇的发现那个文件并不存在。开始以为是文件属性搞的鬼,在三试了几次后确认了他的确不存在。当时也没有在意,就自己直接从explorer里面有复制了一次,这次注意到了windows问我要admin权限来保存这个文件。确认之后,发现文件这次真的在了。 事到如此,也就算了,我也没有深究。但是后来另外一个bug要我存不同的内容到同样的文件里,考虑到上次的事情,这次我手工把这个文件先存到别的地方,然后用explorer复制过去,过程中同样要了我权限,覆盖了原来的内容。 不过文件保存了之后,我发现我的应用程序的行为怎么还是跟以前那个文件一样,不管我怎么修改这个文件,他还是能取到以前那个文件的内容。搞了几次,火了,祭起process monitor,观察了一下,发现我的应用程序读了两个地方,一个是C:\Program Files\Zune,然后又读了%USERPROFILE%\AppData\Local\VirtualStore\Program Files\Zune.而那下面居然有我以前存的文件。 后来折腾了一下发现,如果我从一个没有admin权限的程序去给C:\Program Files\Zune下面保存文件,windows不会提醒错误,而是偷偷的帮我转移的了这个所谓的 Virtual Store里面去。可以理解,现在有很多傻逼程序还是习惯把各种配置文件和临时文件保存在可执行文件所在的目录。Windows 7的这个feature显然是为了对付这些程序的。不知道这个feature是windows 7新出的呢还是Windows Vista的时候就有的。 再次诅咒那些到处乱放临时文件的应用程序的作者~~~~~~

Posted in Win32 Programming | 2 Comments

Unicode和system locale

我相信大多数中国的程序员都知道unicode对于多语言支持和全球化软件的重要性。但是如果问他们不用unicode会有什么后果,可能大多数人只会说,在某些系统上可能会出现乱码之类的现象。其实这只是一个最浅层次的影响,深层次的影响是什么呢?那就是你的程序根本就不工作,并且需要花很多的人力资源去查找发现并解决这个原本很容易避免的问题的根源。为什么这么说呢?因为我昨天晚上碰到了一个例子。 老婆最近在上课,其中有一门课是远程教育的,你买书,然后安装配套的软件,然后每天根据老师的email看书并在软件上完成作业。听起来很不错?是的,的确是这样子,除非你的软件有问题。 昨天晚上书和配套光盘终于到了,我帮老婆装软件,说实话,这是一个很屎的软件,好像是用director做的,安装程序是wise installer。运行安装程序,提示我安装,没有问题,装完了,没有任何出错提示,要求重启,好吧,重启之后,按照指示去开始菜单里,找到了该软件的快捷方式的子菜单,可是点进去一看,nothing!作为一个IT民工,俺自然想到创建快捷方式的那部分出错了,无所谓,咱是专家啊,直接去安装的目录找exe不就结了。打开安装目录,发现没有想要的可执行程序,但是有一个很可疑的临时文件,一看就知道是安装程序留下的,大小还不小。第一反应就是把它的扩展名修改成exe,果然,图标也出来了,没错,就是这个。看起来一切顺利,运行,没有问题,登录,也没有问题,然而到打开课程的时候报exception了。 因为最近在dogfood windows 7,以为他跟win7不兼容,于是又在我的xp的机器上装了一下,问题依旧。想想我老婆她们班怎么说也有几十号人吧,同样的软件,同样的版本,难道他们就没有遇到这个问题?想来想去,还是觉得安装程序就有问题了,于是又开始用universal extractor把程序的安装包自己解开,发现也没有问题啊,看着里面的内容跟我实际安装的一样。难道是光盘出错,某个字节恰好被搞错了?但是安装包一般都是压缩过的,一个字节出错基本上就不可能解压开了。应该不是这个问题,于是祭起process monitor (原来的File monitor),监视了一下安装程序,打算看看到底那个临时文件是怎么回事儿,个人感觉应该是安装程序重命名这个文件的时候出错了。很快,结果出来了,发现process monitor里面安装进程试图重命名这个文件,但是失败了,原因很简单,它企图重命名的新文件名里有个问号,这在windows的路径里面属于非法字符。 可是为什么呢?这个明显的错误,应该所有人都很容易发现,为什么没有人汇报这个问题呢?难道是我的电脑设置有问题?突然问好让我想起了MultiByteToWideChar里面的comment,对于无法转换的字符,会被替换成“?”!好了,知道原因了:我的系统因为要用网银,而某个银行的傻逼网银软件不支持unicode,所以必须把system locale设置成中文,所以久而久之我就养成了习惯,即便是英文系统,system locale也会在装系统的时候改成中文,肯定是这个原因。于是去控制面板,将其改回英文,重启,重装,一切搞定,再进去,没有任何问题了! 下面再来分析一下问题吧,猜猜这个软件为它的exe取的文件名是什么? XXX Pro™5 这里考虑到某些原因我隐藏掉了软件的名字,但是注意名字后面那个TM标志了吗?就是它搞出了问题!如果这一切都是unicode,那么很好,没有任何问题,但是或者这个wise installer不是unicode版本的,他只支持1252 codepage,或者是软件制作人指定名字的时候指定了ANSI version。所以TM标志的编码就是0x99。安装软件rename的时候会调用CreateFileA,也就是ansi版本的createfile,然后传入这个ansi版本的名字。但是系统还是用unicode的,所以系统就会有MultiByteToWideChar来试图把这个转换成unicode,但是MultiByteToWideChar需要一个codepage作为参数,因为这个是non-unicode程序,所以就去了ACP作为参数。ACP怎么解释呢?他就是system locale对应的codepage,在我机器上,就是936,简体中文的codepage。而在这个codepage下面是不存在”\x99\x35”这个组合的,于是MultiByteToWideChar把\x99\x35转换成了一个”?”!   当然问题不止这些,即使我手工把名字改过来,运行后某些地方还是出错,而这一起在system locale是英文的时候没有任何问题,这就说明这个软件本身其他地方还存在类似的问题。

Posted in Win32 Programming | 4 Comments

使用std::string容易犯的一个很难发现的bug

前一阵子同事说他的一段code老出AV,但是查不出来什么毛病,让我帮他看看。仔细看了半天才发现了这么一句: string s = "xxxx"; …. printf("%s", s); 他的本意是输出这个字符串,因为string有const char*的类型转换操作符所以他就没有写。可是却忘了printf是一个变参函数,后面的东西都是。。。里面的,这就意味这编译期间编译器根本不知道printf需要什么参数,编译器所生成的应该只是将这个对象的第一个dword压栈,然后调用printf。然后printf解析格式化字符串,发现s%后便试图按照const char*去解释对应的参数。 这样如果string的memory layout中第一个dword不是所对应的字符串的地址,那就可能出问题了 将其改成printf("%s", s.c_str())之后,就没有问题了。 后来问同事原来他的代码以前是用char *的,后来做了一次refactor,用string来代替所有的字符指针,便出现了这个问题。当时就想把这个问题写下来后来因为忙就忘记了,但是上周末跟另外一个同事改写他的代码的时候,又遇到了同样的问题,想想还是写下来留个纪念吧

Posted in Win32 Programming | 11 Comments

FONT的故事续:Create的时候到底用cell height 好还是char height好?

继上次学习了font的一些术语之后,今天终于发现了我遇到的问题的根源,归根到底就是我们自己create font的时候是用正值呢还是用负值?其实就是用cell height还是char height? 为什么会存在这个问题,自然是因为windows平台下,这两种值创建font的效果是不一样的.因为不同的font size,系统需要作一些scale,如果字体是点阵的或者true type字体中嵌入有几套点阵字体,他就回去寻找一个最佳匹配,问题也就出在这个最佳匹配上面.具体到font engine是如何实现这个匹配我不知道,但是一个小程序可以显示他们的区别 这个小程序会创建10个字体,大小依次增长一个点,然后画一个字符串,下面是在smartphone上的截图: 第一次,用的是cell height 第二次,我们使用char height 不去对比两幅图中字体的绝对大小,只看每一幅图中字体的相对大小,可以发现,在第一副中,对于有些字体大小,字体高度增加一点,实际上的字符并没有被放大,变化的只是internal leading, 这个可以用GetTextMetrics看到.而对于char height,因为我们指定了字符的高度,所以gdi就必须按照我们的制定去缩放,相反internal leading并没有变化,但是这样字体缩放之后效果就不是很好. 所以如果你希望字体看着舒服一些,并不需要强调同一UI里面字体的相对大小的话,那么cell height会好些,而如果你希望字体大小绝对符合你的指定,或者希望同一个UI里面字体有对比的大小字体,并且大小相邻一两个像素左右,那么char height应该是正确的选择.

Posted in Win32 Programming | Leave a comment

Windows里FONT相关的一些术语

估计很多人用过CreateFont系列的函数吧,那里面关于字体高度的指定可以为正,也可以为负,但是他们的区别是什么呢,反正我对于这块儿一直是稀里糊涂,今天刚好遇到了这样的问题,就顺便往下面挖了一下: MSDN上是这么说的,   lfHeight Specifies the height, in logical units, of the font’s character cell or character. The character height value (also known as the em height) is the character cell height value minus the internal-leading value. The font mapper … Continue reading

Posted in Win32 Programming | 2 Comments

神秘的TWAIN_32.dll

昨天John给我们演示Win32汇编代码跟踪时,选择了一个很好的例子:LoadLibraryA,通过跟踪发现了一个很好玩的东西。LoadLibraryA中硬编码了一段比较代码,如果你LoadLibrary的参数时TWAIN_32.dll,不含路径,它就会强制的帮你加上windows的路径,然后去load。   据说时为了保持向前兼容性,因为当时不知道哪个白痴决定的把这个dll放在了windows目录而不是system32目录里。   唉,一个白痴的决定,导致了几代的系统都得付出这样硬编码一段代码的代价。也不知道windows中有多少M的东西是为了向前兼容而存在的。  

Posted in Win32 Programming | Leave a comment