Invoking standard "File changed outside Visual Studio" dialog - c#

I have succesfuly created custom single view editor in my VSPackage. One of many things I had to cope with was reacting to situation when edited file was changed outside Visual Studio - "standard" editors in Visual Studio display dialog with options like "yes", "yes to all" (reload content) etc., so if more files had changed, only one dialog is displayed.
However, the only thing I can do in my VSPackage so far is display custom dialog when the file had changed. It is not pretty - when file edited in my editor changed along with some others, there will be two completely different dialogs displayed to the user.
So the question is - is there any way how to invoke "standard" Visual Studio "file changed outside VS" dialog for my file?

Sounds like you are using the IVSFileChangeEx interface.
This blog post might be almost what you're looking for. Normally this is used for checking to see if a file can be edited, or reloaded and will provide a file dialog prompt to (check-out or reload).
This uses the IVsQueryEditQuerySave2 interface. You probably want to call DeclareReloadableFile, which will "States that a file will be reloaded if it changes on disk."
private bool CanEditFile()
{
// --- Check the status of the recursion guard
if (_GettingCheckoutStatus) return false;
try
{
_GettingCheckoutStatus = true;
IVsQueryEditQuerySave2 queryEditQuerySave =
(IVsQueryEditQuerySave2)GetService(typeof(SVsQueryEditQuerySave));
// ---Now call the QueryEdit method to find the edit status of this file
string[] documents = { _FileName };
uint result;
uint outFlags;
int hr = queryEditQuerySave.QueryEditFiles(
0, // Flags
1, // Number of elements in the array
documents, // Files to edit
null, // Input flags
null, // Input array of VSQEQS_FILE_ATTRIBUTE_DATA
out result, // result of the checkout
out outFlags // Additional flags
);
if (ErrorHandler.Succeeded(hr) && (result ==
(uint)tagVSQueryEditResult.QER_EditOK))
{
return true;
}
}
finally
{
_GettingCheckoutStatus = false;
}
return false;
}

Related

Write into a log file with C#

I am using the JitBit Macro Recorder to create "bots" that save me a lot of time at work. This program can use the mouse and the keyboard and perform tasks by checking different if-options like "if image found on screen".
My newest "bot" is about 900 lines of commands long and I would like to make a log-file to find an error somewhere in there. Sadly, this program doesn't offer such an option, but it let's me use c# as a task. I have NO experience with c# but I thought, that this is easy to do for someone who has some experience.
If I click execute c# code, I get the following input field:
Important: This code MUST contain a class named "Program" with a static method "Main"!
public class Program
{
public static void Main()
{
System.Windows.Forms.MessageBox.Show("test");
}
}
Now I need two code templates:
1. Write a message to a "bot_log.txt" located on my desktop.
[19.05.2016 - 12:21:09] "Checking if item with number 3 exists..."
The number "3" changes with every run and is an exact paste of the clipboard.
2. Add an empty line to the same file
(Everything should be added to a new line at the end of this file.)
If you have no idea how to program in C#, then you should learn it,
if you want to use code provided from answers.
And if you want to generate timestamps and stuff then it's not done within minutes and I don't think someone writes the whole code just for your fitting. Normally questions should have at least a bit of general interest.
Anyway:
This works, if you have a RichTextTbox in your program.
Just do a new event (like clicking a button) and do this inside it.
(This was posted somewhere here too or on another site, with sligh changes)
public static void SaveMyFile(RichTextBox rtb)
{
// Create a SaveFileDialog to request a path and file name to save to.
SaveFileDialog saveLog = new SaveFileDialog();
// Initialize the SaveFileDialog to specify the RTF extention for the file.
saveLog.DefaultExt = "*.rtf";
saveLog.Filter = "RTF Files|*.rtf"; //You can do other extensions here.
// Determine whether the user selected a file name from the saveFileDialog.
if (saveLog.ShowDialog() == System.Windows.Forms.DialogResult.OK &&
saveLog.FileName.Length > 0)
{
// Save the contents of the RichTextBox into the file.
try
{
rtb.SaveFile(saveLog.FileName);
}
catch
{
MessageBox.Show("Error creating the file.\n Is the name correct and is enough free space on your disk\n ?");
}
MessageBox.Show("Logfile was saved successful.");
}
}

How to open a .DWG file in Autocad 2014 through C#

