2008-10-30 9 views
4

Microsoft's DSOFramer 컨트롤을 사용하여 대화 상자에 Excel 파일을 포함시켜 사용자가 자신의 시트를 선택한 다음 해당 범위를 선택하도록 허용합니다. 세포; 대화 상자의 가져 오기 버튼과 함께 사용됩니다.DSOFramer 다른 문서에서 Excel 문서를 닫는 중입니다. 파일에 저장되지 않은 데이터가있는 경우 dsoframer가 "잘못된 주소에 액세스 시도"로 열리지 않습니다.

DSOFramer's OPEN 함수를 호출 할 때 다른 창에서 Excel을 열면 Excel 문서가 닫히지 만 Excel은 실행됩니다. 닫으려고하는 문서에 데이터가 저장되지 않은 경우 다른 창에서 Excel 문서를 닫는 대화 상자가 나타납니다. 파일에 저장하지 않은 데이터가있는 경우 dsoframer 메시지 상자를 사용하여 열 수 없습니다 : Attempt to access invalid address.

나는 소스를 빌드하고 단계별로 진행하여 CDsoDocObject::CreateFromFile 함수를 호출하고 IMoniker 클래스의 객체에 BindToObject을 호출합니다. HR0x8001010aThe message filter indicated that the application is busy입니다. 해당 오류가 발생하면 InstantiateDocObjectServer에 의해 classidCLSID Microsoft Excel 워크 시트 ... 이 0x80040154Class not registered과 함께 실패합니다. InstantiateDocObjectServerclassidCoCreateInstance을 먼저 호출합니다. 먼저 CLSCTX_LOCAL_SERVER으로, 그런 다음 CLSCTX_INPROC_SERVER으로 실패합니다.

알고 계십니까? DSOFramer은 다양한 대화 상자 및 양식에 Office 응용 프로그램을 포함시키기위한 인기있는 샘플 프로젝트입니다. 나는 다른 누군가가이 문제를 겪었고 이것이 어떻게 해결 될 수 있는지에 대한 통찰력을 갖기를 희망한다. 나는 실제로 열려있는 다른 Excel 문서를 닫고 싶지 않으며 저장되지 않은 데이터 때문에 문서를 닫을 수 없으면 오류를 내고 싶지 않습니다.

업데이트 1 : Excel.Application (이 클래스가 해결 될 것이라고 알고 있음)로 전달 된 classid을 변경하려고 시도했지만 작동하지 않았습니다. CDsoDocObject에서 키 HKEY_CLASSES_ROOT\CLSID\{00024500-0000-0000-C000-000000000046}\DocObject을 열려고하지만 실패합니다. 키가 내 레지스트리에 존재하지 않는다고 시각적으로 확인했습니다. 가이드 용 키가 있지만 DocObject 하위 키가 없습니다. 다음 오류 메시지 상자를 생성합니다 : The associated COM server does not support ActiveX document embedding. Excel.Workbook programid을 사용하려고하면 비슷한 결과 (다른 키, 물론)가 발생합니다.

업데이트 2 : 문제 자동화 Excel 인스턴스 대신 내 자동화가 가장 최근에 호출 된 것으로 바인딩되기를 기대하면서 Excel의 두 번째 인스턴스를 시작하려고했지만 그렇게하지 않은 것 같습니다. 결과는 동일했다. 내 문제는 다음과 같습니다. IMoniker 클래스의 개체에 BindToObject을 호출하고 0x8001010A (RPC_E_SERVERCALL_RETRYLATER)The message filter indicated that the application is busy을받는 중입니다. 나는 (SetBindOptions을 통해) BindToObject에 전달 된 플래그로 게임을 시도했지만 아무런 차이가없는 것 같습니다.

업데이트 3 : IMoniker 클래스를 사용하여 먼저 바인딩을 시도합니다. 실패 할 경우 clsidCoCreateInstancefallback 메소드로 호출합니다. 이 기능은 다른 MS Office 개체에서도 작동하지만 Excel 인 경우 클래스는 워크 시트 용입니다. 샘플을 CoCreateInstance _Application으로 수정 한 다음 통합 문서를 얻은 다음 대상 파일에 대해 Workbooks::Open이라고하고 워크 시트 개체를 반환합니다. 그런 다음 해당 포인터를 반환하고 원래 샘플 코드 경로로 다시 병합했습니다. 모두 일하고있어.

답변

0

DSOFRAMER 프로젝트를 사용한다고 가정하면이 코드를 dsofdocobj에 추가해야합니다.CreateFromFile 기능의 CPP는 주위 라인 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> 
} 

, 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; 
} 
0

  1. @Jinjin 당신은 #을 사용할 수 있습니다 import 지시문을 사용하여 Excel의 OLB 파일을 가져옵니다. 이렇게하면 _Application (및 필요한 나머지 부분)의 구조가 포함 된 Excel .tlh 파일이 자동으로 생성됩니다. 이상적으로 지원하려는 가장 오래된 Excel 버전과 일치하는 OLB 파일을 찾아야합니다. 로컬 시스템에있는 파일은 c : \ Program Files \ Microsoft Office \ Office12 (Office 2007이 설치되어 있다고 가정)에있을 수 있습니다. Excel.olb 또는 XL5EN32.OLB라는 이름이 붙을 수 있습니다 (Excel의 미국 영어 버전을 설치하지 않은 경우와는 분명히 다릅니다.)
    .olb 파일을 프로젝트 원본 디렉터리로 복사 한 다음 소스 파일에 #import "XL5EN32.olb"의 행을 추가하십시오.

  2. 예, 이전 버전이 열립니다.이 경우에 가장 적합한 방법은 위의 항목 1에서 언급 한 OLB 파일을 찾는 것입니다 지원할 가장 오래된 버전의 Excel 설치에서 가져온 것입니다. Office 2000의 Excel9.olb를 사용합니다. Office 2007 최신 버전의 Excel 버전 테스트에서 올바르게 작동합니다.

  3. 예 ,이 cha를 만든 후에 정상적으로 dsoframer를 사용해야합니다. nges.

  4. 고용주의 제한으로 인해 그렇게 할 수 없을지 모르겠습니다. 그러나 "주식"dsoframer 프로젝트를 사용하고이 게시물의 1 부에서 설명한 변경 사항을 적용하고 이전 게시물에서 설명한 변경 사항을 적용하면 내가 가지고있는 것을 거의 재현 할 수 있습니다.

0

@Jinjin : 당신이 엑셀 :: _ 응용 프로그램을 사용하는 CPP 파일에 import 문 (# import를 "XL5EN32.olb")를 넣어 않았다? 그렇지 않다면 그냥 프로젝트에 추가 할 수 없습니다. 이미 수행했다면 이 매핑을 #import "Debug \ XL5EN32.tlh"를 사용하는 cpp 파일에 추가하십시오. tlh 파일은 # import를 실행하여 생성 된 헤더입니다. 당신은 당신의 디버그 디렉토리에서 그것을 찾아야한다 (당신이 디버그 빌드를 수행하고 있다고 가정).

_Application to Application (및 기타)의 이름을 바꿀 수는 없습니다. _Application 구조는 매핑이있는 구조입니다. 그래서 app-> get_Workbooks를 찾지 못하는 것입니다.

응용 프로그램을 찾고 있지만 응용 프로그램이 아닌 파일은 무엇입니까?