Skip to content

Commit

Permalink
Added check for outdated dependencies
Browse files Browse the repository at this point in the history
  • Loading branch information
MarkMpn committed Oct 15, 2023
1 parent 93820d6 commit 796cf45
Show file tree
Hide file tree
Showing 3 changed files with 311 additions and 0 deletions.
1 change: 1 addition & 0 deletions MarkMpn.Sql4Cds/MarkMpn.Sql4Cds.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
<ItemGroup>
<Compile Include="Plugin.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="WindowsExplorerFileSelector.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MarkMpn.Sql4Cds.Controls\MarkMpn.Sql4Cds.Controls.csproj">
Expand Down
25 changes: 25 additions & 0 deletions MarkMpn.Sql4Cds/Plugin.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
using System;
using System.ComponentModel.Composition;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;
using XrmToolBox.Extensibility;
using XrmToolBox.Extensibility.Interfaces;

Expand Down Expand Up @@ -34,6 +36,29 @@ static Plugin()

public override IXrmToolBoxPluginControl GetControl()
{
// Tool install can unpack files that should only exist in the MarkMpn.Sql4Cds subfolder into the main plugin folder as well
// Those files are loaded automatically when XrmToolBox starts, so if a newer tool version is installed and those files are
// not overwritten we could end up with unexpected behaviour. The files are locked so we can't delete them automatically, but
// let the user know what's going on and how to fix it.
var pluginFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
var subfolder = Path.Combine(pluginFolder, Path.GetFileNameWithoutExtension(Assembly.GetExecutingAssembly().Location));
var files = Directory.GetFiles(subfolder, "*.dll")
.Select(f => Path.GetFileName(f))
.Where(f => File.Exists(Path.Combine(pluginFolder, f)))
.ToList();

if (files.Count > 0)
{
var expectedVersion = Assembly.GetExecutingAssembly().GetCustomAttribute<AssemblyFileVersionAttribute>().Version;

var result = MessageBox.Show($"You have some files left over from a previous installation of SQL 4 CDS version.\r\n\r\nTo ensure everything works as expected with version {expectedVersion}, please delete the following files that exist in {pluginFolder} and restart XrmToolBox.\r\n\r\n" + String.Join("\r\n", files.Select(f => $"* {f}")) + "\r\n\r\nWould you like to open this folder now?", "Multiple Versions", MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1);

if (result == DialogResult.Yes)
{
windowsExplorerFileSelector.ShowSelectedInExplorer.FilesOrFolders(pluginFolder, files);
}
}

var controlType = _primaryAssembly.GetType("MarkMpn.Sql4Cds.XTB.PluginControl");
return (IXrmToolBoxPluginControl) Activator.CreateInstance(controlType, this);
}
Expand Down
285 changes: 285 additions & 0 deletions MarkMpn.Sql4Cds/WindowsExplorerFileSelector.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,285 @@
/*
* Created by SharpDevelop.
* User: Aurimas Rekstys
* Date: 6/24/2018
* Time: 6:44 PM
* https://raw.githubusercontent.com/aurire/windows-explorer-files-selector/master/windows-explorer-file-selector/windows-explorer-file-selector.cs
*
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;

namespace windowsExplorerFileSelector
{

[Flags]
internal enum SHCONT : ushort
{
SHCONTF_CHECKING_FOR_CHILDREN = 0x0010,
SHCONTF_FOLDERS = 0x0020,
SHCONTF_NONFOLDERS = 0x0040,
SHCONTF_INCLUDEHIDDEN = 0x0080,
SHCONTF_INIT_ON_FIRST_NEXT = 0x0100,
SHCONTF_NETPRINTERSRCH = 0x0200,
SHCONTF_SHAREABLE = 0x0400,
SHCONTF_STORAGE = 0x0800,
SHCONTF_NAVIGATION_ENUM = 0x1000,
SHCONTF_FASTITEMS = 0x2000,
SHCONTF_FLATLIST = 0x4000,
SHCONTF_ENABLE_ASYNC = 0x8000
}

[ComImport,
Guid("000214E6-0000-0000-C000-000000000046"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
ComConversionLoss]
internal interface IShellFolder
{
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void ParseDisplayName(IntPtr hwnd, [In, MarshalAs(UnmanagedType.Interface)] IBindCtx pbc, [In, MarshalAs(UnmanagedType.LPWStr)] string pszDisplayName, [Out] out uint pchEaten, [Out] out IntPtr ppidl, [In, Out] ref uint pdwAttributes);
[PreserveSig]
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
int EnumObjects([In] IntPtr hwnd, [In] SHCONT grfFlags, [MarshalAs(UnmanagedType.Interface)] out IEnumIDList ppenumIDList);

[PreserveSig]
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
int BindToObject([In] IntPtr pidl, [In, MarshalAs(UnmanagedType.Interface)] IBindCtx pbc, [In] ref Guid riid, [Out, MarshalAs(UnmanagedType.Interface)] out IShellFolder ppv);

[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void BindToStorage([In] ref IntPtr pidl, [In, MarshalAs(UnmanagedType.Interface)] IBindCtx pbc, [In] ref Guid riid, out IntPtr ppv);

[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void CompareIDs([In] IntPtr lParam, [In] ref IntPtr pidl1, [In] ref IntPtr pidl2);

[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void CreateViewObject([In] IntPtr hwndOwner, [In] ref Guid riid, out IntPtr ppv);

[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void GetAttributesOf([In] uint cidl, [In] IntPtr apidl, [In, Out] ref uint rgfInOut);


[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void GetUIObjectOf([In] IntPtr hwndOwner, [In] uint cidl, [In] IntPtr apidl, [In] ref Guid riid, [In, Out] ref uint rgfReserved, out IntPtr ppv);

[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void GetDisplayNameOf([In] ref IntPtr pidl, [In] uint uFlags, out IntPtr pName);

[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SetNameOf([In] IntPtr hwnd, [In] ref IntPtr pidl, [In, MarshalAs(UnmanagedType.LPWStr)] string pszName, [In] uint uFlags, [Out] IntPtr ppidlOut);
}

[ComImport,
Guid("000214F2-0000-0000-C000-000000000046"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IEnumIDList
{
[PreserveSig]
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
int Next(uint celt, IntPtr rgelt, out uint pceltFetched);

[PreserveSig]
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
int Skip([In] uint celt);

[PreserveSig]
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
int Reset();

[PreserveSig]
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
int Clone([MarshalAs(UnmanagedType.Interface)] out IEnumIDList ppenum);
}



static class ShowSelectedInExplorer
{


class NativeMethods
{
static readonly int pointerSize = Marshal.SizeOf(typeof(IntPtr));

[DllImport("ole32.dll", EntryPoint = "CreateBindCtx")]
public static extern int CreateBindCtx_(int reserved, out IBindCtx ppbc);

public static IBindCtx CreateBindCtx()
{
IBindCtx result;
Marshal.ThrowExceptionForHR(CreateBindCtx_(0, out result));
return result;
}

[DllImport("shell32.dll", EntryPoint = "SHGetDesktopFolder", CharSet = CharSet.Unicode, SetLastError = true)]
static extern int SHGetDesktopFolder_([MarshalAs(UnmanagedType.Interface)] out IShellFolder ppshf);

public static IShellFolder SHGetDesktopFolder()
{
IShellFolder result;
Marshal.ThrowExceptionForHR(SHGetDesktopFolder_(out result));
return result;
}

[DllImport("shell32.dll", EntryPoint = "SHOpenFolderAndSelectItems")]
static extern int SHOpenFolderAndSelectItems_(
[In] IntPtr pidlFolder, uint cidl, [In, Optional, MarshalAs(UnmanagedType.LPArray)] IntPtr[] apidl, int dwFlags
);

public static void SHOpenFolderAndSelectItems(IntPtr pidlFolder, IntPtr[] apidl, int dwFlags)
{
var cidl = (apidl != null) ? (uint)apidl.Length : 0U;
var result = NativeMethods.SHOpenFolderAndSelectItems_(pidlFolder, cidl, apidl, dwFlags);
Marshal.ThrowExceptionForHR(result);
}

[DllImport("shell32.dll", CharSet = CharSet.Unicode)]
public static extern IntPtr ILCreateFromPath([In, MarshalAs(UnmanagedType.LPWStr)] string pszPath);

[DllImport("shell32.dll")]
public static extern void ILFree([In] IntPtr pidl);
}

static IntPtr GetShellFolderChildrenRelativePIDL(IShellFolder parentFolder, string displayName)
{
var bindCtx = NativeMethods.CreateBindCtx();

uint pchEaten;
uint pdwAttributes = 0;
IntPtr ppidl;
parentFolder.ParseDisplayName(IntPtr.Zero, null, displayName, out pchEaten, out ppidl, ref pdwAttributes);

return ppidl;
}

static IntPtr PathToAbsolutePIDL(string path)
{
var desktopFolder = NativeMethods.SHGetDesktopFolder();
return GetShellFolderChildrenRelativePIDL(desktopFolder, path);
}

static Guid IID_IShellFolder = typeof(IShellFolder).GUID;
static int pointerSize = Marshal.SizeOf(typeof(IntPtr));

static IShellFolder PIDLToShellFolder(IShellFolder parent, IntPtr pidl)
{
IShellFolder folder;
var result = parent.BindToObject(pidl, null, ref IID_IShellFolder, out folder);
Marshal.ThrowExceptionForHR((int)result);
return folder;
}

static IShellFolder PIDLToShellFolder(IntPtr pidl)
{
return PIDLToShellFolder(NativeMethods.SHGetDesktopFolder(), pidl);
}

static void SHOpenFolderAndSelectItems(IntPtr pidlFolder, IntPtr[] apidl, bool edit)
{
NativeMethods.SHOpenFolderAndSelectItems(pidlFolder, apidl, edit ? 1 : 0);
}

public static void FileOrFolder(string path, bool edit = false)
{
if (path == null)
throw new ArgumentNullException("path");

var pidl = PathToAbsolutePIDL(path);
try
{
SHOpenFolderAndSelectItems(pidl, null, edit);
}
finally
{
NativeMethods.ILFree(pidl);
}
}

static IEnumerable<FileSystemInfo> PathToFileSystemInfo(IEnumerable<string> paths)
{
foreach (var path in paths)
{
string fixedPath = path;
if (fixedPath.EndsWith(Path.DirectorySeparatorChar.ToString()) || fixedPath.EndsWith(Path.AltDirectorySeparatorChar.ToString()))
{
fixedPath = fixedPath.Remove(fixedPath.Length - 1);
}

if (Directory.Exists(fixedPath))
yield return new DirectoryInfo(fixedPath);
else if (File.Exists(fixedPath))
yield return new FileInfo(fixedPath);
else
{
throw new FileNotFoundException("The specified file or folder doesn't exists : " + fixedPath, fixedPath);
}
}
}

public static void FilesOrFolders(string parentDirectory, ICollection<string> filenames)
{
if (filenames == null)
throw new ArgumentNullException("filenames");
if (filenames.Count == 0)
return;

var parentPidl = PathToAbsolutePIDL(parentDirectory);
try
{
var parent = PIDLToShellFolder(parentPidl);

List<IntPtr> filesPidl = new List<IntPtr>(filenames.Count);
foreach (var filename in filenames)
{
filesPidl.Add(GetShellFolderChildrenRelativePIDL(parent, filename));
}

try
{
SHOpenFolderAndSelectItems(parentPidl, filesPidl.ToArray(), false);
}
finally
{
foreach (var pidl in filesPidl)
{
NativeMethods.ILFree(pidl);
}
}
}
finally
{
NativeMethods.ILFree(parentPidl);
}
}

public static void FilesOrFolders(string[] paths)
{
FilesOrFolders((IEnumerable<string>)paths);
}

public static void FilesOrFolders(IEnumerable<string> paths)
{
FilesOrFolders(PathToFileSystemInfo(paths));
}

public static void FilesOrFolders(IEnumerable<FileSystemInfo> paths)
{
if (paths == null)
throw new ArgumentNullException("paths");
if (paths.Count() == 0)
return;

var explorerWindows = paths.GroupBy(p => Path.GetDirectoryName(p.FullName));

foreach (var explorerWindowPaths in explorerWindows)
{
var parentDirectory = Path.GetDirectoryName(explorerWindowPaths.First().FullName);
FilesOrFolders(parentDirectory, explorerWindowPaths.Select(fsi => fsi.Name).ToList());
}
}
}
}

0 comments on commit 796cf45

Please sign in to comment.