202508111732

調整開包廂計算關包廂時間
調整寫法
This commit is contained in:
jasonchenwork 2025-08-11 17:36:01 +08:00
parent be19d8bcf7
commit fdd8cf047d
13 changed files with 133 additions and 349 deletions

View File

@ -15,12 +15,9 @@ namespace DBObj
NameSimplified=nameSimplified; NameSimplified=nameSimplified;
} }
public string getName(bool IsSimplified=false) { return IsSimplified ? NameSimplified : Name; } public string getName(bool IsSimplified=false) { return IsSimplified ? NameSimplified : Name; }
public string getName() {return Name;} public string getName() => Name;
public override string ToString() => $"Name: {Name}";
public override string ToString()
{
//return $"Name: {Name}, Phonetic: {Phonetic}, Category: {Category}, Strokes: {Strokes}";
return $"Name: {Name}";
}
} }
} }

View File

@ -119,53 +119,22 @@ namespace DBObj
} }
return dict; return dict;
} }
public void moveNext() public void moveNext() => cursor++;
{ public void movePrevious() => cursor--;
cursor++; public void move(int index) => cursor = index;
} public void moveFirst() => cursor = 0;
public void movePrevious() public void moveEnd() => cursor = table.Rows.Count - 1;
{ public bool bof() => (cursor < 0) || (table.Rows.Count == 0);
cursor--; public bool eof() => cursor > table.Rows.Count - 1;
}
public void move(int index)
{
cursor = index;
}
public void moveFirst()
{
cursor = 0;
}
public void moveEnd()
{
cursor = table.Rows.Count - 1;
}
public bool bof()
{
return (cursor < 0) || (table.Rows.Count == 0);
}
public bool eof()
{
return cursor > table.Rows.Count - 1;
}
public bool Read() public bool Read()
{ {
if (eof()) return false; if (eof()) return false;
moveNext(); moveNext();
return !eof(); return !eof();
} }
public int recordCount() public int recordCount() => table.Rows.Count;
{ public bool found() => table.Rows.Count > 0;
return table.Rows.Count; public void clear() => table.Clear();
}
public bool found()
{
return table.Rows.Count > 0;
}
public void clear()
{
table.Clear();
}
// INSERT / UPDATE / DELETE 方法 // INSERT / UPDATE / DELETE 方法
public int ExecuteNonQuery(string query, MySqlParameter[] parameters) public int ExecuteNonQuery(string query, MySqlParameter[] parameters)

View File

@ -17,10 +17,10 @@ namespace DBObj
FileName=filename; FileName=filename;
HumanVoice =humanVoice; HumanVoice =humanVoice;
} }
public string getNumber() {return Number;} public string getNumber() => Number;
public string getName(bool IsSimplified) {return IsSimplified ? Name_Simplified : Name;} public string getName(bool IsSimplified) => IsSimplified ? Name_Simplified : Name;
public string getName() { return Name;} public string getName() =>Name;
public string getFileName() { return FileName;} public string getFileName() => FileName;
public int getHumanVoice() { return HumanVoice;} public int getHumanVoice() => HumanVoice;
} }
} }

View File

