Форум » [x]Harbour » Снова EXCEL (продолжение) » Ответить

Снова EXCEL (продолжение)

Dima: Ранее с Excel из Harbour ни когда не работал. Поставили тут задачу. У некоторых поставщиков есть определенные формы заказов. Набраны они в Excel. Сейчас народ руками заполняет эти формы и шлет по электронке поставщикам. Задача сводится к тому что бы в этих формах находить нужные коды товара и в нужной ячейке проставлять заказ. Может ткнет кто носом с чего начать что бы не напороться на грабли. Спасибо Сами формы тут http://zalil.ru/33279066

Ответов - 300, стр: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 All

Haz: fokinal21 пишет: А как проверить? Ну есть к примеру enumwindows которая возвращает список активных окон в системе. Возможно есть способ проще, типа похендлу получить статус окна... именно живо ли оно

Петр: Haz пишет: Возможно есть способ проще, типа похендлу получить статус окна Валидность хэндла обычно проверяют с использованием WinAPI функции IsWindow() В MiniGUI функция-враппер носит название IsWindowHandle(). if IsWindowHandle( oExcel:hWnd ) ...

fokinal21: oExcel :=CreateObject( "Excel.Application" ) hWnd:=oExcel:hWnd ? hWnd ? IsWindowHandle(hWnd) // Результаты: 462230 и .T. oExcel:Quit() ? hWnd ? IsWindowHandle(hWnd) // Результаты: 462230 и .T. *По рекомендации Dima oExcel:=nil ? hWnd ? IsWindowHandle(hWnd) // Результаты: 462230 и .T. // Итог: oExcel опять живее всех живых, несмотря на oExcel:Quit() и oExcel:=nil


Dima: fokinal21 пишет: *По рекомендации Dima oExcel:=nil ? hWnd ? IsWindowHandle(hWnd) // Результаты: 462230 и .T. // Итог: oExcel опять живее всех живых, несмотря на oExcel:Quit() и oExcel:=nil Ну тогда нужно так oExcel:Quit() oExcel:=nil ? hWnd:=oExcel:hWnd ? IsWindowHandle(hWnd) // Итог: результат в студию

Sergy: Dima пишет: oExcel:Quit() oExcel:=nil ? hWnd:=oExcel:hWnd ? IsWindowHandle(hWnd) // Итог: результат в студию Можно даже не компилировать - результатом будет ошибка времени исполнения, тк у переменной типа NIL не может быть свойства :hWnd А ноги у этой проблемы вот отсюда растут: http://clipper.borda.ru/?1-4-0-00001096-000-0-0-1440920410 Вот тут тоже обсуждали: http://clipper.borda.ru/?1-4-0-00000591-000-0-0-1317808661 Вот решение: http://clipper.borda.ru/?1-4-0-00000876-000-0-0-1373554002 [pre2] func Start_Excel() Local Res:=.f. #ifndef __XHARBOUR__ #xcommand TRY => BEGIN SEQUENCE WITH {|e| Break( e )} #xcommand CATCH [<!oErr!>] => RECOVER [USING <oErr>] <-oErr-> #endif TRY oExcel := GetActiveObject( "Excel.Application" ) oExcel:DisplayAlerts:=.f. Res:=.t. CATCH Res:=.f. TRY oExcel := CreateObject( "Excel.Application" ) Res:=.t. CATCH Res:=.f. END END Return Res [/pre2] Т.е. если процесс уже есть в памяти - использовать его, а не создавать новый.

fokinal21: В общем понятно, что процесс Excel закрывается только после закрытия вызвавшей его программы, как ни крути Quit - ами и nil - ами. И это значит, что попытки выяснить с помощью хендла закрыл юзер окно с табличкой или нет обречены на провал, а это и надо было мне сделать. Может кто проведет другим путем?

Dima: fokinal21 пишет: это значит, что попытки выяснить с помощью хендла закрыл юзер окно с табличкой или нет обречены на провал А зачем это контролировать ? Выбросил форму в Excel а дальше юзер что хочет с ней то и делает. У себя делаю примерно так: oExcel:DisplayAlerts:=.t. oExcel:Visible := .t. oSheet:Cells( 1, 1 ):select() //oSheet:Protect( "blabla" ) Showexcel(oExcel)

