|
|
用户名:APOO 笔名:APOO 地区: 北京-北京 行业:本科 |
| 日 | 一 | 二 | 三 | 四 | 五 | 六 |
Python的控制台输出语句print的一个bug
Python 的 print 语句有一个很奇怪的 bug。它的功能是向控制台输出字符,这本身不是问题。但是 Python 内部是支持 Unicode 字符串的,而 Unicode 字符串在用 print 输出时 print 要进行一次从 Unicode 到 ANSI/MBCS 编码的编码,编码后才会以 8-bit 流输出结果。
编码就编码吧,这也是很正常的。对于控制台程序来说,输出可能被重定向到文本文件。如 果不指定编码,重定向时就不知道以何种 8-bit 字节流写入文本文件,所以,输出到控制台的东西理论上也应该是经过编码的 8-bit 流。综上所述,确实有必要进行一次 WCHAR 到 char 的转码。
但是问题在于,Python 的 print 语句在转码时,居然用的是 strict 规则。即,待输出字符串若含有当前代码页之外的字符,就会在转码过程中出现不可转码的文字,从而抛出 exception。print 语句又不处理这个 exception,导致一个平平常常 print 语句竟然会引起 Python 程序的异常!这简直是不可思议。
比如说你写了这么一段代码:
a = u'测试啊'
print a
然后把控制台切到某个不包含这些汉字的编码页例如 437,输入chcp 437。然后再运行这段程序,就会看到异常。实际上直接输出到控制台的是另外一种 UnicodeEncodeError 异常,因为控制台设置了代码 页,Python 会试图转码到那个代码页。而更典型的(使开发者发现问题的)异常通常是把输出重定向到文件时,看到的下面这个更典型的异常:
UnicodeEncodeError: 'ascii' codec can't encode character u'\xa1' in position 0-2: ordinal not in range(128)
注意,控制台直接输出有异常,重定向输出也会有异常。这两种异常在系统内部具体过程不同,但原理都是一样的。就是 python 遇到了它认为不能把
Unicode 字符编码成 8-bit 流的情况。区别在于,输出到控制台时,python 会试图按照控制台设置的代码页去编码,而重定向时干脆就按
ASCII
编码,那自然是只有128以内的字符才能显示出来。由此可以看出,输出到控制台时产生的异常更隐蔽,因为绝大部分程序员都是在一种编码下编码+
开发的,很少有考虑到这方面的情况。在一种编码下开发,写进代码的字符串,以及从文本读出来的字符串,通常也能在这个编码下在控制台输出,从而把问题的发
现推迟到了用户(使用了不同代码页)阶段,或是推迟到了重定向输出的时候(因为重定向默认用 ASCII 编码,字符集最小)。知道了原因,会觉得错误可以理解。
说句题外话,令我最不能理解的是,一个好好的 print 语句,输出字符串也不是 zero-terminated,不存在烫烫烫烫过了越到不可访问内存崩溃了的结果,竟然会导致程序异常!首先别跟我说让程序员去控制print 里字符串的内容,这有的时候程序根本控制不了。比如,读出一个文件并显示内容的时候。也别跟我说去 try-except,连 print 都失败了你叫程序员情何以堪啊?看来只能想想办法自己解决这个问题了。
首先要说明的是,既然事关控制台,要做
8-bit 流的输入输出,就没有完美的解决方案。我个人的建议是,在Windows下,一切字符串操作,都应该尽可能使用 WCHAR
及相关函数。遇到需要
跨平台和网络传输的情况,再使用UTC-8编码的char字符串。在与古老的 ANSI/MBCS 程序交互时,在严格限制的情况下使用该种编码的
char 字符串。尽管并没有完美的解决方案,在实际情况中,Windows 下 Python 程序也许应该可以有更好的表现。
解决方案一、最简单解决重定向异常的方法是:
import sys
reload(sys)
sys.setdefaultencoding("utf-8")
然后再输出就可以了。直接调sys.setdefaultencoding()这个函数是不行的,必须要reload一次。具体原因可以参见http://docs.python.org/library/sys.html,我就没有深入研究了。
这个不会影响控制台直接输出,只会影响重定向,所以最好是写 utf-8 反正连 Windows 的记事本都可以打开 UTF-8
的文本。当然这么做也有不足,就是如果某一个程序,调用了你写的 Python
程序,把输出重定向到它的窗口里,这时这个程序很可能是按系统默认编码去解码的,用户就看到一片乱码了。这个没什么好办法,要么外围程序做好点可以设置控
制台解码,要么你就只能获取一下当前控制台编码设置(不知道 Python 里有没有好方法,我可以用 Windows API
做到),当然这样的话就无法防止异常了……
解决方案二、用 print a.encode("gbk", "replace") 取代 print a:
对控制台来说,由于输出的是字节流,所以具体显示成什么字符,取决于控制台的代码页设置。输出重定向也是一样,取决于你打开文件的方式。如果打开文件发现乱码了,那你要说:一定是我打开的方式不对!
这个方案好处在于可以让程序完全像使用了 Windows ANSI 函数的程序那样工作。输入、输出全都是按某个特定编码来做的,仿佛程序内部固化的字符串就是按某个特定编码写的。不过,程序里有几千个 print 就得换几千次就不说了,万一你换漏了,又要出悲剧。
当
然,既然完全像一个 Windows ANSI 程序的行为,那么不可避免的问题就是乱码。假设你所有字符串都按 GBK
在输入输出时编码了,那如果用户设置的控制台代码页根本就不是 GBK 呢?又乱码了不是……而且既然我输入输出都是 GBK,干嘛程序内部还要用
Unicode 呢?大概就只是为了防止内部处理时即出现异常吧。
最关键的是这实在不是一个程序员的作风。就没有自动化一点的方案吗?
解决方案三、更改 sys.stdout 的编码:
既然问题出在 sys.stdout 的编码往往不能满足字符集需求上,为什么不直接更改它的编码呢?http://www.doughellmann.com/PyMOTW/codecs/ 提供了一种方案:
import sys, codecs
sys.stdout = codecs.getwriter('utf-8')(sys.stdout)
这
个方案的好处就是它同时影响控制台直接输出和重定向输出,比方案一强,已经达到了方案二的水平。不过它面临一个方案二没有而方案一还有的问题,就是如果设
置的不是 "utf-8",那么就有可能出 UnicodeEncodeError。如果设置的是 "utf-8",那就要面临配套设施不完善而看到的乱码问题。
最要命的是,其实你是根本无法在控制台设置成 cp65001 的情况下让程序正常运行的!这是方案二也会同样遇到的问题。假设我们设置了 utf-8,要想在控制台正常阅读输出结果,那也就要把控制台用 chcp 65001 设置成 UTF-8。但是,设置之后,python 会以为当前代码页叫 "cp65001",不认,会出这个错误:
LookupError: unknown encoding: cp65001
呃,好吧,这也是有办法可以解决的,出自 http://stackoverflow.com/questions/878972/windows-cmd-encoding-change-causes-python-crash:
import codecs
codecs.register(lambda name: name == 'cp65001' and codecs.lookup('utf-8') or None)
这样 Python 就认 "cp65001" 这个东西就是 "utf-8" 的别名了。这样,你就可以在控制台 chcp 65001 然后看到输出字符了。不过遗憾的是,这只是理论上的。实际上如果你 print a 的时候第一个字符不是纯 ASCII 的,即 Unicode 码在 128 以上,根本无法正常显示。我们不妨把前面学到的知识都拼起来,写一段代码,期望它能正常工作吧:
#coding=utf-8
a = u'测试啊'
import sys
reload(sys)
sys.setdefaultencoding("utf-8")
import codecs
codecs.register(lambda name: name == 'cp65001' and codecs.lookup('utf-8') or None)
print a.encode("utf-8", "replace")
实际上运行结果是:
???试啊Traceback (most recent call last):
File "C:\Python25\Test1.py", line 11, in
print a.encode("utf-8", "replace")
IOError: [Errno 2] No such file or directory
这 莫名其妙的 IOError 是怎么回事?而且字符串第一个字符也无法正常显示,会变成若干个“?”。该字符在 UTF-8 中是几个字节,就有几个“?”字符。我™想破了脑袋也想不出 Python 是怎么写出这样的 bug 来的!注意,不是说第一个字符是纯 ASCII 就可以了,只是那样做的话输出来的异常信息是可以看,但是异常还是有的。如果是用 sys.stdout = codecs.getwriter() 法直接 print a 的话,出现的错误是:
???试啊Traceback (most recent call last):
File "C:\Python25\Test1.py", line 13, in
print a
File "C:\Python25\lib\codecs.py", line 304, in write
self.stream.write(data)
IOError: [Errno 0] Error
所以实际上是根本没法用的。我测试的版本是 Python 2.5.2,不知道后续版本是否有改进。
而且还有一个问题是如果你 chcp 65001 之后,打过一些汉字或者用 type 显示过文件,就会发现怎么光标的位置都不对啊!换行也不对啊喂后面怎么好多东西超出去了看不到啊!
没 错恭喜你遇到了最头疼的问题!在 cp65001 下,并不像那些中国、日本、韩国的代码页下面那样区分全角和半角,所有的字符在计算光标的时候都占同样的宽度,但是字体渲染仍然正常。也就是说,如果(假 设一行设置的是 80 个字符)你在一行里写了 80 个汉字,那么前 40 个渲染的时候就已经把整行占满了,可是没有自动换行,自动换行要到 80 列才有,所以后 40 个汉字就看不见了。
坑爹呀。
遗憾的是这还根本没有解决办法。要想让全角字符正确地占两个半角字符的宽度,就只能用一些支持这个特性的代码页,比如 cp936,就是 GBK。当然,这样就不能显示全部 Unicode 字符了,万一有用户输入了这个,就只能被替换成 ? 或者其它什么东西了。
所以说,只要还跟该死的 char 字节流打交道,跟 stdout 打交道,就没法有一个完美方案。
解决方案四、彻底不使用stdout:
这 堆乱七八糟的事情从根本上来说是因为控制台的 stdout 只能接受 8-bit 字节流,也就是 char,所以才有了这么多有的没的编码问题。如果能够让 python 在用 print 的时候底层使用一个接受 WCHAR 的函数来做事,也许事情就有很大转机。
事实上,还是在 http://stackoverflow.com/questions/5109970/linux-python-encoding-a-unicode-string-for-print 就有一篇终极解决方案。它用接受 WCHAR 的 Windows API 做控制台输出,而同时把重定向交由原有方式处理,在兼顾重定向的情况下,实现了控制台下最完美的输出方案。
首先请看代码:
import sys
if sys.platform == "win32":
import codecs
from ctypes import WINFUNCTYPE, windll, POINTER, byref, c_int
from ctypes.wintypes import BOOL, HANDLE, DWORD, LPWSTR, LPCWSTR, LPVOID
original_stderr = sys.stderr
# If any exception occurs in this code, we'll probably try to print it on stderr,
# which makes for frustrating debugging if stderr is directed to our wrapper.
# So be paranoid about catching errors and reporting them to original_stderr,
# so that we can at least see them.
def _complain(message):
print >>original_stderr, isinstance(message, str) and message or repr(message)
# Work around .
codecs.register(lambda name: name == 'cp65001' and codecs.lookup('utf-8') or None)
# Make Unicode console output work independently of the current code page.
# This also fixes .
# Credit to Michael Kaplan
# and TZΩTZIOY
# .
try:
#
# HANDLE WINAPI GetStdHandle(DWORD nStdHandle);
# returns INVALID_HANDLE_VALUE, NULL, or a valid handle
#
#
# DWORD WINAPI GetFileType(DWORD hFile);
#
#
# BOOL WINAPI GetConsoleMode(HANDLE hConsole, LPDWORD lpMode);
GetStdHandle = WINFUNCTYPE(HANDLE, DWORD)(("GetStdHandle", windll.kernel32))
STD_OUTPUT_HANDLE = DWORD(-11)
STD_ERROR_HANDLE = DWORD(-12)
GetFileType = WINFUNCTYPE(DWORD, DWORD)(("GetFileType", windll.kernel32))
FILE_TYPE_CHAR = 0x0002
FILE_TYPE_REMOTE = 0x8000
GetConsoleMode = WINFUNCTYPE(BOOL, HANDLE, POINTER(DWORD)) \
(("GetConsoleMode", windll.kernel32))
INVALID_HANDLE_VALUE = DWORD(-1).value
def not_a_console(handle):
if handle == INVALID_HANDLE_VALUE or handle is None:
return True
return ((GetFileType(handle) & ~FILE_TYPE_REMOTE) != FILE_TYPE_CHAR
or GetConsoleMode(handle, byref(DWORD())) == 0)
old_stdout_fileno = None
old_stderr_fileno = None
if hasattr(sys.stdout, 'fileno'):
old_stdout_fileno = sys.stdout.fileno()
if hasattr(sys.stderr, 'fileno'):
old_stderr_fileno = sys.stderr.fileno()
STDOUT_FILENO = 1
STDERR_FILENO = 2
real_stdout = (old_stdout_fileno == STDOUT_FILENO)
real_stderr = (old_stderr_fileno == STDERR_FILENO)
if real_stdout:
hStdout = GetStdHandle(STD_OUTPUT_HANDLE)
if not_a_console(hStdout):
real_stdout = False
if real_stderr:
hStderr = GetStdHandle(STD_ERROR_HANDLE)
if not_a_console(hStderr):
real_stderr = False
if real_stdout or real_stderr:
# BOOL WINAPI WriteConsoleW(HANDLE hOutput, LPWSTR lpBuffer, DWORD nChars,
# LPDWORD lpCharsWritten, LPVOID lpReserved);
WriteConsoleW = WINFUNCTYPE(BOOL, HANDLE, LPWSTR, DWORD, POINTER(DWORD), \
LPVOID)(("WriteConsoleW", windll.kernel32))
class UnicodeOutput:
def __init__(self, hConsole, stream, fileno, name):
self._hConsole = hConsole
self._stream = stream
self._fileno = fileno
self.closed = False
self.softspace = False
self.mode = 'w'
self.encoding = 'utf-8'
self.name = name
self.flush()
def isatty(self):
return False
def close(self):
# don't really close the handle, that would only cause problems
self.closed = True
def fileno(self):
return self._fileno
def flush(self):
if self._hConsole is None:
try:
self._stream.flush()
except Exception, e:
_complain("%s.flush: %r from %r"
% (self.name, e, self._stream))
raise
def write(self, text):
try:
if self._hConsole is None:
if isinstance(text, unicode):
text = text.encode('utf-8')
self._stream.write(text)
else:
if not isinstance(text, unicode):
text = str(text).decode('utf-8')
remaining = len(text)
while remaining > 0:
n = DWORD(0)
# There is a shorter-than-documented limitation on the
# length of the string passed to WriteConsoleW (see
# .
retval = WriteConsoleW(self._hConsole, text,
min(remaining, 10000),
byref(n), None)
if retval == 0 or n.value == 0:
raise IOError("WriteConsoleW returned %r, n.value = %r"
% (retval, n.value))
remaining -= n.value
if remaining == 0: break
text = text[n.value:]
except Exception, e:
_complain("%s.write: %r" % (self.name, e))
raise
def writelines(self, lines):
try:
for line in lines:
self.write(line)
except Exception, e:
_complain("%s.writelines: %r" % (self.name, e))
raise
if real_stdout:
sys.stdout = UnicodeOutput(hStdout, None, STDOUT_FILENO,
'<Unicode console stdout>')
else:
sys.stdout = UnicodeOutput(None, sys.stdout, old_stdout_fileno,
'<Unicode redirected stdout>')
if real_stderr:
sys.stderr = UnicodeOutput(hStderr, None, STDERR_FILENO,
'<Unicode console stderr>')
else:
sys.stderr = UnicodeOutput(None, sys.stderr, old_stderr_fileno,
'<Unicode redirected stderr>')
except Exception, e:
_complain("exception %r while fixing up sys.stdout and sys.stderr" % (e,))
# While we're at it, let's unmangle the command-line arguments:
# This works around .
GetCommandLineW = WINFUNCTYPE(LPWSTR)(("GetCommandLineW", windll.kernel32))
CommandLineToArgvW = WINFUNCTYPE(POINTER(LPWSTR), LPCWSTR, POINTER(c_int)) \
(("CommandLineToArgvW", windll.shell32))
argc = c_int(0)
argv_unicode = CommandLineToArgvW(GetCommandLineW(), byref(argc))
argv = [argv_unicode[i].encode('utf-8') for i in xrange(0, argc.value)]
if not hasattr(sys, 'frozen'):
# If this is an executable produced by py2exe or bbfreeze, then it will
# have been invoked directly. Otherwise, unicode_argv[0] is the Python
# interpreter, so skip that.
argv = argv[1:]
# Also skip option arguments to the Python interpreter.
while len(argv) > 0:
arg = argv[0]
if not arg.startswith(u"-") or arg == u"-":
break
argv = argv[1:]
if arg == u'-m':
# sys.argv[0] should really be the absolute path of the module source,
# but never mind
break
if arg == u'-c':
argv[0] = u'-c'
break
# if you like:
sys.argv = argv
简单来说这段代码做了这么几个事:
1、如果输出到控制台,改用 WriteConsoleW()。
2、如果输出被重定向,用 utf-8 编码输出。
3、用 GetCommandLineW() 和 CommandLineToArgvW() 获取命令行参数,在最后一行取代 sys.argv 传入的参数。
这个是我目前能找到的最完美的解决方案了。在控制台下也能不出错,在重定向的时候也可以按 UTF-8 去编码成 char 字节流。唯一的问题是 Python 2.5.2 里似乎没有 LPVOID。我用 c_void_p 取代 LPVOID,似乎是可行的。
当然,它仍然有前述不可避免的问题。例如在非原生支持汉字的代码页(简936繁950日932韩949)下,光标和换行的位置会出问题。如 果对汉字显示有很高的要求,不妨调用 Windows API 设置一下控制台的代码页。此外,输出重定向到外围程序时,如果外围程序不能设置按 UTF-8 解码,就会看到乱码的问题也依然存在。这些问题,就留待读者自行解决吧。
最后,特别说明一下以上问题都是 Windows 平台限定的。Linux 下问题没有这么显著(现在的Linux发行版本多数都设置了默认代码页为 UTF-8),而且就算用户代码页不是 UTF-8,也没有 Windows 下 WriteConsoleW 这么淫霸的函数,所以洗洗睡吧。
[转载+评论]NSIS插件编写入门
原文:http://clseto.mysinablog.com/index.php?op=ViewArticle&articleId=1910084
Many schools taught programming but very few of them taught deploying software. You may be so concentrated while programming your great software and haven't felt the difficulties of deploying it to others' computer. If you really want to deploy your software to general public, I would like to tell you: try to spend several days (or even weeks) to write and test the installer of your great software.
Very often, your software requires some prerequisites to run and your installer will try to check it, download some required components and do some post configurations. There are quite a bunch of logics behind and the installer is a completely distinct project from your original program !
I had spent several days to study NSIS. Why choose NSIS ? It is popular and free of charge. However, it only targets Microsoft Windows platform. You may feel annoying at first about NSIS: "Oh ... my God ! I just want to deploy a few files. I don't want to learn a new language to do such stupid stuff." Yes, that's right. If your program has only one exe, that's a waste of time to do so. But if your installer really need some checking like those previously stated, you will find that NSIS is worth to learn.
Here to mind you one important thing: The NSIS you can download from http://nsis.sourceforge.net/Main_Page is an ANSI version. There's another Unicode version at http://www.scratchpaper.com/ (but the installer made by this Unicode version can't be run on Windows 9X).
There are already many tutorials on how to write an NSIS installer so I don't want to repeat. Here, I would like to talk about writing a plugin to extend the functionalities of an installer ....
Actually, there's already an example plugin at "C:Program Files\NSIS\Unicode\Examples\Plugin" (depends on where you install NSIS), you can take a look at it.
Background knowledge
NSIS plugin is nothing but a DLL exporting one or several C functions (one function one functionality) and which has this kind of prototype:
__declspec(dllexport) void mypluginfunc(HWND hWndParent, int string_size, TCHAR *variables, stack_t **stacktop, extra_parameters *extra);
It uses normal C function calling convention and has no return value. No return value ! So, how to communicate with the script ? Use the stack (not the OS process level stack but a stack maintained internally by the NSIS virtual machine) or those predefined global variables ($0, $1, ..., $9, $R0, $R1, ..., $R9. NSIS calls them registers). Also, all parameters on the stack are in string format. To pass an integer, a conversion is needed. Inefficient ? Yes, it is but we are not writing a real-time 3D shooting game.
What's that pointer pointed to by "extra" above ? I don't know either. This testing plugin won't make use of it. Try to find it out yourself.
Plugin step by step
(1)
I usually use Visual studio to write C programs. So launch a new dll project which exports some symbols. Before writing any code, first change the Runtime library: Project -> Properties -> C/C++ -> Code Generation -> Runtime library. For debug mode, choose "Multi-threaded Debug (/MTd)" whereas release mode, choose "Multi-threaded (/MT)". If not doing so, you will need to deploy the C runtime together with your installer.
(2)
Copy the following files from "C:\Program Files\NSIS\Unicode\Examples\Plugin" and include them to your working project:
api.h, nsis_tchar.h, pluginapi.h, pluginapi.lib
They are the necessary header and object files. Set your project to link with "pluginapi.lib". The functions inside pluginapi.lib are declared in pluginapi.h.
(3)
Try to write our testing plugin C function like this:
extern "C" {
// This is an example of an exported function.
MYPLUGIN_API void mypluginfunc(HWND hWndParent, int string_size,
TCHAR *variables, stack_t **stacktop,
extra_parameters *extra)
{
EXDLL_INIT();
WCHAR szComponent[256];
popstring(szComponent);
int len = (int)wcslen(szComponent);
// make a little change to input parameter
for (int i = 0; i < len; ++i)
szComponent[i] += 1;
// push back on the stack
pushstring(szComponent);
}
}
Remeber to wrap the function by 'extern "C"', otherwise, VC "thinks" it is a C++ function (since it is inside a cpp file) and hence function name decoration may result.
In the function, first insert the macro "EXDLL_INIT()", which sets up the stack and other parameters.
The rest of the function is just to pop the string passed in, change it a little bit and push back on the stack so that caller can get the modified string.
(4)
Compile the DLL (debug or release version). Then copy the DLL to NSIS plugin directory: "C:\Program Files\NSIS\Unicode\Plugins"
(5)
Lastly, write a testing NSIS script to test this plugin:
OutFile "helloworld.exe"
# default section
Section
MessageBox MB_OK "Hello world ! Yes..."
myplugin::mypluginfunc "FDFDqqq我們"
Pop $0
MessageBox MB_OK "ret = $0"
SectionEnd
Save the script as "hello.nsi" and compile it with "C:\Program Files\NSIS\Unicode\makensis" hello.nsi".
(6)
Try to run the resulting "helloworld.exe". Since it is a Unicode version, you can pass non-English string to the plugin and see the modified string (2 chinese characters as above). But to mind you that you have to save the script in Unicode format (i.e. from notepad -> save as -> Encoding -> Unicode).
A screenshot to display the modified string (the 2nd MessageBox above):

