public static void SignPDF( string filePath, string username, string domain, string password, int sigPageNum, int sigX, int sigY, int sigWidth, int sigHeight, string title) { const int SAPI_OK = 0; const int AR_PDF_FLAG_FILESIGN_VERTICAL = 0x00000020; int rc; SAPICrypt SAPI = new SAPICryptClass(); SESHandle sesHandle = null; GraphicImageHandle grpImgHandle = null; try { // Initialize SAPI library if ((rc = SAPI.Init()) != SAPI_OK) { throw new Exception(string.Format("Failed to initialize SAPI ({0})", rc.ToString("X"))); } // Acquire SAPI session handle if ((rc = SAPI.HandleAcquire(out sesHandle)) != SAPI_OK) { throw new Exception(string.Format("Failed in SAPIHandleAcquire() ({0})", rc.ToString("X"))); } // Personalize SAPI Session if ((rc = SAPI.Logon(sesHandle, username, domain, password)) != SAPI_OK) { throw new Exception(string.Format("Failed to authenticate user ({0})", rc.ToString("X"))); } // If the user has more than one graphical signatures, this function opens a new dialog window enabling the user to view and select an image with which to sign. if ((rc = SAPI.GraphicSigImageGUISelect(sesHandle, (int)0xFF, 0, SAPI_ENUM_GR_IMG_SELECT_MODE.SAPI_ENUM_GR_IMG_SEL_MODE_SELECT, out grpImgHandle)) != SAPI_OK) { throw new Exception(string.Format("Failed in SAPIGraphicSigImageGUISelect() ({0})", rc.ToString("X"))); } // Set the graphical image associated with the graphic image handle as the default graphic signature image if ((rc = SAPI.GraphicSigImageSetDefaultEx(sesHandle, grpImgHandle, 0)) != SAPI_OK) { throw new Exception(string.Format("Failed in SAPIGraphicSigImageSetDefaultEx() ({0})", rc.ToString("X"))); } SigFieldSettingsClass SFS = new SigFieldSettingsClass(); TimeFormatClass TF = new TimeFormatClass(); // Define signature field settings SFS.Page = sigPageNum; SFS.X = sigX; SFS.Y = sigY; SFS.Width = sigWidth; SFS.Height = sigHeight; SFS.AppearanceMask = (int)SAPI_ENUM_DRAWING_ELEMENT.SAPI_ENUM_DRAWING_ELEMENT_GRAPHICAL_IMAGE | (int)SAPI_ENUM_DRAWING_ELEMENT.SAPI_ENUM_DRAWING_ELEMENT_SIGNED_BY | (int)SAPI_ENUM_DRAWING_ELEMENT.SAPI_ENUM_DRAWING_ELEMENT_TIME; SFS.SignatureType = SAPI_ENUM_SIGNATURE_TYPE.SAPI_ENUM_SIGNATURE_DIGITAL; SFS.DependencyMode = SAPI_ENUM_DEPENDENCY_MODE.SAPI_ENUM_DEPENDENCY_MODE_INDEPENDENT; TF.DateFormat = "dd/MM/yyyy"; TF.TimeFormat = "hh:mm:ss"; TF.ExtTimeFormat = SAPI_ENUM_EXTENDED_TIME_FORMAT.SAPI_ENUM_EXTENDED_TIME_FORMAT_GMT; // Display GMT offset SFS.TimeFormat = TF; if (!string.IsNullOrEmpty(title)) { // Set signer's title if ((rc = SAPI.ConfigurationValueSet(sesHandle, SAPI_ENUM_CONF_ID.SAPI_ENUM_CONF_ID_TITLE, SAPI_ENUM_DATA_TYPE.SAPI_ENUM_DATA_TYPE_WSTR, title, 1)) != SAPI_OK) { throw new Exception(string.Format("Failed in SAPIConfigurationValueSet() ({0})", rc.ToString("X"))); } SFS.AppearanceMask |= (int)SAPI_ENUM_DRAWING_ELEMENT.SAPI_ENUM_DRAWING_ELEMENT_TITLE; } // Create and sign a new signature field in the document if (SAPI_OK != (rc = SAPI.SignatureFieldCreateSign(sesHandle, SAPI_ENUM_FILE_TYPE.SAPI_ENUM_FILE_ADOBE, filePath, SFS, AR_PDF_FLAG_FILESIGN_VERTICAL, null))) { throw new Exception(string.Format("Failed in SAPISignatureFieldCreateSign() ({0})", rc.ToString("X"))); } } catch (Exception ex) { if (sesHandle != null) { SAPI.Logoff(sesHandle); // Release user context SAPI.HandleRelease(sesHandle); // Release session handle } if (grpImgHandle != null) { SAPI.HandleRelease(grpImgHandle); } throw ex; } }
// This function is thread-safe and could be called by a few threads simoltaneously. // If FieldName parameter is NULL, a new field will be created, otherwise existing field will be signed // and all field-related parameters will be ignored public static void SAPI_sign_file(string FileName, string FieldName, string User, string Password, string SignPassword, int page, int x, int y, int height, int width, bool Invisible, string Reason, int AppearanceMask, string NewFieldName, string GraphImgName) { int rc; SESHandle SesHandle; SigFieldHandle sf = null; SAPICrypt SAPI = new SAPICryptClass(); if ((rc = SAPI.HandleAcquire(out SesHandle)) != 0) { throw new Exception("Failed in SAPIHandleAcquire() with rc = " + rc.ToString("X")); } //Logon if ((rc = SAPI.Logon(SesHandle, User, null, Password)) != 0) { SAPI.HandleRelease(SesHandle); throw new Exception("Failed to authenticate user with rc = " + rc.ToString("X")); } //Set Graphical Image if required if (GraphImgName != null && GraphImgName.Length > 1) { SAPIContext ctxGraphImg = new SAPIContextClass(); //Start Graphical Images Enumeration if ((rc = SAPI.GraphicSigImageEnumInit(SesHandle, ctxGraphImg, AR_GR_SIG_DATA_FORMAT_ALL, 0)) != 0) { SAPI.Logoff(SesHandle); SAPI.HandleRelease(SesHandle); throw new Exception("Failed to enumerate graphical signatures with rc = " + rc.ToString()); } GraphicImageHandle hGrImg = null; bool isFound = false; while (((uint)(rc = SAPI.GraphicSigImageEnumCont(SesHandle, ctxGraphImg, out hGrImg))) != SAPI_ERROR_NO_MORE_ITEMS) { if (rc != 0) { SAPI.ContextRelease(ctxGraphImg); SAPI.Logoff(SesHandle); SAPI.HandleRelease(SesHandle); throw new Exception("Failed to retrieve next graphical signature with rc = " + rc.ToString()); } //Get Graphical Signature Info GraphicImageInfo giInfo = null; if ((rc = SAPI.GraphicSigImageInfoGet(SesHandle, hGrImg, out giInfo, SAPI_ENUM_GRAPHIC_IMAGE_FORMAT.SAPI_ENUM_GRAPHIC_IMAGE_NONE, 0)) != 0) { SAPI.ContextRelease(ctxGraphImg); SAPI.HandleRelease(hGrImg); SAPI.Logoff(SesHandle); SAPI.HandleRelease(SesHandle); throw new Exception("Failed to retrieve graphical signature info with rc = " + rc.ToString()); } //Check if required Graphical image has been found if (giInfo.Name.Trim().ToLower() == GraphImgName.Trim().ToLower()) { //If found - set is as default Graph. Image if ((rc = SAPI.GraphicSigImageSetDefault(SesHandle, hGrImg)) != 0) { SAPI.ContextRelease(ctxGraphImg); SAPI.HandleRelease(hGrImg); SAPI.Logoff(SesHandle); SAPI.HandleRelease(SesHandle); throw new Exception("Failed to define default graphical signature with rc = " + rc.ToString()); } isFound = true; SAPI.ContextRelease(ctxGraphImg); SAPI.HandleRelease(hGrImg); break; } SAPI.HandleRelease(hGrImg); } SAPI.ContextRelease(ctxGraphImg); //If required Graph Image wasn't found... if (!isFound) { SAPI.Logoff(SesHandle); SAPI.HandleRelease(SesHandle); throw new Exception("Failed to find Graphical Image with name: " + GraphImgName); } } //Create new signature field if (FieldName == null) { SigFieldSettingsClass SFS = new SigFieldSettingsClass(); TimeFormatClass TF = new TimeFormatClass(); int Flags = 0; //Define name of the new signature field if (NewFieldName.Length > 0) { SFS.Name = NewFieldName; Flags |= AR_PDF_FLAG_FIELD_NAME_SET; } if (Invisible) { SFS.Invisible = 1; SFS.Page = -1; } else { // VISIBLE: SFS.Invisible = 0; // location: SFS.Page = page; SFS.X = x; SFS.Y = y; SFS.Height = height; SFS.Width = width; // appearance: SFS.AppearanceMask = AppearanceMask; SFS.LabelsMask = AppearanceMask; SFS.DependencyMode = SAPI_ENUM_DEPENDENCY_MODE.SAPI_ENUM_DEPENDENCY_MODE_INDEPENDENT; SFS.SignatureType = SAPI_ENUM_SIGNATURE_TYPE.SAPI_ENUM_SIGNATURE_DIGITAL; SFS.Flags = 0; // time: TF.DateFormat = "dd MMM yyyy"; TF.TimeFormat = "hh:mm:ss"; TF.ExtTimeFormat = SAPI_ENUM_EXTENDED_TIME_FORMAT.SAPI_ENUM_EXTENDED_TIME_FORMAT_NONE; SFS.TimeFormat = TF; } //Create the Field if ((rc = SAPI.SignatureFieldCreate(SesHandle, SAPI_ENUM_FILE_TYPE.SAPI_ENUM_FILE_ADOBE, FileName, SFS, Flags, out sf)) != 0) { SAPI.Logoff(SesHandle); SAPI.HandleRelease(SesHandle); throw new Exception("Failed to create new signature field with rc = " + rc.ToString("X")); } } //Find an existing signature field by name else { SAPIContext ctxField = new SAPIContextClass(); int NumOfFields = 0; //Initiate the Signature Fields enumeration process if ((rc = SAPI.SignatureFieldEnumInit(SesHandle, ctxField, SAPI_ENUM_FILE_TYPE.SAPI_ENUM_FILE_ADOBE, FileName, 0, ref NumOfFields)) != 0) { SAPI.Logoff(SesHandle); SAPI.HandleRelease(SesHandle); throw new Exception("Failed to start signature field enumeration with rc = " + rc.ToString("X")); } bool isFound = false; for (int i = 0; i < NumOfFields; i++) { //Get Next field's handle if ((rc = SAPI.SignatureFieldEnumCont(SesHandle, ctxField, out sf)) != 0) { SAPI.ContextRelease(ctxField); SAPI.Logoff(SesHandle); SAPI.HandleRelease(SesHandle); throw new Exception("Failed in signature fields enumeration with rc = " + rc.ToString("X")); } //Retrieve Signature Field's info SigFieldSettings sfs = new SigFieldSettingsClass(); SigFieldInfo sfi = new SigFieldInfoClass(); if ((rc = SAPI.SignatureFieldInfoGet(SesHandle, sf, sfs, sfi)) != 0) { SAPI.HandleRelease(sf); SAPI.ContextRelease(ctxField); SAPI.Logoff(SesHandle); SAPI.HandleRelease(SesHandle); throw new Exception("Failed to retrieve signature field details with rc = " + rc.ToString("X")); } //Check that the field we've found is not signed. If Signed - just skip it. if (sfi.IsSigned != 0) { continue; } if (sfs.Name == FieldName) { SAPI.ContextRelease(ctxField); isFound = true; break; } //Release handle of irrelevant signature field SAPI.HandleRelease(sf); } if (!isFound) { SAPI.ContextRelease(ctxField); SAPI.Logoff(SesHandle); SAPI.HandleRelease(SesHandle); throw new Exception("The file doesn't contain any signature field named: " + FieldName); } } //Define the Reason if ((rc = SAPI.ConfigurationValueSet(SesHandle, SAPI_ENUM_CONF_ID.SAPI_ENUM_CONF_ID_REASON, SAPI_ENUM_DATA_TYPE.SAPI_ENUM_DATA_TYPE_STR, Reason, 1)) != 0) { SAPI.HandleRelease(sf); SAPI.Logoff(SesHandle); SAPI.HandleRelease(SesHandle); throw new Exception("Failed in SAPIConfigurationValueSet with rc = " + rc.ToString("X")); } if (string.IsNullOrEmpty(SignPassword)) { //Prompt-for-sign mode is disabled rc = SAPI.SignatureFieldSign(SesHandle, sf, 0); } else { //Prompt-for-sign mode is enabled rc = SAPI.SignatureFieldSignEx(SesHandle, sf, 0, SignPassword); } if (rc != 0) { SAPI.Logoff(SesHandle); SAPI.HandleRelease(sf); SAPI.HandleRelease(SesHandle); throw new Exception("Failed to Sign signature field with rc = " + rc.ToString("X")); } SAPI.Logoff(SesHandle); SAPI.HandleRelease(sf); SAPI.HandleRelease(SesHandle); return; }
static void Main(string[] args) { const int SAPI_OK = 0; int rc; SAPICrypt SAPI = new SAPICryptClass(); SESHandle sesHandle = null; // Custom Values string filePath = @"c:\temp\demo.pdf"; // PDF file to sign string username = "******"; // CoSign account username string password = "******"; // CoSign account password string domain = null; // CoSign account domain int sigPageNum = 1; // Create signature on the first page int sigX = 145; // Signature field X location int sigY = 125; // Signature field Y location int sigWidth = 160; // Signature field width int sigHeight = 45; // Signature field height string timeFormat = "hh:mm:ss"; // Time appearance format mask string dateFormat = "dd/MM/yyyy"; // Date appearance format mask int appearanceMask = (int)SAPI_ENUM_DRAWING_ELEMENT.SAPI_ENUM_DRAWING_ELEMENT_GRAPHICAL_IMAGE | // Elements to display on the signature field (int)SAPI_ENUM_DRAWING_ELEMENT.SAPI_ENUM_DRAWING_ELEMENT_SIGNED_BY | (int)SAPI_ENUM_DRAWING_ELEMENT.SAPI_ENUM_DRAWING_ELEMENT_TIME; try { // Initialize SAPI library if ((rc = SAPI.Init()) != SAPI_OK) { throw new Exception(string.Format("Failed to initialize SAPI ({0})", rc.ToString("X"))); } // Acquire SAPI session handle if ((rc = SAPI.HandleAcquire(out sesHandle)) != SAPI_OK) { throw new Exception(string.Format("Failed in SAPIHandleAcquire() ({0})", rc.ToString("X"))); } // Personalize SAPI Session if ((rc = SAPI.Logon(sesHandle, username, domain, password)) != SAPI_OK) { throw new Exception(string.Format("Failed to authenticate user ({0})", rc.ToString("X"))); } SigFieldSettingsClass SFS = new SigFieldSettingsClass(); TimeFormatClass TF = new TimeFormatClass(); // Define signature field settings SFS.Page = sigPageNum; SFS.X = sigX; SFS.Y = sigY; SFS.Width = sigWidth; SFS.Height = sigHeight; SFS.AppearanceMask = appearanceMask; SFS.SignatureType = SAPI_ENUM_SIGNATURE_TYPE.SAPI_ENUM_SIGNATURE_DIGITAL; SFS.DependencyMode = SAPI_ENUM_DEPENDENCY_MODE.SAPI_ENUM_DEPENDENCY_MODE_INDEPENDENT; TF.DateFormat = dateFormat; TF.TimeFormat = timeFormat; TF.ExtTimeFormat = SAPI_ENUM_EXTENDED_TIME_FORMAT.SAPI_ENUM_EXTENDED_TIME_FORMAT_GMT; // Display GMT offset SFS.TimeFormat = TF; // Create and sign a new signature field in the document if (SAPI_OK != (rc = SAPI.SignatureFieldCreateSign( sesHandle, // Session Handle SAPI_ENUM_FILE_TYPE.SAPI_ENUM_FILE_ADOBE, // Type of the file to sign - PDF filePath, // Path to PDF file to sign SFS, // Signature Field details 0, // Flags null))) // Credentials (only if prompt-for-sign feature is enabled) { throw new Exception(string.Format("Failed in SAPISignatureFieldCreateSign() ({0})", rc.ToString("X"))); } Console.WriteLine("The document has been successfully signed!"); } catch (Exception ex) { Console.WriteLine(ex.Message); } finally { if (sesHandle != null) { SAPI.Logoff(sesHandle); // Release user context SAPI.HandleRelease(sesHandle); // Release session handle } } }
static void Main(string[] args) { string InFileName = "C:\\temp\\tag-sample.pdf"; string OutFileName = "C:\\temp\\tag-sample-signed.pdf"; string startDelim = "<<"; string endDelim = ">>"; int rc; SESHandle SesHandle; SigFieldSettingsClass SFS = new SigFieldSettingsClass(); TimeFormatClass TF = new TimeFormatClass(); int Flags = AR_PDF_FLAG_FIELD_NAME_SET; int LocNumber; SAPICrypt SAPI = new SAPICryptClass(); // SAPIInit() should be called once per process if ((rc = SAPI.Init()) != 0) throw new Exception("Failed to initialize SAPI! (" + rc.ToString("X") + ")"); // Open a new SAPI context if ((rc = SAPI.HandleAcquire(out SesHandle)) != 0) throw new Exception("Failed in SAPIHandleAcquire() with rc = " + rc.ToString("X")); if ((rc = SAPI.Logon(SesHandle, "testuser", null, "12345678")) != 0) { SAPI.HandleRelease(SesHandle); throw new Exception("Failed in SAPILogon() with rc = " + rc.ToString("X")); } // // Locate all field tags in the PDF // The PDF filename to be used is defined above. // The format of each field locator in the PDF should be: // << w={width}; h={height}; n={field name}; a={appearance mask} >> // // For example: // << w=120; h=80; n=Signer1; a=15; >> // SAPIContext SigLocatorCtx = new SAPIContext(); Array fileBytes = File.ReadAllBytes(InFileName); SAPIByteArray doc = new SAPIByteArrayClass(); doc.FromArray(ref fileBytes); FileHandle fh; if ((rc = SAPI.CreateFileHandleByMem(out fh, SAPI_ENUM_FILE_TYPE.SAPI_ENUM_FILE_ADOBE, 0, doc)) != 0) { SAPI.HandleRelease(SesHandle); throw new Exception("Failed to create file handle with rc = " + rc.ToString("X")); } // Initiate a new Field Locator enumerator. // The argument LocNumber will contain the number of signature tags found in the PDF document. // if ((rc = SAPI.SignatureFieldLocatorEnumInit(SesHandle, SigLocatorCtx, fh, startDelim, endDelim, 0, out LocNumber)) != 0) { SAPI.HandleRelease(fh); SAPI.HandleRelease(SesHandle); throw new Exception("LocatorEnumInit failed with rc = " + rc.ToString("X")); } // Do for all tags in the document string strEncMsg; for (int i = 0; i < LocNumber; i++) { // Get settings for the next field locator. // (Use strEncMsg string to parse the field locator content if a custom string format has been used) if ((rc = SAPI.SignatureFieldLocatorEnumCont(SesHandle, SigLocatorCtx, SFS, out strEncMsg)) != 0) { SAPI.ContextRelease(SigLocatorCtx); SAPI.HandleRelease(fh); SAPI.HandleRelease(SesHandle); throw new Exception("LocatorEnumCont failed with rc = " + rc.ToString("X")); } // The following values of the SignatureFieldSettings will be automatically set by SAPI: // X/Y Location (including page number) // Width // Height // Field Name // Appearance Mask // SFS.LabelsMask = 0; SFS.DependencyMode = SAPI_ENUM_DEPENDENCY_MODE.SAPI_ENUM_DEPENDENCY_MODE_INDEPENDENT; SFS.SignatureType = SAPI_ENUM_SIGNATURE_TYPE.SAPI_ENUM_SIGNATURE_DIGITAL; SFS.Flags = 0; // time: TF.DateFormat = "dd MMM yyyy"; TF.TimeFormat = "hh:mm:ss"; TF.ExtTimeFormat = SAPI_ENUM_EXTENDED_TIME_FORMAT.SAPI_ENUM_EXTENDED_TIME_FORMAT_NONE; SFS.TimeFormat = TF; // Now create the signature field on the PDF // We make use of SignatureFieldCreateEx function in order to pass the FileHandle for the in-memory // file rather than a UNC file path. if ((rc = SAPI.SignatureFieldCreateSignEx2(SesHandle, SAPI_ENUM_FILE_TYPE.SAPI_ENUM_FILE_ADOBE, "", fh, SFS, Flags, null)) != 0) { SAPI.ContextRelease(SigLocatorCtx); SAPI.HandleRelease(fh); SAPI.HandleRelease(SesHandle); throw new Exception("Failed to create new signature field with rc = " + rc.ToString("X")); } } // Write the PDF to an output file if ((rc = SAPI.GetFileMemData(fh, 0, doc)) != 0) { SAPI.ContextRelease(SigLocatorCtx); SAPI.HandleRelease(fh); SAPI.HandleRelease(SesHandle); throw new Exception("Failed to GetFileMem with rc = " + rc.ToString("X")); } File.WriteAllBytes(OutFileName, (byte[])doc.ToArray()); // Finalize work with SAPI SAPI.ContextRelease(SigLocatorCtx); SAPI.HandleRelease(fh); SAPI.HandleRelease(SesHandle); }
static void Main(string[] args) { string InFileName = "C:\\temp\\tag-sample.pdf"; string OutFileName = "C:\\temp\\tag-sample-signed.pdf"; string startDelim = "<<"; string endDelim = ">>"; int rc; SESHandle SesHandle; SigFieldSettingsClass SFS = new SigFieldSettingsClass(); TimeFormatClass TF = new TimeFormatClass(); int Flags = AR_PDF_FLAG_FIELD_NAME_SET; int LocNumber; SAPICrypt SAPI = new SAPICryptClass(); // SAPIInit() should be called once per process if ((rc = SAPI.Init()) != 0) { throw new Exception("Failed to initialize SAPI! (" + rc.ToString("X") + ")"); } // Open a new SAPI context if ((rc = SAPI.HandleAcquire(out SesHandle)) != 0) { throw new Exception("Failed in SAPIHandleAcquire() with rc = " + rc.ToString("X")); } if ((rc = SAPI.Logon(SesHandle, "testuser", null, "12345678")) != 0) { SAPI.HandleRelease(SesHandle); throw new Exception("Failed in SAPILogon() with rc = " + rc.ToString("X")); } // // Locate all field tags in the PDF // The PDF filename to be used is defined above. // The format of each field locator in the PDF should be: // << w={width}; h={height}; n={field name}; a={appearance mask} >> // // For example: // << w=120; h=80; n=Signer1; a=15; >> // SAPIContext SigLocatorCtx = new SAPIContext(); Array fileBytes = File.ReadAllBytes(InFileName); SAPIByteArray doc = new SAPIByteArrayClass(); doc.FromArray(ref fileBytes); FileHandle fh; if ((rc = SAPI.CreateFileHandleByMem(out fh, SAPI_ENUM_FILE_TYPE.SAPI_ENUM_FILE_ADOBE, 0, doc)) != 0) { SAPI.HandleRelease(SesHandle); throw new Exception("Failed to create file handle with rc = " + rc.ToString("X")); } // Initiate a new Field Locator enumerator. // The argument LocNumber will contain the number of signature tags found in the PDF document. // if ((rc = SAPI.SignatureFieldLocatorEnumInit(SesHandle, SigLocatorCtx, fh, startDelim, endDelim, 0, out LocNumber)) != 0) { SAPI.HandleRelease(fh); SAPI.HandleRelease(SesHandle); throw new Exception("LocatorEnumInit failed with rc = " + rc.ToString("X")); } // Do for all tags in the document string strEncMsg; for (int i = 0; i < LocNumber; i++) { // Get settings for the next field locator. // (Use strEncMsg string to parse the field locator content if a custom string format has been used) if ((rc = SAPI.SignatureFieldLocatorEnumCont(SesHandle, SigLocatorCtx, SFS, out strEncMsg)) != 0) { SAPI.ContextRelease(SigLocatorCtx); SAPI.HandleRelease(fh); SAPI.HandleRelease(SesHandle); throw new Exception("LocatorEnumCont failed with rc = " + rc.ToString("X")); } // The following values of the SignatureFieldSettings will be automatically set by SAPI: // X/Y Location (including page number) // Width // Height // Field Name // Appearance Mask // SFS.LabelsMask = 0; SFS.DependencyMode = SAPI_ENUM_DEPENDENCY_MODE.SAPI_ENUM_DEPENDENCY_MODE_INDEPENDENT; SFS.SignatureType = SAPI_ENUM_SIGNATURE_TYPE.SAPI_ENUM_SIGNATURE_DIGITAL; SFS.Flags = 0; // time: TF.DateFormat = "dd MMM yyyy"; TF.TimeFormat = "hh:mm:ss"; TF.ExtTimeFormat = SAPI_ENUM_EXTENDED_TIME_FORMAT.SAPI_ENUM_EXTENDED_TIME_FORMAT_NONE; SFS.TimeFormat = TF; // Now create the signature field on the PDF // We make use of SignatureFieldCreateEx function in order to pass the FileHandle for the in-memory // file rather than a UNC file path. if ((rc = SAPI.SignatureFieldCreateSignEx2(SesHandle, SAPI_ENUM_FILE_TYPE.SAPI_ENUM_FILE_ADOBE, "", fh, SFS, Flags, null)) != 0) { SAPI.ContextRelease(SigLocatorCtx); SAPI.HandleRelease(fh); SAPI.HandleRelease(SesHandle); throw new Exception("Failed to create new signature field with rc = " + rc.ToString("X")); } } // Write the PDF to an output file if ((rc = SAPI.GetFileMemData(fh, 0, doc)) != 0) { SAPI.ContextRelease(SigLocatorCtx); SAPI.HandleRelease(fh); SAPI.HandleRelease(SesHandle); throw new Exception("Failed to GetFileMem with rc = " + rc.ToString("X")); } File.WriteAllBytes(OutFileName, (byte[])doc.ToArray()); // Finalize work with SAPI SAPI.ContextRelease(SigLocatorCtx); SAPI.HandleRelease(fh); SAPI.HandleRelease(SesHandle); }
// This function is thread-safe and could be called by a few threads simoltaneously. // If FieldName parameter is NULL, a new field will be created, otherwise existing field will be signed // and all field-related parameters will be ignored public static void SAPI_sign_file(string FileName, string FieldName, string User, string Password, string SignPassword, int page, int x, int y, int height, int width, bool Invisible, string Reason, int AppearanceMask, string NewFieldName, string GraphImgName) { int rc; SESHandle SesHandle; SigFieldHandle sf = null; SAPICrypt SAPI = new SAPICryptClass(); if ((rc = SAPI.HandleAcquire(out SesHandle)) != 0) throw new Exception("Failed in SAPIHandleAcquire() with rc = " + rc.ToString("X")); //Logon if ((rc = SAPI.Logon(SesHandle, User, null, Password)) != 0) { SAPI.HandleRelease(SesHandle); throw new Exception("Failed to authenticate user with rc = " + rc.ToString("X")); } //Set Graphical Image if required if (GraphImgName != null && GraphImgName.Length > 1) { SAPIContext ctxGraphImg = new SAPIContextClass(); //Start Graphical Images Enumeration if ((rc = SAPI.GraphicSigImageEnumInit(SesHandle, ctxGraphImg, AR_GR_SIG_DATA_FORMAT_ALL, 0)) != 0) { SAPI.Logoff(SesHandle); SAPI.HandleRelease(SesHandle); throw new Exception("Failed to enumerate graphical signatures with rc = " + rc.ToString()); } GraphicImageHandle hGrImg = null; bool isFound = false; while (((uint)(rc = SAPI.GraphicSigImageEnumCont(SesHandle, ctxGraphImg, out hGrImg))) != SAPI_ERROR_NO_MORE_ITEMS) { if (rc != 0) { SAPI.ContextRelease(ctxGraphImg); SAPI.Logoff(SesHandle); SAPI.HandleRelease(SesHandle); throw new Exception("Failed to retrieve next graphical signature with rc = " + rc.ToString()); } //Get Graphical Signature Info GraphicImageInfo giInfo = null; if ((rc = SAPI.GraphicSigImageInfoGet(SesHandle, hGrImg, out giInfo, SAPI_ENUM_GRAPHIC_IMAGE_FORMAT.SAPI_ENUM_GRAPHIC_IMAGE_NONE, 0)) != 0) { SAPI.ContextRelease(ctxGraphImg); SAPI.HandleRelease(hGrImg); SAPI.Logoff(SesHandle); SAPI.HandleRelease(SesHandle); throw new Exception("Failed to retrieve graphical signature info with rc = " + rc.ToString()); } //Check if required Graphical image has been found if (giInfo.Name.Trim().ToLower() == GraphImgName.Trim().ToLower()) { //If found - set is as default Graph. Image if ((rc = SAPI.GraphicSigImageSetDefault(SesHandle, hGrImg)) != 0) { SAPI.ContextRelease(ctxGraphImg); SAPI.HandleRelease(hGrImg); SAPI.Logoff(SesHandle); SAPI.HandleRelease(SesHandle); throw new Exception("Failed to define default graphical signature with rc = " + rc.ToString()); } isFound = true; SAPI.ContextRelease(ctxGraphImg); SAPI.HandleRelease(hGrImg); break; } SAPI.HandleRelease(hGrImg); } SAPI.ContextRelease(ctxGraphImg); //If required Graph Image wasn't found... if (!isFound) { SAPI.Logoff(SesHandle); SAPI.HandleRelease(SesHandle); throw new Exception("Failed to find Graphical Image with name: " + GraphImgName); } } //Create new signature field if (FieldName == null) { SigFieldSettingsClass SFS = new SigFieldSettingsClass(); TimeFormatClass TF = new TimeFormatClass(); int Flags = 0; //Define name of the new signature field if (NewFieldName.Length > 0) { SFS.Name = NewFieldName; Flags |= AR_PDF_FLAG_FIELD_NAME_SET; } if (Invisible) { SFS.Invisible = 1; SFS.Page = -1; } else { // VISIBLE: SFS.Invisible = 0; // location: SFS.Page = page; SFS.X = x; SFS.Y = y; SFS.Height = height; SFS.Width = width; // appearance: SFS.AppearanceMask = AppearanceMask; SFS.LabelsMask = AppearanceMask; SFS.DependencyMode = SAPI_ENUM_DEPENDENCY_MODE.SAPI_ENUM_DEPENDENCY_MODE_INDEPENDENT; SFS.SignatureType = SAPI_ENUM_SIGNATURE_TYPE.SAPI_ENUM_SIGNATURE_DIGITAL; SFS.Flags = 0; // time: TF.DateFormat = "dd MMM yyyy"; TF.TimeFormat = "hh:mm:ss"; TF.ExtTimeFormat = SAPI_ENUM_EXTENDED_TIME_FORMAT.SAPI_ENUM_EXTENDED_TIME_FORMAT_NONE; SFS.TimeFormat = TF; } //Create the Field if ((rc = SAPI.SignatureFieldCreate(SesHandle, SAPI_ENUM_FILE_TYPE.SAPI_ENUM_FILE_ADOBE, FileName, SFS, Flags, out sf)) != 0) { SAPI.Logoff(SesHandle); SAPI.HandleRelease(SesHandle); throw new Exception("Failed to create new signature field with rc = " + rc.ToString("X")); } } //Find an existing signature field by name else { SAPIContext ctxField = new SAPIContextClass(); int NumOfFields = 0; //Initiate the Signature Fields enumeration process if ((rc = SAPI.SignatureFieldEnumInit(SesHandle, ctxField, SAPI_ENUM_FILE_TYPE.SAPI_ENUM_FILE_ADOBE, FileName, 0, ref NumOfFields)) != 0) { SAPI.Logoff(SesHandle); SAPI.HandleRelease(SesHandle); throw new Exception("Failed to start signature field enumeration with rc = " + rc.ToString("X")); } bool isFound = false; for (int i = 0; i < NumOfFields; i++) { //Get Next field's handle if ((rc = SAPI.SignatureFieldEnumCont(SesHandle, ctxField, out sf)) != 0) { SAPI.ContextRelease(ctxField); SAPI.Logoff(SesHandle); SAPI.HandleRelease(SesHandle); throw new Exception("Failed in signature fields enumeration with rc = " + rc.ToString("X")); } //Retrieve Signature Field's info SigFieldSettings sfs = new SigFieldSettingsClass(); SigFieldInfo sfi = new SigFieldInfoClass(); if ((rc = SAPI.SignatureFieldInfoGet(SesHandle, sf, sfs, sfi)) != 0) { SAPI.HandleRelease(sf); SAPI.ContextRelease(ctxField); SAPI.Logoff(SesHandle); SAPI.HandleRelease(SesHandle); throw new Exception("Failed to retrieve signature field details with rc = " + rc.ToString("X")); } //Check that the field we've found is not signed. If Signed - just skip it. if (sfi.IsSigned != 0) continue; if (sfs.Name == FieldName) { SAPI.ContextRelease(ctxField); isFound = true; break; } //Release handle of irrelevant signature field SAPI.HandleRelease(sf); } if (!isFound) { SAPI.ContextRelease(ctxField); SAPI.Logoff(SesHandle); SAPI.HandleRelease(SesHandle); throw new Exception("The file doesn't contain any signature field named: " + FieldName); } } //Define the Reason if ((rc = SAPI.ConfigurationValueSet(SesHandle, SAPI_ENUM_CONF_ID.SAPI_ENUM_CONF_ID_REASON, SAPI_ENUM_DATA_TYPE.SAPI_ENUM_DATA_TYPE_STR, Reason, 1)) != 0) { SAPI.HandleRelease(sf); SAPI.Logoff(SesHandle); SAPI.HandleRelease(SesHandle); throw new Exception("Failed in SAPIConfigurationValueSet with rc = " + rc.ToString("X")); } if (string.IsNullOrEmpty(SignPassword)) { //Prompt-for-sign mode is disabled rc = SAPI.SignatureFieldSign(SesHandle, sf, 0); } else { //Prompt-for-sign mode is enabled rc = SAPI.SignatureFieldSignEx(SesHandle, sf, 0, SignPassword); } if (rc != 0) { SAPI.Logoff(SesHandle); SAPI.HandleRelease(sf); SAPI.HandleRelease(SesHandle); throw new Exception("Failed to Sign signature field with rc = " + rc.ToString("X")); } SAPI.Logoff(SesHandle); SAPI.HandleRelease(sf); SAPI.HandleRelease(SesHandle); return; }