项目 4 任务 2 网络摄像机:PictureBox、Image / Bitmap、照片列表
- 摄像头:自绘东围墙场景(Camera/scene.svg),按云台位置切成 640×480 帧(build-frames.ts); Pan 每次转一格,红外对射被遮挡时画面出现翻墙的人;类名、委托、事件参数与教材 dll 一致, ImageRead 每 250 ms 在后台线程触发 - Image / Bitmap 保存真实图片数据:Save、FromFile、FromStream,文件夹不存在时报 GDI+ 一般性错误; 图片每张只发给浏览器一次(按内容哈希缓存) - 程序所在目录(AppDomain.CurrentDomain.BaseDirectory,编译检查单独放行)和当前目录指向可写的 bin/Debug, 沙箱里在沙箱的临时目录 - PictureBox(SizeMode、BorderStyle);设计器工具箱加"图片框";运行区显示程序保存的图片,点开看大图; 实训台摄像头图标显示开启状态 - 评分规则加图片框显示图片、摄像头开关与转向、保存图片三种检查;示例 p4-t2-网络摄像机 - 测试:摄像头端到端、图片读写与程序目录、AppDomain 编译检查、评分出错情况 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
4ed9450c02
commit
6b088240da
76 files changed
+1290
-14
No files matched your search
@@ -41,6 +41,13 @@ internal static class ApiPolicy
|
||||
["System.Runtime.InteropServices.NativeMemory"] = "调用本机代码",
|
||||
};
|
||||
|
||||
/// <summary>不允许的类型里单独放行的成员:教材用 AppDomain.CurrentDomain.BaseDirectory 拼出保存照片的路径</summary>
|
||||
private static readonly HashSet<string> AllowedMembers = new()
|
||||
{
|
||||
"System.AppDomain.CurrentDomain",
|
||||
"System.AppDomain.BaseDirectory",
|
||||
};
|
||||
|
||||
public static IEnumerable<Diagnostic> Check(CSharpCompilation compilation)
|
||||
{
|
||||
foreach (var tree in compilation.SyntaxTrees)
|
||||
@@ -69,6 +76,7 @@ internal static class ApiPolicy
|
||||
if (symbol is IDynamicTypeSymbol) return "dynamic 动态调用";
|
||||
// using 指令里的命名空间不算:VS 生成的 AssemblyInfo.cs 会 using System.Runtime.InteropServices
|
||||
if (symbol is INamespaceSymbol) return null;
|
||||
if (symbol is IPropertySymbol && AllowedMembers.Contains($"{symbol.ContainingType.ToDisplayString()}.{symbol.Name}")) return null;
|
||||
var type = symbol as INamedTypeSymbol ?? symbol.ContainingType;
|
||||
// 方法的返回值、参数类型由调用处检查;这里看符号本身属于哪个类型
|
||||
for (var t = type; t != null; t = t.ContainingType)
|
||||
|
||||
@@ -34,6 +34,8 @@ internal static class StudentProgramHost
|
||||
CultureInfo.CurrentCulture = zhCN;
|
||||
CultureInfo.CurrentUICulture = zhCN;
|
||||
|
||||
UseWritableBaseDirectory(dir);
|
||||
|
||||
var assembly = AssemblyLoadContext.Default.LoadFromStream(
|
||||
new MemoryStream(File.ReadAllBytes(Path.Combine(dir, CompileServer.AssemblyFile))),
|
||||
new MemoryStream(File.ReadAllBytes(Path.Combine(dir, CompileServer.PdbFile))));
|
||||
@@ -81,6 +83,28 @@ internal static class StudentProgramHost
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 学生程序的"程序所在目录":和在 VS 里按 F5 一样是工程下的 bin/Debug/,也是当前目录,可以写文件
|
||||
/// (教材把摄像头照片存到 AppDomain.CurrentDomain.BaseDirectory + "Camera/")。
|
||||
/// 沙箱里工程目录只读,改用沙箱自己的临时目录;两种情况下文件都在程序结束后清掉。
|
||||
/// </summary>
|
||||
private static void UseWritableBaseDirectory(string projectDir)
|
||||
{
|
||||
string baseDir;
|
||||
try
|
||||
{
|
||||
baseDir = Directory.CreateDirectory(Path.Combine(projectDir, "bin", "Debug")).FullName;
|
||||
}
|
||||
catch (Exception ex) when (ex is IOException or UnauthorizedAccessException)
|
||||
{
|
||||
baseDir = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), "StudentApp", "bin", "Debug")).FullName;
|
||||
}
|
||||
baseDir = Path.TrimEndingDirectorySeparator(baseDir) + Path.DirectorySeparatorChar;
|
||||
AppContext.SetData("APP_CONTEXT_BASE_DIRECTORY", baseDir);
|
||||
Directory.SetCurrentDirectory(baseDir);
|
||||
SimHost.AppBaseDirectory = baseDir;
|
||||
}
|
||||
|
||||
/// <summary>读取浏览器发来的操作,排队到界面线程执行</summary>
|
||||
private static void ReadActions()
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user