В настоящее время я разрабатываю надстройку для Excel 2010 (.xll) с помощью Excel SDK 2010. К сожалению, у Microsoft мало документации (или, может быть, я просто еще не нашел ее). Я дошел до того, что моя надстройка загружается в 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;
}
Вы до сих пор не предоставили много информации здесь, но я собираюсь догадаться.
Поскольку компьютеры работают с числами, должно быть соглашение о том, как представлен текст. Одно соглашение, используемое языком программирования C, гласит: «первый символ текста находится в первой ячейке памяти, и текст продолжается до тех пор, пока вы не нажмете байт / слово со значением 0». Поскольку вы пишете на C, я думаю, это то, что вы ожидаете.
Но Microsoft изначально не разрабатывал Excel на C. Они разрабатывались на Pascal. А соглашение, используемое Паскалем, гласит: «Первая ячейка памяти содержит длину текста, а фактический текст начинается со второй ячейки памяти, и занимает столько ячеек памяти, сколько определено этой длиной. Окончание 0 отсутствует.»
На самом деле на сайте MSDN доступно довольно много документации, например
http://msdn.microsoft.com/en-us/library/aa730920%28v=office.12%29.aspx
В частности, у них есть графическое изображение (и пример кода), показывающее, какие процедуры вам нужно использовать для преобразования между строками Паскаля и строками Си.
Как уже упоминалось в AnotherParker, xlfGetWorkbook возвращает имя листа в виде строки с префиксом длины, поэтому, чтобы использовать его в своей функции, необходимо преобразовать его в строку с нулевым разделителем.
Кроме того, xlfGetWorkbook ставит префикс имени листа перед именем книги в скобках [], поэтому вам нужно удалить его, чтобы получить фактическое имя листа.
Вот полный рабочий пример на C без использования Framework любого вида, который выводит имена листов в первом столбце 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;
}
Пытаться http://xll.codeplex.com. Это сделает вашу жизнь проще.