Skip to content

Commit

Permalink
Merge pull request #23 from rioil/fix-issue22
Browse files Browse the repository at this point in the history
COM参照を使用しない実装に変更
  • Loading branch information
rioil authored Mar 31, 2024
2 parents 4a0b5cc + c58867d commit 33cdce3
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 33 deletions.
98 changes: 98 additions & 0 deletions VRChatLogWathcer/Utils/COMObject.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
using System;
using System.Runtime.InteropServices;

namespace VRChatLogWathcer.Utils
{
/// <summary>
/// COMオブジェクトの開放処理を確実に行うためのラッパーオブジェクト
/// </summary>
internal class COMObject : IDisposable
{
private dynamic? _object;
private bool _isDisposed;

public dynamic Object => (_isDisposed || _object is null) ? throw new ObjectDisposedException(nameof(COMObject)) : _object;

public COMObject(dynamic comObject)
{
_object = comObject;
}

protected virtual void Dispose(bool disposing)
{
if (!_isDisposed)
{
//if (disposing)
//{
// // TODO: マネージド状態を破棄します (マネージド オブジェクト)
//}

Marshal.ReleaseComObject(_object);
_object = null;
_isDisposed = true;
}
}

~COMObject()
{
// このコードを変更しないでください。クリーンアップ コードを 'Dispose(bool disposing)' メソッドに記述します
Dispose(disposing: false);
}

public void Dispose()
{
// このコードを変更しないでください。クリーンアップ コードを 'Dispose(bool disposing)' メソッドに記述します
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
}

/// <summary>
/// COMオブジェクトの開放処理を確実に行うためのラッパーオブジェクト
/// </summary>
/// <typeparam name="T"></typeparam>
internal class COMObject<T> : IDisposable
{
private dynamic? _object;
private bool _isDisposed;

public dynamic Object => (_isDisposed || _object is null) ? throw new ObjectDisposedException(nameof(COMObject)) : _object;

public T Casted => (T)Object;

public COMObject(dynamic comObject)
{
_object = comObject;
}

protected virtual void Dispose(bool disposing)
{
if (!_isDisposed)
{
//if (disposing)
//{
// // TODO: マネージド状態を破棄します (マネージド オブジェクト)
//}

Marshal.ReleaseComObject(_object);
_object = null;
_isDisposed = true;
}
}

~COMObject()
{
// このコードを変更しないでください。クリーンアップ コードを 'Dispose(bool disposing)' メソッドに記述します
Dispose(disposing: false);
}

public void Dispose()
{
// このコードを変更しないでください。クリーンアップ コードを 'Dispose(bool disposing)' メソッドに記述します
Dispose(disposing: true);
GC.SuppressFinalize(this);
}

public static implicit operator T(COMObject<T> obj) => obj.Casted;
}
}
52 changes: 40 additions & 12 deletions VRChatLogWathcer/Utils/ExplorerUtil.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using SHDocVw;
using Shell32;
using System;
using System;
using System.Collections;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;

namespace VRChatLogWathcer.Utils
Expand Down Expand Up @@ -56,25 +56,53 @@ public static bool Open(string path)
/// <returns></returns>
private static bool TryGetHwndOf(string path, out IntPtr hwnd)
{
var shell = new Shell();
ShellWindows wins = shell.Windows();
foreach (InternetExplorer win in wins)
Type? comShellType = Type.GetTypeFromProgID("Shell.Application");
if (comShellType is null)
{
if (!win.FullName.Equals(ExplorerPath, StringComparison.OrdinalIgnoreCase))
hwnd = default;
return false;
}

try
{
if (!TryCreateShell(comShellType, out var instance))
{
continue;
hwnd = default;
return false;
}
using var shell = new COMObject(instance);
using var wins = new COMObject(shell.Object.Windows());
using var enumerator = new COMObject<IEnumerator>(wins.Object.GetEnumerator());

var uri = new Uri(win.LocationURL);
if (path.Equals(uri.LocalPath, StringComparison.OrdinalIgnoreCase))
while (enumerator.Casted.MoveNext())
{
hwnd = new IntPtr(win.HWND);
return true;
using var win = new COMObject(enumerator.Casted.Current);
if (!win.Object.FullName.Equals(ExplorerPath, StringComparison.OrdinalIgnoreCase))
{
continue;
}

var uri = new Uri(win.Object.LocationURL);
if (path.Equals(uri.LocalPath, StringComparison.OrdinalIgnoreCase))
{
hwnd = new IntPtr(win.Object.HWND);
return true;
}
}
}
catch
{
// COM関連で発生した例外は握りつぶす
}

hwnd = default;
return false;

static bool TryCreateShell(Type type, [NotNullWhen(true)] out object? instance)
{
instance = Activator.CreateInstance(type);
return instance is not null;
}
}

private class NativeMethods
Expand Down
21 changes: 0 additions & 21 deletions VRChatLogWathcer/VRChatLogWathcer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,27 +12,6 @@
<VersionSuffix></VersionSuffix>
</PropertyGroup>

<ItemGroup>
<COMReference Include="Shell32">
<WrapperTool>tlbimp</WrapperTool>
<VersionMinor>0</VersionMinor>
<VersionMajor>1</VersionMajor>
<Guid>50a7e9b0-70ef-11d1-b75a-00a0c90564fe</Guid>
<Lcid>0</Lcid>
<Isolated>false</Isolated>
<EmbedInteropTypes>true</EmbedInteropTypes>
</COMReference>
<COMReference Include="SHDocVw">
<WrapperTool>tlbimp</WrapperTool>
<VersionMinor>1</VersionMinor>
<VersionMajor>1</VersionMajor>
<Guid>eab22ac0-30c1-11cf-a7eb-0000c05bae0b</Guid>
<Lcid>0</Lcid>
<Isolated>false</Isolated>
<EmbedInteropTypes>true</EmbedInteropTypes>
</COMReference>
</ItemGroup>


<ItemGroup>
<Resource Include="Resources\icon.ico" />
Expand Down

0 comments on commit 33cdce3

Please sign in to comment.