diff --git a/deploy/README.md b/deploy/README.md
index 9894b96..e66078c 100644
--- a/deploy/README.md
+++ b/deploy/README.md
@@ -129,6 +129,13 @@ scp "$B"/公共库/设备控制类库/设备控制/DeviceCtrlLibrary.dll "$B"/
"$B"/项目7/任务二/寝室情景模式/寝室情景模式/bin/Debug/*Interop.WMPLib.dll 服务器:IOT_SIM/textbook-libs/
```
+容器里的平台用普通用户运行,目录和文件要让其他用户能读(用 root 拷的文件常常是 `-rw-------`,导出时会提示"权限不够"):
+
+```bash
+chmod 755 ~/IOT_SIM/textbook-libs
+chmod 644 ~/IOT_SIM/textbook-libs/*.dll
+```
+
拷好后不用重启,下一次导出就能用。本机开发时同样放在仓库根目录的 `textbook-libs/`(已在 .gitignore 里),也可以用环境变量 `SIM_TEXTBOOK_LIBS` 指到别处。
## 备份与恢复
diff --git a/runtime/Sim.Runner/ExeExporter.cs b/runtime/Sim.Runner/ExeExporter.cs
index 97fd722..9f1a69d 100644
--- a/runtime/Sim.Runner/ExeExporter.cs
+++ b/runtime/Sim.Runner/ExeExporter.cs
@@ -69,7 +69,7 @@ internal static class ExeExporter
/// libsDir:教材 dll 所在目录;galleryDir:平台素材库
public static Result Export(string projectDir, string libsDir, string galleryDir, string assemblyName)
{
- var libs = Directory.Exists(libsDir) ? Directory.GetFiles(libsDir, "*.dll").OrderBy(p => p, StringComparer.Ordinal).ToArray() : Array.Empty();
+ var libs = TextbookLibs(libsDir);
if (!libs.Any(p => Path.GetFileName(p) == "DeviceCtrlLibrary.dll"))
throw new InvalidOperationException("服务器上没有放教材的设备类库(真机版 DeviceCtrlLibrary.dll 等),不能导出 EXE,请联系老师");
@@ -135,6 +135,32 @@ internal static class ExeExporter
return new Result(emit.Success, pe.ToArray(), diagnostics);
}
+ ///
+ /// 教材 dll 的路径。目录或文件读不了时(服务器上拷进去的文件权限是 600,容器里的平台用户读不到)说明原因,
+ /// 不把英文的系统报错直接给学生看。
+ ///
+ private static string[] TextbookLibs(string libsDir)
+ {
+ if (!Directory.Exists(libsDir)) return Array.Empty();
+ string? current = null;
+ try
+ {
+ var libs = Directory.GetFiles(libsDir, "*.dll").OrderBy(p => p, StringComparer.Ordinal).ToArray();
+ foreach (var lib in libs)
+ {
+ current = lib;
+ using var _ = File.OpenRead(lib);
+ }
+ return libs;
+ }
+ catch (UnauthorizedAccessException)
+ {
+ var what = current == null ? "目录" : Path.GetFileName(current);
+ throw new InvalidOperationException(
+ $"服务器上的教材设备类库读不了({what} 的权限不够),不能导出 EXE,请联系老师(服务器上执行 chmod 755 textbook-libs 和 chmod 644 textbook-libs/*.dll)");
+ }
+ }
+
///
/// 每个窗体、控件类的 .resources:VS 生成的 Designer.cs 用 ComponentResourceManager 读窗体的 .resx,
/// 平台没有 .resx。媒体播放器的 OcxState 放默认状态,其他取到 null(和运行时一样)。