Reply
 
LinkBack Thread Tools Search this Thread Display Modes
  #1   Report Post  
Posted to microsoft.public.excel.programming
external usenet poster
 
Posts: 3
Default Retrieve Excel Cell Range into SAFEARRAY (VC++)

Hi all,

I am very new to Excel Programming and COM/Automation so please forgive
any amateur or foolish questions.

I am trying to extract the values of a range cells from a workbook. I
have successfully opened the workbook and can iterate the worksheets. I
have been able to extract the value of a single cell but to iterate
through all the cells in a workbook is not an option as this is quite
resource intensive. So, I assume there is a way I can load a range of
cells into a SAFEARRAY. The SAFEARRAY being held in a VARIANT.

This is the code that I have (error checking is only displayed where it
failed but I am checking all return values):

#import "C:\Program Files\Microsoft Office\Office\MSO9.DLL"
#import "C:\Program Files\Common Files\Microsoft
Shared\VBA\VBA6\VBE6EXT.OLB"
#import "C:\\Program Files\\Microsoft Office\\Office\\excel9.olb"
rename("DialogBox","DialogBoxXl") rename("RGB","RGBXl") exclude
("IFont","IPicture")

using namespace Excel;

CoInitialize(NULL);
_ApplicationPtr pXl;

hr = pXl.CreateInstance(L"Excel.Application");
WorkbooksPtr pBooks = pXl-Workbooks;

// Open spreadsheet.
pBooks-Open("C:\\Temp\\MySpreadsheet.xls");
WorksheetsPtr pSheets = pXl-GetSheets();

// Get first sheet.
VARIANT vt;
::VariantInit(&vt);
vt.vt = VT_I2;
vt.iVal = (short)1;
_WorksheetPtr thisSheet = pSheets-GetItem(vt);

WCHAR tl[3] = { L'B', L'1', L'\0' };
WCHAR br[3] = { L'B', L'9', L'\0' };
VARIANT cellTL(::SysAllocString(tl));
VARIANT cellBR(::SysAllocString(br));
RangePtr range = a_sheet-GetRange(cellTL, cellBR);

// The VARIANT is an array of VARIANTs
VARIANT tcvt = range-GetValue();
if (tcvt.vt == (VT_ARRAY | VT_VARIANT))
{
// I know what the min and max col values are but was just
// getting used to the APIs.
SAFEARRAY * sa = tcvt.parray;
long colMax;
hr = ::SafeArrayGetUBound(sa, 1, &colMax);
long colMin;
hr = ::SafeArrayGetLBound(sa, 1, &colMin);

long index[2];
index[0] = 1;
for (long colIdx = colMin; colIdx <= colMax; colIdx++)
{
index[1] = colIdx;
VARIANT thisCell;
::VariantInit(&thisCell);
hr = SafeArrayGetElement(sa, index, &thisCell);
if (FAILED(hr))
{
...
}
}
}

The call to SafeArrayGetElement fails with error code E_INVALIDARG. The
calls to SafeArrayGetUBound are both successful and return what I
expect.
If anyone can offer any insight into why the SafeArrayGetElement fails
it would be greatly appreciated.

Many thanks,
Martin.

  #2   Report Post  
Posted to microsoft.public.excel.programming
external usenet poster
 
Posts: 27,285
Default Retrieve Excel Cell Range into SAFEARRAY (VC++)

In VBA it would be

dim v as Variant
v = Workbooks("Sheet1").Range("A1:F30").Value

then v would be an a 2D

v(1 to 30, 1 to 6) array.

--
Regards,
Tom Ogilvy

"Henry" wrote in message
ups.com...
Hi all,

I am very new to Excel Programming and COM/Automation so please forgive
any amateur or foolish questions.

I am trying to extract the values of a range cells from a workbook. I
have successfully opened the workbook and can iterate the worksheets. I
have been able to extract the value of a single cell but to iterate
through all the cells in a workbook is not an option as this is quite
resource intensive. So, I assume there is a way I can load a range of
cells into a SAFEARRAY. The SAFEARRAY being held in a VARIANT.

This is the code that I have (error checking is only displayed where it
failed but I am checking all return values):

#import "C:\Program Files\Microsoft Office\Office\MSO9.DLL"
#import "C:\Program Files\Common Files\Microsoft
Shared\VBA\VBA6\VBE6EXT.OLB"
#import "C:\\Program Files\\Microsoft Office\\Office\\excel9.olb"
rename("DialogBox","DialogBoxXl") rename("RGB","RGBXl") exclude
("IFont","IPicture")

