昨天下午開始,之前用得好好的USB鼠標,突然不能用了,找到個PS/2鼠標,卻發現主板沒有鼠標的PS/2口,只有鍵盤的PS/2口,真是奇葩,幸好在用的鍵盤是PS/2口的,費了九牛二虎之力,用鍵盤操作,Win+R,compmgmt.msc進入計算機管理,上下箭頭移到設備管理器,發現右邊的USB控制器前全是黃色嘆號,嘗試卸載再安裝,卻怎么也裝不上,重新啟動發現鼠標在啟動Windows前還是亮燈的,但到了顯示Windows徽標的時候燈就滅了,應該不是硬件問題,而是驅動問題。
為了進一步證實硬件沒問題,找了個安裝系統的U盤,插進去啟動,能夠正常使用鼠標,于是目標就聚焦在找回驅動上。
開始折騰:
1、首先是找官方驅動啊,我這電腦是老機,AMD7系列主板,找了半天,這個主板驅動并沒有包含USB控制器,因為USB控制器都是Windows自帶的驅動,下載了一個南橋驅動,安裝后并沒有效果;
2、Windows自帶的驅動原來都是放在C:\Windows\System32\DriverStore\FileRepository下,USB控制器相關的驅動,就在usbport.inf_amd64_xxxxxxxxxx文件夾里,xxxxxxxxx是一串16進制數字,悲催的是,安裝這個驅動時要不提示找不到指定文件,要不說第三方INF沒有簽名;
3、自己折騰搞不定,找個軟件吧,第一個想到的是驅動之家官方的驅動精靈,下載下來發現是個全家桶啊,什么騰訊管家,金山毒霸,瀏覽器首頁修改一應俱全,而且沒有鼠標點擊,用TAB鍵根本移動不到取消框,只好默認全部安裝了,裝完啟動,檢測,提示系統自帶驅動缺失,于是回車修復,但每次修復完,重新檢測還是那樣,而且沒有提示USB控制器驅動安裝有問題,有些功能用鍵盤無法操作,不知道是不是還有哪里可以操作一下,于是又搜了一下,如何用鍵盤代替鼠標,居然真的找到了!
4、按WIN鍵,輸入設置,回車,打開設置主頁:

移到“輕松使用”,進去后左邊選擇“鼠標”,在右邊啟用“使用數字小鍵盤在屏幕上移動鼠標”(按空格鍵開關),最好把三個開關都打開,如果沒有啟用CTRL鍵加速功能,鼠標移動非常慢:

好了,現在可以用小鍵盤移動鼠標了;
5、繼續回到驅動精靈,再次修復,還是不行啊,這個東西除了帶來一堆垃圾,什么作用都沒有!于是把它帶來的垃圾以及它自己卸載了。
6、似乎360也有一個驅動大師,于是就下載了一個,這個倒是很純潔,但是功能太弱,完全沒發現問題;
7、剛才搜索“安裝驅動 找不到指定的文件”時,發現一個論壇提到了這個,是驅動人生的論壇,好像還有解決方案,但要注冊才能下載,難道驅動人生可以解決?于是就下載了一個驅動人生,安裝的時候還是附帶全家桶,不過現在可以用鍵盤移動鼠標取消了,只安裝了驅動人生自己,跟剛才兩個軟件不同的是,它提示USB外設驅動沒有安裝,于是點修復,結果反反復復出現等待光標,就是無法完成;
8、之前又搜索到,驅動安裝的日志在C:\Windows\INF\setupapi.dev.log文件里,于是打開這個文件,發現Driver package failed signature verification. Error = 0xE000022F,驅動程序簽名有問題,所以不能安裝成功;
9、Windows10有個高級啟動選項是禁用強制驅動簽名,如何進入高級啟動選項呢?以前是按F8,現在不行了,要在設置里面,更新和安全,恢復,高級啟動,立即重啟,然后設置疑難解答,高級啟動,再重啟,就可以進入高級啟動菜單,按7進入禁止強制驅動簽名模式,重啟后再用驅動人生修復,果然成功了;
10、打開驅動人生下載目錄,DTLFolder\DriversDownLoad,發現它下載了USB驅動目錄是USB_10.0.10240.16384_WHQL_107049,里面文件如下:

除了第一個xml文件是程序自己用的外,其他都是USB驅動用到的文件,點右鍵發現那幾個sys文件,除了usbohci.sys和usbuhci.sys外,其他都有數字簽名,而usbuhci.sys我這里沒用到,問題就出在usbohci.sys上:


11、難道是驅動人生替換了未簽名的文件?圖謀不軌?為了驗證一下,我又下載了一個Windows10安裝光盤(版本是當前使用的1703版):
cn_windows_10_multiple_editions_version_1703_updated_march_2017_x64_dvd_10194190.iso
12、怎么提取安裝光盤中的內置驅動?找了一下,原來Windows的安裝盤從VISTA起,不再使用XP以前的I386目錄和Drivers.cab文件存放驅動,而是打包在一個Install.wim鏡像文件中,要找到驅動文件,必須用工具提取,這個工具就是Imagex.exe,微軟自己做的命令行工具,但是我的電腦上沒有,于是下載了一個64位的,放在C盤根目錄,通過如下命令即可提?。?/div>
c:\IMAGEX_x64 /mount f:\sources\install.wim 5 i:\1703
其中F盤是在iso文件上點右鍵,打開方式選“Windows資源管理器”打開后虛擬出來的盤符,其實就相當于系統自帶的虛擬光驅,I盤是硬盤,用來存放掛載的鏡像文件,5是選擇掛載哪一個版本的Windows(多合一版),如果不知道要掛哪個,把這個數字改成100,會顯示xml文件內容,并提示找不到這個索引號,從xml文件內容就能找到各版本的信息,然后再重新掛載正確的即可。這個掛載其實是個解壓縮過程,時間很長,提取完之后就跟安裝好了Windows一樣,目錄都列好了。
今天又發現另一個圖形化的工具,Dism++,比這個操作更簡單。Dism是PowerShell內置的命令,也是與鏡像有關,也能掛載提取,但用了一下似乎提示權限有問題,Dism++是國內開源愛好者自己開發的圖形化工具,與Dism沒有關系。
13、好了,原版的Windows已經準備好,進入Windows\System32\DriverStore\FileRepository目錄,搜索usbohci.sys,在usbport.inf_amd64_8e5f608c0111283d目錄下,點右鍵一看,也是沒簽名的:
這不是坑爹嗎?你自己帶的東西都沒簽名,然后又不給用?。。。?/div>
14、有點懷疑是Windows自己更新的時候修改了一些策略,導致之前可以用的不能用了,為了再次驗證,又繼續下載了兩個版本的Windows10安裝光盤,分別是早期的1607和最新的1709,找到usbohci.sys,如下所示:
從左到右依次為1607,1703,1709,均未簽名,基本可以判斷是Windows自己抽風了。
15、昨天晚上搞到12點多,搞定鼠標后沒有重啟測試,今天早上開機,果然發現鼠標又不能用了,因為我沒有選擇禁用強制簽名選項來啟動,系統發現那個沒簽名的驅動,就把它停了,嘗試卸載,結果再裝也裝不上,于是只好又設置高級啟動,重新禁止強制簽名,進入系統,裝上驅動,恰好這時Windows又在后臺偷偷摸摸地更新,不知道更新了啥,讓我重啟。
16、重啟之后,奇跡出現,剛才明明提示沒有簽名強制安裝的驅動,現在居然正常啟動也沒問題了,而且查看驅動詳情的時候出現了矛盾的一幕:
外面顯示數字簽名者:未經數字簽名,里面的sys文件又顯示數字簽名者是Microsoft Windows,然而進入C:\Windows\System32\drivers目錄,找到usbohci.sys,點右鍵,卻發現并沒有數字簽名:
好吧,你開心就好,反正不要再禁我的鼠標就行……
感謝這次蛋疼的折騰之旅,讓我知道了驅動程序來自哪里,安裝日志在哪里,哪個軟件坑爹又沒用,怎么玩安裝盤,怎么用鍵盤操作鼠標,怎么進入高級啟動界面……
我為什么要知道這些??????????????為微軟的疏忽買單?。。。。?!
啥都不說了,它又提示我重啟了,不知道又有什么奇跡會發生……
每次換手機,把舊手機的數據遷移到新手機就是個很麻煩的事情,幸好最近華為的“手機克隆”APP越來越強大,居然能夠把微信的聊天記錄包括圖片原封不動地遷移到新手機上,以前用微信自帶的聊天記錄轉移功能只能轉移文字信息,圖片視頻全部丟失,不知道現在的怎么樣。手機克隆還能把SD卡的內容也轉移過來,基本滿足了需要。
但是要把手機上的東西傳到電腦就沒那么簡單了,現在已經沒有了以前的大容量存儲模式,只能選擇MTP模式,這種模式其實不是一個完整的文件系統,有很多限制,所以一些傳統的軟件讀取不到,例如FastCopy是用不了的,用Windows自帶的文件管理器來復制,開始計算時間就要等很久,中間出了個錯就前功盡棄;還有通過手機上的APP訪問電腦共享的方式,在手機上復制也可以,但是同樣會莫名其妙卡死,FTP同理,折騰了好久,還是覺得自己動手比較好。
MTP協議在維基百科里解釋得比較清楚:
https://en.wikipedia.org/wiki/Media_Transfer_Protocol ,簡單點說就是:
1、不是以塊設備的形式訪問,跟U盤不同;
2、只能單線程訪問,不能同時進行多個操作,只能一個接一個;
3、控制權在設備上,對外展示的內容由設備決定;
4、默認不能直接對文件進行部分修改,只能復制過來修改完再復制回去,但Android對協議做了擴展,能夠修改部分文件內容;
5、在Linux上有些軟件能夠把它掛載為文件系統,這樣其他軟件就能像訪問普通文件系統一樣訪問了,但是Windows下似乎沒有。
不過有人開發了一個在Windows下通過JNI實現的Java庫jmtp,項目托管在Google Code,被墻了,但是GitHub有人fork了一個,可以下載下來,我下載的是
https://github.com/reindahl/jmtp
里面包含了C++的代碼和Java的代碼,以及兩個已經編譯好的dll文件,分別用于Win32和Win64,把其中一個dll文件放在工程目錄下,再把Java源代碼加入工程中即可使用,文檔比較簡陋,但是看test目錄下的MtpTest.java,基本可以摸到如何使用了,這個協議比較簡單,其實沒什么功能,我要的只是把文件復制到電腦上。
根據MtpTest.java,稍微修改一下,做個遞歸復制即可把手機上的所有文件復制到電腦上:
package test;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.math.BigInteger;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.rmi.server.SocketSecurityException;
import java.util.ArrayList;
import jmtp.PortableDevice;
import jmtp.PortableDeviceFolderObject;
import jmtp.PortableDeviceManager;
import jmtp.PortableDeviceObject;
import jmtp.PortableDeviceStorageObject;
public class TestApp {
public static void main(String[] args) {
// TODO Auto-generated method stub
ArrayList<PortableDeviceStorageObject> devices = new ArrayList<>();
PortableDeviceManager manager = new PortableDeviceManager();
for (PortableDevice device : manager) {
System.out.println(device);
device.open();
// Iterate over deviceObjects
for (PortableDeviceObject object : device.getRootObjects()) {
String storageName=object.getName();
System.out.println(storageName);
// If the object is a storage object
if (object instanceof PortableDeviceStorageObject) {
PortableDeviceStorageObject storage = (PortableDeviceStorageObject) object;
System.out.println(storage.getChildObjects().length);
for (PortableDeviceObject child : storage.getChildObjects()) {
copyall(child,"E:\\手機備份\\"+object.getName());
}
}
}
device.close();
System.out.println(size);
}
}
public static void copyall(PortableDeviceObject obj,String path) {
if(obj instanceof PortableDeviceFolderObject) {
String objName=obj.getName();
if(objName.contains(":")) {
objName=objName.replace(':', ':');
}
String newPath = path+"\\"+objName;
System.out.println("創建文件夾:"+newPath);
File file = new File(newPath);
if(!file.exists()) {
file.mkdirs();
}
for(PortableDeviceObject subObj:((PortableDeviceFolderObject) obj).getChildObjects()) {
copyall(subObj,newPath);
}
}
else {
if(obj.getName().contains(":"))
return;
System.out.println("開始復制文件到:"+path+"\\"+obj.getName());
File file = new File(path);
obj.copy(file.toPath());
System.out.println("文件復制完成!");
}
}
}
其中發現有點問題:
1、Android設備文件名里是可以包含冒號(:)的,但Windows是不可以的,所以復制到這些文件的時候會有問題,于是遇到目錄名這樣就把它改為中文的冒號(:),但是遇到文件名這樣就不行了,因為這個庫的copy函數只需要指定目標目錄,不需要指定目標文件名,所以這些文件只能放棄;
2、Android手機的MTP協議是由“媒體存儲”這個系統APP控制的,有時候手機上可以看到的文件,通過MTP訪問卻怎么也看不到,重啟手機也不行,應該就是這個APP沒有更新數據,需要把它的系統數據清除掉,等它重建完重新訪問就可以看到了,不過這個重建時間非常長,可以查看它數據占用的空間,剛清除之后會發現它占用的空間會不斷增長,到了不增長的時候就是重建完了,就可以正常訪問了;
3、這個庫有時候還有點bug,有一次發現它讀取到的文件和文件夾都沒有了最后一個.后面的部分,所以總是卡住,重新插拔一下手機數據線又沒問題了;
4、為了避免復制了半天結果發現不完整,又要重來,最好在復制前先統計一下文件大小,看看跟手機上看到的占用存儲空間是不是一致,對于MTP設備上的文件,可以通過getSize函數得到大小,把上面復制操作改為大小累加即可,速度比復制快一些,不過由于小文件太多,也不會快很多。
把手機里的文件復制到電腦后,通過一些簡單的分析,發現有很多其實是垃圾來的,也可以為手機空間清理提供參考,因為在電腦上分析起來比在手機上方便一些。例如一些視頻APP的緩存,居然超過1G,占用了寶貴的內部存儲空間,之前一直都沒發現,通過電腦里的按文件大小搜索才發現。
09款老速騰,不支持USB和AUX,要聽歌除了CD以外,就是刻錄在CD上的MP3了,以前不知道用什么軟件刻錄了一張碟,能夠完美地顯示中文文件名和ID3信息,前幾天用ImgBurn刻了一張,發現中文是亂碼,開始以為是ID3信息顯示亂碼,于是下載了一個Mp3Tag,把所有ID3信息都清除,結果顯示文件名依然亂碼,重新寫入ID3信息,發現ID3可以正常顯示,但文件名還是亂碼。
于是就把原來那張可以正常顯示中文的碟拿來研究一下,發現它的ID3標簽只是ID3v1,而后來重新寫入的ID3是ID3v2.3,兩個都可以正常顯示中文,說明ID3信息是正常的,文件名亂碼不是這個問題。
但是不知道用什么軟件來顯示光盤的文件系統,只能一次次摸索。
幸好有一張CD-RW可以反復嘗試。
ImgBurn默認是使用ISO9660+UDF,而ISO 9660則使用最老的ISO 9660文件系統,也就是1988版本,文件名默認是不支持中文的,不知道是不是這個原因,于是就把文件系統改為ISO 9660+Joliet,如下圖:

并且把ISO 9660標準改為1999:

可能是因為字符編碼那里改為了ASCII,所以就好了。
后來又嘗試只使用UDF文件系統,結果認不出碟。
所以,目前能夠使用中文的環境其實就是:
ImgBurn使用ISO 9660 1999標準;
ID3使用v1或v2.3都可以。