views:

2608

answers:

10

I'm using Microsoft's DSOFramer control to allow me to embed an Excel file in my dialog so the user can choose his sheet, then select his range of cells; it's used with an import button on my dialog.

The problem is that when I call the DSOFramer's OPEN function, if I have Excel open in another window, it closes the Excel document (but leaves Excel running). If the document it tries to close has unsaved data, I get a dialog boxclosing Excel doc in another window. If unsaved data in file, dsoframer fails to open with a messagebox: "Attempt to access invalid address".

I built the source, and stepped through, and its making a call in its CDsoDocObject::CreateFromFile function, calling BindToObject on an object of class IMoniker. The HR is 0x8001010a "The message filter indicated that the application is busy". On that failure, it tries to InstantiateDocObjectServer by classid of CLSID Microsoft Excel Worksheet... this fails with an HRESULT of 0x80040154 "Class not registered". The InstantiateDocObjectServer just calls CoCreateInstance on the classid, first with CLSCTX_LOCAL_SERVER, then (if that fails) with CLSCTX_INPROC_SERVER.

I know DSOFramer is a popular sample project for embedding Office apps in various dialogs and forms. I'm hoping someone else has had this problem and might have some insight on how I can solve this. I really don't want it to close any other open Excel documents, and I really don't want it to error-out if it can't close the document due to unsaved data.

Update 1: I've tried changing the classid that's passed in to "Excel.Application" (I know that class will resolve), but that didn't work. In CDsoDocObject, it tries to open key "HKEY_CLASSES_ROOT\CLSID{00024500-0000-0000-C000-000000000046}\DocObject", but fails. I've visually confirmed that the key is not present in my registry; The key is present for the guid, but there's no DocObject subkey. It then produces an error message box: "The associated COM server does not support ActiveX document embedding". I get similar (different key, of course) results when I try to use the Excel.Workbook programid.

Update 2: I tried starting a 2nd instance of Excel, hoping that my automation would bind to it (being the most recently invoked) instead of the problem Excel instance, but it didn't seem to do that. Results were the same. My problem seems to have boiled down to this: I'm calling the BindToObject on an object of class IMoniker, and receiving 0x8001010A (RPC_E_SERVERCALL_RETRYLATER) "The message filter indicated that the application is busy". I've tried playing with the flags passed to the BindToObject (via the SetBindOptions), but nothing seems to make any difference.

Update 3: It first tries to bind using an IMoniker class. If that fails, it calls CoCreateInstance for the clsid as a "fallback" method. This may work for other MS Office objects, but when it's Excel, the class is for the Worksheet. I modified the sample to CoCreateInstance _Application, then got the workbooks, then called the Workbooks::Open for the target file, which returns a Worksheet object. I then returned that pointer and merged back with the original sample code path. All working now.

A: 

Hi, Steve

I need your help. I've countered same thing with the error that you write down in my programming. When I open the excel file on the form, other excel document is dissappeared in Excel application. I've tried to solve this problem. But I've not solved yet. So arounding the internet, fortunately, I've found this article and meet you. Please help me to solve this problem. Please tell me the code of Update 3. So, I hope to solve the problem by your kind help, the

Are you using the DSOFRAMER sample project?
Steve
A: 

Assuming you are using the DSOFRAMER project, you need to add this code to dsofdocobj.cpp in the CreateFromFile function, at around line 348:

CLSID clsidExcelWS;
hr = CLSIDFromProgID(OLESTR("Excel.Sheet"),clsidExcelWS);                
if (FAILED(hr)) return hr;

if (clsid == clsidExcelWS)
{
     hr = InstantiateAndLoadExcel(pwszFile, &pole);
     if (FAILED(hr)) return hr;
}
else
{
<the IMoniker::BindToObject call and it's failure handling from the "stock" sample goes here>
}

Then, define the following new member function in CDsoDocObject:

////////////////////////////////////////////////////////////////////////
// CDsoDocObject::InstantiateAndLoadExcel (protected)
//
//  Create an instance of Excel and load the target file into its worksheet
//
STDMETHODIMP CDsoDocObject::InstantiateAndLoadExcel(LPWSTR pwszFile, IOleObject **ppole)
{
IUnknown *punkApp=NULL;
Excel::_Application *app=NULL;
Excel::Workbooks *wbList=NULL;
Excel::_Workbook *wb;

CLSID clsidExcel;
HRESULT hr = CLSIDFromProgID(OLESTR("Excel.Application"), &clsidExcel);
if (FAILED(hr)) return hr;

hr = CoCreateInstance(clsidExcel, NULL, CLSCTX_LOCAL_SERVER,  IID_IUnknown, (void**)&punkApp);
if (SUCCEEDED(hr)) 
 {
 hr = punkApp->QueryInterface(__uuidof(Excel::_Application),(LPVOID *)&app);
 if (SUCCEEDED(hr))
  {
  hr = app->get_Workbooks(&wbList);

  VARIANT vNoParam;
  VariantInit(&vNoParam);
  V_VT(&vNoParam) = VT_ERROR;
  V_ERROR(&vNoParam) = DISP_E_PARAMNOTFOUND;

  VARIANT vReadOnly;
  VariantInit(&vReadOnly);
  V_VT(&vReadOnly) = VT_BOOL;
  V_BOOL(&vReadOnly) = VARIANT_TRUE;

  BSTR bstrFilename = SysAllocString(pwszFile);

  hr = wbList->Open(bstrFilename, vNoParam,vNoParam,vNoParam,vNoParam,vReadOnly,vNoParam,vNoParam,vNoParam,vNoParam,vNoParam,vNoParam,vNoParam,0,&wb);
  if (SUCCEEDED(hr))
   hr = wb->QueryInterface(IID_IOleObject, (void**)ppole);

  VariantClear(&vReadOnly);
  VariantClear(&vNoParam);
  SysFreeString(bstrFilename);
  }
 }

if (wb != NULL) wb->Release();
if (wbList != NULL) wbList->Release();
if (app != NULL) app->Release();
if (punkApp != NULL) punkApp->Release();

return hr;
}
Steve
A: 