using namespace Excel;

CoInitialize(NULL);
_ApplicationPtr pXl;

hr = pXl.CreateInstance(L"Excel.Application");
WorkbooksPtr pBooks = pXl-Workbooks;

// Open spreadsheet.
pBooks-Open("C:\\Temp\\MySpreadsheet.xls");
WorksheetsPtr pSheets = pXl-GetSheets();

// Get first sheet.
VARIANT vt;
::VariantInit(&vt);
vt.vt = VT_I2;
vt.iVal = (short)1;
_WorksheetPtr thisSheet = pSheets-GetItem(vt);

WCHAR tl[3] = { L'B', L'1', L'\0' };
WCHAR br[3] = { L'B', L'9', L'\0' };
VARIANT cellTL(::SysAllocString(tl));
VARIANT cellBR(::SysAllocString(br));
RangePtr range = a_sheet-GetRange(cellTL, cellBR);

// The VARIANT is an array of VARIANTs
VARIANT tcvt = range-GetValue();
if (tcvt.vt == (VT_ARRAY | VT_VARIANT))
{
// I know what the min and max col values are but was just
// getting used to the APIs.
SAFEARRAY * sa = tcvt.parray;
long colMax;
hr = ::SafeArrayGetUBound(sa, 1, &colMax);
long colMin;
hr = ::SafeArrayGetLBound(sa, 1, &colMin);

long index[2];
index[0] = 1;
for (long colIdx = colMin; colIdx <= colMax; colIdx++)
{
index[1] = colIdx;
VARIANT thisCell;
::VariantInit(&thisCell);
hr = SafeArrayGetElement(sa, index, &thisCell);
if (FAILED(hr))
{
...
}
}
}

The call to SafeArrayGetElement fails with error code E_INVALIDARG. The
calls to SafeArrayGetUBound are both successful and return what I
expect.
If anyone can offer any insight into why the SafeArrayGetElement fails
it would be greatly appreciated.

Many thanks,
Martin.



  #3   Report Post  
Posted to microsoft.public.excel.programming
external usenet poster
 
Posts: 21
Default Retrieve Excel Cell Range into SAFEARRAY (VC++)

You could try using the SafeArrayAccessData and SafeArrayUnaccessData
functions. That way you can get the whole thing at once and its faster.

Also, is the lower bound of the safearray zero or one? It may be zero


Henry wrote:
#import "C:\Program Files\Microsoft Office\Office\MSO9.DLL"
#import "C:\Program Files\Common Files\Microsoft
Shared\VBA\VBA6\VBE6EXT.OLB"
#import "C:\\Program Files\\Microsoft Office\\Office\\excel9.olb"
rename("DialogBox","DialogBoxXl") rename("RGB","RGBXl") exclude
("IFont","IPicture")

using namespace Excel;

CoInitialize(NULL);
_ApplicationPtr pXl;

hr = pXl.CreateInstance(L"Excel.Application");
WorkbooksPtr pBooks = pXl-Workbooks;

// Open spreadsheet.
pBooks-Open("C:\\Temp\\MySpreadsheet.xls");
WorksheetsPtr pSheets = pXl-GetSheets();

// Get first sheet.
VARIANT vt;
::VariantInit(&vt);
vt.vt = VT_I2;
vt.iVal = (short)1;
_WorksheetPtr thisSheet = pSheets-GetItem(vt);

WCHAR tl[3] = { L'B', L'1', L'\0' };
WCHAR br[3] = { L'B', L'9', L'\0' };
VARIANT cellTL(::SysAllocString(tl));
VARIANT cellBR(::SysAllocString(br));
RangePtr range = a_sheet-GetRange(cellTL, cellBR);

// The VARIANT is an array of VARIANTs
VARIANT tcvt = range-GetValue();
if (tcvt.vt == (VT_ARRAY | VT_VARIANT))
{
// I know what the min and max col values are but was just
// getting used to the APIs.
SAFEARRAY * sa = tcvt.parray;
long colMax;
hr = ::SafeArrayGetUBound(sa, 1, &colMax);
long colMin;
hr = ::SafeArrayGetLBound(sa, 1, &colMin);

long index[2];
index[0] = 1;
for (long colIdx = colMin; colIdx <= colMax; colIdx++)
{
index[1] = colIdx;
VARIANT thisCell;
::VariantInit(&thisCell);
hr = SafeArrayGetElement(sa, index, &thisCell);
if (FAILED(hr))
{
...
}
}
}

