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

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.

Related

Google gflags library in visual studio: Can't inspect FLAGS_ variables

I have built google gflags in windows using visual studio 2015.
The built is a Debug build (so Program Database (/Zi) is set) and I'm stepping through the gflags_unittest_main.cc.
The unit test passes successfully. However, while debugging I can't see the contents of the FLAGS_## variables.
For example, line 1515 of gflags_unittest_main.cc is
FLAGS_changed_bool2 = true;
I can't see the value of FLAGS_changed_bool2 in the watch window. I have tried adding the google:: and gflags:: namespaces in front of FLAGS_changed_bool2 but it just says identifier is undefined. Here it says you can access these flags just as a normal variables.
Why can't I see the values of these variables while debugging? What can I do to see them? maybe some build option?
I'm trying to understand the code of another open source library that uses gflags and has hundreds of FLAGS_ variables. Not being able to see the contents of these variables makes the task more difficult.
I found a workaround for this. Each of the FLAGS_ variables are created inside namespaces which include a short identifier for the type (see DEFINE_VARIABLE macro in gflags.h). For example, fLI for integer, fLB for bool, fLS for String, etc.
So if I add to the watch window the following:
fLB::FLAGS_changed_bool2
fLI64::FLAGS_this_is_an_int64_variable
I can see their values.
The DEFINE_VARIABLE macro adds a using statement
using fL##shorttype::FLAGS_##name
after the definition of the variable inside the fL##shorttype, which allows the user code to refer to FLAGS_##name directly. However the Visual Studio debugger ignores this using and needs the namespace for each of these variables. I guess the next question is how to get visual studio to use this using statements, so that I can hover my mouse pointer over the variable a see its value.

"Invalid use of New Keyword" in VBA using old com object written in c++

I've scoured the web and stackoverflow for this answer but can't find anything. I have written a com object in C++ (for the fist time) that works when used in vbscript and through cocreateinstance in an executable file. So I decided to see if it would work in Excel VBA.
So I went into "References" and located my object there. Checked the box and started coding away. The following is the VBA code.
Function doCos(x As Double) As Double
Dim t As SimpleLib.IMath
Set t = New SimpleLib.IMath ' <- "Invalid use of New keyword" error here
doCos = t.Cos(x)
End Function
Intellisense recognizes my object in the Dim statement, but it does not appear when I use a Set statement. Obviously I am using a registered type library or else intellisense wouldn't work at all. Again, the com object can be used in vbscript or an executable, but for some reason can't be used, at least with the new keyword, in VBA.
Does anyone have an idea what may be wrong, or what may have to be added to the com object? Thanks.
One approach is to define a coclass in the IDL that includes the interface needed (IMath in my case). NOTE: That the [default] interface is hidden by default. So I simply defined interface IUnknown as the default. After compiling with MIDL a type library is generated which one should register with regtlibv12.exe.
I then included an additional IF statement in DllGetClassObject like if (rclsid == CLSID_Math) where CLSID_Math is corresponds to the CLSID defined in the file automatically generated from MIDL. All I did was copy and paste the body of the IF statement from if ( rclsid == IID_IMath ), updated the DLLRegisterServer and DLLUnRegisterServer functions, recompiled the project, and regsvr32.exe.
So the following works now.
Function docos(x As Double) As Double
Dim a As SimpleLib.IMath
Set a = New SimpleLib.Math
docos = a.Cos(x)
End Function
Thanks to Hans for the tip about the coclass. Learned something new and useful.

How can I debug a C++ DLL function, called from VBA, using Visual Studio

