From f10a1b7663a5b98f44d14be41893b6b40bfb1894 Mon Sep 17 00:00:00 2001 From: Daniel Triendl Date: Fri, 16 Sep 2022 12:32:25 +0200 Subject: [PATCH] Initial import --- .gitignore | 405 ++++++++++++++++++++ PdbFind.Gui/App.config | 18 + PdbFind.Gui/FormPdbFind.Designer.cs | 189 +++++++++ PdbFind.Gui/FormPdbFind.cs | 119 ++++++ PdbFind.Gui/FormPdbFind.resx | 63 +++ PdbFind.Gui/PdbFind.Gui.csproj | 33 ++ PdbFind.Gui/Program.cs | 28 ++ PdbFind.Gui/Properties/Settings.Designer.cs | 50 +++ PdbFind.Gui/Properties/Settings.settings | 12 + PdbFind.Gui/ShowSelectedInExplorer.cs | 260 +++++++++++++ PdbFind.Lib/Locator.cs | 48 +++ PdbFind.Lib/PdbFind.Lib.csproj | 13 + PdbFind.sln | 37 ++ PdbFind/PdbFind.csproj | 14 + PdbFind/Program.cs | 26 ++ PdbFind/Properties/launchSettings.json | 8 + 16 files changed, 1323 insertions(+) create mode 100644 .gitignore create mode 100644 PdbFind.Gui/App.config create mode 100644 PdbFind.Gui/FormPdbFind.Designer.cs create mode 100644 PdbFind.Gui/FormPdbFind.cs create mode 100644 PdbFind.Gui/FormPdbFind.resx create mode 100644 PdbFind.Gui/PdbFind.Gui.csproj create mode 100644 PdbFind.Gui/Program.cs create mode 100644 PdbFind.Gui/Properties/Settings.Designer.cs create mode 100644 PdbFind.Gui/Properties/Settings.settings create mode 100644 PdbFind.Gui/ShowSelectedInExplorer.cs create mode 100644 PdbFind.Lib/Locator.cs create mode 100644 PdbFind.Lib/PdbFind.Lib.csproj create mode 100644 PdbFind.sln create mode 100644 PdbFind/PdbFind.csproj create mode 100644 PdbFind/Program.cs create mode 100644 PdbFind/Properties/launchSettings.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b06db92 --- /dev/null +++ b/.gitignore @@ -0,0 +1,405 @@ +# Created by https://www.toptal.com/developers/gitignore/api/visualstudio +# Edit at https://www.toptal.com/developers/gitignore?templates=visualstudio + +### VisualStudio ### +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.tlog +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio 6 auto-generated project file (contains which files were open etc.) +*.vbp + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) +*.dsw +*.dsp + +# Visual Studio 6 technical files + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# Visual Studio History (VSHistory) files +.vshistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +# VS Code files for those working on multiple tools +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp + +# JetBrains Rider +*.sln.iml + +### VisualStudio Patch ### +# Additional files built by Visual Studio + +# End of https://www.toptal.com/developers/gitignore/api/visualstudio diff --git a/PdbFind.Gui/App.config b/PdbFind.Gui/App.config new file mode 100644 index 0000000..02a0838 --- /dev/null +++ b/PdbFind.Gui/App.config @@ -0,0 +1,18 @@ + + + + +
+ + + + + + True + + + + + + + \ No newline at end of file diff --git a/PdbFind.Gui/FormPdbFind.Designer.cs b/PdbFind.Gui/FormPdbFind.Designer.cs new file mode 100644 index 0000000..cb251fc --- /dev/null +++ b/PdbFind.Gui/FormPdbFind.Designer.cs @@ -0,0 +1,189 @@ +namespace PdbFind.Gui +{ + partial class FormPdbFind + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.label1 = new System.Windows.Forms.Label(); + this.textBoxSysStore = new System.Windows.Forms.TextBox(); + this.buttonSymStoreBrowse = new System.Windows.Forms.Button(); + this.notifyIcon1 = new System.Windows.Forms.NotifyIcon(this.components); + this.textBoxPeFile = new System.Windows.Forms.TextBox(); + this.buttonPeFileBrowse = new System.Windows.Forms.Button(); + this.label2 = new System.Windows.Forms.Label(); + this.textBoxPdbFile = new System.Windows.Forms.TextBox(); + this.buttonPdbExplore = new System.Windows.Forms.Button(); + this.label3 = new System.Windows.Forms.Label(); + this.buttonLocatePdb = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(12, 15); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(77, 15); + this.label1.TabIndex = 0; + this.label1.Text = "Symbol Store"; + // + // textBoxSysStore + // + this.textBoxSysStore.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textBoxSysStore.Location = new System.Drawing.Point(157, 12); + this.textBoxSysStore.Name = "textBoxSysStore"; + this.textBoxSysStore.Size = new System.Drawing.Size(512, 23); + this.textBoxSysStore.TabIndex = 1; + // + // buttonSymStoreBrowse + // + this.buttonSymStoreBrowse.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.buttonSymStoreBrowse.Location = new System.Drawing.Point(675, 12); + this.buttonSymStoreBrowse.Name = "buttonSymStoreBrowse"; + this.buttonSymStoreBrowse.Size = new System.Drawing.Size(113, 23); + this.buttonSymStoreBrowse.TabIndex = 2; + this.buttonSymStoreBrowse.Text = "Browse"; + this.buttonSymStoreBrowse.UseVisualStyleBackColor = true; + this.buttonSymStoreBrowse.Click += new System.EventHandler(this.buttonSymStoreBrowse_Click); + // + // notifyIcon1 + // + this.notifyIcon1.Text = "notifyIcon1"; + this.notifyIcon1.Visible = true; + // + // textBoxPeFile + // + this.textBoxPeFile.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textBoxPeFile.Location = new System.Drawing.Point(157, 41); + this.textBoxPeFile.Name = "textBoxPeFile"; + this.textBoxPeFile.Size = new System.Drawing.Size(512, 23); + this.textBoxPeFile.TabIndex = 3; + this.textBoxPeFile.TextChanged += new System.EventHandler(this.textBoxPeFile_TextChanged); + // + // buttonPeFileBrowse + // + this.buttonPeFileBrowse.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.buttonPeFileBrowse.Location = new System.Drawing.Point(675, 41); + this.buttonPeFileBrowse.Name = "buttonPeFileBrowse"; + this.buttonPeFileBrowse.Size = new System.Drawing.Size(113, 23); + this.buttonPeFileBrowse.TabIndex = 4; + this.buttonPeFileBrowse.Text = "Browse"; + this.buttonPeFileBrowse.UseVisualStyleBackColor = true; + this.buttonPeFileBrowse.Click += new System.EventHandler(this.buttonPeFileBrowse_Click); + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(12, 45); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(41, 15); + this.label2.TabIndex = 5; + this.label2.Text = "PE File"; + // + // textBoxPdbFile + // + this.textBoxPdbFile.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textBoxPdbFile.Location = new System.Drawing.Point(157, 99); + this.textBoxPdbFile.Name = "textBoxPdbFile"; + this.textBoxPdbFile.ReadOnly = true; + this.textBoxPdbFile.Size = new System.Drawing.Size(512, 23); + this.textBoxPdbFile.TabIndex = 6; + // + // buttonPdbExplore + // + this.buttonPdbExplore.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.buttonPdbExplore.Location = new System.Drawing.Point(675, 99); + this.buttonPdbExplore.Name = "buttonPdbExplore"; + this.buttonPdbExplore.Size = new System.Drawing.Size(113, 23); + this.buttonPdbExplore.TabIndex = 7; + this.buttonPdbExplore.Text = "Show in Explorer"; + this.buttonPdbExplore.UseVisualStyleBackColor = true; + this.buttonPdbExplore.Click += new System.EventHandler(this.buttonPdbExplore_Click); + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(12, 102); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(50, 15); + this.label3.TabIndex = 8; + this.label3.Text = "PDB File"; + // + // buttonLocatePdb + // + this.buttonLocatePdb.Location = new System.Drawing.Point(157, 70); + this.buttonLocatePdb.Name = "buttonLocatePdb"; + this.buttonLocatePdb.Size = new System.Drawing.Size(113, 23); + this.buttonLocatePdb.TabIndex = 9; + this.buttonLocatePdb.Text = "Locate PDB"; + this.buttonLocatePdb.UseVisualStyleBackColor = true; + this.buttonLocatePdb.Click += new System.EventHandler(this.buttonLocatePdb_Click); + // + // FormPdbFind + // + this.AllowDrop = true; + this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; + this.ClientSize = new System.Drawing.Size(800, 145); + this.Controls.Add(this.buttonLocatePdb); + this.Controls.Add(this.label3); + this.Controls.Add(this.buttonPdbExplore); + this.Controls.Add(this.textBoxPdbFile); + this.Controls.Add(this.label2); + this.Controls.Add(this.buttonPeFileBrowse); + this.Controls.Add(this.textBoxPeFile); + this.Controls.Add(this.buttonSymStoreBrowse); + this.Controls.Add(this.textBoxSysStore); + this.Controls.Add(this.label1); + this.Name = "FormPdbFind"; + this.Text = "Pdb Find"; + this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.FormPdbFind_FormClosed); + this.DragDrop += new System.Windows.Forms.DragEventHandler(this.FormPdbFind_DragDrop); + this.DragEnter += new System.Windows.Forms.DragEventHandler(this.FormPdbFind_DragEnter); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private Label label1; + private TextBox textBoxSysStore; + private Button buttonSymStoreBrowse; + private NotifyIcon notifyIcon1; + private TextBox textBoxPeFile; + private Button buttonPeFileBrowse; + private Label label2; + private TextBox textBoxPdbFile; + private Button buttonPdbExplore; + private Label label3; + private Button buttonLocatePdb; + } +} \ No newline at end of file diff --git a/PdbFind.Gui/FormPdbFind.cs b/PdbFind.Gui/FormPdbFind.cs new file mode 100644 index 0000000..9f1e041 --- /dev/null +++ b/PdbFind.Gui/FormPdbFind.cs @@ -0,0 +1,119 @@ +using System.Diagnostics; +using PdbFind.Gui.Properties; +using PdbFind.Lib; + +namespace PdbFind.Gui +{ + public partial class FormPdbFind : Form + { + public FormPdbFind() + { + InitializeComponent(); + + textBoxSysStore.Text = Settings.Default.SymStore; + } + + private void buttonSymStoreBrowse_Click(object sender, EventArgs e) + { + using var fbd = new FolderBrowserDialog(); + fbd.InitialDirectory = textBoxSysStore.Text; + if (fbd.ShowDialog() == DialogResult.OK) + { + if (!string.IsNullOrWhiteSpace(fbd.SelectedPath) && Directory.Exists(fbd.SelectedPath)) + { + textBoxSysStore.Text = fbd.SelectedPath; + } + } + } + + private void FormPdbFind_FormClosed(object sender, FormClosedEventArgs e) + { + Settings.Default.SymStore = textBoxSysStore.Text; + Settings.Default.Save(); + } + + private void buttonPdbExplore_Click(object sender, EventArgs e) + { + var pdb = textBoxPdbFile.Text; + if (!string.IsNullOrWhiteSpace(pdb) && File.Exists(pdb)) + { + ShowSelectedInExplorer.FileOrFolder(pdb); + } + } + + private void buttonPeFileBrowse_Click(object sender, EventArgs e) + { + using var ofd = new OpenFileDialog(); + ofd.CheckFileExists = true; + ofd.Multiselect = false; + var pe = textBoxPeFile.Text; + if (!string.IsNullOrWhiteSpace(pe) && File.Exists(pe)) + { + ofd.InitialDirectory = Path.GetDirectoryName(pe); + ofd.FileName = Path.GetFileName(pe); + } + + if (ofd.ShowDialog() == DialogResult.OK) + { + if (File.Exists(ofd.FileName)) + { + textBoxPeFile.Text = ofd.FileName; + LocatePdb(); + } + } + } + + private void LocatePdb() + { + var store = textBoxSysStore.Text; + var pe = textBoxPeFile.Text; + + if (string.IsNullOrWhiteSpace(store) || !Directory.Exists(store)) + { + return; + } + + if (string.IsNullOrWhiteSpace(pe) || !File.Exists(pe)) + { + return; + } + + try + { + textBoxPdbFile.Text = Locator.LocatePdbInStore(pe, store); + } + catch (Exception e) + { + MessageBox.Show(e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + + private void textBoxPeFile_TextChanged(object sender, EventArgs e) + { + textBoxPdbFile.Text = ""; + } + + private void buttonLocatePdb_Click(object sender, EventArgs e) + { + LocatePdb(); + } + + private void FormPdbFind_DragEnter(object sender, DragEventArgs e) + { + if (e.Data != null && e.Data.GetDataPresent(DataFormats.FileDrop)) + { + e.Effect = DragDropEffects.Copy; + } + } + + private void FormPdbFind_DragDrop(object sender, DragEventArgs e) + { + var files = (string[]?)e.Data?.GetData(DataFormats.FileDrop); + if (files is { Length: > 0 }) + { + textBoxPeFile.Text = files.First(); + LocatePdb(); + } + } + } +} \ No newline at end of file diff --git a/PdbFind.Gui/FormPdbFind.resx b/PdbFind.Gui/FormPdbFind.resx new file mode 100644 index 0000000..1c2f734 --- /dev/null +++ b/PdbFind.Gui/FormPdbFind.resx @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + \ No newline at end of file diff --git a/PdbFind.Gui/PdbFind.Gui.csproj b/PdbFind.Gui/PdbFind.Gui.csproj new file mode 100644 index 0000000..3887a24 --- /dev/null +++ b/PdbFind.Gui/PdbFind.Gui.csproj @@ -0,0 +1,33 @@ + + + + WinExe + net6.0-windows + enable + true + enable + PdbFind.Gui + + + + + + + + + + + True + True + Settings.settings + + + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + \ No newline at end of file diff --git a/PdbFind.Gui/Program.cs b/PdbFind.Gui/Program.cs new file mode 100644 index 0000000..df250cf --- /dev/null +++ b/PdbFind.Gui/Program.cs @@ -0,0 +1,28 @@ +using PdbFind.Gui.Properties; + +namespace PdbFind.Gui +{ + internal static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + // To customize application configuration such as set high DPI settings or default font, + // see https://aka.ms/applicationconfiguration. + ApplicationConfiguration.Initialize(); + + if (Settings.Default.UpgradeNeeded) + { + Settings.Default.Upgrade(); + Settings.Default.UpgradeNeeded = false; + Settings.Default.Save(); + Settings.Default.Reload(); + } + + Application.Run(new FormPdbFind()); + } + } +} \ No newline at end of file diff --git a/PdbFind.Gui/Properties/Settings.Designer.cs b/PdbFind.Gui/Properties/Settings.Designer.cs new file mode 100644 index 0000000..15eec84 --- /dev/null +++ b/PdbFind.Gui/Properties/Settings.Designer.cs @@ -0,0 +1,50 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace PdbFind.Gui.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.4.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool UpgradeNeeded { + get { + return ((bool)(this["UpgradeNeeded"])); + } + set { + this["UpgradeNeeded"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string SymStore { + get { + return ((string)(this["SymStore"])); + } + set { + this["SymStore"] = value; + } + } + } +} diff --git a/PdbFind.Gui/Properties/Settings.settings b/PdbFind.Gui/Properties/Settings.settings new file mode 100644 index 0000000..34c1a1a --- /dev/null +++ b/PdbFind.Gui/Properties/Settings.settings @@ -0,0 +1,12 @@ + + + + + + True + + + + + + \ No newline at end of file diff --git a/PdbFind.Gui/ShowSelectedInExplorer.cs b/PdbFind.Gui/ShowSelectedInExplorer.cs new file mode 100644 index 0000000..f0fff46 --- /dev/null +++ b/PdbFind.Gui/ShowSelectedInExplorer.cs @@ -0,0 +1,260 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.ComTypes; + +namespace PdbFind.Gui; + +static class ShowSelectedInExplorer +{ + [Flags] + 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] + 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)] + 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 NativeMethods + { + [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 = SHOpenFolderAndSelectItems_(pidlFolder, cidl, apidl, dwFlags); + Marshal.ThrowExceptionForHR(result); + } + + [DllImport("shell32.dll")] + public static extern void ILFree([In] IntPtr pidl); + } + + static IntPtr GetShellFolderChildrenRelativePIDL(IShellFolder parentFolder, string displayName) + { + 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 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 PathToFileSystemInfo(IEnumerable paths) + { + foreach (var path in paths) + { + var 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 + (string.Format("The specified file or folder doesn't exists : {0}", fixedPath), + fixedPath); + } + } + } + + public static void FilesOrFolders(string parentDirectory, ICollection filenames) + { + if (filenames == null) throw new ArgumentNullException("filenames"); + if (filenames.Count == 0) return; + + var parentPidl = PathToAbsolutePIDL(parentDirectory); + try + { + var parent = PIDLToShellFolder(parentPidl); + var filesPidl = filenames + .Select(filename => GetShellFolderChildrenRelativePIDL(parent, filename)) + .ToArray(); + + try + { + SHOpenFolderAndSelectItems(parentPidl, filesPidl, false); + } + finally + { + foreach (var pidl in filesPidl) + { + NativeMethods.ILFree(pidl); + } + } + } + finally + { + NativeMethods.ILFree(parentPidl); + } + } + + public static void FilesOrFolders(params string[] paths) + { + FilesOrFolders((IEnumerable)paths); + } + + public static void FilesOrFolders(IEnumerable paths) + { + if (paths == null) throw new ArgumentNullException("paths"); + + FilesOrFolders(PathToFileSystemInfo(paths)); + } + + public static void FilesOrFolders(IEnumerable paths) + { + if (paths == null) throw new ArgumentNullException("paths"); + var pathsArray = paths.ToArray(); + if (pathsArray.Length == 0) return; + + var explorerWindows = pathsArray.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()); + } + } +} \ No newline at end of file diff --git a/PdbFind.Lib/Locator.cs b/PdbFind.Lib/Locator.cs new file mode 100644 index 0000000..679ba74 --- /dev/null +++ b/PdbFind.Lib/Locator.cs @@ -0,0 +1,48 @@ +using PeNet; + +namespace PdbFind.Lib +{ + public class Locator + { + public static (string? pdbName, string? checksum) GetPdbChecksum(string path) + { + if (!File.Exists(path)) + { + throw new FileNotFoundException("PE File not found", path); + } + + var peFile = new PeFile(path); + + var pdb70 = peFile.ImageDebugDirectory?.Where(d => d.CvInfoPdb70 != null).Select(d => d.CvInfoPdb70).FirstOrDefault(); + + var pdbName = (pdb70?.PdbFileName != null) ? Path.GetFileName(pdb70.PdbFileName) : null; + + var checksum = pdb70?.Signature != null ? $"{pdb70.Signature:N}{pdb70.Age}" : null; + + return (pdbName, checksum); + } + + public static string LocatePdbInStore(string path, string store) + { + if (!Directory.Exists(store)) + { + throw new DirectoryNotFoundException($"Directory \"{store}\" not found."); + } + + var (pdbName, checksum) = GetPdbChecksum(path); + + _ = pdbName ?? throw new InvalidOperationException("PDB name not found in PE header."); + _ = checksum ?? throw new InvalidOperationException("Checksum not found in PE header."); + + var isIndex2 = File.Exists(Path.Combine(store, "index2.txt")); + + var pdbPath = Path.Combine(pdbName, checksum, pdbName); + if (isIndex2) + { + pdbPath = Path.Combine(pdbName.Substring(0, 2), pdbName, checksum, pdbName); + } + + return Path.Combine(store, pdbPath); + } + } +} \ No newline at end of file diff --git a/PdbFind.Lib/PdbFind.Lib.csproj b/PdbFind.Lib/PdbFind.Lib.csproj new file mode 100644 index 0000000..0f94a39 --- /dev/null +++ b/PdbFind.Lib/PdbFind.Lib.csproj @@ -0,0 +1,13 @@ + + + + net6.0 + enable + enable + + + + + + + diff --git a/PdbFind.sln b/PdbFind.sln new file mode 100644 index 0000000..3c70a0e --- /dev/null +++ b/PdbFind.sln @@ -0,0 +1,37 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.4.32912.340 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PdbFind", "PdbFind\PdbFind.csproj", "{6A645585-5A87-4FBA-8487-8D309A3E6B37}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PdbFind.Lib", "PdbFind.Lib\PdbFind.Lib.csproj", "{7A66B869-1636-4187-A372-51922CC7B25A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PdbFind.Gui", "PdbFind.Gui\PdbFind.Gui.csproj", "{C61E7476-AE69-4885-A32D-982EAF42BC70}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {6A645585-5A87-4FBA-8487-8D309A3E6B37}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6A645585-5A87-4FBA-8487-8D309A3E6B37}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6A645585-5A87-4FBA-8487-8D309A3E6B37}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6A645585-5A87-4FBA-8487-8D309A3E6B37}.Release|Any CPU.Build.0 = Release|Any CPU + {7A66B869-1636-4187-A372-51922CC7B25A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7A66B869-1636-4187-A372-51922CC7B25A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7A66B869-1636-4187-A372-51922CC7B25A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7A66B869-1636-4187-A372-51922CC7B25A}.Release|Any CPU.Build.0 = Release|Any CPU + {C61E7476-AE69-4885-A32D-982EAF42BC70}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C61E7476-AE69-4885-A32D-982EAF42BC70}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C61E7476-AE69-4885-A32D-982EAF42BC70}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C61E7476-AE69-4885-A32D-982EAF42BC70}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {13C06892-3C65-48DB-80B8-F150F18A6E30} + EndGlobalSection +EndGlobal diff --git a/PdbFind/PdbFind.csproj b/PdbFind/PdbFind.csproj new file mode 100644 index 0000000..77213f9 --- /dev/null +++ b/PdbFind/PdbFind.csproj @@ -0,0 +1,14 @@ + + + + Exe + net6.0 + enable + enable + + + + + + + diff --git a/PdbFind/Program.cs b/PdbFind/Program.cs new file mode 100644 index 0000000..8873bef --- /dev/null +++ b/PdbFind/Program.cs @@ -0,0 +1,26 @@ +// See https://aka.ms/new-console-template for more information + +using PdbFind.Lib; + +if (args.Length < 1) +{ + Console.WriteLine("Usage: PdbFind "); + Environment.ExitCode = 1; + return; +} + +var file = args[0]; +var store = @"\\cpsrvbuild10\symbols"; + +if (args.Length >= 2) +{ + store = args[1]; +} + +var path = Locator.LocatePdbInStore(file, store); +Console.WriteLine($"PDB Location: {path}"); +if (!File.Exists(path)) +{ + Environment.ExitCode = 1; + Console.WriteLine("PDB not found in store"); +} \ No newline at end of file diff --git a/PdbFind/Properties/launchSettings.json b/PdbFind/Properties/launchSettings.json new file mode 100644 index 0000000..6630d43 --- /dev/null +++ b/PdbFind/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "PdbFind": { + "commandName": "Project", + "commandLineArgs": "D:\\CPA_NetFrameApplication.dll" + } + } +} \ No newline at end of file