Created
September 28, 2017 11:19
-
-
Save smourier/0b85ab1336c0e3e3f15a75315cc6fe63 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.ComponentModel; | |
using System.IO; | |
using System.Runtime.InteropServices; | |
using Microsoft.Office.Interop.Access.Dao; | |
using Microsoft.Win32; | |
namespace ConsoleApp2 | |
{ | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
const string progid = "DAO.DBEngine.120"; | |
var engineClsid = GetClickToRunClsid(progid); | |
string acedaoPath = GetClickToRunServerPath(progid); | |
using (var server = new ComServer(acedaoPath)) | |
{ | |
// you can still use the Microsoft.Office.Interop.Access.Dao references | |
var engine = (DBEngine)server.CreateInstance(engineClsid, typeof(DBEngine).GUID); | |
foreach (Property prop in engine.Properties) | |
{ | |
try | |
{ | |
Console.WriteLine(prop.Name + " = " + prop.Value); | |
} | |
catch | |
{ | |
Console.WriteLine(prop.Name + " ?"); | |
} | |
} | |
} | |
} | |
public const string ClickToRunClasses = @"SOFTWARE\Microsoft\Office\ClickToRun\REGISTRY\MACHINE\Software\Classes"; | |
// this needs to run as 64-bit if OS is 64, etc. | |
public static string GetClickToRunServerPath(string progid) | |
{ | |
if (progid == null) | |
throw new ArgumentNullException(nameof(progid)); | |
using (var key = Registry.LocalMachine.OpenSubKey(Path.Combine(ClickToRunClasses, "CLSID", GetClickToRunClsid(progid).ToString("B"), "InprocServer32"), false)) | |
{ | |
return key?.GetValue(null) as string; | |
} | |
} | |
// this needs to run as 64-bit if OS is 64, etc. | |
public static Guid GetClickToRunClsid(string progid) | |
{ | |
if (progid == null) | |
throw new ArgumentNullException(nameof(progid)); | |
using (var key = Registry.LocalMachine.OpenSubKey(Path.Combine(ClickToRunClasses, progid, "CLSID"), false)) | |
{ | |
var str = key?.GetValue(null) as string; | |
if (str == null || !Guid.TryParse(str, out Guid clsid)) | |
return Guid.Empty; | |
return clsid; | |
} | |
} | |
} | |
public sealed class ComServer : IDisposable | |
{ | |
private DllGetClassObject _getClassObject; | |
public ComServer(string path) | |
{ | |
if (path == null) | |
throw new ArgumentNullException(nameof(path)); | |
Module = LoadLibrary(path); | |
if (Module == IntPtr.Zero) | |
throw new Win32Exception(Marshal.GetLastWin32Error()); | |
IntPtr gpa = GetProcAddress(Module, nameof(DllGetClassObject)); | |
if (gpa == IntPtr.Zero) | |
throw new Win32Exception(Marshal.GetLastWin32Error()); | |
_getClassObject = Marshal.GetDelegateForFunctionPointer<DllGetClassObject>(gpa); | |
} | |
public IntPtr Module { get; private set; } | |
public object CreateInstance(Guid clsid, Guid riid) | |
{ | |
if (Module == IntPtr.Zero) | |
throw new ObjectDisposedException(nameof(Module)); | |
int hr = _getClassObject.Invoke(clsid, typeof(IClassFactory).GUID, out IClassFactory factory); | |
if (hr != 0) | |
throw new Win32Exception(hr); | |
return factory.CreateInstance(null, riid); // InvalidCastException here means the class doesn't support the requested interface | |
} | |
public void Dispose() | |
{ | |
if (Module != IntPtr.Zero) | |
{ | |
FreeLibrary(Module); | |
Module = IntPtr.Zero; | |
} | |
} | |
private delegate int DllGetClassObject([MarshalAs(UnmanagedType.LPStruct)] Guid rclsid, [MarshalAs(UnmanagedType.LPStruct)] Guid riid, out IClassFactory ppv); | |
[DllImport("kernel32.dll", SetLastError = true)] | |
private static extern IntPtr LoadLibrary(string lpFileName); | |
[DllImport("kernel32.dll", SetLastError = true)] | |
private static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName); | |
[DllImport("kernel32.dll")] | |
private static extern bool FreeLibrary(IntPtr hModule); | |
[Guid("00000001-0000-0000-c000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] | |
private interface IClassFactory | |
{ | |
[return: MarshalAs(UnmanagedType.Interface)] | |
object CreateInstance([MarshalAs(UnmanagedType.Interface)] object pUnkOuter, [MarshalAs(UnmanagedType.LPStruct)] Guid riid); | |
void LockServer(bool fLock); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment