I am trying to merge c# documents. My idea is to have a master document and just append the other documents to this master document. Environment is in SharePoint, so basically the documents exist in the document library and I have no problem with my code being able to find the documents. Once I locate them programattically I have no clue how to open and merge them. I have been searching and seems to be like OpenXML SDK 2.0 is a way to do it, but I am not familar with that tool at all and was trying to see if their is a way to do it with the current tools I have in Visual Studio 3.5 . Either using Microsoft.Office.Interop.Word or something else. From what I understand, the actual files are stored in the content database as binary form so the physical file doesn't actually exist, so I cant just easily open them with word. Any help.
I think this link is exactly what you're looking for:
Merging Word Documents on the Server Side with SharePoint 2010
There's a little Open Xml, but nothing too bad. If you decide that this isn't giving you the control you need, you can check this article out:
Creating Documents by Using the Open XML Format SDK 2.0 (Part 3 of 3)
The following script, taken from Tortoise SVN, could help you to get a clue about how to merge .doc files. Be careful with the license if your going to distribute it.
You need to invoke the script from C# using the following:
wscript.exe "C:\<path_to_the_script>\merge-doc.js" merged.doc theirs.doc mine.doc base.doc //E:javascript
This is the script code, only for doc, there is other for docx that I have not included here, but you can take a look installing Tortoise SVN.
//
// TortoiseSVN Merge script for Word Doc files
//
// Copyright (C) 2004-2008 the TortoiseSVN team
// This file is distributed under the same license as TortoiseSVN
//
// Last commit by:
// $Author: tortoisesvn $
// $Date: 2008-12-05 17:38:43 +0100 (Fr, 05 Dez 2008) $
// $Rev: 14781 $
//
// Authors:
// Dan Sheridan, 2008
// Davide Orlandi and Hans-Emil Skogh, 2005
//
var objArgs,num,sTheirDoc,sMyDoc,sBaseDoc,sMergedDoc,objScript,word,baseDoc,WSHShell;
// Microsoft Office versions for Microsoft Windows OS
var vOffice2000 = 9;
var vOffice2002 = 10;
var vOffice2003 = 11;
var vOffice2007 = 12;
// WdCompareTarget
var wdCompareTargetSelected = 0;
var wdCompareTargetCurrent = 1;
var wdCompareTargetNew = 2;
objArgs = WScript.Arguments;
num = objArgs.length;
if (num < 4)
{
WScript.Echo("Usage: [CScript | WScript] merge-doc.js merged.doc theirs.doc mine.doc base.doc");
WScript.Quit(1);
}
sMergedDoc=objArgs(0);
sTheirDoc=objArgs(1);
sMyDoc=objArgs(2);
sBaseDoc=objArgs(3);
objScript = new ActiveXObject("Scripting.FileSystemObject")
if ( ! objScript.FileExists(sTheirDoc))
{
WScript.Echo("File " + sTheirDoc +" does not exist. Cannot compare the documents.", vbExclamation, "File not found");
WScript.Quit(1);
}
if ( ! objScript.FileExists(sMergedDoc))
{
WScript.Echo("File " + sMergedDoc +" does not exist. Cannot compare the documents.", vbExclamation, "File not found");
WScript.Quit(1);
}
objScript = null
try
{
word = WScript.CreateObject("Word.Application");
}
catch(e)
{
WScript.Echo("You must have Microsoft Word installed to perform this operation.");
WScript.Quit(1);
}
word.visible = true
// Open the base document
baseDoc = word.Documents.Open(sTheirDoc);
// Merge into the "My" document
if (parseInt(word.Version) < vOffice2000)
{
baseDoc.Compare(sMergedDoc);
}
else if (parseInt(word.Version) < vOffice2007)
{
baseDoc.Compare(sMergedDoc, "Comparison", wdCompareTargetNew, true, true);
} else {
baseDoc.Merge(sMergedDoc);
}
// Show the merge result
if (parseInt(word.Version) < 12)
{
word.ActiveDocument.Windows(1).Visible = 1;
}
// Close the first document
if (parseInt(word.Version) >= 10)
{
baseDoc.Close();
}
// Show usage hint message
WSHShell = WScript.CreateObject("WScript.Shell");
if(WSHShell.Popup("You have to accept or reject the changes before\nsaving the document to prevent future problems.\n\nWould you like to see a help page on how to do this?", 0, "TSVN Word Merge", 4 + 64) == 6)
{
WSHShell.Run("http://office.microsoft.com/en-us/assistance/HP030823691033.aspx");
}
Related
I have an application that creates multiple (regularly 1000+) Word files and then prints them.
I have created the below code that, once the PrintDialog is Ok'd proceeds to print the documents that reside in a folder. However recently we've had some strange behaviour following some Office updates (its Office 2010, which we cannot upgrade). The screen literally flickers, like a really bad graphics problem, then Word crashes after about 500 prints. This hasn't happened before and has been running for probably 12 months+ without issue.
As you can see, the application opens one instance of Word, then uses that to open>print>close each document. I can't see how this causes a problem, as Word only ever has one document open at a time. The memory size of winword.exe also doesn't increase significantly beyond the size of when its first opened too, so the Office updates don't initially appear to have introduced a memory leak.
Is there a more efficient way of doing this?
if (printDialog.ShowDialog() == DialogResult.OK)
{
int c = 1;
int total = directoryInfo.GetFiles().Count();
// Set the Progress bar details
App.Current.Dispatcher.Invoke((Action)delegate { MainWindow.ui_progressBar.Maximum = directoryInfo.GetFiles().Length; });
// loop through the files in order
foreach (FileInfo report in directoryInfo.GetFiles().OrderBy(x => x.FullName))
{
UpdateUI("Printing " + c.ToString() + " / " + total.ToString());
Microsoft.Office.Interop.Word.Document reportFile = wordApp.Documents.Add(report.FullName);
wordApp.ActivePrinter = printDialog.PrinterSettings.PrinterName;
wordApp.ActiveDocument.PrintOut();
reportFile.Close(SaveChanges: false);
reportFile = null;
PrinterCounter++;
App.Current.Dispatcher.Invoke((Action)delegate { MainWindow.ui_progressBar.Value = PrinterCounter; });
c++;
}
}
I'm looking for a way to access a linked Autocad File using the Revit API. I have SnoopDB already installed which is a huge help.
I found this which was also another step forward however I'm not able to get the points or lines of the file.
I've explored a bit and have found that I am able to access the filename and then get the hashcode of the cadlink but after that, idk how to get the goemetry within.
Any and all help is appreciated.
here is what I have so far:
UIApplication uiapp = commandData.Application;
UIDocument uidoc = uiapp.ActiveUIDocument;
Application app = uiapp.Application;
Document doc = uidoc.Document;
Selection sel = uidoc.Selection;
using (Transaction tx = new Transaction(doc))
{
try
{
tx.Start("Tracing Cad");
Reference refer = sel.PickObject(ObjectType.Element, "Select a CAD Link");
Element elem = doc.GetElement(refer);
GeometryElement geoElem = elem.get_Geometry(new Options());
Debug.WriteLine("elem.Category.Name: " + elem.Category.Name); // can grab title of CAD
foreach (GeometryObject geoObj in geoElem)
{
GeometryInstance instance = geoObj as GeometryInstance;
foreach (GeometryObject instObj in instance.SymbolGeometry)
{
Debug.WriteLine("geoObj.GraphicsStyleId: " + geoObj.GraphicsStyleId);
Debug.WriteLine("geoObj.GetHashCode(): " + geoObj.GetHashCode()); // gets hashcode of selected cad link
if (instObj.GetType().Name == "PolyLine")
// if (instObj.GetType().Name == "GeometryInstance")
{
}
else
{
Debug.WriteLine("there are no blocks found in this CAD File");
}
}
}
tx.Commit();
} catch (Exception e )
{
Debug.WriteLine(e.StackTrace);
}
The Revit API does not provide any access to the internals of a linked CAD file.
All you can do is implement some AutoCAD.NET code to read the DWG file itself, provided you have access to the DWG and AutoCAD is installed.
The Building Coder shares some samples showing how to launch AutoCAD within a Revit add-in.
Can anyone suggest c# code that can be used to iterate over every control on all reports in a Microsoft Access database? The reason for doing this is that I am converting reports from Microsoft Access to Reporting Services and I want to find all reports in access that has specific text in the control source property.
Currently I am using the Microsoft.Office.Interop.Access assemblies but the code I am using is not working. This is because Access API knowledge is limited.
private static void Main(string[] args)
{
OpenDatabase();
DisplayReportElements();
Console.ReadLine();
}
private static void OpenDatabase()
{
app = new Application();
app.OpenCurrentDatabase(#"database.mdb");
app.Visible = false;
//app.OpenCurrentDatabase(#"C:\DLDWorkspace\Truama\Skills Training.mdb");
}
public static void DisplayReportElements()
{
for (int i = 0; i < app.CurrentProject.AllReports.Count - 1; i++)
{
Report report = app.Reports[i];
foreach (Control control in report.Controls)
{
Console.WriteLine("{0} - {1}", report.FormName, control.Name);
ControlProperties(control);
}
}
}
The following code produces an exception with the message "The number you used to refer to the report is invalid." on line Report report = app.Reports[i];. To get around this I go through and Open each report by calling app.DoCmd.OpenReport in a loop. There is two problems with this. 1. It takes over 12 hours to process 300 reports. and 2. after about 300 (of 600) reports I get an Index is out of bounds somewhere in DisplayReportElements
To iterate through the reports and their controls from within an Access.Application your approach is correct. If you find that process to be too slow or otherwise troublesome then an alternative approach would be to dump all of the reports to text files using the Application.SaveAsText method ...
var app = new Application();
app.OpenCurrentDatabase(#"C:\Users\Public\Database1.accdb");
for (int i = 0; i < app.CurrentProject.AllReports.Count; i++)
{
string rptName = app.CurrentProject.AllReports[i].Name;
Console.WriteLine("Dumping [{0}] ...", rptName);
string fileSpec = #"C:\__tmp\ReportDump\" + rptName + ".txt";
app.SaveAsText(AcObjectType.acReport, rptName, fileSpec);
}
app.CloseCurrentDatabase();
app.Quit();
and then use your favorite text-searching tool to scan the files for lines that contain 'ControlSource =' followed by the string you want to find, e.g.,
ControlSource ="LastName"
From c#, I want to launch a process which will open a text file in any editor and automatically move cursor to a certain line number.
I can open a file using
Process.Start(#"c:\myfile.txt");
but I don't know how to move cursor at specific location in that file.
Answer with source code:
yes, I used notepad++
private void openLog() {
try {
// see if notepad++ is installed on user's machine
var nppDir = (string)Registry.GetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\Notepad++", null, null);
if (nppDir != null) {
var nppExePath = Path.Combine(nppDir, "Notepad++.exe");
var nppReadmePath = Path.Combine(yourDirectory,fileName );
var line = 20;
var sb = new StringBuilder();
sb.AppendFormat("\"{0}\" -n{1}", nppReadmePath, lineNo);
Process.Start(nppExePath, sb.ToString());
} else {
string newPath = #"\\mySharedDrive\notpad++\bin\notepad++.exe";
Process.Start(newPath, #"\\" + filePath + " -n" + lineNo); // take exe from my shared drive
}
} catch (Exception e) {
Process.Start(#"\\" + FilePath); // open using notepad
}
}
Get Notepad++, then you can do this:
var nppDir = (string)Registry.GetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\Notepad++", null, null);
var nppExePath = Path.Combine(nppDir, "Notepad++.exe");
var nppReadmePath = Path.Combine(nppDir, "readme.txt");
var line = 20;
var sb = new StringBuilder();
sb.AppendFormat("\"{0}\" -n{1}", nppReadmePath, line);
Process.Start(nppExePath, sb.ToString());
In this example we get install path of n++ from the registry, build path to exe and readme.txt file, opens its own readme.txt file with cursor on line 20.
Using StringBuilder is more efficient than using multiple appends (explanation somewhere on SO).
The solution very heavily depends on which process/editor is opened on your system. That editor would have to have a developer API that you could use to access functionality such as setting ranges and altering the cursor position. For example, if the editor that is opened is Microsoft Word, you would use the Word Interop API to set a selection at a specific position. There is no universal way to do this in 'any editor' since each one has its own API (or no outward facing API at all).
Perhaps you are going this the wrong way. I'm not sure what you are trying to accomplish, but I think it would be alot easier to just open the text file in an editor that belongs to your application. Perhaps another form with a WYSIWYG editor control. That way you have full control on where the cursor will land in that editor. Otherwise, there are just way too many unknowns for anything feasibly workable.
I need to add a custom activity to the default workflow template to increase assembly versions at the earliest point possible in the build process.
What I would like to achieve is to create and map the exact same workspace (that is be created further down in the workflow) inside my custom activity so that I can check out an xml file, increase the version number held within, write it back to the xml file and check the xml file back in.
I'm aware that this workspace will be created later on in the workflow but that will be too late in the build process for what I'm trying to achieve, so instead of moving any of the activities or duplicating them in a position above my custom activity (this should be ok as this workspace will be deleted and recreated again later)
I think the details I need are the BuildDirectory, WorkspaceName and SourcesDirectory. Can anyone tell me how to achieve the creation of the workspace or how obtain this data in code?
the build will be carried out on a build server, and I am using TFS 2010 and c#.
Thanks in advance
I followed the series of blog articles by Ewald Hofman as a primer and created a custom activity that does the check-out, update and check-in of a GlobalAssemblyInfo file that I parse the current version from. My task is inserted at the top of the "Update Drop Location" which is right after it does the "Get the build" portion of the workflow. I just use require the IBuildDetail and a File Mask as arguments from which you can pull out the VersionControlServer to be able to access TFS. My code is below:
protected override string Execute(CodeActivityContext context)
{
// Obtain the runtime value of the input arguments.
string assemblyInfoFileMask = context.GetValue(AssemblyInfoFileMask);
IBuildDetail buildDetail = context.GetValue(BuildDetail);
var workspace = buildDetail.BuildDefinition.Workspace;
var versionControl = buildDetail.BuildServer.TeamProjectCollection.GetService<VersionControlServer>();
Regex regex = new Regex(AttributeKey + VersionRegex);
// Iterate of the folder mappings in the workspace and find the AssemblyInfo files
// that match the mask.
foreach (var folder in workspace.Mappings)
{
string path = Path.Combine(folder.ServerItem, assemblyInfoFileMask);
context.TrackBuildMessage(string.Format("Checking for file: {0}", path));
ItemSet itemSet = versionControl.GetItems(path, RecursionType.Full);
foreach (Item item in itemSet.Items)
{
context.TrackBuildMessage(string.Format("Download {0}", item.ServerItem));
string localFile = Path.GetTempFileName();
try
{
// Download the file and try to extract the version.
item.DownloadFile(localFile);
string text = File.ReadAllText(localFile);
Match match = regex.Match(text);
if (match.Success)
{
string versionNumber = match.Value.Substring(AttributeKey.Length + 2, match.Value.Length - AttributeKey.Length - 4);
Version version = new Version(versionNumber);
Version newVersion = new Version(version.Major, version.Minor, version.Build + 1, version.Revision);
context.TrackBuildMessage(string.Format("Version found {0}", newVersion));
return newVersion.ToString();
}
}
finally
{
File.Delete(localFile);
}
}
}
return null;
}