visual-studio visual-c++ activex dsoframer

visual studio - DSOFramer cierra Excel doc en otra ventana. Si no se guardan los datos en el archivo, dsoframer no puede abrir con "Intento de acceder a una dirección no válida"



visual-studio visual-c++ (3)

@Jinjin

  1. Puede usar la directiva #import para importar el archivo OLB de Excel. esto debería generar (e incluir automáticamente un archivo Excel .tlh que contiene las estructuras para _Application (y el resto que necesita)). Idealmente, debería encontrar un archivo OLB que coincida con la versión de Excel más antigua que desee. El de su sistema local probablemente se encuentre en c: / Archivos de programa / Microsoft Office / Office12 (suponiendo que tenga instalado Office 2007). Puede llamarse Excel.olb o XL5EN32.OLB (diferente, obviamente, si no ha instalado la versión en inglés de Excel de los Estados Unidos).
    Por lo tanto, copie el archivo .olb en el directorio de origen del proyecto, luego en la parte superior del archivo fuente, agregue una línea para #import "XL5EN32.olb".

  2. Sí, abre versiones anteriores. La mejor manera de garantizar que este sea el caso es encontrar un archivo OLB (mencionado en el punto 1 anterior) que proviene de una instalación de Excel que es la primera versión que desea admitir. Uso Excel9.olb de Office 2000. Funciona bien con mis pruebas de las versiones de Excel hasta las últimas de Office 2007.

  3. Sí, debe usar dsoframer normalmente después de hacer estos cambios.

  4. Me temo que probablemente no pueda hacerlo debido a las restricciones de mi empleador. Sin embargo, si toma el proyecto de dsoframer "estándar", realice los cambios descritos en la parte 1 de esta publicación y los cambios que describí en mi publicación anterior, prácticamente ha recreado exactamente lo que tengo.

Estoy usando Microsoft''s DSOFramer control Microsoft''s DSOFramer para permitirme incrustar un archivo Excel en mi cuadro de diálogo para que el usuario pueda elegir su hoja y luego seleccionar su rango de celdas; se usa con un botón de importación en mi diálogo.

El problema es que cuando llamo a la función DSOFramer''s OPEN , si tengo Excel abierto en otra ventana, cierra el documento de Excel (pero deja Excel en ejecución). Si el documento que intenta cerrar tiene datos no guardados, aparece un cuadro de diálogo que cierra el documento de Excel en otra ventana. Si no se dsoframer datos en el archivo, dsoframer no puede abrir con un mensaje: Attempt to access invalid address .

Construí el código fuente, lo CDsoDocObject::CreateFromFile y hace una llamada en su función CDsoDocObject::CreateFromFile , llamando a BindToObject en un objeto de la clase IMoniker. El HR es 0x8001010a The message filter indicated that the application is busy . En ese error, intenta classid por classid de classid de classid de Microsoft Excel de CLSID ... esto falla con una Class not registered HRESULT de 0x80040154 Class not registered . El InstantiateDocObjectServer simplemente llama a CoCreateInstance en el classid , primero con CLSCTX_LOCAL_SERVER , luego (si eso falla) con CLSCTX_INPROC_SERVER .

Sé que DSOFramer es un proyecto de muestra popular para integrar aplicaciones de Office en diversos DSOFramer diálogo y formularios. Espero que alguien más haya tenido este problema y pueda tener alguna idea de cómo puedo resolverlo. Realmente no quiero que cierre ningún otro documento abierto de Excel, y realmente no quiero que salga el error si no puede cerrar el documento debido a datos no guardados.

Actualización 1: he intentado cambiar el classid que se pasó a Excel.Application . Excel.Application (sé que la clase se resolverá), pero eso no funcionó. En CDsoDocObject , intenta abrir la clave HKEY_CLASSES_ROOT/CLSID/{00024500-0000-0000-C000-000000000046}/DocObject , pero falla. He confirmado visualmente que la clave no está presente en mi registro; La clave está presente para la guía, pero no hay DocObject subclave DocObject . Luego produce un cuadro de mensaje de error: The associated COM server does not support ActiveX document embedding . Obtengo resultados similares (diferentes claves, por supuesto) cuando trato de usar el Excel.Workbook programid .

Actualización 2: Intenté iniciar una segunda instancia de Excel, con la esperanza de que mi automatización se enlazaría (siendo la última invocada) en lugar de la instancia problema de Excel, pero no parecía hacer eso. Los resultados fueron iguales. Mi problema parece haberse reducido a esto: estoy llamando a BindToObject en un objeto de la clase IMoniker , y recibiendo 0x8001010A (RPC_E_SERVERCALL_RETRYLATER) The message filter indicated that the application is busy . He intentado jugar con las banderas pasadas a BindToObject (a través de SetBindOptions ), pero nada parece hacer ninguna diferencia.

Actualización 3: primero intenta vincularse usando una clase IMoniker. Si eso falla, llama a CoCreateInstance para el clsid como método fallback . Esto puede funcionar para otros objetos de MS Office, pero cuando se trata de Excel, la clase es para la Hoja de trabajo. CoCreateInstance _Application la muestra en CoCreateInstance _Application , luego obtuve los libros de trabajo y luego los denominados Workbooks::Open para el archivo de destino, que devuelve un objeto de hoja de cálculo. Luego devolví ese puntero y me fusioné con la ruta del código de muestra original. Todos trabajando ahora.


@Jinjin: ¿Pusiste la declaración de importación (#import "XL5EN32.olb") en el archivo cpp donde estás usando la aplicación Excel :: _? Si no, haz eso ... no puedes agregarlo al proyecto. Si ya lo ha hecho, intente agregar esta declaración al archivo cpp donde está usando las asignaciones #import "Debug / XL5EN32.tlh". El archivo tlh es un encabezado que se genera ejecutando #import; deberías encontrarlo en tu directorio Debug (suponiendo que estés realizando una compilación Debug).

Cambiar el nombre _Aplicación a la aplicación (y a los demás) no es el camino correcto a seguir. La estructura _Application es la que tiene las asignaciones. Es por eso que no está encontrando la aplicación-> get_Workbooks.

¿Qué archivo está buscando para encontrar la Aplicación, pero no _Aplicación?


Suponiendo que está utilizando el proyecto DSOFRAMER, necesita agregar este código a dsofdocobj.cpp en la función CreateFromFile, alrededor de la línea 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> }

Luego, defina la siguiente función miembro nueva en 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; }