The call to SafeArrayGetElement fails with error code E_INVALIDARG. The
calls to SafeArrayGetUBound are both successful and return what I
expect.
If anyone can offer any insight into why the SafeArrayGetElement fails
it would be greatly appreciated.

Many thanks,
Martin.

  #4   Report Post  
Posted to microsoft.public.excel.programming
external usenet poster
 
Posts: 3
Default Retrieve Excel Cell Range into SAFEARRAY (VC++)

David,

I have tried using these and they both succeed. But I am unsure as to
how to access the array returned by SafeArrayAccessData. Here is the
code I am using:

// Array obtained as per code snippet from previous post.
SAFEARRAY * sa = tcvt.parray;

// Upper and lower bounds retrieved
....

// The call succeeds so error checking not included.
VARIANT * myX = NULL;
hr = ::SafeArrayAccessData(sa, (void HUGEP * FAR*)&myX);

// This is what I am unsure of. How do I access the elements of the
// array. Just using '[]' operator ? When I attempt to do this I get
// an unknown exception so I guess I am accessing it incorrectly. So,
// the following causes the exception to be thrown.
if (VT_BSTR == myX[0].vt)
{
}

// Call succeeds.
hr = ::SafeArrayUnaccessData(sa);

From the documentation that I have read I know this is faster as the

array is locked once and not every time I access it - so if I can get
it working I would use this approach. However, it would be useful to
know why the SafeArrayGetElement is failing as well but thanks for the
advice.

Thanks,
Martin.

David Welch wrote:
You could try using the SafeArrayAccessData and SafeArrayUnaccessData
functions. That way you can get the whole thing at once and its faster.

Also, is the lower bound of the safearray zero or one? It may be zero


Henry wrote:
#import "C:\Program Files\Microsoft Office\Office\MSO9.DLL"
#import "C:\Program Files\Common Files\Microsoft
Shared\VBA\VBA6\VBE6EXT.OLB"
#import "C:\\Program Files\\Microsoft Office\\Office\\excel9.olb"
rename("DialogBox","DialogBoxXl") rename("RGB","RGBXl") exclude
("IFont","IPicture")

using namespace Excel;

CoInitialize(NULL);
_ApplicationPtr pXl;

hr = pXl.CreateInstance(L"Excel.Application");
WorkbooksPtr pBooks = pXl-Workbooks;

// Open spreadsheet.
pBooks-Open("C:\\Temp\\MySpreadsheet.xls");
WorksheetsPtr pSheets = pXl-GetSheets();

// Get first sheet.
VARIANT vt;
::VariantInit(&vt);
vt.vt = VT_I2;
vt.iVal = (short)1;
_WorksheetPtr thisSheet = pSheets-GetItem(vt);

WCHAR tl[3] = { L'B', L'1', L'\0' };
WCHAR br[3] = { L'B', L'9', L'\0' };
VARIANT cellTL(::SysAllocString(tl));
VARIANT cellBR(::SysAllocString(br));
RangePtr range = a_sheet-GetRange(cellTL, cellBR);

// The VARIANT is an array of VARIANTs
VARIANT tcvt = range-GetValue();
if (tcvt.vt == (VT_ARRAY | VT_VARIANT))
{
// I know what the min and max col values are but was just
// getting used to the APIs.
SAFEARRAY * sa = tcvt.parray;
long colMax;
hr = ::SafeArrayGetUBound(sa, 1, &colMax);
long colMin;
hr = ::SafeArrayGetLBound(sa, 1, &colMin);

long index[2];
index[0] = 1;
for (long colIdx = colMin; colIdx <= colMax; colIdx++)
{
index[1] = colIdx;
VARIANT thisCell;
::VariantInit(&thisCell);
hr = SafeArrayGetElement(sa, index, &thisCell);
if (FAILED(hr))
{
...
}
}
}

The call to SafeArrayGetElement fails with error code E_INVALIDARG. The
calls to SafeArrayGetUBound are both successful and return what I
expect.
If anyone can offer any insight into why the SafeArrayGetElement fails
it would be greatly appreciated.

Many thanks,
Martin.


  #5   Report Post  
Posted to microsoft.public.excel.programming
external usenet poster
 
Posts: 21
Default Retrieve Excel Cell Range into SAFEARRAY (VC++)


Actually, your problem is he

VARIANT tcvt = range-GetValue();

if you change the VARIANT to a _variant_t then everything is fine!

Henry wrote:
David,

