Vítejte !   Přihlášení | Registrace
Hlavní menu
CATIA fórum.cz
Novinky
Seriál CATIA
Obecně o CAD
Novinky ze světa DS
Makra pro CATIA V5
Diskuse
Vytvořit téma
Koncepty
Seznam oblíbených
Soukromé zprávy
Pravidla
Live CHAT
VIP žádost
Základy Catia
Ke stažení
Doporučujeme
Pracovní příležitosti
Reklama a kampaně
O fóru
Nápověda

SettingController pro nový Product popř. FindWindowExA z WinAPI

Kompletní přehled příspěvků v tématu SettingController pro nový Product popř. FindWindowExA z WinAPI řazený podle data jejich publikace na fóru.

UživatelPříspěvek
Břeťa Doležal

Poslat zprávu | Profil
Datum: 19.2. 2015 | Zobrazeno: 18700x
Konfigurace CATIA: V5 R19

Text dotazu:
Zdravím, chci za pomocí makra vytvořit novou prázdnou sestavu a potýkám se s tímto problémem: Při vytváření sestavy je uživatel vyzván k zadání názvu sestavy, což je možno potlačit v Options, ale přepínač viz. jeden z obrázků nelze ovládat přes VBA. Potřeboval bych tedy poradit, buď s tím jak vypnout/zapnout přepínač v Options, pokud někdo umí a nebo bych potřeboval poradit jak nasimulovat stisk OK tlačítka při vytváření sestavy.


myproc = Process.GetProcessesByName("CNEXT")
If myproc.Count > 1 Then
'!!!! pokud běží více CATII najednou, nutno ošetřit
End If
MainHWND = myproc(0).MainWindowHandle
blnVysledek = API.BringWindowToTop(lngHWND)

'hlavní problém je zde, nevím jaké zadat přesně argumenty? Co je to v Catii za okno-class, které potřebuji chytit?
ChildHWND = API.FindWindowExA(MainHWND, IntPtr.Zero, "DialogBox", "Part Number")


Přiložené obrázky:

Ing Jan Cinert