Dear Steve

Thank you for your helping. I'll always regards your kind help on mind.

And please help me one more. I have problems and questions.

  1. I've added the code into DSOFramer project, and tried to build the revised project. But I have errors in Excel::_Application. So in order to solve this error I've walked
    around the internet and realized to add the library to automate Excel. But when I add the library by using MFC Class From TypeLib, the error is displayed with
    "The MFC classes can only be added to MFC project!". How do I solve this problem.

  2. Does this revised project can open the Excel2007 file(.xlsx) as well as older verion
    files?

  3. When I program using this modified OCX control, do I ought to pass the Workbook file
    name to Open function of control as then same before.

  4. And finally, Do you mind send me the builed project of revise on your computer? If possible, please give me. thank you.

Best Regards Jinjin

A: 

@Jinjin

  1. You can use the #import directive to import your Excel's OLB file. this should generate (and automatically include an Excel .tlh file which contains the structures for _Application (and the rest you need)). Ideally, you should find an OLB file that matches the earliest Excel version that you wish to support. The one on your local system is probably in c:\Program Files\Microsoft Office\Office12 (presuming you have Office 2007 installed). It may be named Excel.olb, or XL5EN32.OLB (different, obviously if you haven't installed the US English verion of Excel.
    So, copy the .olb file to your project source directory, then at the top of the source file, add a line for #import "XL5EN32.olb".

  2. Yes, opens older versions. Best way to guarantee that this will be the case is to find an OLB file (mentioned in item 1 above) that is from an installation of Excel that is the earliest version you wish to support. I use an Excel9.olb from Office 2000. Works fine with my testing of Excel versions all the way to the latest from Office 2007.

  3. Yes, you should use dsoframer normally after making these changes.

  4. I'm afraid I probably can't do that due to restrictions of my employer. However, if you take the "stock" dsoframer project, make the changes described in part 1 of this post, and the changes I described in my earlier post, you have pretty much recreated exactly what I have.

Steve
A: 

Dear Steve

Thank you for your reply. As you mentioned, I've imported the XL5EN32.olb file on the project. I've got the some errors. When I build the modified project, the compile error is displayed on the added code.

  1. Excel::_Application is undefined, but alternately is defined Application. So I added the code 'rename("Application", "_Application")'.

  2. Excel::_Workbook error is same with above problem.

  3. app->get_Workbooks function is not defined.

Of course, I've tried to solve this probelm all day, but I cant this. In frankly, I'm begginer on this project. What's the reason? How do I must? Please help me.

PS. Now I'm programming the project that embed the excel applciation. Please tell me your gmail address, because I'll send you my source and need your help in order to revise error in my project and for good communication.

Best Regards Jinjin

Hello, how did you solve this? Is the olb provided with current office versions wrong?
Tarnschaf
A: 

To Dear Steve

I've missed one thing above posting. On the following code is also displayed.

hr = wbList->Open(bstrFilename, vNoParam,vNoParam,vNoParam,vNoParam,vReadOnly,vNoParam,vNoParam,vNoParam,vNoParam,vNoParam,vNoParam,vNoParam,0,&wb);

please tell me policy.

Best Regards Jinjin

A: 

@Jinjin: did you put the import statement (#import "XL5EN32.olb") in the cpp file where you are using the Excel::_Application? If not, do that... can't just add it to the project. If you have already done that, try also adding this statement to the cpp file where you are using those mappings #import "Debug\XL5EN32.tlh". The tlh file is a header that is generated by running the #import; you should find it in your Debug directory (presuming you're performing a Debug build).

Renaming _Application to Application (and the others) is not the right way to go. The _Application structure is the one that has the mappings. That is why you are not finding the app->get_Workbooks.

What file are you looking in that you are finding Application but not _Application?

Steve
A: 

Dear Steve Thank you for your reply.

Of course, I imported the XL5LEN32.olb file on to the project. But I can't find the Excel::_Application right. the XL5LEN32.tlh file is in Debug directory. I followed the order of process that you teached. Sorry , Please send me the file "dsofdocobj.cpp" file that you modifed on your computer. and also XL5LEN32.OLB file.

Best Regards Jinjin

A: 

My Gmail address is [email protected] Please send me these files that I need into this address. Please help me to solve this problem.

A: 

Dear Steve Unfortunately, I don't have Office 2000. Please send me the Excel9.olb file too. Regards Jinjin