Adding Signature Line Word-Excel - c#

I can add a signature line to the word document but i feel not good with my approach. I've searched a lot to handle my sitautation but not found any.
Well here is my code
private void CreateNewPage()
{
object missing = System.Reflection.Missing.Value;
object fileName = #"C:\docs\mydoc.docx";
object readOnly = false;
object isVisible = true;
//Start Word and open a document.
Word._Application oWord;
Word._Document oDoc;
oWord = new Word.Application();
oWord.Visible = true;
oDoc = oWord.Documents.Open(ref fileName, ref missing, ref readOnly,
ref missing, ref missing, ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing, ref isVisible, ref missing,
ref missing, ref missing, ref missing);
// var numberOfPages = oDoc.ComputeStatistics(Word.WdStatistic.wdStatisticPages, false);
object oEndOfDoc = "\\endofdoc";
object paramNextPage = Word.WdBreakType.wdSectionBreakNextPage;
oDoc.Bookmarks.get_Item(ref oEndOfDoc).Range.InsertBreak(ref paramNextPage);
//Insert a page break
object breakPage = Word.WdBreakType.wdPageBreak;
object saveOption = Word.WdSaveOptions.wdDoNotSaveChanges;
object originalFormat = Word.WdOriginalFormat.wdOriginalDocumentFormat;
object routeDocument = false;
object what = Microsoft.Office.Interop.Word.WdGoToItem.wdGoToPage;
object which = Microsoft.Office.Interop.Word.WdGoToDirection.wdGoToLast;
object count = 3;
oWord.Selection.GoTo(ref what, ref which, ref count, ref missing);
object sigID = "{00000000-0000-0000-0000-000000000000}";
Timer t = new Timer();
t.Elapsed += (sender, args) =>
{
SendKeys.SendWait("{TAB}");
SendKeys.SendWait("~");
t.Stop();
};
t.Interval = 2000;
t.Start();
try
{
oWord.Activate();
SignatureSet signatureSet = oWord.ActiveDocument.Signatures;
// signatureSet.ShowSignaturesPane = false;
Signature objSignature = signatureSet.AddSignatureLine(sigID);
objSignature.Setup.SuggestedSigner = "docSigner";
objSignature.Setup.SuggestedSignerEmail = "abc#xyz.com";
objSignature.Setup.ShowSignDate = true;
// dynamic shape = objSignature.SignatureLineShape;
}
catch (Exception ex){}
oWord.Documents.Save();
oWord.Quit();
try
{
Marshal.ReleaseComObject(oWord);
}
catch (Exception){}
}
Well as you see below, when i call AddSignatureLine funciton, this window opens modal (like showdialog) and until close this, the code does not flow..
and I am bypass this by using sendkey but we know that it is not a good way. However, If i cant find any other solution then I will try to do that finding this window (word's child window) using Win32 APIs.
But I am curious if is there anyway to bypass this? Because there are thousand documents and I am looking for also a faster way.
After adding this signature line, then we can able to sign document with DocuSign. But if there is no any signature line in the document, DocuSign does not sign the document digitally. Then We have to add this line.

As there seems no way of circumventing the display of the modal Signature Setup dialog, I would suggest you the following workaround which is based on a building block containing a properly configured signature line:
Create a new empty .dotx template. This template will be used to save the building block entry.
Create a sample document containing a signature line and add this signature line via Insert > Quick Parts > Save Selection to Quick Part Gallery to the template created in the previous step.
Include the template in your project and deploy the template with your executable or add-in.
At runtime, load the template as an add-in
Application.AddIns.Add(fullPathToDotx);
You can now insert the building block from the template
var template = Application.Templates
.OfType<Microsoft.Office.Interop.Word.Template>()
.FirstOrDefault(t => t.Name == addInFileName);
var buildingBlock = template.BuildingBlockEntries.Item("Signature Line");
buildingBlock.Insert(range, true);
(Unload the building block template)
If you need to modify the properties of the signature line, you could either
Prepare multiple signature line building blocks which are configured accordingly, or
Dynamically patch the building block template (e.g. by creating a copy at runtime, open and manipulating the file using the Open XML SDK and temporarily load the modified version.

Related

Creating strike-through in Word document with C#

I'm attempting to create a word document, but text between certain words should be crossed out. I tried looking online for solutions but the only solution I could find was:
Set myRange = document.Range(Start:= document.Words(1).Start, _End:= document.Words(3).End)
myRange.Font.StrikeThrough = True
from here https://msdn.microsoft.com/en-us/vba/word-vba/articles/font-strikethrough-property-word for VBA. Unfortunately there was nothing for C#.
Does anyone know how you would add a strike-through to specific pieces of text before saving it all to a word document?
My code for reference:
//input is a StringBuilder received by method
try {
//Create an instance for word app
Microsoft.Office.Interop.Word.Application winword = new Microsoft.Office.Interop.Word.Application();
//Set animation status for word application
winword.ShowAnimation = false;
//Set status for word application is to be visible or not.
winword.Visible = false;
//Create a missing variable for missing value
object missing = System.Reflection.Missing.Value;
//Create a new document
Microsoft.Office.Interop.Word.Document document = winword.Documents.Add(ref missing, ref missing, ref missing, ref missing);
//adding text to document
document.Content.SetRange(0, 0);
document.Content.Text = input.ToString();
//Save the document
object filename = #"C:\Users\TempUser\Desktop\temp1.docx";
document.SaveAs2(ref filename);
document.Close(ref missing, ref missing, ref missing);
document = null;
winword.Quit(ref missing, ref missing, ref missing);
winword = null;
Console.WriteLine("Document created successfully!");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
I've extracted the relevant part from your code to make it easier to follow.
My assumption with this sample is that text should be inserted at the end of the document and formatted as "strikethrough". Notice how I declare a Word.Range object and assign the body of the document to it. For understanding how it works, think of a Range like a Selection, but you can have more than one and it's not visible in the document.
The next line "collapses" the Range to its end-point - like pressing Right arrow. If you did not collapse the Range, the text assigned to it would replace what's in the document (like over-typing a selection). The text is then assigned to the Range and the Strikethrough applied.
Note that in the old Word Basic days "true" and "false" were not concepts used for setting font decoration. Word's object model still uses these old Word Basic commands. Under the covers they still use -1 for true and 0 for false (and sometimes 1 for something else). While the VB languages can use the "pseudo boolean" settings (true/false) that have been added to the object model for convenience, C# doesn't "see" them, so you need -1 for true.
//adding text to document
object oCollapseEnd = Word.WdCollapseDirection.wdCollapseEnd;
Word.Range rng = document.Content;
rng.Collapse(ref oCollapseEnd);
rng.Text = input.ToString();
rng.Font.Strikethrough = -1; // 0 for false

Merging multiple docx files to one

I am developing a desktop application in C#. I have coded a function to merge multiple docx files but it does not work as expected. I don't get the content exactly as how it was in the source files.
A few blank lines are added in between. The content extends to the next pages, header and footer information is lost, page margins gets changed, etc..
How can I concatenate docs as it is without and change in it.Any suggestions will be helpful.
This is my code.
public bool CombineDocx(string[] filesToMerge, string destFilepath)
{
Application wordApp = null;
Document wordDoc = null;
object outputFile = destFilepath;
object missing = Type.Missing;
object pageBreak = WdBreakType.wdPageBreak;
try
{
wordApp = new Application { DisplayAlerts = WdAlertLevel.wdAlertsNone, Visible = false };
wordDoc = wordApp.Documents.Add(ref missing, ref missing, ref missing, ref missing);
Selection selection = wordApp.Selection;
foreach (string file in filesToMerge)
{
selection.InsertFile(file, ref missing, ref missing, ref missing, ref missing);
selection.InsertBreak(ref pageBreak);
}
wordDoc.SaveAs( ref outputFile, ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing, ref missing);
return true;
}
catch (Exception ex)
{
Msg.Log(ex);
return false;
}
finally
{
if (wordDoc != null)
{
wordDoc.Close();
}
if (wordApp != null)
{
wordApp.DisplayAlerts = WdAlertLevel.wdAlertsAll;
wordApp.Quit();
Marshal.FinalReleaseComObject(wordApp);
}
}
}
In my opinion it's not so easy. Therefore I'll give you some tips here.
I think you need to implement the following changes to your code.
1.instead of pageBreak you need to add any of section breaks which could be the most appropriate:
object sectionBrak = WdBreakType.wdSectionBreakNextPage;
'other section break types also available
and use this new variable within your loop.
As a result you get all- text, footers and headers of the source document to new one.
2.However, you will still need to read margin parameters and apply them to your new document 'manually' using additional code. Therefore you will need to open source document and check it's margins in this way:
intLM = SourceDocument.Sections(1).PageSetup.LeftMargin;
'...and similar for other margins
and next you need to apply it to new document, to appropriate section:
selection.Sections(1).PageSetup.LeftMargin = intLM;
3.Some other document section could require some other techniques.
You could use the Open XML SDK and the DocumentBuilder tool.
See Merge multiple word documents into one Open Xml

Word Interop 2007 silent printing issue

I am using:
Office 2007
VC# Express 2010
1x Citrix virtual XP network environment accessed through Windows 7 laptop host
1x printer set to output to .prn in a given network-mapped drive
I am using C# and Word Interop to silently print a given set of files automatically. The application scans an input folder every 10 minutes for .doc / .docx files only, and inputs their path&filename into a list. Foreach found file, attempt to print via the following code:
public static Boolean PrintFoundFiles(List<string> foundFiles)
{
successful = false;
foreach (string file in foundFiles)
{
object fileAndPath = file; //declare my objects here, since methods want an object passed
object boolTrue = true; //
object boolFalse = false; //
object output = FormatOutputName(file); //
object missing = System.Type.Missing; //
object copies = "1"; //
object pages = ""; //
object items = Word.WdPrintOutItem.wdPrintDocumentContent; //
object range = Word.WdPrintOutRange.wdPrintAllDocument; //
object pageType = Word.WdPrintOutPages.wdPrintAllPages; //
Word.Application wordApp = new Word.Application(); //open word application
wordApp.Visible = false; //invisible
Word.Document doc = wordApp.Documents.Open(ref fileAndPath, ref missing, ref missing, ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing); //opens the word document into application behind the scenes
doc.Activate(); //activates document, else when I print the system will throw an exception
wordApp.ActivePrinter = "my printer name"; //Specify printer I will print from
doc.PrintOut(ref boolTrue, ref boolFalse, ref range, ref output, ref missing, ref missing,
ref items, ref copies, ref pages, ref pageType, ref boolTrue, ref boolTrue,
ref missing, ref boolFalse, ref missing, ref missing, ref missing, ref missing);
doc.Close(SaveChanges: false);
doc = null;
((Word._Application)wordApp).Quit(SaveChanges: false); //kill word process the right way
wordApp = null; //reset to null
successful = true;
}
return successful;
}
After I receive the true boolean of "successful", I will back up the file automatically in a backup folder, delete it in the input folder, and look for the .prn in the output folder (it just sits here for processing later).
If I don't provide an output (see ref output on doc.PrintOut()), the output directory doesn't get updated or printed to at all. If I DO provide an output, the .prn is created, though it is a 0kb empty file.
The printer is set up as the default printer, and it has been configured to automatically output to said output folder. If I open Word manually with the same file I'm trying to automatically print from, hit print, it will create a 6kb .prn file in the output directory without having to hit anything other than CTRL + P, OK.
I'm fairly confident the file is being opened OK via "Word.Document doc = wordApp.Documents.Open()" because I did a doc.FullName and got the full path of the input word document in question. I just cannot for the life of me get the .prn to output correctly to the output folder.
If I start my word (2010) and record a macro of me pressing Ctrl+P and hitting print - I'm getting
Application.PrintOut fileName:="", Range:=wdPrintAllDocument, Item:= _
wdPrintDocumentWithMarkup, Copies:=1, Pages:="", PageType:= _
wdPrintAllPages, Collate:=True, Background:=True, PrintToFile:=False, _
PrintZoomColumn:=0, PrintZoomRow:=0, PrintZoomPaperWidth:=0, _
PrintZoomPaperHeight:=0
Change your PrintOut to reflect what Word did and see if it solves your issue.
There's no reason to be "fairly confident", just remove
wordApp.Visible = false
Debug your program and make certain it's OK.

Word Automation - File is in use by another application or user

I have a WinForms application where I am using Word Automation to build documents via a template, and then save them to the database. After the document is created, I retrieve the document from the database, write it to the file system in a temp directory, and then open the document using the Word Interop services.
There is a list of documents loaded and the user can open only 1 instance of each document, but can open multiple different documents simultaneously. I don't have any problems with opening, saving, and closing when they open 1 document, however, when they open multiple documents simultaneously, I get the following error when closing any of my instances of Word:
The file is in use by another application or user. (C:\...\Templates\Normal.dotm)
This error is commonly encountered when a read lock is set on the file that you are attempting to open.
I am using the following code to open the document and handle the BeforeDocumentClosed event:
public void OpenDocument(string filePath, Protocol protocol, string docTitle, byte[] document)
{
_protocol = protocol;
documentTitle = docTitle;
_path = filePath;
if (!_wordDocuments.ContainsKey(_path))
{
FileUtility.WriteToFileSystem(filePath, document);
Word.Application wordApplication = new Word.Application();
wordApplication.DocumentBeforeClose += WordApplicationDocumentBeforeClose;
wordApplication.Documents.Open(_path);
_wordDocuments.Add(_path, wordApplication);
}
_wordApplication = _wordDocuments[_path];
_currentWordDocument = _wordApplication.ActiveDocument;
ShowWordApplication();
}
public void ShowWordApplication()
{
if (_wordApplication != null)
{
_wordApplication.Visible = true;
_wordApplication.Activate();
_wordApplication.ActiveWindow.SetFocus();
}
}
private void WordApplicationDocumentBeforeClose(Document doc, ref bool cancel)
{
if (!_currentWordDocument.Saved)
{
DialogResult dr = MessageHandler.ShowConfirmationYnc(String.Format(Strings.DocumentNotSavedMsg, _documentTitle), Strings.DocumentNotSavedCaption);
switch (dr)
{
case DialogResult.Yes:
SaveDocument(_path);
break;
case DialogResult.Cancel:
cancel = true;
return;
}
}
try
{
if (_currentWordDocument != null)
_currentWordDocument.Close();
}
finally
{
Cleanup();
}
}
public void Cleanup()
{
if (_currentWordDocument != null)
while(Marshal.ReleaseComObject(_currentWordDocument) > 0);
if (_wordApplication != null)
{
_wordApplication.Quit();
while (Marshal.ReleaseComObject(_wordApplication) > 0);
_wordDocuments.Remove(_path);
}
}
Does anyone see anything wrong that I am doing to allow opening of multiple documents at the same time? I am fairly new to Word Automation and the Word Interop services, so any advice is appreciated. Thanks.
I found the solution via this MSDN article: http://support.microsoft.com/kb/285885
You need to do this before calling Application.Quit();
_wordApplication.NormalTemplate.Saved = true;
This prevents Word from trying to save the Normal.dotm template. I hope this helps someone else.
I have used Word in C# doc2pdf application. Before close doc, set the save option like this:
object saveOption = Microsoft.Office.Interop.Word.WdSaveOptions.wdDoNotSaveChanges;
oDoc.Close(ref saveOption, ref oMissing, ref oMissing);
oWord.Quit(ref saveOption, ref oMissing, ref oMissing);
I have help links in my application and wanted to open a particular word doc to a particular bookmark. If the document is already open, it should not open it again. If Word is already open, it should not open a new instance of Word.
This code worked for me:
object filename = #"C:\Documents and Settings\blah\My Documents\chapters.docx";
object confirmConversions = false;
object readOnly = true;
object visible = true;
object missing = Type.Missing;
Application wordApp;
object word;
try
{
word = System.Runtime.InteropServices.Marshal.GetActiveObject("Word.Application");
}
catch (COMException)
{
Type type = Type.GetTypeFromProgID("Word.Application");
word = System.Activator.CreateInstance(type);
}
wordApp = (Application) word;
wordApp.Visible = true;
Console.WriteLine("There are {0} documents open.", wordApp.Documents.Count);
var wordDoc = wordApp.Documents.Open(ref filename, ref confirmConversions, ref readOnly, ref missing,
ref missing, ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing, ref visible,
ref missing, ref missing, ref missing, ref missing);
wordApp.Activate();
object bookmarkName = "Chapter2";
if (wordDoc.Bookmarks.Exists(bookmarkName.ToString()))
{
var bookmark = wordDoc.Bookmarks.get_Item(bookmarkName);
bookmark.Select();
}
Keep in mind that the code:
Word.Application wordApplication = new Word.Application();
will always spin up a new instance of Word, even if there's already an instance loaded.
Usually, you're better off checking for a loaded instance (via GETOBJECT) and using it if there is one, and only spinning up a new instance if you need to.

Word Document Permission through C#

I am working on a document management program. I want to open up a Word document with the click of a button and according to the permissions to the user whoever logged in will be given certain permissions (like read-only, edittable).
I tried with this code:
object missing = System.Reflection.Missing.Value;
Microsoft.Office.Interop.Word.ApplicationClass doc = new Microsoft.Office.Interop.Word.ApplicationClass();
object name = #"some.doc";
object read = true;
object t = true;
doc.Documents.Open(ref name, ref missing, ref read, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref t, ref missing, ref missing, ref missing, ref missing);
doc.Visible = true;
This code is opening up the document but as I have set the read-only true, it should open the document in readonly mode. When document is opened in Word 2003 it is editable whereas when opened in Word 2010 it is read-only.
Also, I'd like to know if is it worth it to disable all the toolbars of Word and create my own with the buttons which I want. I want to give only the functionality which I want - like I want to disable the SaveAs functionality.
How about something like the following code.
By specifying proc.StartInfo.UseShellExecute = true, Windows will automatically launch the application associated with the Word document, for the current user.
namespace ConsoleApplication1
{
using System.Diagnostics;
using System.Windows.Forms;
class Program
{
static void Main( string[] args )
{
var docName = #"some.doc";
try
{
using ( var proc = new Process() )
{
proc.StartInfo.UseShellExecute = true;
proc.StartInfo.FileName = docName;
proc.Start();
}
}
catch ( System.Exception ex )
{
MessageBox.Show( string.Format( "Unable to display document '{0}': {1}", docName, ex.Message ) );
}
}
}
}

Categories

Resources