I have tried using these and they both succeed. But I am unsure as to
how to access the array returned by SafeArrayAccessData. Here is the
code I am using:

// Array obtained as per code snippet from previous post.
SAFEARRAY * sa = tcvt.parray;

// Upper and lower bounds retrieved
...

// The call succeeds so error checking not included.
VARIANT * myX = NULL;
hr = ::SafeArrayAccessData(sa, (void HUGEP * FAR*)&myX);

// This is what I am unsure of. How do I access the elements of the
// array. Just using '[]' operator ? When I attempt to do this I get
// an unknown exception so I guess I am accessing it incorrectly. So,
// the following causes the exception to be thrown.
if (VT_BSTR == myX[0].vt)
{
}

// Call succeeds.
hr = ::SafeArrayUnaccessData(sa);

From the documentation that I have read I know this is faster as the

array is locked once and not every time I access it - so if I can get
it working I would use this approach. However, it would be useful to
know why the SafeArrayGetElement is failing as well but thanks for the
advice.

Thanks,
Martin.

David Welch wrote:

You could try using the SafeArrayAccessData and SafeArrayUnaccessData
functions. That way you can get the whole thing at once and its faster.

Also, is the lower bound of the safearray zero or one? It may be zero


Henry wrote:
#import "C:\Program Files\Microsoft Office\Office\MSO9.DLL"


#import "C:\Program Files\Common Files\Microsoft
Shared\VBA\VBA6\VBE6EXT.OLB"
#import "C:\\Program Files\\Microsoft Office\\Office\\excel9.olb"
rename("DialogBox","DialogBoxXl") rename("RGB","RGBXl") exclude
("IFont","IPicture")

using namespace Excel;

CoInitialize(NULL);
_ApplicationPtr pXl;

hr = pXl.CreateInstance(L"Excel.Application");
WorkbooksPtr pBooks = pXl-Workbooks;

// Open spreadsheet.
pBooks-Open("C:\\Temp\\MySpreadsheet.xls");
WorksheetsPtr pSheets = pXl-GetSheets();

// Get first sheet.
VARIANT vt;
::VariantInit(&vt);
vt.vt = VT_I2;
vt.iVal = (short)1;
_WorksheetPtr thisSheet = pSheets-GetItem(vt);

WCHAR tl[3] = { L'B', L'1', L'\0' };
WCHAR br[3] = { L'B', L'9', L'\0' };
VARIANT cellTL(::SysAllocString(tl));
VARIANT cellBR(::SysAllocString(br));
RangePtr range = a_sheet-GetRange(cellTL, cellBR);

// The VARIANT is an array of VARIANTs
VARIANT tcvt = range-GetValue();
if (tcvt.vt == (VT_ARRAY | VT_VARIANT))
{
// I know what the min and max col values are but was just
// getting used to the APIs.
SAFEARRAY * sa = tcvt.parray;
long colMax;
hr = ::SafeArrayGetUBound(sa, 1, &colMax);
long colMin;
hr = ::SafeArrayGetLBound(sa, 1, &colMin);

long index[2];
index[0] = 1;
for (long colIdx = colMin; colIdx <= colMax; colIdx++)
{
index[1] = colIdx;
VARIANT thisCell;
::VariantInit(&thisCell);
hr = SafeArrayGetElement(sa, index, &thisCell);
if (FAILED(hr))
{
...
}
}
}

The call to SafeArrayGetElement fails with error code E_INVALIDARG. The
calls to SafeArrayGetUBound are both successful and return what I
expect.
If anyone can offer any insight into why the SafeArrayGetElement fails
it would be greatly appreciated.

Many thanks,
Martin.





  #6   Report Post  
Posted to microsoft.public.excel.programming
external usenet poster
 
Posts: 3
Default Retrieve Excel Cell Range into SAFEARRAY (VC++)

David,

thanks a million!! I will look into this and try and understand why
this now works. I have been pulled off onto something else but I did
what you said and everything is indeed fine! That was annoying me for
nearly a week and I don't think I would have found it so thanks again.

Cheers,
Martin.

  #7   Report Post  
Posted to microsoft.public.excel.programming
external usenet poster
 
Posts: 21
Default Retrieve Excel Cell Range into SAFEARRAY (VC++)

Also, this is a much better way of doing this, which is to use a library
where someone has already done the work for you. See

http://www.cuj.com/documents/s=9765/cuj9904alexandr/


Henry wrote:
David,

