论坛首页
论坛首页 开发者论坛 PortableApps开发 PAL中DirectoriesMove失效?

PAL中DirectoriesMove失效?

讨论关于便携软件开发的技术与问题,包括PAL、NSIS、VMware ThinApp及其他。
paulhybryant 头像
分舵香主
分舵香主

帖子: 56
今天在做一个百度影音的版本,在launcher.ini下面用了如下的代码
[DirectoriesMove]
LocalLow\Baidu=%USERPROFILE%\AppData\LocalLow\Baidu\
Roaming\Baidu=%APPDATA%\Baidu\
ProgramData\Baidu=%PROGRAMDATA%\Baidu\

文件夹可以顺利的移动到那些目录下,但是程序退出的时候文件夹并没有被移动回来。
不知道是不是因为权限的问题。不过我测试的机器直接用的admin账户,照理说应该不是。

David Pi 头像
建寨老工
建寨老工

帖子: 213

是不是最后多加了个后斜杠?

paulhybryant 头像
分舵香主
分舵香主

帖子: 56
David Pi 写道:
是不是最后多加了个后斜杠?


是的,去掉反斜杠后正常工作,谢谢!

paulhybryant 头像
分舵香主
分舵香主

帖子: 56
还有另一个关于DirecoriesMove的问题

在制作百度影音的便携版的时候,需要移动几个文件夹到%USERPROFILE%\AppData\LocalLow,
%APPDATA%和%PROGRAMDATA%下。
如果在launcher.ini里写

[DirectoriesMove]
LocalLow\Baidu=%USERPROFILE%\AppData\LocalLow\Baidu
Roaming\Baidu=%APPDATA%\Baidu
ProgramData\Baidu=%PROGRAMDATA%\Baidu

会发现每次百度影音启动以后总是默认的配置(配置在LocalLow\Baidu\BaiduPlayer里面)
而我其实是以在LocalLow\Baidu里面的配置作为默认配置(LocalLow\Baidu也放在了DefaultData里面)

貌似DirectoriesMove在BaiduPlayer.exe被执行之后才被执行,这时百度影音已经自己创建了LocalLow\Baidu\BaiduPlayer并生成了默认配置。

如果在CustomCode里在SegmentPre里面用NSIS代码来移动这些文件夹的话则没有问题。

David Pi 头像
建寨老工
建寨老工

帖子: 213

paulhybryant 写道:
还有另一个关于DirecoriesMove的问题

在制作百度影音的便携版的时候,需要移动几个文件夹到%USERPROFILE%\AppData\LocalLow,
%APPDATA%和%PROGRAMDATA%下。
如果在launcher.ini里写

[DirectoriesMove]
LocalLow\Baidu=%USERPROFILE%\AppData\LocalLow\Baidu
Roaming\Baidu=%APPDATA%\Baidu
ProgramData\Baidu=%PROGRAMDATA%\Baidu

会发现每次百度影音启动以后总是默认的配置(配置在LocalLow\Baidu\BaiduPlayer里面)
而我其实是以在LocalLow\Baidu里面的配置作为默认配置(LocalLow\Baidu也放在了DefaultData里面)

貌似DirectoriesMove在BaiduPlayer.exe被执行之后才被执行,这时百度影音已经自己创建了LocalLow\Baidu\BaiduPlayer并生成了默认配置。

如果在CustomCode里在SegmentPre里面用NSIS代码来移动这些文件夹的话则没有问题。



1. 所有的运行前工作都是在软件运行前完成的,你可以写一个这样的CustomCode:
${SegmentFile}

${SegmentPreExecPrimary}
MessageBox MB_OK "Done!"
!macroend
这样,在软件运行前会弹出对话框,暂停运行。这时候看看是否文件都移动到位了,方便排查错误。

2. 另外,不推荐用Data\LocalLow\Baidu这样的路径,可能因为父目录不存在而移动失败,用一级目录Data\Local可能好一些。

3. 最好不要备份整个Baidu文件夹,因为也许有其它百度的软件也需要用到这个目录,假如被便携软件移走了,会影响本机安装的其它百度软件。而应该备份程序真正用到的目录,例如LocalLow\Baidu\BaiduPlayer。