I have written a DLL function in C++, which I am calling from VBA (Excel).
How can I setup the Visual Studio properties to allow me to debug the function? I have tried specifying Excel, but that doesn’t seem to work.
You have two choices: "direct debug", or "attach".
I strongly prefer the "direct debug" approach for a long list of reasons omitted from here.
There are steps required on both the DLL and Excel/VBA sides, your posting is unclear if all of those steps are addressed.
There are variations on the following:
1) In VS, depending on the version, enter Project Settings, or Project Properties, or equivalent, in the "Debug (not release) Target", go to the Debug or Debugging settings. :
a) There will be an field called "Executable for debugging session", or "command", or something like that depending on VS ver. Here, enter the full path of your Excel exe
b) Optionally, if the same "test spread sheet" is used frequently, enter the full path of your xls (or whatever) in the field called "Command argument", or "program argument" or as in your VS ver.
You may need to surround this with double quotes (e.g. if there are spaces in your path/file names).
c) You can also set the output of your project to a Dir that is "addin helpful", such as a Dir called AddIn (c.f. having the DLL end up in Debug (or Release) Dirs)
... it is assumed that your DLL has all the bits required to export the functions, with the project being of type DLL, plus any DLLEXPORT and compiler directives, etc etc.
... the specifics of the DLLEXPORT settings (and related compiler switches) and Calling Convention will determine many things ... it is assumed you have done all that correctly and consistently (and especially consistently with what the Excel-side is expecting).
... your DLL may or may not have a DLL_Main, if it does, more discussion is required.
2) Before anything else, be sure to have created the Excel-side "interface" for your DLL, ie. the "Add-In". This can be either via .xla, or via .xll. I strongly suggest the .xla route as your first approach.
See the Excel help files etc for creating the .xla
Then, in your XLA's VBA Module(s), declare the functions/subs etc from your DLL. For example, if you have a DLL called Add2_DLL.dll, which contains an exported function "add2_pho_xl", then:
Public Declare Function Add2_Pho_XX Lib "E:\EclipseWorkSpace\Add2_DLL\Debug\Add2_DLL.dll" _
Alias "add2_pho_xl" (A As Double, B As Double) As Double
I have used the Alias approach here, for reasons required below.
In many instances, this declaration can be used directly as User Defined Function (UDF) in your sheets, etc. However, for a vast number of cases, you will need to create a VBA "spinner" function/sub that creates the "ultimate" UDF, and relies on this direct entry function (see below). This is also a very long story, but necessary where more complex matters are required (arrays, variants, etc etc).
NOTICE:
a) the DLL's full path is required unless special steps have been taken. If your Addin is for general distribution ... a much longer discussion is required.
b) the Alias must be the EXACT entry name of the function in your DLL. If you view near the end of the DLL (or .Def) files, and unless you set your DLL modules as Private, those will show the entry names expected on the DLL side.
In this example, the entry name is NOT "decorated" due to the choices in the Calling Convention and compiler switches, but it could look something like
"_add2_pho_xl_#08" etc depending your choices.
... in any case, you must use whatever the DLL has.
3) Once both the .xla and dll exist (it is best if they are in the same Dir), Excel must be "told" about the Add-In. The easiest approach is Excel/Tools/Addins, but there are various strategies for "registering" DLL functions.
4) CRUCIALLY, the argument list properties/declarations MUST BE CONGRUENT with BOTH those in your DLL and the Calling Convention. Three (of many possible) examples of "issues" are,
(i) A Boolean on the VBA-side is two-bytes, if the Bool/Logical on your DLL side is 1-byte, then the Debug will fail, since the two sides "cannot connect" properly.
(ii) Strings ... this can be a very long story. It depends if sent ByVal or ByRef, it depends if the DLL side has "hidden length" Args, etc. etc. Remember, VBA uses COM/OLE VBStrings, which have their own can of worms.
(iii) Variants/Objects: these require a tome onto themselves
5) If ALL (and likely more) of the above have gone well, then in VS set your break points, if required, and "Go" or "Start" the debug (depending on VS ver, etc.). This should launch Excel, and if you also set the target xls, it will launch too. Go to the cell(s) where you addin function (e.g. =add2_pho_XX(A1, B1) ) resides, and execute the cell (sometimes using the "fx" menu item is useful, but there are other ways also).
Some hints:
a) if the func execution crashes/hangs etc Excel and does not even arrive back to the VS side, then likely there is a Arg list conflict (e.g. you are passing a Double to an Int or a million other possibilities), or Calling Convention conflict, etc.
b) In general, you may (while in the VS debug session) simultaneously perform a VBA debug session. That is, after starting the VS bebug, entre the VBA IDE, and set break points in VBA UDF's, if a "spinner" UDF's have been created. For example, a VBA UDF that relies also on the DLL's function.
Private Function Add2_Pho( FirstNum as Double, SecondNum as Double, Optional lMakeRed as Variant) As Variant
'
'
Add2_Pho = Add2_Pho_XX( FirstNum, SecondNum ) ' this is the actual DLL func accessed via Delcare above
'
If( IsMissing(lMakeRed) ) Then
Else
If( cBool(lMakeRed) ) Then
If( Add2_Pho < 0 ) Then
'
' ' make the result Red, or something
'
End If
End If
End If
'
'
End Function
... here, setting a break point at the first line can be helpful to see if the UDF is even entered on the VBA side. If it is, click Continue in VBA, and see if it makes it to the VS side, if not, check Args, Calling Convention, etc again, etc etc
c) If the cell's content are #Value or some other unexpected result, then at least the UDF is "recognised" but not functioning correctly, either due to sheet->VBA issues, or VBA-> DLL issues, or after the return DLL-> VBA
d) Save often! and Use the VBA IDE's Debug/ Compile VBA Project before running anything just make sure VBA internal consistency.
e) Also, if you are using VBA/XLA's, then get a copy of CleanProject (VBA can mess up its internals sometimes, and this Tool will be a life saver)
Please make sure that Debug mode is the active mode.
How to debug your DLL with Excel/VBA

