Just nu i M3-nätverket
Gå till innehåll

Styra annan applikation med shell


JakobS

Rekommendera Poster

Jag vill kunna starta en applikation och sedan styra vilken fil som öppnas och stängs i den.

 

När det gäller office-programmen och en del andra windowsprogram så kan man använda detta:

Set XLApp = CreateObject("Excel.Application")
Set XLFile = XLApp.Workbooks.Open("C:\test1.xlsm")

För andra program kan man använda Shell:

programPath = "C:\Program Files\AnnanApp\AnnnApp.exe"
fileToLaunch = "C:\test.acb"
AnnanApp = Shell(programPath + " " + fileToLaunch, vbNormalFocus)

Men med Shell lyckas jag bara öppna en fil samtidigt som jag öppnar programmet, detta är besvärligt om själva programmet tar en stund att starta.

 

Kan man styra program med Shell på samma sätt som t ex excel?

 

/JakobS

Länk till kommentar
Dela på andra webbplatser

Jag tror det beror lite på programmet och vilka operationer du vill utföra.

 

Notepad kan du tillexempel skriva ut en textfil direkt ifrån kommandoraden. Dock öppnas en ny instans varje gång du anroppar det via kommanoraden.

 

Windows Media Player däremot kan du bara öppna en instans åt gången så där kan du säkert styra.

 

Så det beror nog helt enkelt lite på hur programmet du försöker styra är skapat.

Länk till kommentar
Dela på andra webbplatser

Jag har testat lite med kommandot SendKey och lyckas faktiskt både öppna och stänga filer.

 

Exemplet är med Notpad++ och Notpad:

Sub SendKeysExample()

   Dim AppID, AppID2 As Variant

Öppnar Notepad++ & Notepad
   AppID = Shell("C:\Program Files\Notepad++\notepad++.exe", vbNormalFocus)
   AppID2 = Shell("C:\Windows\notepad.exe", vbNormalFocus)

Väntar så att programmen hinner öppna
   Application.Wait (Now() + 1 / 86400)

Öppnar en fil i Notepad++
   AppActivate AppID
   SendKeys "%aö", True
  Väntar lite
   Application.Wait (Now() + 1 / 86400)
   SendKeys "C:\test.txt", True
   SendKeys "%ö", True

Skriver lite i Notepad
   AppActivate AppID2
   SendKeys "Hello", True
   SendKeys "~", True
   SendKeys "world", True

Byter fil i Notepad++
   AppActivate AppID
 stänger öppen fil
   SendKeys "%at", True
   SendKeys "%aö", True
   Application.Wait (Now() + 1 / 86400)
   SendKeys "C:\test2.txt", True
   SendKeys "%ö", True

Stänger Notepad utan att spara
   AppActivate AppID2
   SendKeys "%aan", True

End Sub

Jag fick dock som man ser lägga in Application.Wait här och där för att vara säker på att programmen var redo att ta emot nästa SendKeys. Så nu har jag två nya frågor:

 

1. Finns det något bättre sätt att känna av när programmet man startat är redo för nästa kommando(SendKeys)? Som det är nu blir det ju en chansning.

 

2. Hur styr man hur fönstret för programmet är placerat och hur stort det är? Detta går lätt med t ex office-programmen:

With XLApp
   .Left = 200
   .Top = 200
   .Height = 140
   .Width = 250
End With

 