Poslat zprávu | Profil
[#4957] | Publikováno: 19.02. 2015 - 11:09
Ahoj,

já řeším něco podobného takto - jde o přejmenování názvu setů s Constraints. V podstatě si dialog sám vyvolám a pošlu do něj CTLR+V a pak Enter. Funguje to celkem obstojně, ale musí se vychytat prodleva, aby se okno stihlo otevřít. Jinak to makro pošle přímo do hlavního okna Catie a je zle...

Win API
<DllImport("User32.dll")> _

Private Shared Function SetForegroundWindow(ByVal point As IntPtr) As Integer
End Function


A funkce pro odeslani stisku klaves do okna...
Private Function RenameConstraintSet(ByVal sSetName As String) As Boolean

Dim CatiaProcess As Process
Try
CATIA.StartCommand("Properties")
CatiaProcess = Process.GetProcessesByName("cnext").FirstOrDefault()

If CatiaProcess IsNot Nothing Then
SetForegroundWindow(CatiaProcess.MainWindowHandle)
System.Threading.Thread.Sleep(200)

' kopirovani Do schranky
Clipboard.SetText(sSetName)

' simulace sticku CTRL+V
SendKeys.SendWait("^v")
System.Threading.Thread.Sleep(200)

' simulace stisku ENTER
SendKeys.SendWait("{ENTER}")

Return True
End If
Catch
MsgBox("Nepodařilo se přejmenovat Set s vazbami!", MsgBoxStyle.Critical, "Přejmenování setu")
Return False
End Try
End Function
Břeťa Doležal

Poslat zprávu | Profil
[#5203] | Publikováno: 27.05. 2015 - 09:45
Řešil někdy někdo, jak případně uživateli zajistit volbu se kterou Catií má makro spolupracovat?

myproc = Process.GetProcessesByName("CNEXT")

If myproc.Count > 1 Then

'!!!! pokud běží více CATII najednou, nutno ošetřit

End If


Jde nějak z procesu vyzískat object
 INFITF.Application 
?

Pokud běží vícero Catií najednou, jakou si makro vybere, pokud dám následující příkaz?
locCATApp = CType(GetObject(, "CATIA.Application"), INFITF.Application)

Je zde nějaké pravidlo? Čas spuštění, poslední aktivní....apod.
Ing Jan Cinert

Poslat zprávu | Profil
[#5205] | Publikováno: 28.05. 2015 - 13:51
Zdravím,

při použití GetObject se chytá první spuštěná instance Catie. Pokud je každá jiná (Release, SP), dá se to poznat, ale pak už nevím jak si chytit tu správnou.

Měl jsem s tím velký problém, když mi současně běžely V5 a V6. Oba procesy se jmenují úplně stejně (někdo nepřemýšlel) a tak se mi pořád chytala V6. Objektový model je podobný, takže jsem se vždycky dlouho vztekal a nemohl přijít na to, kde mám chybu.
Milan Kubišta

Poslat zprávu | Profil
[#5208] | Publikováno: 29.05. 2015 - 09:26
Běžící programy ve Windows jsou odněkud spouštěny. Tento údaj by nepomohl?
Ing Jan Cinert

Poslat zprávu | Profil
[#5210] | Publikováno: 29.05. 2015 - 11:30
To ano, ale problém je v tom, jak se dostat k tomu druhému procesu. Metoda GetObject prostě vezme jeden z nich a s tím pracuje. Pokud je to zrovna ten nesprávný, už s tím nic (alespoň zatím se na tu na to nepřišlo) nenaděláte.

Běžící procesy se dají najít, ale otázka je, jak už psal p. Doležal, jak z procesu vytáhnout objekt CATIA.Application.
Tomáš Drbohlav

Poslat zprávu | Profil
[#5497] | Publikováno: 26.11. 2015 - 11:27
Uživatel odpovídá na příspěvek #5203:

Ahoj Břéťo,
metodou Process.GetProcesses se mi nepodařilo Catii chytit. Ale mělo by to jít přes win api - funkce FindWindow. V příloze máš mikroProjekt, kde se jména všech viditelných oken programů načtou do ListBoxu. Pak můžeš dvojklikem na určitý řádek okno aktivovat (SetForegroundWindow).

Pak můžeš přiložený VB projekt upravit. Vyfiltrovat jen instance Catie a aktivovat dle libosti.

Pomůže to?
Měj se!
T.

Přiložené soubory:
API Win Visible.zip

Břeťa Doležal

Poslat zprávu | Profil
[#5215] | Publikováno: 03.08. 2016 - 12:09
Díky Drbi. Tvoje aplikace vylistuje seznam oken, to bych ještě snad i zvládl. Já ještě chci následně získat objekt aplikace z handleru okna.

Nadějně vypadá tento zdrojový kód pro Excel, ale nevím jestli se tím dokážu prokousat. Win API neznám a vyhýbám se mu, jako čert kříži

První na čem končím je, že neznám tyto konstanty pro Catii, vypadá to jako nějaký klíč z registrů, ale jestli to je na všech počítačích stejné pro Catii, to nevím?:
Const IID_IDispatch As String = "{00020400-0000-0000-C000-000000000046}"
Const OBJID_NATIVEOM As LongPtr = &HFFFFFFF0



Option Explicit

#If Win64 Then

Private Declare PtrSafe Function FindWindowEx Lib "user32" AliAs "FindWindowExA" (ByVal hWnd1 As LongPtr, ByVal hWnd2 As LongPtr, ByVal lpsz1 As String, ByVal lpsz2 As String) As LongPtr
Private Declare PtrSafe Function GetClassName Lib "user32" AliAs "GetClassNameA" (ByVal Hwnd As LongPtr, ByVal lpClassName As String, ByVal nMaxCount As LongPtr) As LongPtr
Private Declare PtrSafe Function IIDFromString Lib "ole32" (ByVal lpsz As LongPtr, ByRef lpiid As UUID) As LongPtr
Private Declare PtrSafe Function AccessibleObjectFromWindow Lib "oleacc" (ByVal Hwnd As LongPtr, ByVal dwId As LongPtr, ByRef riid As UUID, ByRef ppvObject As Object) As LongPtr

#Else

Private Declare Function FindWindowEx Lib "user32" AliAs "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
Private Declare Function GetClassName Lib "user32" AliAs "GetClassNameA" (ByVal hwnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
Private Declare Function IIDFromString Lib "ole32" (ByVal lpsz As Long, ByRef lpiid As UUID) As Long
Private Declare Function AccessibleObjectFromWindow Lib "oleacc" (ByVal hwnd As Long, ByVal dwId As Long, ByRef riid As UUID, ByRef ppvObject As Object) As Long

#End If

Type UUID 'GUID
Data1 As Long
Data2 As Integer
Data3 As Integer
Data4(7) As Byte
End Type

Const IID_IDispatch As String = "{00020400-0000-0000-C000-000000000046}"
Const OBJID_NATIVEOM As LongPtr = &HFFFFFFF0

' Run As enTry point of example
Public Sub Test()

Dim i As Long
Dim xlApps() As Application

If GetAllExcelInstances(xlApps) Then
For i = LBound(xlApps) To UBound(xlApps)
If xlApps(i).Workbooks(1).Name <> ThisWorkbook.Name Then
MsgBox(xlApps(i).Workbooks(1).Name)
End If
Next
End If

End Sub

' Actual Public facing Function to be called in other code
Public Function GetAllExcelInstances(xlApps() As Application) As Long

On Error GoTo MyErrorHandler

Dim n As Long
#If Win64 Then
Dim hWndMain As LongPtr
#Else
Dim hWndMain As Long
#End If
Dim app As Application

' Cater For 100 potential Excel instances, clearly could be better
ReDim xlApps(1 To 100)

hWndMain = FindWindowEx(0&, 0&, "XLMAIN", vbNullString)

Do While hWndMain <> 0
app = GetExcelObjectFromHwnd(hWndMain)
If Not (app Is Nothing) Then
If n = 0 Then
n = n + 1
xlApps(n) = app
ElseIf checkHwnds(xlApps, app.Hwnd) Then
n = n + 1
xlApps(n) = app
End If
End If
hWndMain = FindWindowEx(0&, hWndMain, "XLMAIN", vbNullString)
Loop

If n Then
ReDim Preserve xlApps(1 To n)
GetAllExcelInstances = n
Else
Erase xlApps
End If

Exit Function

MyErrorHandler:
MsgBox "GetAllExcelInstances" & vbCrLf & vbCrLf & "Err = " & Err.Number & vbCrLf & "Description: " & Err.Description

End Function

#If Win64 Then
Private Function checkHwnds(xlApps() As Application, Hwnd As LongPtr) As Boolean
#Else
Private Function checkHwnds(xlApps() As Application, Hwnd As Long) As Boolean
#End If

Dim i As Integer

For i = LBound(xlApps) To UBound(xlApps)
If xlApps(i).Hwnd = Hwnd Then
checkHwnds = False
Exit Function
End If
Next i

checkHwnds = True

End Function

#If Win64 Then
Private Function GetExcelObjectFromHwnd(ByVal hWndMain As LongPtr) As Application
#Else
Private Function GetExcelObjectFromHwnd(ByVal hWndMain As Long) As Application
#End If

On Error GoTo MyErrorHandler

#If Win64 Then
Dim hWndDesk As LongPtr
Dim Hwnd As LongPtr
#Else
Dim hWndDesk As Long
Dim Hwnd As Long
#End If
Dim strText As String
Dim lngRet As Long
Dim iid As UUID
Dim obj As Object

hWndDesk = FindWindowEx(hWndMain, 0&, "XLDESK", vbNullString)

If hWndDesk <> 0 Then

Hwnd = FindWindowEx(hWndDesk, 0, vbNullString, vbNullString)

Do While Hwnd <> 0

strText = String$(100, Chr$(0))
lngRet = CLng(GetClassName(Hwnd, strText, 100))

If Left$(strText, lngRet) = "EXCEL7" Then

Call IIDFromString(StrPtr(IID_IDispatch), iid)

If AccessibleObjectFromWindow(Hwnd, OBJID_NATIVEOM, iid, obj) = 0 Then 'S_OK

GetExcelObjectFromHwnd = obj.Application
Exit Function

End If

End If

Hwnd = FindWindowEx(hWndDesk, Hwnd, vbNullString, vbNullString)
Loop

On Error Resume Next

End If

Exit Function

MyErrorHandler:
MsgBox "GetExcelObjectFromHwnd" & vbCrLf & vbCrLf & "Err = " & Err.Number & vbCrLf & "Description: " & Err.Description

End Function

Public Declare Function GetDesktopWindow Lib "user32" () As Long
Public Declare Function FindWindowEx Lib "user32" AliAs _
"FindWindowExA" (ByVal hWnd1 As Long, ByVal
hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long

Function ExcelInstances() As Long
Dim hWndDesk As Long
Dim hWndXL As Long

'Get a handle to the desktop
hWndDesk = GetDesktopWindow

Do
'Get the Next Excel window
hWndXL = FindWindowEx(GetDesktopWindow, hWndXL, _
"XLMAIN", vbNullString)

'If we got one, increment the count
If hWndXL > 0 Then
ExcelInstances = ExcelInstances + 1
End If

'Loop Until we've found them all
Loop Until hWndXL = 0
End Function



Chce to někoho zkušeného na Win API. Zkusím nejprve zprovoznit toto pro Excel a pak budu zkoušet pro Catii.
Ing Jan Cinert

Poslat zprávu | Profil
[#5944] | Publikováno: 03.08. 2016 - 12:28
Taky si přidám trošku. V nedávné minulosti jsem se tím znovu, už poněkolikáté zabýval, leč bezúspěšně. Přes GetObject si .NET vždycky vytáhne první instanci Catie.

Našel jsem řešení přes tzv. ROT - Running Object Table, kde se přes CLSID dala získat konkrétní Catie. Zde je ale problém v tom, že Catie je tzv. MultiInstance - každá Catie má svůj proces. I touto metodou (která už tak byla nad moje znalosti a jen jsem kód lehce upravoval), jsem se neustále dostával pouze na první běžící instanci. Takže i zde bez úspěchu.

Pak jsem našel někde na zahraničním fóru další slibně vypadající metodu, která přes pro mě opět nedosažitelné knihovny v C uložila objekt CNext do souboru (???) a z něj pak získala konkrétní instanci. Bohužel se zde muselo pracovat s kódy v C a tak jsem to vzdal. Navíc si myslím, že byla nutná nějaké příprava v systému, která se musela dělat u každé stanice, nešlo to nasadit plošně.

No a nakonec přikládám video, kde to evidentně jde - jmenuje se to CSessionManager. I jsem psal autorovi, ale nikdo se neozval.




Takže nezbývá než pátrat dál. Doufám, že se jednou dopátráme ....


Uživatel nepřihlášen

Pro zobrazení obsahu stránky / provedení akce (vytvoření nového téma, napsání odpovědi do diskuse apod.) musíte být přihlášeni.