Здравствуйте уважаемые знатоки ассемблера и программирования под Win32. С наступающим Новым Годом Вас. А теперь вопрос: В printer interface DLL есть точка входа Код (Text): BOOL DrvConvertDevMode( LPTSTR pPrinterName, PDEVMODE pdmIn, PDEVMODE pdmOut, PLONG pcbNeeded, DWORD fMode ); Когда fMode == CDM_DRIVER_DEFAULT функция должна в конечном итоге скопировать в pdmOut DEVMODE по умолчанию. DEVMODE определена так (начало определения ) Код (Text): typedef struct _devicemodew { WCHAR dmDeviceName[CCHDEVICENAME]; WORD dmSpecVersion; WORD dmDriverVersion; WORD dmSize; ... где CCHDEVICENAME == 32 На мой "непросвещенный" взгляд в памяти это все должно располагаться "примерно" так: 32*2 байта dmDeviceName, 2 байта dmSpecVersion и так далее. Собственно так и получается. Но, при попытке установить драйвер принтера, спулер падает со страшным грохотом и в отладчике выпадает вот в таком месте: Код (Text): 77C37FCC mov edi,edi 77C37FCE push ebp 77C37FCF mov ebp,esp 77C37FD1 mov eax,dword ptr [ebp+8] 77C37FD4 mov cx,word ptr [eax] ; вот на это отладчик и ругаеццо. WinDbg считает что это в wcslen 77C37FD7 inc eax 77C37FD8 inc eax 77C37FD9 test cx,cx ругаецца он потому что eax содержит указатель на "что попало". При чем тут DEVMODE? Если например заполнить поле dmDeviceName следующей строчкой L"Mega" то в заполненой структурке в памяти увидим следующее: 0x00A7E958 4d 00 65 00 67 00 61 00 00 00 00 00 00 M.e.g.a...... 0x00A7E965 00 00 00 00 00 00 00 00 00 00 00 00 00 ............. что собственно и ожидалось. Но ни как не ожидалось что что содержимое eax будет 0x0065004d. Получаецца что спулер, а вернее провайдер печати, воспринимают DEVMODE как Код (Text): typedef struct _devicemodew { WCHAR* dmDeviceName; WORD dmSpecVersion; WORD dmDriverVersion; WORD dmSize; ... Вопрос - это я в шары долблюсь(неправ) или децствительно есть "альтернативное" определение DEVMODE? Ос WinXp Заранее благодарен за любой ответ. Еще раз с праздником.
wdm Какая связь приведённого куска кода с DrvConvertDevMode и DEVMODE ? Видно, что это начало какой-то ф-ции, вероятно берущей первым аргументом указатель на WCHAR-строку (или указатель на структуру, с такой строкой первым полем). Т.е. вполне возможно, что первый арг. - это указатель на DEVMODE. Откуда такой вывод? Из приведённого кода это не следует.
DrvConvertDevMode возвращает спулеру заполненную DEVMODE. спулер (локальный провайдер печати) "что-то" с ней делает и попадает в это место. Приведенный кусок кода это место где собственно и происходит ошибка. WinDbg говорит что это msvcrt.dll и ф-ция wcslen. соответственно первый аргумент и есть WCHAR-строка. кусок кода просто скопирован из окна отладчика для иллюстрации. Ошибка происходит если я заполняю в DEVMODE поле dmDeviceName. И я просто обратил внимание что первые четыре байта, которые я записываю в это поле попадают в качестве адреса строки в wcslen. Собственно потому я такой вывод и сделал. Это следует не из приведенного кода. Я конечно предполагаю, что возможной причиной ошибки является некорректное заполнение мной DEVMODE, но... Код (Text): BOOL DrvConvertDevMode( LPTSTR pPrinterName, PDEVMODE pdmIn, PDEVMODE pdmOut, PLONG pcbNeeded, DWORD fMode ){ DbgMessageW( L"PlotUI: DrvConvertDevMode\n" ); DbgMessageW( L"PlotUI: pPrinterName == %s\n", pPrinterName ); DbgMessageW( L"PlotUI: Needed: %u\n\r", *pcbNeeded ); bool bRes = false; switch(fMode){ case CDM_CONVERT: DbgMessageW( L"PlotUI: fMode == CDM_CONVERT\n" ); break; case CDM_CONVERT351: DbgMessageW( L"PlotUI: fMode == CDM_CONVERT351\n" ); break; case CDM_DRIVER_DEFAULT: DbgMessageW( L"PlotUI: fMode == CDM_DRIVER_DEFAULT\n" ); if( (*pcbNeeded < sizeof(DEVMODE)) || (pdmOut == NULL) ){ *pcbNeeded = sizeof(DEVMODE); SetLastError( ERROR_INSUFFICIENT_BUFFER ); DbgMessageW( L"PlotUI: ERROR_INSUFFICIENT_BUFFER. Needed: %u\n\r", sizeof(DEVMODE) ); bRes = false; }else{ *pcbNeeded= sizeof(DEVMODE); memset( pdmOut, 0, sizeof( DEVMODE ) ); wcsncpy( pdmOut->dmDeviceName, L"MegaPlotter", wcslen(L"MegaPlotter") ); pdmOut->dmSize = sizeof(DEVMODE); pdmOut->dmSpecVersion = DM_SPECVERSION; pdmOut->dmDriverVersion = 4; pdmOut->dmDriverExtra = 0; pdmOut->dmFields = DM_ORIENTATION|DM_PAPERLENGTH |DM_PAPERWIDTH|DM_SCALE|DM_DEFAULTSOURCE |DM_PRINTQUALITY|DM_COLOR|DM_DUPLEX; pdmOut->dmOrientation = DMORIENT_LANDSCAPE; pdmOut->dmPaperLength = 10000; pdmOut->dmPaperWidth = 10000; pdmOut->dmScale = 100; pdmOut->dmDefaultSource = DMBIN_MANUAL; pdmOut->dmPrintQuality = DMRES_HIGH; pdmOut->dmColor = DMCOLOR_MONOCHROME; pdmOut->dmDuplex = DMDUP_SIMPLEX; DbgMessageW( L"PlotUI: Copy DEVMODE\n\r" ); bRes = true; } break; default: DbgMessageW( L"PlotUI: fMode == DEFAULT\n" ); }; return bRes; } Вот на всякий случай моя DrvConvertDevMode .... Вроде бы все тупо до невозможности
wdm Грох происходит после вызова DrvConvertDevMode, но до вызова всех других ф-ций драйвера? Вот это ошибка, кстати: Нужно:
Код (Text): Нужно: wcsncpy( pdmOut->dmDeviceName, L"MegaPlotter", CCHDEVICENAME) ); Я так и делал изначально. В данном случае не играет ни какой роли...я так понимаю.. Да. Сразу после вызова DrvConvertDevMode