Visual Studio Addin - Get Name\Path of binary of a c++ project? - c++

I want to get the binary name of a C++ Project with a Visual Studio C# Addin.
I googled and found, that the the EnvDTE.Configuration.properties should have a element called "AssemblyName" but C++ projects do not seem to have this element.
Did somebody know where could I get this information inside a visual studio addin?

For VC++ projects you need to get access to the VCConfiguration object which you should be able to get at from the EnvDTE.Project's Object property like:
EnvDTE.Project project = ...
VCProject vcProj = (VCProject)project.Object;
IVCCollection configs = (IVCCollection)vcProj.Configurations;
VCConfiguration config = (VCConfiguration)configs.Item(configName); // like "Debug"
At that point with the VCConfiguration how exactly to get at the correct properties depends on your set up. You can access the the VCLinkerTool from the Tools property and get at the OutputFile and other properties. Or, if you use the newer inherited property sheets you may access those through the Rules property.
IVCCollection tools = (IVCCollection)config.Tools;
VCLinkerTool linkTool = (VCLinkerTool)tools.Item("Linker Tool");
string outputFile = linkTool.OutputFile;
// -------
IVCRulePropertyStorage ruleStorage = config.Rules.Item(ruleName);
string outputFile = ruleStorage.GetEvaluatedPropertyValue("TargetName");

In order to get the complete path of the binary, follow the steps as #Chadwick said to get the VCConfiguration object. And then, just use the following line of code:
//returns the complete binary name including path as a string
var primaryOutput = config.PrimaryOutput;

Related

Embedding localized satellite dll into exe application

I have a C++ CLR/CLI project, I wonder how to embed a localized satellite dll into my exe application, I found similar solutions but it's for C# projects which is pretty different from my project structure.
Is it possible to embed it directly into the binary?
By the way I'm getting issues with namespaces, it seems my custom namespace is not linked to my localized resource file.
I've been searching for hours to find a solution for a C++ CLR/CLI project which is pretty different comparing with C# projects which apparently comes with Build Action and Custom Tool Namespace all these options we don't have in a CLR/CLI project, it's really important, especially if we have changed Namespaces so we gotta use Resource Logical Name instead. Here's my answer how to solve Namespace issues, this also works for localized resource files linked to satellite dlls.
After your localized satellite dll is generated, include that in your project as Compiled Managed Resource you can set that by opening its file property and setting the Item Type. In projects such as C# you won't find that but something similar like "Embedded Resource". Anyways this is intended to C++ CLR/CLI projects only. If you have changed namespaces, don't forget to set Resource Logical Name of the respective resource file.
Next step is to do some code in order to embed that dll into our exe application, here's a good one for that:
Since C++ CLR/CLI doesn't support lambda expressions we have to do this way:
private: System::Reflection::Assembly^ currentDomainAssemblyResolve(System::Object^ sender, System::ResolveEventArgs^ args) {
System::Reflection::AssemblyName^ assemblyName = gcnew System::Reflection::AssemblyName(args->Name);
System::String^ resourceName = assemblyName->Name + ".dll";
System::IO::Stream^ stream = System::Reflection::Assembly::GetExecutingAssembly()->GetManifestResourceStream(resourceName);
array<Byte>^ assemblyData = gcnew array<Byte>((unsigned long) stream->Length);
try {
stream->Read(assemblyData, 0, assemblyData->Length);
} finally {
if (stream != nullptr) delete stream;
}
return System::Reflection::Assembly::Load(assemblyData);
}
Usage:
//Put it in your constructor before InitializeComponent()
MyClass(void) {
AppDomain::CurrentDomain->AssemblyResolve += gcnew System::ResolveEventHandler(this, &MyNameSpace::MyClass::currentDomainAssemblyResolve);
InitializeComponent();
}
So now it's no longer necessary satellite dlls to load your localized resources.
Use a free application packer to bundle files into a single exe.
https://enigmaprotector.com/en/aboutvb.html
This one is free, I use it and it works very well for me.

VSIX how to get current snapshot document name?

I have been trying to to create an extension that highlights specific line numbers for me in Visual Studio in the margins.
I manged to get my marking in the margins using predefined line number but for it to work properly I need to know what the current document FullName is (Path and filename)
After much googling I figured out how to do it with the sample code (which is not ideal)
DTE2 dte = (DTE2)System.Runtime.InteropServices.Marshal.GetActiveObject("VisualStudio.DTE.15.0");
var activeDocument = dte.ActiveDocument;
var docName = activeDocument.Name;
var docFullName = activeDocument.FullName;
Now I know the problems here
is that is for specific version bases on the text
there is no way to select which instance (when running more than one VS)
It seems to be very slow
I have a feeling I should be doing this with MEF Attributes but the MS docs examples are so simple that they do not work for me. I scanned a few SO questions too and I just cannot get them to work. They mostly talk about Services.. which I do not have and have no idea how to get.
The rest of my code uses SnapshotSpans as in the example Extension of Todo_Classification examples which is great if you do NOT need to know the file name.
I have never done any extensions development. Please can somebody help me do this correctly.
You can use following code to get a file from a snapshot without any dependencies.
public string GetDocumentPath(Microsoft.VisualStudio.Text.ITextSnapshot ts)
{
Microsoft.VisualStudio.Text.ITextDocument textDoc;
bool rc = ts.TextBuffer.Properties.TryGetProperty(
typeof(Microsoft.VisualStudio.Text.ITextDocument), out textDoc);
if (rc && textDoc != null)
return textDoc.FilePath;
return null;
}
If you don't mind adding Microsoft.CodeAnalysis.EditorFeatures.Text to your project it will provide you with an extension method Document GetOpenDocumentInCurrentContextWithChanges() on the Microsoft.VisualStudio.Text.Snapshot class. (Plus many other Rosyln based helpers)
using Microsoft.CodeAnalysis.Text;
Document doc = span.Snapshot.GetOpenDocumentInCurrentContextWithChanges();

