2

目前,我正在使用 Excel SDK 2010 开发 Excel 2010 加载项 (.xll)。不幸的是,微软提供的文档很少(或者我可能还没有找到)。我的加载项已加载到 Excel 中,它的菜单出现,并且我能够从菜单中调用一个函数,该函数确实被执行。在其中,我尝试收集所有工作表名称,但每次调用该函数都会产生不同的结果。返回的工作表名称中存在正确的工作表名称,XLOPER但它们被不断变化的“奇怪”字符包围。

有问题的代码:

LPXLOPER12 GetWorkbook(void){
    LPXLOPER12 workbooksheets=new XLOPER12,xworkbookname = new XLOPER12;

    memset(xworkbookname,0,sizeof(XLOPER12));
    memset(workbooksheets,0,sizeof(XLOPER12));

    Excel12f(xlfGetDocument,xworkbookname,1,TempInt12(88));
    Excel12f(xlfGetWorkbook,workbooksheets,2,TempInt12(1),xworkbookname);

    // at this point I expect xworkbookname->val.str to contain the workbook name
    // but instead it has garbage before and after
    return 0;
}
4

3 回答 3

2

您在这里仍然没有提供太多信息,但我会猜测。

由于计算机使用数字,因此必须有一个关于如何表示文本的约定。C 编程语言使用的一个约定是说“文本的第一个字符位于第一个内存位置,并且文本一直持续到您遇到值为 0 的字节/单词”。由于您使用 C 语言编写,我想这就是您所期望的。

但微软最初并没有用 C 语言开发 Excel。他们是用 Pascal 开发的。Pascal 使用的约定是“第一个内存位置包含文本的长度,实际文本从第二个内存位置开始,到达长度指定的内存位置。没有终止 0。”

实际上在 MSDN 站点上有很多可用的文档,例如 http://msdn.microsoft.com/en-us/library/aa730920%28v=office.12%29.aspx

特别是,它们有一个图形(和示例代码),显示了在 Pascal 字符串和 C 字符串之间转换所需的例程。

于 2013-11-12T15:38:23.857 回答
2

正如 AnotherParker 所暗示的那样,xlfGetWorkbook 将工作表名称作为长度前缀字符串返回,因此要在函数中使用它,您需要将其转换为空分隔字符串。

此外,xlfGetWorkbook 在工作表名称前加上 [] 括号中的工作簿名称,因此您需要将其剥离以获取实际的工作表名称。

这是一个完整的 C 语言示例,没有使用任何风格的框架,它在 Activesheet 的第一列中输出工作表名称。

int __stdcall ListSheetsD (void)
{
    static XLOPER12 xWorkbook;
    XLOPER12        xRef, xNumParm, xAutoFit, xFalse, xlCell[10], xlArray;
    int             rc, i, iSheets;
    size_t          fullnamelen, sheetnamelen;
    wchar_t         *fullname, *sheetname;
    XCHAR           *ptr;
    OLECHAR         buffer[100];
    OLECHAR         *function = L"ListSheetsD";

    xNumParm.xltype = xltypeNum;
    xNumParm.val.num = 1;

    rc = Excel12 ( xlfGetWorkbook, (LPXLOPER12)&xWorkbook, 1, (LPXLOPER12)&xNumParm);
    if ( rc != xlretSuccess )
    {
        swprintf ( buffer, 100, L"xlfGetWorkbook. rc=%d", rc ); 
        MessageBox (NULL, buffer, function, MB_OK | MB_SETFOREGROUND );
    }

    //Get Number of Sheets
    iSheets = xWorkbook.val.array.columns;

    for ( i = 0; i < iSheets; i++ ) 
    {
        if ( i < 10 )
        {
            //Pickup Sheet Name (format: [Book.xls]Sheet1) & set it up as a Null Delimited String
            fullnamelen = xWorkbook.val.array.lparray[i].val.str[0];
            fullname = (wchar_t *) malloc ( (fullnamelen + 2) * sizeof (wchar_t) );
            memcpy (fullname, (xWorkbook.val.array.lparray[i].val.str + 1), 
                   (fullnamelen) * sizeof(wchar_t));
            fullname[fullnamelen] = L'\0';     

            //Extract Sheet Name (format: Sheet1) & set it up as a Length Prefixed String
            sheetname = (wchar_t *) malloc ( (fullnamelen + 2) * sizeof (wchar_t) );
            ptr = wcschr (fullname, L']');
            sheetnamelen = wcslen (ptr);
            wcscpy ( sheetname, ptr );
            sheetname[0] = sheetnamelen;

            //Setup Output Row
            xlCell[i].xltype = xltypeStr;
            xlCell[i].val.str = sheetname;

            free (fullname);
        }
    }

    if ( i > 10 ) i = 10;    

    xlArray.xltype = xltypeMulti;
    xlArray.val.array.rows = i;
    xlArray.val.array.columns = 1;
    xlArray.val.array.lparray = &xlCell[0];

    xRef.xltype = xltypeSRef;
    xRef.val.sref.count = 1;
    xRef.val.sref.ref.rwFirst = 0;
    xRef.val.sref.ref.rwLast = i - 1;
    xRef.val.sref.ref.colFirst = 0;
    xRef.val.sref.ref.colLast = 0;  

    rc = Excel12 ( xlSet, 0, 2, (LPXLOPER12)&xRef, (LPXLOPER12)&xlArray );
    if ( rc != xlretSuccess )
    {  
        swprintf ( buffer, 100, L"xlSet. Error=%d", rc );   
        MessageBox (NULL, buffer, function, MB_OK | MB_SETFOREGROUND );
    }

    rc = Excel12 (xlFree, NULL, 2, &xWorkbook, &xlArray );
    if ( rc != xlretSuccess )
    {
        swprintf ( buffer, 100, L"xlFree. rc=%d", rc ); 
        MessageBox (NULL, buffer, function, MB_OK | MB_SETFOREGROUND );
    }

    rc = Excel12 ( xlcSelect, 0, 1, (LPXLOPER12)&xRef );
    if ( rc != xlretSuccess )
    {
        swprintf ( buffer, 100, L"xlcSelect. rc=%d", rc );  
        MessageBox (NULL, buffer, function, MB_OK | MB_SETFOREGROUND );
    }

    xAutoFit.xltype = xltypeNum;
    xAutoFit.val.num = 3;

    xFalse.xltype = xltypeBool;  
    xFalse.val.xbool = 0;   

    rc = Excel12 ( xlcColumnWidth, 0, 4, &xNumParm, (LPXLOPER12)&xRef, &xFalse, &xAutoFit );
    if ( rc != xlretSuccess )
    {
        swprintf ( buffer, 100, L"xlcColumnWidth. rc=%d", rc ); 
        MessageBox (NULL, buffer, function, MB_OK | MB_SETFOREGROUND );
    }
    return 1;
}
于 2014-12-31T09:14:28.790 回答
1

试试http://xll.codeplex.com。它会让你的生活更轻松。

于 2013-07-02T01:57:13.680 回答