Hi I have a requirement in which I have to open a drawing file stored in C:\Temp Folder.
I tried the following code
public void launchacad(string pth) //pth is the path to the .DWG file
{
const string progID = "AutoCAD.Application.19.1";
const string exePath = #"C:\Program Files\Autodesk\AutoCAD 2014\acad.exe";
AcadApplication acApp = null;
try
{
acApp =
(AcadApplication)Marshal.GetActiveObject(progID);
}
catch { }
if (acApp != null)
{
MessageBox.Show("An instance of AutoCAD is already running.");
}
else
{
try
{
ProcessStartInfo psi =new ProcessStartInfo(exePath);
psi.WorkingDirectory = #"C:\Temp";
psi.Arguments = pth;
Process pr = Process.Start(psi);
pr.WaitForInputIdle();
while (acApp == null)
{
try
{
acApp =(AcadApplication)Marshal.GetActiveObject(progID);
}
catch
{
Application.DoEvents();
}
}
}
catch (Exception ex)
{
MessageBox.Show(
"Cannot create or attach to AutoCAD object: "
+ ex.Message
);
}
}
if (acApp != null)
{
acApp.Visible = true;
acApp.ActiveDocument.SendCommand("_MYCOMMAND ");
}
}
But as soon as Autocad starts it popups an error message saying Cannot find the specified drawing. When I use CMD.exe and type
"C:\Program Files\Autodesk\AutoCAD 2014\acad.exe" "C:\Temp\41 Stabd.dwg" It opens Autocad with the file(41 Stand.dwg) open.
I can't understand where I am making an error. Can someone help me out.
If still the drawing persists with problems, continue on to the next set of steps.
These can be done in any order, but have been listed in the order that Autodesk recommends makes the most sense. The file can be checked after each step. If things appear back to normal, there is no need to continue on to the rest of the steps.
​Open a blank DWG and type RECOVER at the command line. Browse to the problematic file to - allow AutoCAD a chance to restore the file.
Type OVERKILL at the command line, and select all objects. Check or uncheck properties to include or ignore, then click OK.
Type DELCON at the command line, and select all objects.
Type BREP and select all objects (if there are solids or surfaces in the file)
Type -SCALELISTEDIT, then "R" for reset, then "Y" for yes.
Type FILTERS, then click on the 'delete filters' button.
The DGNPURGE tool can be run if the file size is unexpectedly very large: http://knowledge.autodesk.com/article/AutoCAD-DWG-files-unexpectedly-increase-in-file-size
Try using a different version of AutoCAD to open the drawing, such as AutoCAD 2013 vs. AutoCAD 2015 or plain AutoCAD vs. AutoCAD Architecture, etc. Try different computers if available.
Open a blank DWG, and try to attach the problematic file as an XREF. If it allows you to attach the file, try next to BIND it to the current file. If that works, run the repair steps listed above.
Use the SAVEAS command to save the DWG in an older file format. Attempt to open the newly created file.
Export the file to DXF format using the DXFOUT command. Next, open a blan DWG and use the DXFIN command to import the file just created.
< Restore the Layout tabs:
Right-Click one of the default layout tabs
Select 'From Template...'
Open the original file
Choose the layout tabs to restore. (It is recommended to do this one tab at a time, in case one or more layout tabs are corrupted)
Move drawing objects between model and paper space. You may find that only one drawing space is usable in your file, although your main concern is model space:
​​1. Create a new layout and if need be, create a viewport.
Use CHSPACE to move all the geometry to paper space.
Create a new drawing and use the Design Center (ADC) to move the layout from the damaged file into it.
Use CHSPACE again to move the geometry back to model space.
Restore the original layouts from the bad file using the Design Center.
Dissect the drawing. In a copy of the file, conduct a process of elimination using QSELECT to select different object types and then delete them to see if that fixes what is wrong in the file. Do PURGE All after each deletion. Eventually you should remove the problem elements and then you can choose to leave them out, copy them in again from another file, recreate them, or further troubleshoot individual items to pinpoint exactly which one is problematic. A quick start to this whole process is to delete everything in the drawing and then test it. This will quickly tell you if the issue is with a drawing object or if it is a part of the drawing database.​

Application hanging on DialogResult.OK