Return value of a function in Visual studio

HI,
I am very much new to using Visual studio.
I am trying to debug an application.
where i came across a statement like below:
double tmp =
myPart->bat_qty() * timeFactor / myPart->AUB() * myPart->UCost * myAIM->param->myAnalysisParams->wd_year;
in VS when put the cursor at
timeFactor
myPart->UCost
myAIM->param->myAnalysisParams->wd_year
it shows the corresponding values.But Not of the values returned by
myPart->bat_qty()
myPart->AUB()
what is the easiest way to find the values returned by those functions.
Apologies if this appears to be a cliche kind of a query.But i am completely new to VS.
I need a better way to find the values returned without editing the files for storing the values in some temporary variables.i mean i sould not edit the files.
In VS 2010 you can put the breakpoint at the function call site and activate the "Autos" Window (if the Autos window is not visible you can make it visible from Debug -> Windows -> Autos Ctrl + Alt + V, A). In the Autos Window after you step over the function call (F10) you will see something in the lines of:
Name Value Type
[Func] Returned [Return Value] [Return Type]
where [Return Value] and [Return Type] are the appropriate return value and type for your function named [Func].
I hope this helps.
This has the advantage that you do not have to edit the code. The disadvantage I see is that if the returned type is complex you cannot expand it and inspect its attributes like you can do if you assign the return value to an automatic variable. However for simple structs the return value is expanded to something like this: {var1=[val1], var2=[val2]...} where var1, var2 are the attributes of the struct.
As far as I know the Autos Window is there (and did the same thing) back in VS 6.0 so this applies to VS 2005 too I guess (someone asked about VS 2005 too).
The quickest way is just to enter myPart->bat_qty() in the Immediate window. This way you don't need to change the code.
Assign them to a temporary, like this :
const double bat_qty_val = myPart->bat_qty();
const double AUB_val = myPart->AUB();
then use those in the equation instead of calling functions.
Off the top of my head, and Im sure there would be a more elegant way, but you could assign the return values of bat_qty() and AUB() to a temporary variable and watch them in the debugger.

Create registry entry to associate file extension with application in C++

