День добрый уважаемые господа. Прошу помощи в решении проблемы над которой бьюсь уже несколько дней. Задача очень проста: запустить MS Excel и сделать его видимым, все остальное я сделаю сам. Проблема: есть код на C++ работает без проблем (делаю с excel все что захочу), но я не хочу C++, нужно все тоже самое только на asm. Ниже исходники на C++ и на asm на мой взгляд они идентичны, но сишный работает, а asm нет (Excel запускается, но видимым становиться ну совершенно не хочет) не пойму что не так. ############C++############# #include "stdafx.h" #include <ole2.h> #include <stdlib.h> int main() { IDispatch *pXlApp = 0; CLSID clsid; wchar_t *wbuffer = L"Visible"; DISPID dispID = 0; DISPPARAMS dp = { NULL, NULL, 0, 0 }; DISPID dispidNamed = DISPID_PROPERTYPUT; VARIANT parm; CoInitialize(NULL); CLSIDFromProgID(L"Excel.Application",&clsid); CoCreateInstance(clsid,NULL,CLSCTX_LOCAL_SERVER,IID_IDispatch,(void **)&pXlApp); parm.vt = VT_BOOL; parm.boolVal = 1; dp.cArgs = 1; dp.rgvarg = &parm; dp.cNamedArgs = 1; dp.rgdispidNamedArgs = &dispidNamed; pXlApp->GetIDsOfNames(IID_NULL, &wbuffer, 1, LOCALE_USER_DEFAULT, &dispID); pXlApp->Invoke(dispID,IID_NULL,LOCALE_SYSTEM_DEFAULT,DISPATCH_PROPERTYPUT,&dp,NULL,NULL,NULL); CoUninitialize(); return 0; } ############ASM############# .386 .model flat,stdcall option casemap:none include windows.inc include kernel32.inc include oaidl.inc include ole32.inc include oleaut32.inc includelib kernel32.lib includelib ole32.lib includelib oleaut32.lib main proto .data clsid CLSID <> IID_NULL GUID <0,0,0,<0,0,0,0,0,0,0,0>> IID_IDispatch GUID <000020400H,00000H,00000H,<0C0H,000H,000H,000H,000H,000H,000H,046H>> szExcelApp db "Excel.Application",0 dispID DISPID 0 pXlApp dd 0 mtdVisible db "Visible",0 parm VARIANTARG <> dsppar DISPPARAMS <0,0,0,0> dispidNamed DISPID DISPID_PROPERTYPUT .data? buffer db 256 dup(?) wbuffer db 512 dup(?) .const .code start: invoke main invoke ExitProcess,eax main proc invoke MultiByteToWideChar,CP_ACP,0,addr szExcelApp,-1,addr wbuffer,510 invoke CLSIDFromProgID,addr wbuffer,addr clsid test eax,eax jne @UNINITCOM invoke CoInitialize,0 test eax,eax js @RETURN invoke CoCreateInstance,addr clsid,NULL,CLSCTX_LOCAL_SERVER,addr IID_IDispatch,addr pXlApp test eax,eax jne @UNINITCOM mov parm.vt,VT_BOOL mov parm.boolVal,1 mov dsppar.cArgs,1 lea eax,parm mov dsppar.rgvarg,eax mov dsppar.cNamedArgs,1 lea eax,dispidNamed mov dsppar.rgdispidNamedArgs,eax invoke MultiByteToWideChar,CP_ACP,0,addr mtdVisible,-1,addr wbuffer,510 coinvoke pXlApp,IDispatch,GetIDsOfNames,addr IID_NULL,addr wbuffer,1,LOCALE_USER_DEFAULT,addr dispID coinvoke pXlApp,IDispatch,Invoke,dispID,addr IID_NULL,800h,DISPATCH_PROPERTYPUT,addr dsppar,NULL,NULL,NULL @UNINITCOM: invoke CoUninitialize @RETURN: xor eax,eax ret main endp end start
Код даже смотреть не стал как увидел подключение oaidl.inc Запиши в него правильную структуру DISPPARAMS. В masm последние 2 прараметра WORD. Сам помню крыл всех х...ми DISPPARAMS STRUCT DWORD rgvarg PVOID ? rgdispidNamedArgs PVOID ? cArgs DWORD ? cNamedArgs DWORD ? DISPPARAMS ENDS И не стесняйся пользоваться SysAllocString и SysFreeString
И охота одному строки гонять? Ведь MASM уже способен здание UNICODE-приложений. Здесь должен быть указатель на массив строк, но не на массив символов, ага.
Ilgar Я не понял шутки юмора... Sol_Ksacap Абсолютно прав на счёт addr wbuffer. Правильно записать так: coinvoke pXlApp,IDispatch,GetIDsOfNames,addr IID_NULL,addr pBuf, 1, LOCALE_USER_DEFAULT, addr dispID pBuf dd offset szCommand szCommand WCHAR L(<XXX\0>) xxx - это не обозначение фильмов для взрослых... Посмотри это: http://www.ironahot.idknet.com/
Да конечно, прошу прощения, Sol_Ksacap не сомненно прав, ему также моя благодарность. По поводу "L MACRO" - не знаю почему, но я очень не люблю макросы (кроме invoke&coinvoke ) и высокоуровневые инструкции (типа .if .else и т.п.), и никогда их не использую, возможно это извращение, но мне нравиться. Еще раз большое спасибо всем кто ответил, а для тех кто столкнется с данной проблемой в будующем рабочий исходник: .386 .model flat,stdcall option casemap:none include windows.inc include kernel32.inc include oaidl.inc ;(исправить структуру DISPPARAMS см. пост MirrorBlack) include ole32.inc include oleaut32.inc includelib kernel32.lib includelib ole32.lib includelib oleaut32.lib main proto .data clsid CLSID <> IID_NULL GUID <0,0,0,<0,0,0,0,0,0,0,0>> IID_IDispatch GUID <000020400H,00000H,00000H,<0C0H,000H,000H,000H,000H,000H,000H,046H>> szExcelApp db "Excel.Application",0 dispID DISPID 0 pXlApp dd 0 mtdVisible db "Visible",0 parm VARIANTARG <> dsppar DISPPARAMS <0,0,0,0> dispidNamed DISPID DISPID_PROPERTYPUT .data? wbuffer db 512 dup(?) pwbuffer dd ? .const .code start: invoke main invoke ExitProcess,eax main proc invoke MultiByteToWideChar,CP_ACP,0,addr szExcelApp,-1,addr wbuffer,510 invoke CLSIDFromProgID,addr wbuffer,addr clsid test eax,eax jne @UNINITCOM invoke CoInitialize,0 test eax,eax js @RETURN invoke CoCreateInstance,addr clsid,NULL,CLSCTX_LOCAL_SERVER,addr IID_IDispatch,addr pXlApp test eax,eax jne @UNINITCOM mov parm.vt,VT_BOOL mov parm.boolVal,1 mov dsppar.cArgs,1 lea eax,parm mov dsppar.rgvarg,eax mov dsppar.cNamedArgs,1 lea eax,dispidNamed mov dsppar.rgdispidNamedArgs,eax invoke MultiByteToWideChar,CP_ACP,0,addr mtdVisible,-1,addr wbuffer,510 lea eax,wbuffer mov pwbuffer,eax coinvoke pXlApp,IDispatch,GetIDsOfNames,addr IID_NULL,addr pwbuffer,1,LOCALE_USER_DEFAULT,addr dispID coinvoke pXlApp,IDispatch,Invoke,dispID,addr IID_NULL,800h,DISPATCH_PROPERTYPUT,addr dsppar,NULL,NULL,NULL @UNINITCOM: invoke CoUninitialize @RETURN: xor eax,eax ret main endp end start Тока не забудте перед "invoke CoUninitialize" хотя бы MessageBox вызвать, иначе вы ничего не заметите
Подскажите: а как теперь реализовать Workbooks.Add или Rows("2:2").Select или Range("A1").Select?? Как на АСМе сделать с excel все что захочу?
Поделюсь, т.к. сам очень долго искал подобную информацию, мало кто отвечает конкретно, приходится вытягивать каждое движение, но я понимаю, лень, я и сам такой, пока мне не лень отвечать - вот исходник, компилится в WinAsm Studio, можно и в masm. Делает следующее: 1. Запускает MS Excel 2. Делает его видимым 3. Выделяет диапазон "A1:B1" 4. Рисует границы 5. Окрашивает диапазон в желтый цвет 6. Выравнивает по центру (горизонталь, вертикаль) 7. Работает с Safe Array (это хорошая штука, если нужно вставить много данных во много ячеек и сразу) 8. Вид -> разметка страницы 9. Масштаб 128% 10. Перенос по словам 11. Авто фильтр 12. Пишем нехорошие слова, шрифтом "Time New Roman/красный/жирный/косой/подчеркнутый" 12. Сохраняем как "D:\test.xls" (как это сделать мне вообще никто не смог ответить, даже на C++ - на этом форуме не спрашивал, здесь, если не лень, всему научат ) 13. Выходим Все телодвижения делаются с помощью плагиатированной функции MS AutoWrap, реализация возможно не совершенна, но рабочая. С ее помощью можно делать все, что захотите, в рамках того что может сам Excel/Word. Как сделать то, чего нет в исходнике? Ответ: Запускаем Excel->Сервис->Макрос->Начать запись->Делаем все что нужно->Смотрим что получилось->Используя MS AutoWrap делаем то же самое. Как это сделать с MS Word? Ответ: также как и с MS Excel Ну вот мне уже и стало лень. Надеюсь это кому нибуль пригодиться
Ilgar, а Вы не пробовали реализовать доступ к COM Excel и не запуская Excel выполнять все операции в своем окне своей программы?
А подскажет кто нибудь, как открыть xls файл. Делал вот так Добавил в программу Ilgar, вот это: Код (Text): mtdOpen db "Open",0 xlsOpen proc LOCAL l_parm:VARIANT LOCAL l_result:VARIANT LOCAL bstr_in:BSTR mov l_parm.vt,VT_I4 mov l_parm.lVal,1 invoke AutoWrap,DISPATCH_PROPERTYGET,addr l_result,pXlApp,addr mtdWorkBooks,1,addr l_parm mov eax,l_result.pdispVal mov pXlWorkBooks,eax invoke MultiByteToWideChar,CP_ACP,0,addr szSaveAs,-1,addr wbuffer,510 mov l_parm.vt,VT_BSTR invoke SysAllocString,addr wbuffer mov bstr_in,eax mov l_parm.bstrVal,eax invoke AutoWrap,DISPATCH_METHOD,0,pXlWorkBooks,addr mtdOpen,1,addr l_parm invoke SysFreeString,bstr_in ret xlsOpen EndP Заменил call xlsAddBook на call xlsOpen Но что то не хочет открываться, только пустая форма EXCEL и все.