amp@java

amplifier's java blog

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  98 随笔 :: 0 文章 :: 228 评论 :: 0 Trackbacks

2017年11月17日 #

 昨天下午开始,之前用得好好的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盘根目录,通过如下命令即可提取:
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目录下,点右键一看,也是没签名的:
这不是坑爹吗?你自己带的东西都没签名,然后又不给用!!!!
14、有点怀疑是Windows自己更新的时候修改了一些策略,导致之前可以用的不能用了,为了再次验证,又继续下载了两个版本的Windows10安装光盘,分别是早期的1607和最新的1709,找到usbohci.sys,如下所示:
从左到右依次为1607,1703,1709,均未签名,基本可以判断是Windows自己抽风了。
15、昨天晚上搞到12点多,搞定鼠标后没有重启测试,今天早上开机,果然发现鼠标又不能用了,因为我没有选择禁用强制签名选项来启动,系统发现那个没签名的驱动,就把它停了,尝试卸载,结果再装也装不上,于是只好又设置高级启动,重新禁止强制签名,进入系统,装上驱动,恰好这时Windows又在后台偷偷摸摸地更新,不知道更新了啥,让我重启。
16、重启之后,奇迹出现,刚才明明提示没有签名强制安装的驱动,现在居然正常启动也没问题了,而且查看驱动详情的时候出现了矛盾的一幕:
外面显示数字签名者:未经数字签名,里面的sys文件又显示数字签名者是Microsoft Windows,然而进入C:\Windows\System32\drivers目录,找到usbohci.sys,点右键,却发现并没有数字签名:
好吧,你开心就好,反正不要再禁我的鼠标就行……
感谢这次蛋疼的折腾之旅,让我知道了驱动程序来自哪里,安装日志在哪里,哪个软件坑爹又没用,怎么玩安装盘,怎么用键盘操作鼠标,怎么进入高级启动界面……
我为什么要知道这些??????????????为微软的疏忽买单啊!!!!!
啥都不说了,它又提示我重启了,不知道又有什么奇迹会发生……
posted @ 2017-11-19 12:43 amp@java 阅读(279) | 评论 (0)编辑 收藏

 每次换手机,把旧手机的数据迁移到新手机就是个很麻烦的事情,幸好最近华为的“手机克隆”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,占用了宝贵的内部存储空间,之前一直都没发现,通过电脑里的按文件大小搜索才发现。
posted @ 2017-11-17 14:54 amp@java 阅读(246) | 评论 (0)编辑 收藏