Open in memory XML string as an Excel workbook without saving using windows Forms C#
Asked Answered
F

2

2

I have an excel string (which I built) in memory; the code looks something like this:

public static void exportToExcel()
        {
            const string startExcelXML = "<xml version>\r\n<Workbook " +
                  "xmlns=\"urn:schemas-microsoft-com:office:spreadsheet\"\r\n"
+
                  " xmlns:o=\"urn:schemas-microsoft-com:office:office\"\r\n " +
                  "xmlns:x=\"urn:schemas-    microsoft-com:office:" +
                  "excel\"\r\n xmlns:ss=\"urn:schemas-microsoft-com:"
+
                  "office:spreadsheet\">\r\n <Styles>\r\n " +
                  "<Style ss:ID=\"Default\" ss:Name=\"Normal\">\r\n " +
                  "<Alignment ss:Vertical=\"Bottom\"/>\r\n <Borders/>" +
                  "\r\n <Font/>\r\n <Interior/>\r\n <NumberFormat/>" +
                  "\r\n <Protection/>\r\n </Style>\r\n " +
                  "<Style ss:ID=\"BoldColumn\">\r\n <Font " +
                  "x:Family=\"Swiss\" ss:Bold=\"1\"/>\r\n </Style>\r\n " +
                  "<Style     ss:ID=\"StringLiteral\">\r\n <NumberFormat" +
                  " ss:Format=\"@\"/>\r\n </Style>\r\n <Style " +
                  "ss:ID=\"Decimal\">\r\n <NumberFormat/>\r\n </Style>\r\n " +
                  "<Style ss:ID=\"Integer\">\r\n <NumberFormat "
+
                  "ss:Format=\"0\"/>\r\n </Style>\r\n <Style " +
                  "ss:ID=\"DateLiteral\">\r\n <NumberFormat " +
                  "ss:Format=\"dd/mm/yyyy;@\"/>\r\n </Style>\r\n " +
                  "</Styles>\r\n ";
            const string endExcelXML = "</Workbook>";

            int sheetCount = 1;
            StringBuilder sb = new StringBuilder();

            sb.Append(startExcelXML);
            sb.Append("<Worksheet ss:Name=\"Sheet" + sheetCount + "\">");
            sb.Append("<Table>");
            sb.Append("<Row>");
            sb.Append("<Cell ss:StyleID=\"BoldColumn\"><Data ss:Type=\"String\">");
            sb.Append("Home country");
            sb.Append("</Data></Cell>");
            sb.Append("<Cell ss:StyleID=\"BoldColumn\"><Data ss:Type=\"String\">");
            sb.Append("Expatriation Type");
            sb.Append("</Data></Cell>");
            sb.Append("</Row>");
            sb.Append("<Row>");
     sb.Append("<Cell ss:StyleID=\"StringLiteral\">" +
      "<Data ss:Type=\"String\">");
     sb.Append("Singapore");
     sb.Append("</Data></Cell>");
     sb.Append("<Cell ss:StyleID=\"StringLiteral\">" +
      "<Data ss:Type=\"String\">");
     sb.Append("Benchmark");
     sb.Append("</Data></Cell>");
            sb.Append("</Row>");
            sb.Append("</Table>");
            sb.Append(" </Worksheet>");
            sb.Append(endExcelXML);
        }

I able to open the file as excel sheet only if I save the file physically; but is there any other way to just open the xml string from the memory as excel sheet?

Flanch answered 27/1, 2010 at 5:20 Comment(3)
How are you opening it from the file system?Abdomen
As of now we save to the physical disk and open the file using excel object. We want to avoid saving as a file to user's physical disk.Flanch
As a VB user, I can't understand how come C# is so backwords as far as it concerns XML literals.Bove
Z
1

I think what you'll need is a memory mapped file implementation of some kind.

I believe, though, that .NET 4.0 will have built-in MemoryMappedFile support.

You may be able to find other .net implementations using a search engine.

Zurheide answered 27/1, 2010 at 5:31 Comment(3)
I searched for MemoryMappedFile and got a few implementation in .net. One such impelementaion is filemap-2.0.2.zip.I am still checking on it, but on first look it looks like it is a bit complex. Is it really so complex to just open a stream using an application?Flanch
Yes, it is pretty complex. Honestly, I don't think it is worth the effort -- it doesn't take very long to write that string out to the file system.Zurheide
Yes; that's what I thought. We are not implementing this. Now we have changed our requirement and ask the user for the location to save the file and then save it to that location.Flanch
S
0

i don't know for sure, but most Microsoft automation objects support IPersist or IPersistStream, which may let you load from a stream in memory.

Something like (pseudo-code):

xl = new Office.ExcelApplication;
(xl as IPersistStream).Load(myMemoryStream);

You can use the shell helper function CreateStreamOnHGlobal to create an IStream wrapper around some memory:

functionCreateStreamOnMemory(pData: Pointer; nCount: DWORD): IStream;
var
    hMem: HGLOBAL;
    dwError: DWORD;
    p: Pointer;
begin
    hMem := GlobalAlloc(GMEM_MOVEABLE or GMEM_NODISCARD, nCount); 
       //CreateStreamOnHGlobal says "The handle must be 
       //allocated as movable and nondiscardable."
    if hMem = 0 then
        RaiseLastWin32Error;

    p := GlobalLock(hMem);
    if p = nil then
    begin
        dwError := GetLastError;
        GlobalFree(hMem);
        raise EWin32Error.Create('Could not lock global memory object: '+SysErrorMessage(dwError));
    end;
    try
        CopyMemory(p, pData, nCount);
    finally
        GlobalUnlock(hMem);
    end;

    OleCheck(CreateStreamOnHGlobal(hMem, True, Result)); //Because we pass True, the stream will take care of freeing the HGLOBAL when the stream is released
end;

Stuff your string in the memory and see if it loads.

Staffordshire answered 28/1, 2010 at 21:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.