[教程]双击文件自动通过虚拟机中的windows程序打开
Tofloor
poster avatar
177******61
deepin
2018-03-18 03:26
Author
本帖最后由 mokyle 于 2018-9-1 21:52 编辑

#效果是可以通过直接双击文件,来调用虚拟机中的应用打开:


#原理:
对于虚拟机中windows系统的程序,在deepin中建立对应的启动图标(Desktop Entity),在启动图标中指定可以打开文件的(MIME)类型,指定执行的内容(Exec=)为使用xfreerdp 以remoteApp的形式打开windows系统中的应用程序,并且将当前要打开文件的路径转换成虚拟机windows系统中的网络路径一并传入即可.

#教程:
##1. 虚拟机安装windows系统系统推荐 server 2012 R2.
虚拟机以vmware为例,.
windows系统这里以server 2012 R2为例,推荐使用,兼容性好。其他系统也可以,具体支持型号参见:http://www.kimknight.net/remoteapptool 。系统下载地址https://msdn.itellyou.cn/(见下图) 或百度可得.
名称:    Windows Server 2012 R2 VL with Update (x64) - DVD (Chinese-Simplified)镜像:    cn_windows_server_2012_r2_vl_with_update_x64_dvd_6052729.iso



##2. 系统安装到虚拟机中并激活.不表. 设置并记下登录账户密码备用.账户应该默认是Administrator.记下ip.


##3.Windows Server 2012 R2安装RemoteApp工具
下载地址 http://www.kimknight.net/remoteapptool
在windows系统中安装上RemoteApp.
在windows系统安装自己要装的应用.比如office 2016.
打开RemoteApp Tool,将office加入.   记下应用显示名称,稍后脚本中使用


##4. deepin安装xfreerdp工具.
参照: https://github.com/FreeRDP/FreeRDP/wiki/Compilationhttp://blog.csdn.net/kaizi318/article/details/7787825
##6.  允许多用户远程访问
下载 https://github.com/stascorp/rdpwrap/releases 的最新zip包
解压到任意目录比如(C:\Program Files\RDPWrap-v1.6.2)。双击执行install.bat,然后双击执行RDPConf.exe进行配置如下:

##5.  开启远程桌面并允许多用户远程访问
下载 https://github.com/stascorp/rdpwrap/releases 的最新zip包
解压到任意目录比如(C:\Program Files\RDPWrap-v1.6.2)。双击执行install.bat,然后双击执行RDPConf.exe进行配置如下:

保存后再次打开确保4个蓝色字体如图所示即可。
##6. 测试xfreerdp调用windows应用功能.

配置好RemoteAPP后, 以 ip:192.168.130.130,登录账户:Administrator,登录密码:k 调用Excel为例.
终端执行:
/usr/local/bin/xfreerdp /u:Administrator /p:k /cert-ignore /app:'||Microsoft Excel' /v:192.168.130.130
不出意外的话,你应该可以看到打开的Excel了.




##7. 添加应用图标到deepin的启动菜单(开始屏幕)中.

编写启动图标文件放置到~/.local/share/applications下.
vim ~/.local/share/applications/excel.desktop
```shell
#!/usr/bin/env xdg-open
[Desktop Entry]
Version=1.0
Name=Microsoft Excel 2016
Name[zh_CN]=Microsoft Excel 2016
Comment=Microsoft Excel 2016
MimeType=application/wps-office.et;application/wps-office.ett;application/wps-office.xls;application/wps-office.xlt;application/vnd.ms-excel;application/msexcel;application/x-msexcel;application/wps-office.xlsx;application/wps-office.xltx;
Exec=/usr/bin/runme.sh Excel %F
Terminal=false
Icon=/usr/icon/excel.png
Type=Application
Categories=Office;network;
StartupWMClass=excel
X-Deepin-AppID=excel
```
这个文件内容是参考的wps改的.
其中需要注意这几个地方:
MimeType  此项记录这个图标能打开的文件类型(此为excel类型).不填写会导致右键excel文件的打开方式中不会出现此图标,就更不能设置此图标为excel文件的默认打开程序.
Exec            这里我填写了一个脚本地址/usr/bin/runme.sh和两个参数. 其中脚本内容稍后介绍."Excel"是一个普通参数,跟脚本中内容对应. %F表示被打开的一个或多个文件的路径.每个被打开的文件都作为单独的参数传递给runme.sh脚本. 具体参考:https://specifications.freedeskt ... ry-spec-latest.html
Icon            填写图标图片地址. 图标可以网上下载,也可以直接从windows系统中的程序中提取.(用windows下的IconsExtract工具可以提取应用的图标)

##8 使用脚本改变被打开文件的路径.即 将路径转换成windows下的磁盘路径.
因为xfreerdp支持远程的时候将本地某个路径挂载到windows下的网络挂载点中.只需要在xfreerdp调用时加入参数/drive:deepin,/home/k即可.例如执行:
/usr/local/bin/xfreerdp /u:Administrator /p:k /cert-ignore /v:192.168.130.130 /drive:k,/home/k
会直接打开windows的远程桌面,效果见图:

由图片可知实际作用是将 deepin的路径 "/home/k" 映射到了windows下的\\tsclient\k.

因为本地路径跟远程映射路径不一致.所以需要将路径通过脚本转换.
故有此脚本:
```shell
k@k-pc:~$ cat /usr/bin/runme.sh
#!/bin/bash
if [ $# -gt 1 ]
then
    file=`echo ${*} | sed "s/$1 //g" | sed 's#\/#\\\#g; s/^/\\\\\\\\tsclient\\\\deepin&/g'`
fi
case "$1" in
        Excel)
                exec /usr/local/bin/xfreerdp /u:Administrator /p:k /cert-ignore /app:'||Microsoft Excel' /app-cmd:"\"$file\"" /v:192.168.130.130 /drive:deepin,/r  /sound:sys:alsa
                ;;
        Explorer)
                exec /usr/local/bin/xfreerdp /u:Administrator /p:k /cert-ignore /v:192.168.130.130 +fonts +clipboard /drive:deepin,/r /drive:k,/home/k /sound:sys:alsa
                ;;
        CloudMusic)
                exec /usr/local/bin/xfreerdp /u:Administrator /p:k /cert-ignore /app:'"||NetEase Cloud Music"' /v:192.168.130.130 +fonts +clipboard /sound:sys:alsa
                ;;
esac
```
注意!!! 脚本中有"/drive:deepin,/r " ,实际我的目的是挂载跟路径,但是写成"/drive:deepin,/ "会导致挂载的网络磁盘打开里面没有任何文件,所以我单独做了软连接 .
即控制台先执行: ln -s / /r

在脚本中除了Excel的例子,还有一个windows桌面的例子和网易云音乐的例子.file开头的那行的作用就是将传入的所有参数比如"Word /home/k/1 - 副本.docx" 提取转换变成: "\\tsclient\deepin\home\k\1 - 副本.docx"
脚本中的xfreerdp命令后还带有一些参数.解释:        /u                        用户名
        /p                        密码
        /app                    应用程序完整路径 或者为 双竖线加RemoteApp Tool里的名字 (如果是完整路径,需要在RemoteApp Tool设置中开启Allow Unlisted Remote Programs)
        /app-cmd           传递参数 (脚本中为了兼容路径中包含空格的,故在冒号里面套了俩个被斜线转义的冒号.)
        /cert-ignore       忽略证书
        +fonts                效果是字体看起来圆润了
        /sound:sys:alsa  传递声音
        +clipboard        同步剪贴板
        更多用法,移步:https://github.com/awakecoding/F ... ser-Manual.markdown
编辑完成此脚本后加入执行权限即可.此时可以通过控制台执行 /usr/bin/runme.sh Excel 看看是否Excel被打开了.

===================================================================================

完成以上步骤后就可以在deepin开始菜单中看到启动图标:



现在可以在excel文件上右键选择打开方式为刚刚配置的图标来直接打开文件了.如果系统本来已安装有其他打开Excel文件的工具,比如wps,那么需要更改下默认打开方式才能达到双击直接已windows应用打开的效果.












Reply Favorite View the author
All Replies
avatar
177******61
deepin
2018-03-18 03:26
#1
本帖最后由 mokyle 于 2018-8-30 23:00 编辑

=================以下是一些选做内容======================


##1 设置vmware中的windows server 2008R2 为开机后台自启动,关机自暂停(suspend虚拟系统).
参考:http://www.atrixnet.com/autostar ... s-on-boot-in-linux/
这里提供精简了注释的脚本:
cat /etc/init.d/vmautostart
```shell
#!/usr/bin/env bash

### BEGIN INIT INFO
# Provides: vmwareautostart
# Required-Start: $vmware $network $syslog
# Required-Stop: $vmware $network $syslog
# X-Start-Before:
# X-Stop-After:
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: This service auto-starts and stops VMware guests
### END INIT INFO

VM_wait_between=30
VM_max_stop_wait=30
VM_user=k
VM_list=(
        /home/k/vmware/2008R2x64/2008R2x64.vmx
);
# ======== THE REST OF THIS CODE IS NOT CONFIGURABLE ==========
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
if [[ $( id -u ) -ne 0 ]];
then
   echo You must run this script as root or with sudo
   exit 1
fi
if [[ "$( getent passwd $VM_user )" == "" ]];
then
   echo Could not locate specified VM user "'$VM_user'" on the system.  Abort.
   exit 1
fi
VM_user_group=$( id -gn $VM_user );
VM_cmd_exec="sudo -u $VM_user -g $VM_user_group vmrun"
case "$1"
in
   start)
      VM_iter=0
      VM_list_length=${#VM_list[@]};
      for vm in "${VM_list[@]}";
      do
         if [[ $( vmrun list 2>/dev/null | grep $vm | wc -l ) -ne 0 ]];
         then
            echo VM "$vm" is already running
            continue;
         fi
         echo Starting up VM "$vm" ...
         $VM_cmd_exec start "$vm" nogui >/dev/null 2>&1
         VM_iter=$(( $VM_iter + 1 ));
         if [[ $VM_iter -lt $VM_list_length ]];
         then
            echo -n ...waiting $VM_wait_between seconds before starting next VM
            for tick in $( seq 1 $VM_wait_between );
            do
               echo -n .
               sleep 1
            done
            echo
         fi
      done
      $0 status
   ;;
   stop)
      for vm in "${VM_list[@]}";
      do
         if [[ $( vmrun list 2>/dev/null | grep "$vm" | wc -l ) -eq 0 ]];
         then
            echo VM "$vm" is not running
            continue;
         fi
         echo Stopping "$vm"...
         $VM_cmd_exec suspend "$vm" soft >/dev/null 2>&1 &
         VM_stop_pid=$!
         VM_stop_waited=0;
         echo -n ...Waiting $VM_max_stop_wait seconds for it to stop
         while kill -0 $VM_stop_pid >/dev/null 2>&1 ;
         do
            echo -n .
            sleep 1
            VM_stop_waited=$(( $VM_stop_waited + 1 ));
            if [[ $VM_stop_waited -gt $VM_max_stop_wait ]];
            then
               echo
               echo -n ...Timeout reached while waiting for graceful shutdown.
               echo -n Hard shutdown forced...
               $VM_cmd_exec stop "$vm" hard >/dev/null 2>&1;
            fi
         done
         echo
         echo ...VM "$vm" stopped.
      done
      $0 status
   ;;
   status)
      $VM_cmd_exec list
   ;;
   restart)
      $0 stop && $0 start
   ;;
   *)
      echo Usage: $0 '{start|stop|status|restart}'
      exit 1
   ;;

esac
```
脚本中只需要改VM_user为自己的用户名,VM_list为自己的windows系统所在路径即可.路径获取见图:



将脚本加入开机自启动服务即可.
方法假设自启动脚本为/etc/init.d/vmautostart)
chmod +x /etc/init.d/vmautostart
systemctl enable vmautostart

##2 声音不能用
需要确保windows上右下角音量图标不是红叉.如果是红叉,右键选择录音设备应该就可以了.

##3 输入法默认切换键:Alt+Shift

##4 某些应用点击菜单会短暂显示随后马上隐藏
这应该是个bug,我的解决办法是使用issues中这个补丁重新编译安装freerdp:
https://github.com/FreeRDP/FreeRDP/issues/4660#issuecomment-416016785
##5 所有应用在任务栏都显示在一个图标上,非常不方便
这个我的解决办法是在windows系统中为每个应用新建一个账户对应。









Reply View the author
avatar
188******04
deepin
2018-03-18 03:49
#2
厲害了,原來可以這樣
Reply View the author
avatar
.Andy
deepin
2018-03-18 03:56
#3
很厉害的样子
还是wine省事点
Reply View the author
avatar
风吹过的绿洲
deepin
2018-11-24 18:50
#4
厉害,厉害
Reply View the author
avatar
ylxdxx
deepin
2018-11-24 19:34
#5
学习了,还可以这样操作
Reply View the author
avatar
youngwq
deepin
2019-10-03 18:15
#6
厉害!正需要这个功能
Reply View the author
avatar
2019-10-03 20:21
#7
楼上也非常厉害
Reply View the author
avatar
139******14
deepin
2019-10-03 20:43
#8
这个很好用,VirtualBox+Win10lsb版本测试成功
Reply View the author
avatar
星辰使者
deepin
2019-12-18 22:47
#9
这个不是得一直开着虚拟机?
Reply View the author
avatar
177******61
deepin
2019-12-19 03:38
#10
deepin_zxr 发表于 2019-12-18 14:47
这个不是得一直开着虚拟机?

也可以在调用windows程序时在脚本中增加先检查虚拟机和虚拟系统是否运行着的逻辑,没运行着那么先打开就是了。
Reply View the author
avatar
JesseyLawson
deepin
2019-12-19 04:00
#11
感jio有点走偏了
Reply View the author
avatar
ghostry
deepin
2019-12-19 05:31
#12
很强,照这个玩法,应该也可以双机并用.
Reply View the author
avatar
136******89
deepin
2019-12-23 00:51
#13
也是一个很好的办法,就是有点麻烦,但是比用wine兼容性好。
Reply View the author
avatar
snsmqing
deepin
2019-12-23 16:55
#14
这是windows rdp支持的seamless,以前远程办公时用过,app通过rdp就像本地应用一样,还有个类似的东西ctrix。在linux下配合freexrdp能够在虚拟机中运行任意windows程序,而界面显示则在linux窗口中,体验特别好。略微不足是配置起来有点繁琐。
Reply View the author
avatar
chensj
deepin
2019-12-23 17:57
#15
马克一下,wine其实也就是这个思路,只是对方法进行了深度封装,对性能做了优化,直接调用dll了
Reply View the author
avatar
sleepytime
deepin
2024-04-10 16:16
#16

👍 太棒了,学到了!

远程本机虚拟机或者机房windows机器,比wine等方案使用场景更多,适合搭配其它需求,兼容性更好,非常有用。

Reply View the author