Im having some trouble my program hanging when selecting a file in a file dialog. This is the code that is showing the file browser dialog:
private void isForgeIncluded_btn_Click(object sender, EventArgs e)
{
this.isForgeIncluded.Text = FolderFileDialog("file", isForgeIncluded.Text, "Forge installer file (*.jar)|*.jar");
}
public string FolderFileDialog(string type, string current, string fileTypes = "All files (*.*)|*.*|All files (*.*)|*.*", string StartFolder = "C:\\")
string ReturnString = current;
if (current != "")
{
StartFolder = Path.GetFullPath(current);
}
if (type == "file")
{
OpenFileDialog minecraftFile = new OpenFileDialog();
minecraftFile.Title = "Select file";
minecraftFile.InitialDirectory = StartFolder;
minecraftFile.RestoreDirectory = true;
minecraftFile.Filter = fileTypes;
if (minecraftFile.ShowDialog() == DialogResult.OK)
{
ReturnString = minecraftFile.FileName;
return ReturnString;
}
minecraftFile = null;
}
return ReturnString;
}
I've narrowed the problem down to between the "if" statement and the "Return string = minecraftFile.FileName;" .. When using the debugger the program takes up to a five second break between those two lines. After its break it comes back and returns the value as if nothing was wrong. But IntelliTrace sometimes comes up with a "FileNotFound Exception" even though the program never shows me any error messages, and returns the correct value to the textbox as it should.
The wierd part is that it is not always this happens. Its random and can happen even though i select the same file as last time. The files i select are local files too on the system drive.
What could be wrong? Does the code look as it should?
Two basic problems can cause trouble with OpenFileDialog. First is misbehaving shell extension installed on your machine, they'll get loaded into your process when you open the dialog. A basic check is that you don't see trouble with Notepad's File + Open command and that you see nothing special in the Visual Studio Output window while the dialog is active. Enabling unmanaged debugging gives you more info.
The second cause is having an issue with the thread state of your UI thread. If must be initialized as a single-threaded apartment to be able to show this dialog properly. Go back to your Main() method, normally in Program.cs, and ensure it has the [STAThread] attribute.
If that doesn't pan out then we need more info about the code that's misbehaving. You need to enable unmanaged debugging, Project + Properties, Debug tab. And enable the Microsoft symbol server, Tools + Options, Debugging, Symbols. And disable Just My Code debugging, Tools + Options, Debugging, General. Hit Debug + Break All right after you get it to misbehave and post the content of the Call Stack window.

how to insert the text in the editor in the TextAdornment template in Visual Studio?

I follow the steps in this page http://blogs.msdn.com/b/visualstudio/archive/2009/12/09/building-and-publishing-an-extension-for-visual-studio-2010.aspx
I create a TextAdornment project and a search box. I wan to do some different in this page. I want to query a link , get a list in the WPF user control and then write the info into the editor back. so the question is I do not know how to write the text back into the editor in seachbox(WPF user control)?
I searched a lot, and get a way to use the code look like this:
IVsTextManager txtMgr = (IVsTextManager)GetService(typeof(SVsTextManager));
IVsTextView vTextView = null;
int mustHaveFocus = 1;
txtMgr.GetActiveView(mustHaveFocus, null, out vTextView);
IVsUserData userData = vTextView as IVsUserData;
if (userData == null)
{
return null;
}
else
{
IWpfTextViewHost viewHost;
object holder;
Guid guidViewHost = DefGuidList.guidIWpfTextViewHost;
userData.GetData(ref guidViewHost, out holder);
viewHost = (IWpfTextViewHost)holder;
return viewHost;
}
However, the method "GetService" also said not found. I think the reason is this method is for VSPackage. and it is not suitable for Adornment project.
Please help to point how the write the text back into the editor from WPF user control. Thanks!
======================================================================================
Solution:
when creating the SearchBox(WPF User Control), pass through the IWpfTextView to WPF control.and then,it is possible to use this in SearchBox.xaml.cs. Also need to be aware to use the Dispatcher function to keep the UI thread is the active one.
Dispatcher.Invoke(new Action(() =>
{
ITextEdit edit = _view.TextBuffer.CreateEdit();
ITextSnapshot snapshot = edit.Snapshot;
int position = snapshot.GetText().IndexOf("gist:");
edit.Delete(position, 5);
edit.Insert(position, "billmo");
edit.Apply();
}));
The code you have there is if you're in a package and you are trying to figure out what view is currently active...it's overkill for what you're trying to do.
Assuming you started from the TextAdornment template, the adornment object is given an IWpfTextView in the constructor. (If not, you probably have an implementation of IWpfTextCreationListener.TextViewCreated which got it and you need to thread it through.) The IWpfTextView derives ITextView which has a property ITextBuffer. From here, you can call CreateEdit() and edit text from there.