I would like to know the cleanest way of registering a file extension with my C++ application so that when a data file associated with my program is double clicked, the application is opened and the filename is passed as a parameter to the application.
Currently, I do this through my wix installer, but there are some instances where the application will not be installed on ths user's computer, so I also need the option of creating the registry key through the application.
Additionally, will this also mean that if the application is removed, unused entries in the registry will be left lying around?
Your basic overview of the process is found in this MSDN article. The key parts are at the bottom of the list:
Register the ProgID
A ProgID (essentially, the file type registry key) is what contains your important file type properties, such as icon, description, and context menu items including applications used when the file is double clicked. Many extensions may have the same file type. That mapping is done in the next step:
Register the file name extension for the file type
Here, you set a registry value for your extension, setting that extension's file type to the ProgID you created in the previous step.
The minimum amount of work required to get a file to open with your application is setting/creating two registry keys. In this example .reg file, I create a file type (blergcorp.blergapp.v1) and associate a file extension (.blerg) with it.
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Classes\blergcorp.blergapp.v1\shell\open\command]
#="c:\path\to\app.exe \"%1\""
[HKEY_CURRENT_USER\Software\Classes\.blerg]
#="blergcorp.blergapp.v1"
Now, you probably want to accomplish this programmatically. To be absolutely kosher, you could check for the existence of these keys, and change your program behavior accordingly, especially if you're assuming control of some common file extension. However, the goal can be accomplished by setting those two keys using the SetValue function.
I'm not positive of the exact C++ syntax, but in C# the syntax looks something like this:
Registry.SetValue(#"HKEY_CURRENT_USER\Software\Classes\blergcorp.blergapp.v1\shell\open\command", null, #"c:\path\to\app.exe \"%1\"");
Registry.SetValue(#"HKEY_CURRENT_USER\Software\Classes\.blerg", null, "blergcorp.blergapp.v1");
Of course you could manually open each sub key, manually create the ProgID and extension subkey, and then set the key value, but a nice thing about the SetValue function is that if the keys or values don't exist, they will automatically be created. Very handy.
Now, a quick word about which hive to use. Many file association examples online, including ones on MSDN, show these keys being set in HKEY_CLASSES_ROOT. I don't recommend doing this. That hive is a merged, virtual view of HKEY_LOCAL_MACHINE\Software\Classes (the system defaults) and HKEY_CURRENT_USER\Software\Classes (the per-user settings), and writes to any subkey in the hive are redirected to the same key in HKEY_LOCAL_MACHINE\Software\Classes. Now, there's no direct problem doing this, but you may run into this issue: If you write to HKCR (redirected to HKLM), and the user has specified the same keys with different values in HKCU, the HKCU values will take precedence. Therefore, your writes will succeed but you won't see any change, because HKEY_CURRENT_USER settings take precedence over HKEY_LOCAL_MACHINE settings.
Therefore, you should take this into consideration when designing your application. Now, on the flip side, you can write to only HKEY_CURRENT_USER, as my examples here show. However, that file association setting will only be loaded for the current user, and if your application has been installed for all users, your application won't launch when that other user opens the file in Windows.
That should be a decent primer for what you want to do. For further reading I suggest
Best Practices for File Association
File Types and File Association, especially
How File Associations Work
And see also my similar answer to a similar question:
Associating file extensions with a program
This is a two step process:
1. Define a program that would take care of extension: (unless you want to use existing one)
1.1 create a key in "HKCU\\Software\\Classes\\" for example
"Software\\Classes\\YourProgramName.file.ext"
1.2 create subkey "Software\\Classes\\YourProgramName.file.ext\\DefaultIcon"
1.2.1 set default value ("") to your application full path to get
icon from resources
1.3 create a subkey "Software\\Classes\\YourProgramName.file.ext\\Shell\\OperationName\\Command"
OperationName = for example Open, Print or Other
1.3.1 set default value ("") to your application full path +optional runtime params (filename)
2.Associate file extension with program.
2.1 create a key HKCU\\Software\\Classes\\.ext - here goes your extension
2.2 set default value to the program definition key
("YourProgramName.file.ext")
Below is part of the program written in c# which associate file extension. It is not c++ but i think it is simple enought to explain itself and AFAIK it is verv simmilar if not identical to the code in c++
1.
RegistryKey keyPFCTExt0 = Registry.CurrentUser.OpenSubKey("Software\\Classes\\PFCT.file.enc", true);
if (keyPFCTExt0 == null)
{
keyPFCTExt0 = Registry.CurrentUser.CreateSubKey("Software\\Classes\\PFCT.file.enc");
keyPFCTExt0.CreateSubKey("DefaultIcon");
RegistryKey keyPFCTExt0ext = Registry.CurrentUser.OpenSubKey("Software\\Classes\\PFCT.file.enc\\DefaultIcon", true);
keyPFCTExt0ext.SetValue("", Application.ExecutablePath +",0");
keyPFCTExt0ext.Close();
keyPFCTExt0.CreateSubKey("Shell\\PFCT_Decrypt\\Command");
}
keyPFCTExt0.SetValue("", "PFCT.file.enc");
keyPFCTExt0.Close();
2.
RegistryKey keyPFCTExt1 = Registry.CurrentUser.OpenSubKey("Software\\Classes\\PFCT.file.enc\\Shell\\PFCT_Decrypt\\Command", true);
if (keyPFCTExt1 == null)
keyPFCTExt1 = Registry.CurrentUser.CreateSubKey("Software\\Classes\\PFCT.file.enc\\Shell\\PFCT_Decrypt\\Command");
keyPFCTExt1.SetValue("", Application.ExecutablePath + " !d %1"); //!d %1 are optional params, here !d string and full file path
keyPFCTExt1.Close();
I don't know why people keep saying that HKEY_CURRENT_USER\Software\Classes\<.ext>'s Default value (which will redirect you into another (software-created) class.
It does work, but it will be overridden by
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\<.ext>\UserChoice
And I believe Microsoft recommends the second practice- because it's what the built-in "open with" is doing. The value of Progid" key is equal to default value of HKEY_CURRENT_USER\Software\Classes\<.ext> in this case.
I found the following while trying to manipulate associations using C#:
hkcu\software\microsoft\windows\currentVersion\explorer\fileexts.reg\userchoice -> for user specific settings. The values in the openWithProgIds
key point to the keys in the hkcr.
hkcr\xfile\shell\open\muiVerb value or hkcr\xfile\shell\open\command\default value -> affects open handler. This is the value that contains the path to a program.
hkcr\ .x -> affects context menu (new x) among other things related to the menus.
I don't know the C++ code, but given these info you must be able to manipulate the registry using the registry API.