4. LocalLow这个路径在Vista以上的系统才存在,在XP中,可能软件会使用%LocalAppData%,或者完全放在其它位置。%USERPROFILE%\AppData\LocalLow\Baidu 这种写法应该配合CustomCode写成:
代码: 全选
${SegmentFile}

${SegmentInit}
   ${If} ${AtLeastWinVista}
      System::Call `shell32::SHGetKnownFolderPath(g"{A520A1A4-1780-4FF6-BD18-167343C5AF16}",i0x4000,in,*w.R0)`
      ${SetEnvironmentVariablesPath} LocalLow $R0
   ${Else}
      ${SetEnvironmentVariablesPath} LocalLow $LOCALAPPDATA ;或其它位置
   ${Endif}
!macroend


如果大于等于Windows Vista,设置环境变量 %LocalLow% 为真正的 LocalLow 目录,否则,设置为另一个(程序使用的)位置。

在Launcher.ini中就可以使用LocalLow这个环境变量了:
LocalLow\Baidu=%LocalLow%\Baidu

paulhybryant 头像
分舵香主
分舵香主

帖子: 56
谢谢David的建议和指正。
我不太明白
2. 另外,不推荐用Data\LocalLow\Baidu这样的路径,可能因为父目录不存在而移动失败,用一级目录Data\Local可能好一些
是什么意思。你是说如果文件夹LocalLow不存在的话,目录移动会失败?
但是程序本身会把目录创建在LocalLow下,所以如果不移动到LocalLow里面程序可能无法读取。

对于第3点,如果系统中并没有其他的Baidu软件,那么Baidu这个文件夹可能并不存在。如果父目录不存在的话,
那么移动LocalLow\Baidu\BaiduPlayer也会失败。
对于百度影音这种情况,是不是还是用custom code来移动文件夹比较保险一些(用custom code检查是否存在LocalLow\Baidu这个目录)。

因为我在{SegmentPre}里面注册了一些Dll,所以在目录未移动之前就创建了一下Baidu文件夹,是在regsvr32执行
的过程中被创建的
把注册dll的代码移动到SegmentPreExecPrimary里面就没有问题了。

David Pi 头像
建寨老工
建寨老工

帖子: 213

paulhybryant 写道:
谢谢David的建议和指正。
我不太明白
2. 另外,不推荐用Data\LocalLow\Baidu这样的路径,可能因为父目录不存在而移动失败,用一级目录Data\Local可能好一些
是什么意思。你是说如果文件夹LocalLow不存在的话,目录移动会失败?
但是程序本身会把目录创建在LocalLow下,所以如果不移动到LocalLow里面程序可能无法读取。

对于第3点,如果系统中并没有其他的Baidu软件,那么Baidu这个文件夹可能并不存在。如果父目录不存在的话,
那么移动LocalLow\Baidu\BaiduPlayer也会失败。
对于百度影音这种情况,是不是还是用custom code来移动文件夹比较保险一些(用custom code检查是否存在LocalLow\Baidu这个目录)。

因为我在{SegmentPre}里面注册了一些Dll,所以在目录未移动之前就创建了一下Baidu文件夹,是在regsvr32执行
的过程中被创建的
把注册dll的代码移动到SegmentPreExecPrimary里面就没有问题了。


呵呵,第一点是一个小技巧,用来在主程序启动前暂停运行,来检查文件移动等准备工作是否到位。因为主程序运行以后会生成各种文件和目录,可能就不那么好排查错误了。

第二点是指,等号左边最好不要用多级目录,假如目标和便携软件在同一盘符(比如都在C盘),Launcher是用重命名的方式移动目录的。那么假如 Data\LocalLow 不存在,Launcher 将%LocalLow%\Baidu 重命名为 Data\LocalLow\Baidu 时就会出错。等号左右两边的目录名称不一定要相同,AnyThing=%LocalLow%\Baidu\BaiduPlayer 都是可以的,不需要建立多级目录。写成 Data\BaiduPlayer=%LocalLow%\Baidu\BaiduPlayer ,再用[RegistryCleanupIfEmpty]来清除掉 Launcher创建的父目录就行了。

