Home » excel » c# – How can I enable the "Sharing" options on Excel workbooks?

c# – How can I enable the "Sharing" options on Excel workbooks?

Posted by: admin May 14, 2020 Leave a comment

Questions:

Is it possible to enable “Sharing” on excel documents through OpenXML or ClosedXML? Or any other library if it can help… I believe this is usually performed when you save the document (at least that’s how it works in VBA), but I can’t find how to specify saving arguments in C#.

I’d like to avoid using InterOp since I might batch this process on multiple files through a network.

EDIT: According to some old pages from 2009, there are limitations where OpenXML cannot operate protected files. However, would that apply to sharing too?

How to&Answers:

Sharing Excel documents using OpenXML SDK is not well documented.
I did some tests and found that it is possible to enable sharing on Excel documents
using OpenXML SDK. The following steps are necessary to enable sharing:

  1. Add a WorkbookUserDataPart to your Excel document. Add an empty Users collection
    to the part. In this collection Excel stores all users who currently have
    this shared workbook open.

  2. Add a WorkbookRevisionHeaderPart to your Excel document. Add a Headers collection
    to the part. In this collection Excel will store references to history, version and revision
    information. Add a first element (Header) to the collection which contains the
    SheetIdMap (used for tracking revision records). In the code sample below
    I’ve added all worksheets included in the document.
    Furthermore add a WorkbookRevisionLogPart to the workbook’s revision header part.
    In the log part a list of revision made to the document is stored.

The code sample below shows how to enable sharing on an Excel document.
The code also checks whether sharing is already enabled on a document.

Before you enable sharing you should create a backup of your original documents.

using (SpreadsheetDocument sd = SpreadsheetDocument.Open("c:\temp\enable_sharing.xlsx", true))
{
  WorkbookPart workbookPart = sd.WorkbookPart;

  if (workbookPart.GetPartsCountOfType<WorkbookRevisionHeaderPart>() != 0)
  {
    Console.Out.WriteLine("Excel document already shared!");
    return;
  }

  // Create user data part if it does not exist.
  if (workbookPart.GetPartsCountOfType<WorkbookUserDataPart>() == 0)
  {
    Console.Out.WriteLine("Adding user data part");
    WorkbookUserDataPart workbookUserDataPart = workbookPart.AddNewPart<WorkbookUserDataPart>();

    Users users = new Users() { Count = (UInt32Value)0U };
    users.AddNamespaceDeclaration("r", "http://schemas.openxmlformats.org/officeDocument/2006/relationships");

    workbookUserDataPart.Users = users;
  }

  // Create revision header part and revision log part.
  WorkbookRevisionHeaderPart workbookRevisonHeaderPart = workbookPart.AddNewPart<WorkbookRevisionHeaderPart>();

  WorkbookRevisionLogPart workbookRevisionLogPart = workbookRevisonHeaderPart.AddNewPart<WorkbookRevisionLogPart>();

  // Create empty collection of revisions.
  Revisions revisions = new Revisions();
  revisions.AddNamespaceDeclaration("r", "http://schemas.openxmlformats.org/officeDocument/2006/relationships");

  workbookRevisionLogPart.Revisions = revisions;

  string lastSetOfRevisionsGuid = Guid.NewGuid().ToString("B");

  // Create headers collection (references to history, revisions)
  Headers headers = new Headers() { Guid = lastSetOfRevisionsGuid };
  headers.AddNamespaceDeclaration("r", "http://schemas.openxmlformats.org/officeDocument/2006/relationships");

  int worksheetPartsCount = workbookPart.GetPartsCountOfType<WorksheetPart>();                        

  // Create first element in headers collection
  // which contains the SheetIdMap.
  Header header = new Header() { Guid = lastSetOfRevisionsGuid, DateTime = DateTime.Now, 
                                 MaxSheetId = (UInt32Value)(uint)worksheetPartsCount+1, UserName = "hans", Id = "rId1" };

  // Create the list of sheet IDs that are used for tracking
  // revision records. For every worksheet in the document
  // create one SheetId.
  SheetIdMap sheetIdMap = new SheetIdMap() { Count = (UInt32Value)(uint)worksheetPartsCount };

  for (uint i = 1; i <= worksheetPartsCount; i++)
  {
    SheetId sheetId = new SheetId() { Val = (UInt32Value)i };

    sheetIdMap.Append(sheetId);
  }        

  header.Append(sheetIdMap);
  headers.Append(header);

  workbookRevisonHeaderPart.Headers = headers;
}