@ -20,14 +20,9 @@ namespace DBObj
public SongData(string songNumber, string song, string artistA, string artistB, string filename, string artistASimplified, string artistBSimplified, string songSimplified, int humanVoice) public SongData(string songNumber, string song, string artistA, string artistB, string filename, string artistASimplified, string artistBSimplified, string songSimplified, int humanVoice)
{ {
basic=new(songNumber,song,songSimplified,filename,humanVoice); basic=new(songNumber,song,songSimplified,filename,humanVoice);
A= new Artist(artistA, artistASimplified); A = new Artist(artistA, artistASimplified);
if(!artistB.Equals("")){ B = !artistB.Equals("") ? new Artist(artistB, artistBSimplified) : null;
B = new Artist(artistB, artistBSimplified); isPublicSong = false;
} else
{
B = null;
}
isPublicSong = false;
} }
public SongData(SongData value,PlayState s){ public SongData(SongData value,PlayState s){
basic = value.getBasic(); basic = value.getBasic();
@ -39,15 +34,15 @@ namespace DBObj
public Artist getA() => A; public Artist getA() => A;
public Artist getB() => B; public Artist getB() => B;
public string getNumber() {return basic.getNumber();} public string getNumber() => basic.getNumber();
public string getName(bool IsSimplified=false) { return basic.getName(IsSimplified); } public string getName(bool IsSimplified=false) => basic.getName(IsSimplified);
public string getName() { return basic.getName();} public string getName() => basic.getName();
public string getArtist_A(bool IsSimplified) { return A.getName(IsSimplified); } public string getArtist_A(bool IsSimplified) => A.getName(IsSimplified);
public string getArtist_A() { return A.getName();} public string getArtist_A() => A.getName();
public string getArtist_B(bool IsSimplified) { return B.getName(IsSimplified); } public string getArtist_B(bool IsSimplified) => B.getName(IsSimplified);
public string getArtist_B() { return B.getName();} public string getArtist_B() => B.getName();
public int getNameLength() { return basic.getName().Length; } public int getNameLength() =>basic.getName().Length;
public string getFileName() {return basic.getFileName();} public string getFileName() => basic.getFileName();
public string next_song_text() public string next_song_text()
{ {
var str = (state == PlayState.InsertPlayback) ? GetStateTxt(false) : ""; var str = (state == PlayState.InsertPlayback) ? GetStateTxt(false) : "";
@ -101,26 +96,21 @@ namespace DBObj
} }
return null; // 找不到就回原本的 filename不加路徑 return null; // 找不到就回原本的 filename不加路徑
} }
public Color GetStateColor(){ public Color GetStateColor() => state switch
Color c = Color.White; {
if (state == PlayState.Played) c = Color.Gray;//Color.FromArgb(200, 75, 125); // 播畢顏色:紫紅色 PlayState.Played => Color.Gray,
else if (state == PlayState.Skipped)c = Color.Gray; PlayState.Skipped => Color.Gray,
else if (state == PlayState.NoFile)c = Color.Gray; PlayState.NoFile => Color.Gray,
else if (state == PlayState.Playing)c = Color.LimeGreen; PlayState.Playing => Color.LimeGreen,
else if (state == PlayState.InsertPlayback)c = Color.Gold; PlayState.InsertPlayback => Color.Gold,
return c; _ => Color.White
} };
public string GetStateTxt(bool IsSimplified){ public string GetStateTxt(bool IsSimplified) => (state==PlayState.NotPlayed)?"":$"({state.GetDescription(IsSimplified)})";
return (state==PlayState.NotPlayed)?"":$"({state.GetDescription(IsSimplified)})";
}
public void SetState(PlayState s) => state = s; public void SetState(PlayState s) => state = s;
public PlayState GetState() public PlayState GetState() => state;
{
return state;
}
public int getHumanVoice() { return basic.getHumanVoice(); } public int getHumanVoice() => basic.getHumanVoice();
public override string ToString() public override string ToString()
{ {
return String.Format("{0} {1}", basic.getName(),state.GetDescription() ); return String.Format("{0} {1}", basic.getName(),state.GetDescription() );

View File

@ -162,7 +162,6 @@ namespace DBObj
} }
public static void clearSong() public static void clearSong()
{ {
isWelcome = true; isWelcome = true;
not_played.Clear(); not_played.Clear();
played.Clear(); played.Clear();

View File

@ -38,7 +38,6 @@ namespace OverlayFormObj
private int topMargin; private int topMargin;
private int bottomMargin; private int bottomMargin;
public static System.Windows.Forms.Timer displayTimer = new System.Windows.Forms.Timer(); public static System.Windows.Forms.Timer displayTimer = new System.Windows.Forms.Timer();
public static System.Timers.Timer songDisplayTimer = new System.Timers.Timer();
public static System.Timers.Timer unifiedTimer; public static System.Timers.Timer unifiedTimer;
private System.Windows.Forms.Timer stickerTimer1 = new System.Windows.Forms.Timer(); private System.Windows.Forms.Timer stickerTimer1 = new System.Windows.Forms.Timer();
private System.Windows.Forms.Timer stickerTimer2 = new System.Windows.Forms.Timer(); private System.Windows.Forms.Timer stickerTimer2 = new System.Windows.Forms.Timer();
@ -360,12 +359,6 @@ namespace OverlayFormObj
displayTimer.Interval = 15000; displayTimer.Interval = 15000;
displayTimer.Tick += DisplayTimer_Tick; displayTimer.Tick += DisplayTimer_Tick;
songDisplayTimer = new System.Timers.Timer(30000);
songDisplayTimer.Elapsed += new ElapsedEventHandler(SongDisplayTimer_Elapsed);
songDisplayTimer.AutoReset = true;
songDisplayTimer.Enabled = true;
unifiedTimer = new System.Timers.Timer(15000); unifiedTimer = new System.Timers.Timer(15000);
unifiedTimer.Elapsed += new ElapsedEventHandler(UnifiedTimer_Elapsed); unifiedTimer.Elapsed += new ElapsedEventHandler(UnifiedTimer_Elapsed);
@ -416,35 +409,6 @@ namespace OverlayFormObj
displayTimer.Stop(); // 停止计时器 displayTimer.Stop(); // 停止计时器
} }
// 當 songDisplayTimer 計時完成時會呼叫此函式
private static void SongDisplayTimer_Elapsed(object sender, EventArgs e)
{
// 檢查是否需要跨執行緒操作 UI 控制項
if (MainForm.InvokeRequired)
{
// 如果目前不在 UI 執行緒上,必須透過 Invoke 安全執行 UI 更新邏輯
Console.WriteLine("SongDisplayTimer_Tick invoked on UI thread.");
MainForm.BeginInvoke(new Action(() =>
{
if (MainForm.topLeftLabel != null)
MainForm.topLeftLabel.Visible = true;
}));
}
else
{
// 如果已經在 UI 執行緒,就直接更新 UI 控制項
Console.WriteLine("SongDisplayTimer_Tick invoked on background thread.");
//MainForm.songDisplayLabel.Text = "";
MainForm.topLeftLabel.Visible = true;
}
// 停止計時器,避免重複觸發
songDisplayTimer.Stop();
}
private readonly object _lockObject = new object(); private readonly object _lockObject = new object();
private bool _handlingTimeout = false; private bool _handlingTimeout = false;
private async void UnifiedTimer_Elapsed(object sender, EventArgs e) private async void UnifiedTimer_Elapsed(object sender, EventArgs e)

View File

@ -175,7 +175,6 @@ namespace DualScreenDemo
private PictureBox serviceBellPictureBox; // 添加为类成员变量 private PictureBox serviceBellPictureBox; // 添加为类成员变量
private Timer autoRefreshTimer; private Timer autoRefreshTimer;
private TimeSpan remainingTime;
private Timer timerCountdown; private Timer timerCountdown;
string Rtime; string Rtime;
@ -232,7 +231,7 @@ namespace DualScreenDemo
timerCountdown = new Timer(); timerCountdown = new Timer();
timerCountdown.Interval = 1000; // 1 second timerCountdown.Interval = 1000; // 1 second
timerCountdown.Tick += TimerCountdown_Tick; timerCountdown.Tick += TimerCountdown_Tick;
timerCountdown.Start();
} }
// 添加 DPI 感知支持 // 添加 DPI 感知支持
@ -252,18 +251,10 @@ namespace DualScreenDemo
} }
} }
public void RoomTimeStart()
{
//DateTime now = DateTime.Now;
//DateTime tenMinutesLater = now.AddMinutes(120);
//remainingTime = tenMinutesLater - now;
remainingTime = Program.room.timePeriod;
timerCountdown.Start();
}
private async void TimerCountdown_Tick(object sender, EventArgs e) private async void TimerCountdown_Tick(object sender, EventArgs e)
{ {
TimeSpan remainingTime = Program.room.getTimeSpan();
if (remainingTime.TotalSeconds > 0) if (remainingTime.TotalSeconds > 0)
{ {
remainingTime = remainingTime.Subtract(TimeSpan.FromSeconds(1)); remainingTime = remainingTime.Subtract(TimeSpan.FromSeconds(1));

View File

@ -13,7 +13,7 @@ namespace DualScreenDemo
private static PrimaryForm primaryForm; // 儲存實例的參考 private static PrimaryForm primaryForm; // 儲存實例的參考
public static Room room = new Room(); public static Room room = new Room();
public static string verSion = "Server V2.8 202508081823"; public static string verSion = "Server V2.8 202508111732";
[STAThread] [STAThread]
static void Main() static void Main()

19
Room.cs
View File

@ -13,7 +13,6 @@ namespace DualScreenDemo
private string State = "error"; private string State = "error";
private DateTime? startedAt; private DateTime? startedAt;
private DateTime? endedAt; private DateTime? endedAt;
public TimeSpan timePeriod;
public Room() public Room()
{ {
@ -47,14 +46,13 @@ namespace DualScreenDemo
var Statedb = db.Field<string>("status"); var Statedb = db.Field<string>("status");
startedAt = ParseTime(db.Field<string>("started_at")); startedAt = ParseTime(db.Field<string>("started_at"));
endedAt = ParseTime(db.Field<string>("ended_at")); endedAt = ParseTime(db.Field<string>("ended_at"));
timePeriod = (TimeSpan)(endedAt - DateTime.Now);
PrimaryForm.Instance.RoomTimeStart();
if (Statedb.Equals("maintain")) { Statedb = "active"; } if (Statedb.Equals("maintain")) { Statedb = "active"; }
return Statedb; return Statedb;
} }
} }
return "error"; return "error";
} }
public TimeSpan getTimeSpan() => (endedAt!=null && endedAt.HasValue) ?(TimeSpan)(endedAt.Value - DateTime.Now):TimeSpan.Zero;
public void setDB(string value) public void setDB(string value)
{ {
using (var db = new MyDB()) using (var db = new MyDB())
@ -72,13 +70,9 @@ namespace DualScreenDemo
{ {
string StateDB=getDB(); string StateDB=getDB();
if (!StateDB.Equals(State)) if (!StateDB.Equals(State))
{
State = StateDB; State = StateDB;
}
else else
{
return; return;
}
string marqueeMessage = "歡迎使用超級巨星歡唱,與你共度美好時光。"; string marqueeMessage = "歡迎使用超級巨星歡唱,與你共度美好時光。";
Color c = Color.White; Color c = Color.White;
@ -119,14 +113,9 @@ namespace DualScreenDemo
return dt; return dt;
return null; return null;
} }
public bool IsClose() public bool IsClose() => State.Equals("closed");
{
return State.Equals("closed"); public bool IsOpen() => State.Equals("active");
}
public bool IsOpen()
{
return State.Equals("active");
}
} }