系统内有没有 %LocalLow%\Baidu 是不用考虑的,Launcher 一定会创建目标的父目录。如果可以在Launcher.ini中实现的,最好不要用CustomCode,因为PAL对文件的备份、还原机制非常成熟,没必要重新制造轮子。

另外注册DLL一定要放到 SegmentPreExecPrimary 里面,因为在 SegmentPrePrimary (较先运行)里面要备份注册表,如果顺序颠倒了,就导致先注册DLL,破坏系统安装的原程序,然后备份注册表,将注册的DLL抹掉,再运行程序的结果。

还有一个问题是,SegmentPre 是每次运行便携软件都要执行的,例如,先运行了 AppPortable.exe ,在未关闭程序的情况下,第二次运行 AppPortable.exe,SegmentPre 仍然会执行。一般这是没有必要的,DLL只要在首次运行时注册一次就行了。所以一般用带“Primary”的Segment,即第一个实例执行。

paulhybryant 头像
分舵香主
分舵香主

帖子: 56
David Pi 写道:
paulhybryant 写道:
谢谢David的建议和指正。
我不太明白
2. 另外,不推荐用Data\LocalLow\Baidu这样的路径,可能因为父目录不存在而移动失败,用一级目录Data\Local可能好一些
是什么意思。你是说如果文件夹LocalLow不存在的话,目录移动会失败?
但是程序本身会把目录创建在LocalLow下,所以如果不移动到LocalLow里面程序可能无法读取。

对于第3点,如果系统中并没有其他的Baidu软件,那么Baidu这个文件夹可能并不存在。如果父目录不存在的话,
那么移动LocalLow\Baidu\BaiduPlayer也会失败。
对于百度影音这种情况,是不是还是用custom code来移动文件夹比较保险一些(用custom code检查是否存在LocalLow\Baidu这个目录)。

因为我在{SegmentPre}里面注册了一些Dll,所以在目录未移动之前就创建了一下Baidu文件夹,是在regsvr32执行
的过程中被创建的
把注册dll的代码移动到SegmentPreExecPrimary里面就没有问题了。


呵呵,第一点是一个小技巧,用来在主程序启动前暂停运行,来检查文件移动等准备工作是否到位。因为主程序运行以后会生成各种文件和目录,可能就不那么好排查错误了。

第二点是指,等号左边最好不要用多级目录,假如目标和便携软件在同一盘符(比如都在C盘),Launcher是用重命名的方式移动目录的。那么假如 Data\LocalLow 不存在,Launcher 将%LocalLow%\Baidu 重命名为 Data\LocalLow\Baidu 时就会出错。等号左右两边的目录名称不一定要相同,Data\AnyThing=%LocalLow%\Baidu\BaiduPlayer 都是可以的,不需要建立多级目录。写成 Data\BaiduPlayer=%LocalLow%\Baidu\BaiduPlayer ,再用[RegistryCleanupIfEmpty]来清除掉 Launcher创建的父目录就行了。

系统内有没有 %LocalLow%\Baidu 是不用考虑的,Launcher 一定会创建目标的父目录。如果可以在Launcher.ini中实现的,最好不要用CustomCode,因为PAL对文件的备份、还原机制非常成熟,没必要重新制造轮子。

另外注册DLL一定要放到 SegmentPreExecPrimary 里面,因为在 SegmentPrePrimary (较先运行)里面要备份注册表,如果顺序颠倒了,就导致先注册DLL,破坏系统安装的原程序,然后备份注册表,将注册的DLL抹掉,再运行程序的结果。

还有一个问题是,SegmentPre 是每次运行便携软件都要执行的,例如,先运行了 AppPortable.exe ,在未关闭程序的情况下,第二次运行 AppPortable.exe,SegmentPre 仍然会执行。一般这是没有必要的,DLL只要在首次运行时注册一次就行了。所以一般用带“Primary”的Segment,即第一个实例执行。


明白了,谢谢David的解释,学习了。


回到 PortableApps开发