Source of the above example: 2197742-mynsisplugin.zip
Enjoy!
我的补充:
1、你从NSIS网站上也能下载到NSIS Plugin Example。但是那个for是NSIS ANSI的。如果要开发for NSIS Unicode的,得从NSIS Unicode的安装目录拿东西。
2、函数的传入参数string_size既不是你从NSIS传入参数的字符串的个数,也不是字符串的长度。而是NSIS编译时的一个常量的值。这个值在NSIS ANSI版里固定为1024,在NSIS Unicode版里上升到8196。参见http://www.scratchpaper.com/home/faq,“Where's the large string version of the Unicode NSIS?”。
3、传入参数是在程序里用popstring(LPTSTR)获取的。如果你是用popstring、pushstring等函数,且在函数参数处用TCHAR来修饰variables,则编译出来的dll文件只能用于ANSI或Unicode二者其一。也许通过强制使用PopStringA和PushStringA可以让一个dll适应ANSI和Unicode,但是我没试过。参见pluginapi.h。
4、传入参数在程序里popstring的时候是从左到右获得的。例如传入参数是pluginName::functionName "123" "456",第一次popstring会得到123,第二次456。
诺基亚702T + 北京神州行cmwap无限流量卡
把北神无限卡放进702T
开机
出现3.5G标志(当然是刷过open固件的)
上网
虽然还是只能上cmwap(当然也可以上MM-Nokia商店专用接入点cmcc cmmm)
不过速度已经轻松飙到了170KB/s
下个QQ几秒钟
太爽了!
不过不知道3G模式下上网会不会另外收钱
晚上看看话费变化
没问题的话北神流量卡就值大钱了
15元/月
全国漫游
3G无限流量上网
orz
小悦悦事件之我见
Windows XP 原版(SP0)和SP1无法安装nVidia新驱动的解决方案
[转载]Windows 7下ThinkPad T500 指纹识别软件故障的解决
来自:http://hi.baidu.com/zt37/blog/item/634e20a41d54b7fc9052eee3.html
年前换了t500从oem的vista折腾到win7 旗舰版颇费周章。结果。升级后蛮高科技的指纹识别功能over了。
每次开机注册都说“无法与传感器通讯”

虽然装驱动的时候有些古怪。但用thinkvantage toolbox检查设备显示正常

心生疑惑。看网上搜到的消息都说和驱动有关。还有说跟BIOS设置有关的。但是上面的检查结果说明bios设置并没有关掉指纹设备,驱动也应该是可用的。(ps:驱动是从联想官网下的win7指纹驱动,且用联想的驱动自动检查工具检查说明系统不需要更新驱动)
因此对网上下驱动调bios的说法不再信服。转而认为是软件问题。
在联想官方已经收录的问题说明文档中也看到在以前升级vista系统后也出现过类似无法识别现象。估计是老毛病又犯了。
按此思路在查询了一下反映无法连通指纹设备的软件编号如下

3.3058
从联想支持中心搜了一下。貌似最新版已经到了5.9版本。下了装上看看

版本升级了了,软件名也从“lenovo指纹”升级成了“thinkvantage指纹软件”
安装重启。指纹注册ok了。看来毛病是出在指纹软件上。不是bios问题。也不是驱动问题。
lenovo的中文支持网站上没有找到相关的软件更新,这个软件是从他英文网页上搜出来的