(ps. måste man ha med något "slut kommentar"-tecken när man skriver kod här i inläggen, använder jag ' blir allt grönt och svårläst i resten av koden?)

Länk till kommentar
Dela på andra webbplatser

Kod-taggarna är inte perfekta som du märker...

 

till frågan.

 

Det är skillnad på att styra program inom en programgrupp och de som är fristående program. Office-paketet har ett API som du kan jobba emot och styra programmen via. Som i ditt sista kodexempel..

 

Att styra andra program, som Notepad, låter sig inte göras på samma vis då de inte har ett öppet API att jobba emot med kod. Vi ska även minnas att VBA är en begränsad version av VB. I princip allt som går att göra i VB går att göra i VBA men det kan krävas en del tjuvtrix för att få det att fungera.

Minns dock att VB i sig inte är det mest avancerade språket.

 

Med detta vill jag säga - jag tror SendKeys är den metod du kan använda.

Länk till kommentar
Dela på andra webbplatser

Jag har gjort ett program i C# där jag känner av om ett program är igång eller ej och startar det. Mitt första förslag på att begära att man repparerar buggen som krashar programmet var tydligen inte intressant.

 

Men hur som helst så fungerar det så att man hämtar en lista på alla processer som kör och kollar om den process man vill ska vara igång finns med där eller inte. Finns den inte med så startar jag den.

 

Så du skulle kunna göra något liknande. Jag är inte helt hundra på om det finns timers. Men om det finns så kan du låta ett event gå varje sekund där du kollar om processen är igång och sen skickar keys till den.

 

Men som du redan märkt, att styra program som inte är designade att kunna bli styrda är "lite knepigt" och du kommer nog få göra ett flertal fullösningar innan du är klar.

 

Men varför vill du styra notepad för egentligen?

Länk till kommentar
Dela på andra webbplatser

Jag tog bara Notepad som ett enkelt exempel det kan egentligen vara vilket program som helst där man vill växla mellan ett antal filer av dess typ.

 

Min fråga bottnar egentligen i en annan fråga (//eforum.idg.se/topic/331153-anvanda-flera-skarmar/) där man har en dator som har skrivbordet utvidgat till fyra skärmar och man vill ha en meny på en skärm som styr innehållet(excel, word, ie etc.) på de andra.

 

När det gäller office/ie lyckas jag ju både starta, placera applikationen i rätt position(skärm) och maximera för att sedan öppna valda filer. Problemet är att jag också har andra program som visar t ex process-trender, och hur jag får dessa på rätt plats.

 

Exempel på hur man kollar aktiviteten av en process i VBA? Detta kanske även är ett måste om man använder ett makro för att starta en applikation och ett annat för att ändra öppnad fil (för man tappar väl det ID som applikationen får när den startas med Shell då!?)

Ideér om fönsterhanteringen?

Länk till kommentar
Dela på andra webbplatser

Vilken version av office har du? Har du kanske även Visual Studio, professional version? Du kan du istället styra Office via något .Net-språk.

 

VBA - Visual Basic Appliction är begränsad och kan inte så mycket. Vill man utvidga VBA funktioner kan man ladda in DLL-filer från Windows men så jekla mycket kan man helt enkelt inte göra.

 

VBA är till för att styra Excel, Word osv, inte för att styra hela datorn.

 

Men jag säger inte att det inte går att göra det du önskar. Tror bara vägen kan vara längre än du tror för att nå ditt mål.

 

.Net-språken är med avancerade fast ska sägas, stödet för att styra Office via dessa är inget jag orkar ge mig in på. Att certifiera kod man skrivit så den fungerar för alla... nej tack. En djungel.

 

Fönsterhantering, jag gav dig väl tips i den tråden?

Länk till kommentar
Dela på andra webbplatser

Jag kör Office2010 på Win7. (det är ju inte alltid så där helkul när vissa användare man har att göra med ligger kvar på Office2003 på XP!)

 

Vad gäller fönsterhanteringen så måste den vara så automatiskt som möjligt (användarna är i allmänhet bekväma) och det var för de program som startats med shell som jag stötte på problem (office-programmen är det enkelt, se tidigare inlägg).

 

Jag har sökt lite och kommit fram till följande som faktiskt funkar (ligger på en nivå där jag normalt inte rör mig i VBA-kodning):

Option Explicit

Public Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" (ByVal lpClassName As Any, ByVal lpWindowName As String) As Long

Public Declare Function ShowWindow Lib "user32.dll" (ByVal hwnd As Long, ByVal nCmdShow As Long) As Long
Public Const SW_MAXIMIZE = 3
Public Const SW_SHOWMINIMIZED = 2
Public Const SW_SHOWNORMAL = 1

Public Declare Function SetWindowPos Lib "user32.dll" (ByVal hwnd As Long, ByVal hWndInsertAfter As Long, ByVal x As Long, ByVal y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long
Public Const SWP_NOZORDER As Long = &H4
Public Const SWP_SHOWWINDOW As Long = &H40
Public Const SWP_NOSIZE As Long = &H1

Sub PlaceraProgrammet()
   Dim AppID As Variant
   Dim AppHandtag As Long

   'Öppnar Notepad
   AppID = Shell("C:\Windows\notepad.exe", vbNormalFocus)

   'Tar reda på fönstrets "handtag" - måste veta vad som står i listen
   AppHandtag = FindWindow(vbNullString, "Namnlös - Anteckningar")

   'Placerar där jag vill ha det - x=1700 ger mig skärm 2 vid 1680x1050
   SetWindowPos AppHandtag, 0, 1700, 10, 500, 500, SWP_NOZORDER Or SWP_SHOWWINDOW Or SWP_NOSIZE

   'Maximerar fönstret på den skärm där det ligger
   ShowWindow AppHandtag, SW_MAXIMIZE
End Sub

 

Det som känns lite sådär är att använda fönstrets "Caption" för att hitta "handtaget", det kan ju faktiskt finnas flera som har samma text, jag har dock provat att öppna och placerat ut två notepad efter varandra och det funkar trots att de är lika.

 

När det gäller att känna av om ett program öppnat klart och är redo för en SendKeys så går jag bet, det verkar som att man måste veta ungefär hur lång tid som behövs och vänta ut det!?

Länk till kommentar
Dela på andra webbplatser

Tänkte att jag skulle få tag i "handtaget" för applikationsfönstret på ett lite bättre sätt och hittade en funktion som jag tycker borde hjälpa!?

Public Declare Function GetActiveWindow Lib "user32" () As Long

När jag just startat en applikation så ligger väl den "överst"=aktiv!? Men när jag kör makrot så blir värdet 0 men när jag stegar makrot så får jag (som sig bör) hantaget för VBA-editorn. :(

 

Har även provat

Public Declare Function GetTopWindow Lib "user32" (ByVal hwnd As Long) As Long

som när hwnd har värdet Null borde ge mig översta fönstret(!?) men här vet jag inte riktigt vad jag får för handtag(GetWindowText ger "MSCTFIME UI")! Har en variabel av typen Long värdet Null när jag deklarerar den och inte ger den ngt annat värde?

 

Som sagt, jag är en bit utanför mina vanliga "domäner"! :blink:

Länk till kommentar
Dela på andra webbplatser

Stega inte i koden, då kan den som du ser ge lite konstiga resultat. Använde istället Debug.print och skriv med denna till direktfönstret i VBA-editorn så får du en bättre koll på vad som sker i falla som detta.

 

Du är lite utanför det jag brukar pilla med i VBA men du verkar ha hyfsad koll på vad du gör...

Länk till kommentar
Dela på andra webbplatser

Mmh, du skulle inte vara intresserad av att ladda upp ett exempel med det du skapat? En xls-fil går bra...

 

Och ja, som sagt, i princip kan man nå hela Windows API från VBA. Inte helt smidigt och kanske inte så MS tänkt sig man ska nyttja VBA men det går...

Länk till kommentar
Dela på andra webbplatser

Bifogar här ett exempel på hur man får tag på handtaget. Man får dock inte vara "för snabb" i koden när man söker för då har programmet eventuellt inte hunnit starta ordentligt och man får inte handtaget för dess huvudfönster! OBS! Man måste återvända till excel för att se resultatet!

FindWindowHndlFromInstanceHndl.zip

 

Nu börjar jag få ihop fragmenten av funktioner som jag behöver för att starta och styra placeringen av program och visa filer från en excel-meny. Jag kan lägga upp en exempelfil när jag väl knåpat ihop det hela!

 

ps. av någon anledning så kan jag inte starta "Skärmtangentbordet" (osk.exe) som finns i win7 med shell-kommandot, det fungerar ju å andra sidan lite speciellt!?

Länk till kommentar
Dela på andra webbplatser

Arkiverat

Det här ämnet är nu arkiverat och är stängt för ytterligare svar.

×
×
  • Skapa nytt...