Haz: fokinal21 пишет: Может кто проведет другим путем? Да легко Суть в том что любое окно порождено конкретным процессом. Отслеживать хендл окна дело бесперспективное т. к. Винда использует повторное пернназначение (хендл закрытого окна может пллучтьб вновь созданное) Поэтому имеет смысл привязыватьсяименно к процессу еоторый это окно родил. И задача сводится к тому что бы определить жив ли сам процесс. Как определить? По алгоритму 1.зная окно можно найти процесс который его создал 2.зная процесс получить программу которая в нем выполняетя 3.и если это тот процесс и та программа то юзер ее еще не убил Ps в харбуре есть инструмент чтоб этот алгоритм проверить Будут вопросы пиши. На чтото я смогу ответить на что-то коллеги помогут

fokinal21: Haz пишет: Как определить? По алгоритму 1.зная окно можно найти процесс который его создал 2.зная процесс получить программу которая в нем выполняетя 3.и если это тот процесс и та программа то юзер ее еще не убил Пока на все один большой вопрос ? Чтобы превратить его в несколько маленьких ,стремящихся к 0, можно чуть подробнее и небольшой пример, можно ссылку, если таковой уже есть.

Петр: fokinal21 пишет: Пока на все один большой вопрос ? Чтобы превратить его в несколько маленьких ,стремящихся к 0, можно чуть подробнее и небольшой пример, можно ссылку, если таковой уже есть. Зачем это все прикладному программисту? fokinal21 пишет: В общем понятно, что процесс Excel закрывается только после закрытия вызвавшей его программы, как ни крути Quit - ами и nil - ами. И это значит, что попытки выяснить с помощью хендла закрыл юзер окно с табличкой или нет обречены на провал, а это и надо было мне сделать. Может кто проведет другим путем? oExсel:hWnd хранит хэндл главного окна oExсel (с классом 'XLMAIN'), как вы его собираетесь использовать для определения окна с табличкой, это еще вопрос. oExсel также имеет коллекцию Windows - "that represents all the windows in all the workbooks", вот я б с ней пробовал работать в вашей ситуации.