How to debug ref class properties in Windows store app (C++)

When debugging Windows store app with Visual studio 2013, I can't seem to evaluate ref class properties in Watch and Immediate Window.
eg)
_inputGrid = ref new XEditTransform();
_inputGrid->HorizontalAlignment = Windows::UI::Xaml::HorizontalAlignment::Left;
_inputGrid->VerticalAlignment = Windows::UI::Xaml::VerticalAlignment::Top;
And I want to find the value of _inputGrid->VerticalAlignment I get following errors in the Watch Window.
_inputGrid->VerticalAlignment::get() name followed by '::' must be a class or namespace name
_inputGrid->VerticalAlignment Implicit function evaluation of properties is not supported.
Does anyone know how to debug with ref class properties? I'm getting tired of adding debug code snippets everytime I want to check the property.

How do I use DTE.ExecuteCommand("Edit.GoToDefinition") in a VS2010 C++ macro?

I recorded a macro that includes a keypress of F12 (Go To Definition), but the recording omits the second parameter that is passed to DTE.ExecuteCommand, causing the macro to crash during execution. Presumably the second arg is the name of the function I want to find, but I can't figure out how to get and pass the value. If I select the function or method name (but not the args or the class prefix), I can use DTE.ActiveDocument.Selection.Text.ToString to pass the selection, but instead of jumping to the definition, it returns the both the .h file and the .cpp file in the Find Symbol Results window.
(And I'm not sure selection is really what I want, though I could probably get the macro to select the "right thing" if that's the way to go. Is there any way to see what F12 is passing, just to see what it looks like? Or better yet, find out what programmatic object F12 is passing?
Vs2010 Pro
Turns out running the same command via IVsUIShell works:
Dim cmd As EnvDTE.Command
Dim shell As Microsoft.VisualStudio.Shell.Interop.IVsUIShell
Dim arg As Object
Dim guid As System.Guid
Dim serviceProvider As System.IServiceProvider
serviceProvider = New Microsoft.VisualStudio.Shell.ServiceProvider(CType(DTE, Microsoft.VisualStudio.OLE.Interop.IServiceProvider))
shell = serviceProvider.GetService(GetType(Microsoft.VisualStudio.Shell.Interop.SVsUIShell))
cmd = DTE.Commands.Item("Edit.GoToDefinition", 0)
guid = New System.Guid(cmd.Guid)
shell.PostExecCommand(guid, cmd.ID, 0, arg)
The code works as is in Visual Commander. To run it from Visual Studio macros IDE, you need to add references to
Microsoft.VisualStudio.OLE.Interop.dll
Microsoft.VisualStudio.Shell.10.0.dll
Microsoft.VisualStudio.Shell.Interop.dll
Microsoft.VisualStudio.Shell.Interop.8.0.dll
Microsoft.VisualStudio.Shell.Interop.9.0.dll
And to add references you first need to copy these files to the Microsoft Visual Studio 10.0\Common7\IDE\PublicAssemblies directory.

A quick way to remove properties from .dfm files in Delphi

I have recently modified one of my components, and it so happens it is no longer using one of the properties it used before.
However, those properties are written in multiple .dfm files throughout the project.
Now, when i try to compile the project, i get
"Error reading .: Property <...> does not exist"
The complicated part is that the property value is binary data (stored in multiple lines), and i cant just delete it with Delphi replace or notepad++ regexp (since they are single-line based).
So my question would be:
Are there any third party tools or ways to easily remove properties from multiple .dfm files?
Try this tool Delphi DFM properties remover, works with old versions of delphi but maybe can help you.
One possible approach is to modify your component so that it is capable of simply ignoring these properties. That way you don't have to hunt them down in each and every .dfm file.
For example:
type
TIgnoreFormPropertyHelper = class
public
class procedure IgnoreBooleanProperty(Reader: TReader);
class procedure IgnoreIntegerProperty(Reader: TReader);
end;
{ TIgnoreFormPropertyHelper }
class procedure TIgnoreFormPropertyHelper.IgnoreBooleanProperty(Reader: TReader);
begin
Reader.ReadBoolean;
end;
class procedure TIgnoreFormPropertyHelper.IgnoreIntegerProperty(Reader: TReader);
begin
Reader.ReadInteger;
end;
type
TMyComponent = class(...)
....
protected
procedure DefineProperties(Filer: TFiler); override;
....
procedure TMyComponent.DefineProperties(Filer: TFiler);
begin
inherited;
Filer.DefineProperty('MyLegacyBooleanProperty',
TIgnoreFormPropertyHelper.IgnoreBooleanProperty, nil, False);
Filer.DefineProperty('MyLegacyIntegerProperty',
TIgnoreFormPropertyHelper.IgnoreIntegerProperty, nil, False);
end;
The Jedi VCL contains a tool called DFMCleaner:
DFMCleaner is a tool to remove unsupported properties from DFMs. If
you save a dfm file in one version of Delphi and want to use it in an
earlier version, chances are there are some unsupported properties in
it, generating an error when the form is opened in Delphi. What's even
worse, if the dfm is part of a design-time package, Delphi will
install the package without errors but when you try to access the form
at design-time (f ex if the form is used by a property editor), Delphi
generates an AV instead.
It is located in jvcl-install\devtools\DFMCleaner (project with source code and example configuration file)
In my case simply closing the project and deleting the DProj file helped.