Prevent an object from being coppied in C# PowerPoint 2010 add-in

I am building a PowerPoint 2010 C# add-in using Visual Studio 2010. One of the functions of the add-in is to add a shape to the current slide. Once the shape is added to the slide though, I need to prevent it from being copied. That is where I am running into issues. I have looked at all the application level events and am not seeing any sort of beforeCopy or beforePaste type of events.
The only option I can think of right now is to add a keydown event listener to listen for "ctrl+c" and block that if my shape is selected and then create a custom right click menu (not even sure if I can yet) to remove the "Copy" option if my shape is selected. There has to be simpler option though.
Anyone have any ideas how I would prevent a user from copying a shape?
The commands executed by built-in ribbon buttons Microsoft Office can be disabled or re-routed. Microsoft calls this "Repurposing", an introduction can be found here.
So another approach could be to "repurpose" the built-in Copy button with something like this. (Needs to be returned by GetCustomUI to customize the ribbon, see the link above.) This modifies the action executed by the Copy button and the callback method that determines whether the button is enabled or not.
<command idMso="Copy" onAction="copyAction" getEnabled="copyEnabled" />
Implement copyAction to return cancelDefault = true when your shape is selected so it will not be copied.
Implement copyEnabled to return false if your shape is selected. Remember to invalidate the button on selection change events.
Actually, one of both approaches should be sufficient. I guess onAction is easier to implement.
Just to close the loop on this, I am sharing my work-around in the hopes that someone else who has this issue will not waste as much time as I have on this. I ended up just using the SlideSelectionChanged and WindowSelectionChange events and a dictionary to delete my objects that have been coppied.
First, when my shape is added to the stage I add a new entry into the dictionary containing the shape name (in my case it was actually a group of shapes) and its ID.
itemIDDictionary.Add(myGroup.Name, myGroup.Id);
WindowSelectionChange is a fairly simple check. It just looks to see if the newly selected item is in the dictionary already. If it is, it then checks to see if the ID matches. If not, it deletes the item. This works because when you copy and paste an item, the newly pasted item is automatically selected on the slide.
public void itemSelectionChange(PowerPoint.Selection SelectedItem)
{
try
{
if (Globals.Ribbons.Ribbon2.itemIDDictionary.ContainsKey(SelectedItem.ShapeRange.Name))
{
for (int shapeIDCount = 0; shapeIDCount < Globals.Ribbons.Ribbon2.itemIDDictionary.Count; shapeIDCount++)
{
if (!Globals.Ribbons.Ribbon2.itemIDDictionary.ContainsValue(SelectedItem.ShapeRange[1].Id))
{
SelectedItem.Delete();
MessageBox.Show("You can not copy the browser object.\nAdd a new one using the ribbon bar");
}
}
}
}
catch {}
SlideSelectionChanged is just a little bit more complicated as I have to loop through all the shapes on the slide.
try
{
if (SldRange.Count > 0)
{
var showWarning = false;
for (int slideCount = 1; slideCount <= SldRange.Count; slideCount++)
{
int shapeCount = 1;
while (shapeCount <= SldRange[slideCount].Shapes.Count)
{
if (Globals.Ribbons.Ribbon2.itemIDDictionary.ContainsKey(SldRange[slideCount].Shapes[shapeCount].Name))
{
if (!Globals.Ribbons.Ribbon2.itemIDDictionary.ContainsValue(SldRange[slideCount].Shapes[shapeCount].Id))
{
SldRange[slideCount].Shapes[shapeCount].Delete();
showWarning = true;
}
else
{
shapeCount++;
}
}
else
{
shapeCount++;
}
}
}
if(showWarning == true)
{
MessageBox.Show("You can not copy the browser object.\nAdd a new one using the ribbon bar");
}
}
}
catch { }
As I said in my initial post, I am sure there is a cleaner way to do this. I just couldn't find one to save my life.

Categories