Haz: fokinal21 пишет: Пока на все один большой вопрос ? Чтобы превратить его в несколько маленьких ,стремящихся к 0, можно чуть подробнее и небольшой пример, можно ссылку, если таковой уже есть. Вот тот самый небольшой пример. Показывает окна их класс и заголовки. В том числе если есть открытая книга в Excel то ее и покажет в списке [pre2] #include "common.ch" #include "i_winuser.ch" #define WM_GETTEXT 0x000D #define WM_SETTEXT 0x000C #define WM_GETTEXTLENGTH 0x000E Func main() local hWnd := 0 local aWin := {} local aChild := {} local hChildWindow := 0 local i := 0 local j := 0 local nLen := 0 local nLenCh := 0 REQUEST HB_LANG_RU866 HB_LANGSELECT("RU866") REQUEST HB_CODEPAGE_RU1251 hb_cdpSelect( "RU1251" ) aWin := EnumWindows() nLen := len( aWin ) for i := 1 to nLen aChild := EnumChild( aWin[ i ] ) nLenCh := LEN( aChild ) for j := 1 TO nLenCh ? aChild[j][2], aChild[ j ][3] end end return NIL Func EnumChild( hWin ) local aChild := {} EnumChildWindows( hWin, { |hChild, nLParam | AADD( aChild, { hChild, GetClassName( hChild ), GetChildWindowText(hChild) } ) , .T. }, 0 ) return aChild FUNCTION GetChildWindowText(hWnd ) LOCAL nLen, cText nLen := SendMessage(hWnd, WM_GETTEXTLENGTH, 0, 0) + 1 cText := Space( nLen) nLen := SendMessageString(hWnd, WM_GETTEXT, nLen, @cText) RETURN substr(cText,1,nLen) ********************************************************************************************************************************************** * ********************************************************************************************************************************************** #pragma BEGINDUMP #include <windows.h> #include "hbapi.h" #include "hbapiitm.h" #include <hbapi.h> #include <hbapiitm.h> #include <windows.h> void hb_evalBlock( PHB_ITEM pCodeBlock, ... ); static PHB_ITEM pCodeBlock = NULL; BOOL CALLBACK static EnumChildProc( HWND hWnd, LPARAM lParam ) { PHB_ITEM pHWnd = hb_itemPutNL( NULL, ( LONG ) hWnd ); PHB_ITEM pParam = hb_itemPutNL( NULL, ( LONG ) lParam ); if( pCodeBlock ) hb_evalBlock( pCodeBlock, pHWnd, pParam, 0 ); hb_itemRelease( pHWnd ); hb_itemRelease( pParam ); return hb_parl( -1 ); } HB_FUNC( ENUMCHILDWINDOWS ) { HWND hWnd = ( HWND ) hb_parnl( 1 ); LPARAM lParam = ( LPARAM ) hb_parnl( 3 ); pCodeBlock = hb_param( 2, HB_IT_BLOCK ); hb_retl( EnumChildWindows( hWnd, EnumChildProc, lParam ) ); pCodeBlock = NULL; } BOOL CALLBACK static EnumWinProc( HWND hWnd, LPARAM lParam ) { PHB_ITEM pHWnd = hb_itemPutNL( NULL, ( LONG ) hWnd ); PHB_ITEM pParam = hb_itemPutNL( NULL, ( LONG ) lParam ); if( pCodeBlock ) hb_evalBlock( pCodeBlock, pHWnd, pParam, 0 ); hb_itemRelease( pHWnd ); hb_itemRelease( pParam ); return TRUE; } static PHB_ITEM pArray; #if defined( __BORLANDC__ ) #pragma argsused #endif BOOL CALLBACK EnumWindowsProc( HWND hWnd, LPARAM lParam ) { PHB_ITEM pHWnd = hb_itemPutNL( NULL, ( LONG ) hWnd ); #if defined( __MINGW32__ ) UNREFERENCED_PARAMETER( lParam ); #endif hb_arrayAddForward( pArray, pHWnd ); hb_itemRelease( pHWnd ); return TRUE; } HB_FUNC ( ENUMWINDOWS ) { pArray = hb_itemArrayNew( 0 ); EnumWindows( ( WNDENUMPROC ) EnumWindowsProc, ( LPARAM ) 0 ); hb_itemReturnRelease( pArray ); pArray = NULL; } BOOL CALLBACK EnumThreadWndProc( HWND hWnd, LPARAM lParam ) { PHB_ITEM pHWnd = hb_itemPutNL( NULL, ( LONG ) hWnd ); #if defined( __MINGW32__ ) UNREFERENCED_PARAMETER( lParam ); #endif hb_arrayAddForward( pArray, pHWnd ); hb_itemRelease( pHWnd ); return TRUE; } HB_FUNC ( GETCLASSNAME ) { HWND hWnd = (HWND) hb_parnl( 1 ); TCHAR ClassName[ 1024 ]; GetClassName( hWnd, ClassName, sizeof (ClassName) / sizeof (TCHAR) ); hb_retc( ClassName ); } HB_FUNC( GETWINDOWTEXT ) { HWND hWnd = ( HWND ) hb_parnl( 1 ); int iLen = GetWindowTextLength( hWnd ); char * cText = ( char * ) hb_xgrab( iLen + 1 ); int iRet = GetWindowText( hWnd, ( LPSTR ) cText, iLen + 1 ); hb_retclen( cText, iRet ); hb_xfree( cText ); } HB_FUNC( SENDMESSAGE ) { hb_retnl( ( LONG ) SendMessage( ( HWND ) hb_parnl( 1 ), ( UINT ) hb_parni( 2 ), ( WPARAM ) hb_parnl( 3 ), ( LPARAM ) hb_parnl( 4 ) ) ); } HB_FUNC( SENDMESSAGESTRING ) { hb_retnl( ( LONG ) SendMessage( ( HWND ) hb_parnl( 1 ), ( UINT ) hb_parni( 2 ), ( WPARAM ) hb_parnl( 3 ), ( LPARAM ) ( LPSTR ) hb_parc( 4 ) ) ); } HB_FUNC ( POSTMESSAGE ) { hb_retl( (BOOL) PostMessage ( (HWND) hb_parnl (1), (UINT) hb_parni (2), (WPARAM) hb_parnl (3), (LPARAM) hb_parnl (4) ) ); } #pragma ENDDUMP [/pre2]