View File

@ -8,63 +8,12 @@ namespace DualScreenDemo.Services
{ {
public IGraphBuilder graphBuilder; public IGraphBuilder graphBuilder;
private IMediaControl mediaControl; private IMediaControl mediaControl;
private IBaseFilter videoRenderer; public IBaseFilter renderer;
//private IBaseFilter audioRenderer;
private IBaseFilter lavSplitter; private IBaseFilter lavSplitter;
private IBaseFilter lavVideoDecoder; public int Run() => (mediaControl != null) ? mediaControl.Run() : 0;
private IBaseFilter lavAudioDecoder; public int Stop() => (mediaControl != null) ? mediaControl.Stop() : 0;
private IPin outputPin; public int Pause() => (mediaControl != null) ? mediaControl.Pause() : 0;
private IBaseFilter audioRenderer;
private IVideoWindow videoWindow;
public int Run()
{
if (mediaControl != null)
return mediaControl.Run();
else
return 0;
}
public int Stop()
{
if (mediaControl != null)
return mediaControl.Stop();
else
return 0;
}
public int Pause()
{
if (mediaControl != null)
return mediaControl.Pause();
else
return 0;
}
public void VideoPlayerFormClosing()
{
if (videoWindow != null)
{
videoWindow.put_Visible(OABool.False);
videoWindow.put_Owner(IntPtr.Zero);
Marshal.ReleaseComObject(videoWindow);
videoWindow = null;
}
}
public void StopAndReleaseResources()
{
if (mediaControl != null)
{
mediaControl.Stop();
SafeRelease(ref mediaControl);
}
SafeRelease(ref videoWindow);
SafeRelease(ref videoRenderer);
SafeRelease(ref lavAudioDecoder);
SafeRelease(ref outputPin);
SafeRelease(ref lavVideoDecoder);
SafeRelease(ref lavSplitter);
SafeRelease(ref graphBuilder);
}
public bool isAtEnd() public bool isAtEnd()
{ {
bool isAtEnd = false; bool isAtEnd = false;
@ -92,42 +41,22 @@ namespace DualScreenDemo.Services
} }
return isAtEnd; return isAtEnd;
} }
public void RenderMediaFile(string filePath, nint Handle, int Width, int Height) public void RenderMediaFile(string filePath)
{ {
StopAndReleaseResources(); Stop();
if (videoWindow != null) videoWindow.put_Visible(OABool.False); SafeRelease(ref renderer);
SafeRelease(ref lavSplitter);
SafeRelease(ref graphBuilder);
int hr = 0; int hr = 0;
graphBuilder = (IGraphBuilder)new FilterGraph(); graphBuilder = (IGraphBuilder)new FilterGraph();
if (graphBuilder == null)
{
Console.WriteLine("Failed to create FilterGraph");
throw new Exception("Failed to create FilterGraph");
}
try try
{ {
lavSplitter = AddFilterByClsid(graphBuilder, "LAV Splitter", Clsid.LAVSplitter); lavSplitter = AddFilterByClsid(graphBuilder, "LAV Splitter", Clsid.LAVSplitter);
lavVideoDecoder = AddFilterByClsid(graphBuilder, "LAV Video Decoder", Clsid.LAVVideoDecoder); AddFilterByClsid(graphBuilder, "LAV Video Decoder", Clsid.LAVVideoDecoder);
lavAudioDecoder = AddFilterByClsid(graphBuilder, "LAV Audio Decoder", Clsid.LAVAudioDecoder); renderer = AddFilterByClsid(graphBuilder, "Secondary Video Renderer", Clsid.VideoRenderer);
outputPin = FindPin(lavAudioDecoder, "Output"); //audioRenderer = AddFilterByClsid(graphBuilder, "Default DirectSound Device", Clsid.AudioRenderer);
videoRenderer = AddFilterByClsid(graphBuilder, "Secondary Video Renderer", Clsid.VideoRenderer);
if (videoRenderer == null)
{
Console.WriteLine("Failed to initialize Secondary Video Renderer.");
return;
}
hr = graphBuilder.AddFilter(videoRenderer, "Secondary Video Renderer");
DsError.ThrowExceptionForHR(hr);
var clsidAudioRenderer = new Guid("79376820-07D0-11CF-A24D-0020AFD79767"); // CLSID for DirectSound Renderer
audioRenderer = (IBaseFilter)Activator.CreateInstance(Type.GetTypeFromCLSID(clsidAudioRenderer));
hr = graphBuilder.AddFilter(audioRenderer, "Default DirectSound Device");
DsError.ThrowExceptionForHR(hr);
mediaControl = (IMediaControl)graphBuilder; mediaControl = (IMediaControl)graphBuilder;
if (mediaControl == null)
{
Console.WriteLine("Failed to get Media Control");
return;
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -135,40 +64,25 @@ namespace DualScreenDemo.Services
} }
hr = graphBuilder.RenderFile(filePath, null); hr = graphBuilder.RenderFile(filePath, null);
if (hr == 0) if (hr == 0)
{
Console.WriteLine("Secondary File rendered successfully.");
SetAudioTrackTo(1); SetAudioTrackTo(1);
}
else else
{
Console.WriteLine("Failed to render secondary file."); Console.WriteLine("Failed to render secondary file.");
}
// 绑定视频窗口到副屏幕
videoWindow = videoRenderer as IVideoWindow;
if (videoWindow != null)
{
videoWindow.put_Owner(Handle); // 副屏幕窗口句柄
videoWindow.put_WindowStyle(WindowStyle.Child | WindowStyle.ClipChildren | WindowStyle.ClipSiblings);
videoWindow.SetWindowPosition(0, 0, Width, Height);
videoWindow.put_Visible(OABool.True); // 显示窗口
}
} }
public void SetVolume(int volume) public void SetVolume(int volume)
{ {
if (audioRenderer != null) if (graphBuilder != null)
{ {
IBasicAudio basicAudio = audioRenderer as IBasicAudio; IBasicAudio basicAudio = graphBuilder as IBasicAudio;
if (basicAudio != null) if (basicAudio != null)
{ basicAudio.put_Volume( Math.Max(-10000, Math.Min(0, volume)));
basicAudio.put_Volume(volume);
}
} }
} }
public int GetVolume() public int GetVolume()
{ {
if (audioRenderer != null) if (graphBuilder != null)
{ {
IBasicAudio basicAudio = audioRenderer as IBasicAudio; IBasicAudio basicAudio = graphBuilder as IBasicAudio;
if (basicAudio != null) if (basicAudio != null)
{ {
int volume; int volume;

View File

@ -9,46 +9,14 @@ namespace DualScreenDemo.Services
IGraphBuilder graphBuilder; IGraphBuilder graphBuilder;
IBaseFilter lavSplitter; IBaseFilter lavSplitter;
IBaseFilter lavVideoDecoder; IBaseFilter lavVideoDecoder;
IBaseFilter videoRenderer; public IBaseFilter videoRenderer;
IVideoWindow videoWindow;
IMediaControl mediaControl; IMediaControl mediaControl;
IBaseFilter sourceFilter; IBaseFilter sourceFilter;
public MediaServicePrimary() { } public MediaServicePrimary() { }
public int Run() public int Run() => (mediaControl != null) ? mediaControl.Run() : 0;
{ public int Stop() => (mediaControl != null)? mediaControl.Stop() : 0;
if (mediaControl != null) public int Pause() => (mediaControl != null) ? mediaControl.Pause() : 0;
return mediaControl.Run();
else
return 0;
}
public int Stop()
{
if (mediaControl != null)
return mediaControl.Stop();
else
return 0;
}
public int Pause()
{
if (mediaControl != null)
return mediaControl.Pause();
else
return 0;
}
public void VideoPlayerFormClosing()
{
if (videoWindow != null)
{
videoWindow.put_Visible(OABool.False);
videoWindow.put_Owner(IntPtr.Zero);
Marshal.ReleaseComObject(videoWindow);
videoWindow = null;
}
}
public void StopAndReleaseResources() public void StopAndReleaseResources()
{ {
@ -57,7 +25,6 @@ namespace DualScreenDemo.Services
mediaControl.Stop(); mediaControl.Stop();
SafeRelease(ref mediaControl); SafeRelease(ref mediaControl);
} }
SafeRelease(ref videoWindow);
SafeRelease(ref videoRenderer); SafeRelease(ref videoRenderer);
SafeRelease(ref sourceFilter); SafeRelease(ref sourceFilter);
SafeRelease(ref lavVideoDecoder); SafeRelease(ref lavVideoDecoder);
@ -65,10 +32,10 @@ namespace DualScreenDemo.Services
SafeRelease(ref graphBuilder); SafeRelease(ref graphBuilder);
} }
public void RenderMediaFile(string filePath, nint Handle, int Width, int Height) public void RenderMediaFile(string filePath)
{ {
StopAndReleaseResources(); StopAndReleaseResources();
if (videoWindow != null) videoWindow.put_Visible(OABool.False);
int hr; int hr;
graphBuilder = (IGraphBuilder)new FilterGraph(); graphBuilder = (IGraphBuilder)new FilterGraph();
@ -84,38 +51,12 @@ namespace DualScreenDemo.Services
hr = graphBuilder.AddFilter(videoRenderer, "Primary Video Renderer"); hr = graphBuilder.AddFilter(videoRenderer, "Primary Video Renderer");
DsError.ThrowExceptionForHR(hr); DsError.ThrowExceptionForHR(hr);
mediaControl = (IMediaControl)graphBuilder;
if (mediaControl == null)
{
Console.WriteLine("Failed to get Media Control for primary monitor.");
return;
}
hr = ConnectFilters(graphBuilder, sourceFilter, "Output", lavSplitter, "Input"); hr = ConnectFilters(graphBuilder, sourceFilter, "Output", lavSplitter, "Input");
DsError.ThrowExceptionForHR(hr); DsError.ThrowExceptionForHR(hr);
hr = ConnectFilters(graphBuilder, lavSplitter, "Video", lavVideoDecoder, "Input"); hr = ConnectFilters(graphBuilder, lavSplitter, "Video", lavVideoDecoder, "Input");
DsError.ThrowExceptionForHR(hr); DsError.ThrowExceptionForHR(hr);
hr = ConnectFilters(graphBuilder, lavVideoDecoder, "Output", videoRenderer, "VMR Input0"); hr = ConnectFilters(graphBuilder, lavVideoDecoder, "Output", videoRenderer, "VMR Input0");
DsError.ThrowExceptionForHR(hr); DsError.ThrowExceptionForHR(hr);
try
{
IVideoWindow videoWindow = (IVideoWindow)videoRenderer;
videoWindow.put_Owner(Handle);
videoWindow.put_WindowStyle(WindowStyle.Child | WindowStyle.ClipChildren);
// ⬅ 左上角對齊(固定從 0,0 開始)
videoWindow.SetWindowPosition(0, 0, Width, Height);
videoWindow.put_Visible(OABool.True);
// Console.WriteLine("Video window configured successfully.");
}
catch (Exception ex)
{
Console.WriteLine(String.Format("Error syncing to primary monitor: {0}", ex.Message));
MessageBox.Show(String.Format("Error syncing to primary monitor: {0}", ex.Message));
}
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

@ -54,7 +54,7 @@ namespace DualScreenDemo.Services
{ {
PinInfo pinInfo; PinInfo pinInfo;
pins[0].QueryPinInfo(out pinInfo); pins[0].QueryPinInfo(out pinInfo);
Console.WriteLine(pinInfo); //Console.WriteLine(pinInfo+":"+pinInfo.name);
if (pinInfo.name == pinName) if (pinInfo.name == pinName)
{ {

View File

@ -71,6 +71,8 @@ namespace DualScreenDemo
private const uint SWP_NOZORDER = 0x0004; private const uint SWP_NOZORDER = 0x0004;
private MediaServicePrimary primary = new MediaServicePrimary(); private MediaServicePrimary primary = new MediaServicePrimary();
private MediaService secondary = new MediaService(); private MediaService secondary = new MediaService();
private IVideoWindow videoWindowPrimary;
private IVideoWindow videoWindowSecondary;
public static OverlayForm overlayForm; public static OverlayForm overlayForm;
public bool isMuted = false; public bool isMuted = false;
@ -158,8 +160,20 @@ namespace DualScreenDemo
private void VideoPlayerForm_FormClosing(object sender, FormClosingEventArgs e) private void VideoPlayerForm_FormClosing(object sender, FormClosingEventArgs e)
{ {
primary.VideoPlayerFormClosing(); if (videoWindowPrimary != null)
secondary.VideoPlayerFormClosing(); {
videoWindowPrimary.put_Visible(OABool.False);
videoWindowPrimary.put_Owner(IntPtr.Zero);
Marshal.ReleaseComObject(videoWindowPrimary);
videoWindowPrimary = null;
}
if (videoWindowSecondary != null)
{
videoWindowSecondary.put_Visible(OABool.False);
videoWindowSecondary.put_Owner(IntPtr.Zero);
Marshal.ReleaseComObject(videoWindowSecondary);
videoWindowSecondary = null;
}
// 清理COM // 清理COM
CoUninitialize(); CoUninitialize();
} }
@ -273,10 +287,6 @@ namespace DualScreenDemo
SerialPortManager.mySerialPort.Write(commandBytesIncreasePitch1, 0, commandBytesIncreasePitch1.Length); SerialPortManager.mySerialPort.Write(commandBytesIncreasePitch1, 0, commandBytesIncreasePitch1.Length);
} }
} }
// pathToPlay 需要調整
var pathToPlay = songToPlay.getFile();
// 更新畫面上顯示的下一首歌資訊 // 更新畫面上顯示的下一首歌資訊
SongList.UpdateNextSongLabel(); SongList.UpdateNextSongLabel();
@ -286,45 +296,40 @@ namespace DualScreenDemo
// 隱藏「暫停中」標籤 // 隱藏「暫停中」標籤
overlayForm.HidePauseLabel(); overlayForm.HidePauseLabel();
await _InitializeAndPlayMedia(pathToPlay); await _InitializeAndPlayMedia(songToPlay);
} }
public async Task ReplayCurrentSong() public async Task ReplayCurrentSong() =>await _InitializeAndPlayMedia(SongList.Current());
{
var songToPlay = SongList.Current(); private async Task _InitializeAndPlayMedia(SongData song)
var pathToPlay = songToPlay.getFile();
// UpdateMarqueeTextForCurrentSong(songToPlay);
await _InitializeAndPlayMedia(pathToPlay);
}
private async Task _InitializeAndPlayMedia(string pathToPlay)
{ {
try try
{ {
if (InvokeRequired) if (InvokeRequired)
{ {
await InvokeAsync(() => InitializeAndPlayMedia(pathToPlay)); await InvokeAsync(() => InitializeAndPlayMedia(song));
} }
else else
{ {
await InitializeAndPlayMedia(pathToPlay); await InitializeAndPlayMedia(song);
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
Console.WriteLine($"播放時發生錯誤: {ex.Message}"); Console.WriteLine($"播放時發生錯誤: {ex.Message}");
await RetryInitializeAndPlayMedia(pathToPlay); await RetryInitializeAndPlayMedia(song);
} }
} }
private async Task RetryInitializeAndPlayMedia(string path) private async Task RetryInitializeAndPlayMedia(SongData song)
{ {
try try
{ {
int hr = CoInitializeEx(IntPtr.Zero, COINIT.APARTMENTTHREADED); int hr = CoInitializeEx(IntPtr.Zero, COINIT.APARTMENTTHREADED);
if (hr >= 0) if (hr >= 0)
{ {
await InitializeAndPlayMedia(path); await InitializeAndPlayMedia(song);
} }
else else
{ {
@ -356,11 +361,35 @@ namespace DualScreenDemo
return tcs.Task; return tcs.Task;
} }
private Task InitializeAndPlayMedia(string pathToPlay) private Task InitializeAndPlayMedia(SongData song)
{ {
string pathToPlay = song.getFile();
if (videoWindowPrimary != null) videoWindowPrimary.put_Visible(OABool.False);
if (videoWindowSecondary != null) videoWindowSecondary.put_Visible(OABool.False);
// 渲染媒體文件 // 渲染媒體文件
primary.RenderMediaFile(pathToPlay,PrimaryForm.Instance.primaryScreenPanel.Handle,newWidth,newHeight); primary.RenderMediaFile(pathToPlay);
secondary.RenderMediaFile(pathToPlay,this.Handle,secondMonitor.Bounds.Width,secondMonitor.Bounds.Height); secondary.RenderMediaFile(pathToPlay);
videoWindowPrimary = primary.videoRenderer as IVideoWindow;
if (videoWindowPrimary != null)
{
videoWindowPrimary.put_Owner(PrimaryForm.Instance.primaryScreenPanel.Handle);
videoWindowPrimary.put_WindowStyle(WindowStyle.Child | WindowStyle.ClipChildren);
videoWindowPrimary.SetWindowPosition(0, 0, newWidth, newHeight);
videoWindowPrimary.put_Visible(OABool.True);
}
// 绑定视频窗口到副屏幕
videoWindowSecondary = secondary.renderer as IVideoWindow;
if (videoWindowSecondary != null)
{
videoWindowSecondary.put_Owner(this.Handle);
videoWindowSecondary.put_WindowStyle(WindowStyle.Child | WindowStyle.ClipChildren | WindowStyle.ClipSiblings);
videoWindowSecondary.SetWindowPosition(0, 0, secondMonitor.Bounds.Width, secondMonitor.Bounds.Height);
videoWindowSecondary.put_Visible(OABool.True);
}
// 音量處理 // 音量處理
SetVolume(isMuted ? -10000 : previousVolume); SetVolume(isMuted ? -10000 : previousVolume);
@ -392,6 +421,7 @@ namespace DualScreenDemo
{ {
Task.Run(async () => Task.Run(async () =>
{ {
await Task.Delay(10000);
Console.WriteLine("開始監聽媒體事件..."); Console.WriteLine("開始監聽媒體事件...");
while (true) while (true)
{ {