I have tried using these and they both succeed. But I am unsure as to
how to access the array returned by SafeArrayAccessData. Here is the
code I am using:

// Array obtained as per code snippet from previous post.
SAFEARRAY * sa = tcvt.parray;

// Upper and lower bounds retrieved
...

// The call succeeds so error checking not included.
VARIANT * myX = NULL;
hr = ::SafeArrayAccessData(sa, (void HUGEP * FAR*)&myX);

// This is what I am unsure of. How do I access the elements of the
// array. Just using '[]' operator ? When I attempt to do this I get
// an unknown exception so I guess I am accessing it incorrectly. So,
// the following causes the exception to be thrown.
if (VT_BSTR == myX[0].vt)
{
}

// Call succeeds.
hr = ::SafeArrayUnaccessData(sa);

From the documentation that I have read I know this is faster as the

array is locked once and not every time I access it - so if I can get
it working I would use this approach. However, it would be useful to
know why the SafeArrayGetElement is failing as well but thanks for the
advice.

Thanks,
Martin.

David Welch wrote:

You could try using the SafeArrayAccessData and SafeArrayUnaccessData
functions. That way you can get the whole thing at once and its faster.

Also, is the lower bound of the safearray zero or one? It may be zero


Henry wrote:
#import "C:\Program Files\Microsoft Office\Office\MSO9.DLL"


#import "C:\Program Files\Common Files\Microsoft
Shared\VBA\VBA6\VBE6EXT.OLB"
#import "C:\\Program Files\\Microsoft Office\\Office\\excel9.olb"
rename("DialogBox","DialogBoxXl") rename("RGB","RGBXl") exclude
("IFont","IPicture")

using namespace Excel;

CoInitialize(NULL);
_ApplicationPtr pXl;

hr = pXl.CreateInstance(L"Excel.Application");
WorkbooksPtr pBooks = pXl-Workbooks;

// Open spreadsheet.
pBooks-Open("C:\\Temp\\MySpreadsheet.xls");
WorksheetsPtr pSheets = pXl-GetSheets();

// Get first sheet.
VARIANT vt;
::VariantInit(&vt);
vt.vt = VT_I2;
vt.iVal = (short)1;
_WorksheetPtr thisSheet = pSheets-GetItem(vt);

WCHAR tl[3] = { L'B', L'1', L'\0' };
WCHAR br[3] = { L'B', L'9', L'\0' };
VARIANT cellTL(::SysAllocString(tl));
VARIANT cellBR(::SysAllocString(br));
RangePtr range = a_sheet-GetRange(cellTL, cellBR);

// The VARIANT is an array of VARIANTs
VARIANT tcvt = range-GetValue();
if (tcvt.vt == (VT_ARRAY | VT_VARIANT))
{
// I know what the min and max col values are but was just
// getting used to the APIs.
SAFEARRAY * sa = tcvt.parray;
long colMax;
hr = ::SafeArrayGetUBound(sa, 1, &colMax);
long colMin;
hr = ::SafeArrayGetLBound(sa, 1, &colMin);

long index[2];
index[0] = 1;
for (long colIdx = colMin; colIdx <= colMax; colIdx++)
{
index[1] = colIdx;
VARIANT thisCell;
::VariantInit(&thisCell);
hr = SafeArrayGetElement(sa, index, &thisCell);
if (FAILED(hr))
{
...
}
}
}

The call to SafeArrayGetElement fails with error code E_INVALIDARG. The
calls to SafeArrayGetUBound are both successful and return what I
expect.
If anyone can offer any insight into why the SafeArrayGetElement fails
it would be greatly appreciated.

Many thanks,
Martin.



Reply
Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules

Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On


Similar Threads
Thread Thread Starter Forum Replies Last Post
have Excel retrieve conditional operator ( < = ) from a cell [email protected] Excel Worksheet Functions 1 May 17th 07 07:16 PM
Need formula to retrieve last non-blank cell in range Eric Excel Discussion (Misc queries) 7 July 20th 06 01:29 PM
SAFEARRAY [in] and [out] MB Blackburn Excel Programming 0 May 12th 05 10:08 PM
Fill a Range with VB SafeArray Rob[_17_] Excel Programming 3 April 9th 04 09:41 AM
How to retrieve content of the Excel cell? Jack Excel Programming 5 February 10th 04 10:52 PM


All times are GMT +1. The time now is 11:17 AM.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Copyright ©2004-2025 ExcelBanter.
The comments are property of their posters.
 

About Us

"It's about Microsoft Excel"