fokinal21: Всем спасибо за помощь и консультации! Haz пишет: Вот тот самый небольшой пример Буду, по возможности, разбираться с примером...

Dima: fokinal21 пишет: Буду, по возможности, разбираться с примером... Пример по ходу отображается не верно , там где есть [ i ] только без пробелов внутри скобок

SergKis: Dima пишет Пример по ходу отображается не верно тут [pre2] for i := 1 to nLen aChild := EnumChild( aWin[ i ] ) nLenCh := LEN( aChild ) for j := 1 TO nLenCh ? aChild[j][2], aChild[j][3] end end[/pre2]

Haz: SergKis пишет: тут Дима , Сергей , спасибо . Подправил [ и ]

Петр: [pre2] REQUEST HB_LANG_RU866 REQUEST HB_CODEPAGE_RU1251 procedure Main( p, m ) local oExcel, oWorkBook, oWindows local nI, nCount, w hb_LangSelect( "RU866" ) hb_cdpSelect( "RU1251" ) hb_default( @p, "/" ) hb_default( @m, "/m" ) if hb_LeftEqI( p, "/g" ) .or. hb_LeftEqI( p, "-g" ) oExcel := win_oleGetActiveObject( "Excel.Application" ) elseif hb_LeftEqI( p, "/c" ) .or. hb_LeftEqI( p, "-c" ) oExcel := win_oleCreateObject( "Excel.Application" ) else ? Upper( __FILE__ ), '[/G|/C] [/M]' ? ' /C - Create new Excel object' ? ' /G - Get existing object' ? ' /M - Merge instances [by default]' ? '' endif if oExcel != NIL IF hb_LeftEqI( m, "/m" ) .or. hb_LeftEqI( m, "-m" ) oExcel:MergeInstances := .T. else oExcel:MergeInstances := .F. endif ? oExcel:hwnd ? '---------' oWindows := oExcel:Windows() oWorkBook := oExcel:WorkBooks:Add() nCount := oWindows:Count // Note that the active window is always Windows[1] oWindows[1]:Caption := "xl#win#" + hb_NtoS( nCount ) for each w in oWindows ? w:caption ? w:hwnd next oExcel:Visible := .T. //oExcel:Quit() else ? "Error: MS Excel not available. [" + win_oleErrorText() + "]" endif return [/pre2] Программа консольная. Компилировать как-то так hbmk2 myexcel.prg -lhbwin Запускать myexcel /c /m myexcel /g myexcel /g myexcel /g Рекомендую посмотреть, проанализировать и сделать выводы Интересно будет посмотреть на результат для разных версий Excel P.S. Excel 2016 работает чудненько.

Dima: Петр пишет: P.S. Excel 2016 работает чудненько. На 2003 падает на oExcel:MergeInstances и закоментил пока , пересобрал , запустил с ключом /C и упал в цикле на ? w:hwnd

Петр: Dima пишет: На 2003 падает на oExcel:MergeInstances Настоящий Эксель начинается с 2013 Dima пишет: упал в цикле на ? w:hwnd Припоминаю, что где-то мы уже это обсуждали, у Ворда свойство hwnd есть, у Экселя нет. В 2007(?) вроде уже есть.

Dima: Петр пишет: Настоящий Эксель начинается с 2013 Кажется в примере не хватает проверки перед его запуском на версию офиса , впрочем это уже обсуждали в одной из тем , так что кому надо тот сам и допилит. PS У многих еще стоит XP и далеко не SP3 , так что заюзать могут офис только ниже 2010

Петр: Dima пишет: Кажется в примере не хватает проверки перед его запуском на версию офиса Можно добавить в любом удобном месте ? oExcel:version И танцевать от результата Excel 2003 - 11.0 Excel 2007 - 12.0 Excel 2010 - 14.0 Excel 2013 - 15.0 Excel 2016 - 16.0



полная версия страницы