Warum funktioniert der Code im Compiler und nicht als exe?

Anfängerfragen zum Programmieren mit PureBasic.
Benutzeravatar
Zerosurf
Beiträge: 131
Registriert: 11.10.2005 15:46

Warum funktioniert der Code im Compiler und nicht als exe?

Beitrag von Zerosurf »

Kurze Erklärung:

Eine laufende App soll ausgewählt werden die dann immer nach Start des Programms in den Vordergrund kommen soll.

Bei der compilierten exe funktioniert das Auswählen und anschließende in den Vordergrund bringen ja recht gut, aber nach dem die .ini Datei geschrieben wurde funktioniert das Programm beim neuerlichen Start dann nicht mehr.
Im Purebasic Editor funktioniert alles wunderbar!

Wo liegt da der Hund begraben?

Code: Alles auswählen

EnableExplicit

Define Title$, hWndnr, App$

Global PID
Global MODULEENTRY32.MODULEENTRY32
Global Snapshot

Procedure ListWindows(hwnd,lParam)
  Protected.s title = Space(1000),class = Space(1000)
  If GetWindowLong_(hwnd,#GWL_EXSTYLE) ! #WS_EX_TOOLWINDOW And GetWindowLong_(hwnd,#GWL_STYLE) & #WS_VISIBLE
    GetClassName_(hwnd,class,1000)
    GetWindowText_(hwnd,title,1000)
    If title <> ""
      MODULEENTRY32\dwSize = SizeOf(MODULEENTRY32)
      GetWindowThreadProcessId_(FindWindow_(0,title), @PID)
      Snapshot = CreateToolhelp32Snapshot_(#TH32CS_SNAPMODULE, PID)
      If Module32First_(Snapshot, MODULEENTRY32)
        ;Debug PeekS(@MODULEENTRY32\szExePath)
        ;Debug "Title: "+title+" | Class: "+class+" | Handle: "+Str(hwnd)+" | App: "+GetFilePart(PeekS(@MODULEENTRY32\szExePath))+" | Path: "+PeekS(@MODULEENTRY32\szExePath)
        ;AddGadgetItem (0, -1, title+Chr(10)+class+Chr(10)+Str(hwnd)+Chr(10)+GetFilePart(PeekS(@MODULEENTRY32\szExePath))+Chr(10)+PeekS(@MODULEENTRY32\szExePath)) 
        AddGadgetItem (0, -1, title+Chr(10)+GetFilePart(PeekS(@MODULEENTRY32\szExePath))+Chr(10)+PeekS(@MODULEENTRY32\szExePath)) 
      EndIf
      CloseHandle_(Snapshot)
    EndIf
  EndIf
  ProcedureReturn #True
EndProcedure

Procedure.I GetSelectedColumn(ListIconID.I)
  Protected CursorLocation.POINT
  Protected HitInfo.LVHITTESTINFO
  GetCursorPos_(CursorLocation)
  MapWindowPoints_(0, GadgetID(ListIconID), CursorLocation, 1)             
  Hitinfo\pt\x = CursorLocation\x
  HitInfo\pt\y = CursorLocation\y
  SendMessage_(GadgetID(ListIconID), #LVM_SUBITEMHITTEST, 0, HitInfo)
  ProcedureReturn HitInfo\iSubItem 
EndProcedure

Procedure.s GetProcessWindowText(Process.s)
  Protected handle.i
  Protected pid.i
  Protected proc.PROCESSENTRY32
  Protected buffer.s
  Protected check.i
  handle = CreateToolhelp32Snapshot_(#TH32CS_SNAPPROCESS,#Null);<- snapshot handle holen
  If Not handle = #INVALID_HANDLE_VALUE                        ;<- wenn das handle ok ist weitermachen
    proc\dwSize = SizeOf(PROCESSENTRY32)                       ;<- um die struktur benutzen zu können muss die größe übergeben werden
    If Process32First_(handle,@proc)                           ;<- den ersten eintrag in der prozess liste holen
      Repeat
        If PeekS(@proc\szExeFile) = Process;<- schauen ob der eintrag der gesuchte ist (string vergleich)
          pid = proc\th32ProcessID         ;<- wenn der eintrag der gesuchte ist die process id auslesen
          Break                            ;<- die suche abbrechen da die process id gefunden wurde
        EndIf
      Until Process32Next_(handle,@proc) = #False;<- falscher eintrag? dann weitersuchen
    EndIf
    CloseHandle_(handle);<- handle wieder freigeben
    If pid              ;<- wurde die process id gefunden?
      handle = GetWindow_(GetDesktopWindow_(),#GW_CHILD);<- das erste fenster handle holen (erstes fenster is immer das 'child' des desktops)
      If handle                                         ;<- gibt es ein fenster weitermachen
        Repeat
          GetWindowThreadProcessId_(handle,@check);<- process id des fensters ermitteln
          If check = pid And IsWindowVisible_(handle);<- wenn das fenster sichtbar (reicht meist um das richtige fenster zu bekommen *) ist und die process id die gesuchte ist weitermachen
            check = GetWindowTextLength_(handle)     ;<- die länge des fenster titels ermitteln (in chars)
            If check                                 ;<- gibt es eine länge weitermachen
              buffer = Space(check)                  ;<- speicher für den titel reservieren
              If GetWindowText_(handle,@buffer,check + 1) = check;<- den titel auslesen (wichtig die api will einen char mehr! - siehe msdn)
                ProcedureReturn buffer                           ;<- den titel zurückgeben
              EndIf
            EndIf
          EndIf
          handle = GetWindow_(handle,#GW_HWNDNEXT);<- falsches fenster - weitersuchen
        Until handle = #Null
      EndIf
    EndIf
  EndIf
  ProcedureReturn #Null$;<- nichts wurde gefunden
EndProcedure

If FileSize("AppForFocus.ini") => 0
  ;Debug "Datei existiert!"
  ReadFile(0, "AppForFocus.ini")
  App$ = ReadString(0)
  CloseFile(0)
  Title$ = GetProcessWindowText(App$)
  ;Debug Title$
  hWndnr = FindWindow_(0, Title$)
  ;Debug hWndnr
  SendMessage_(GetForegroundWindow_(), #WM_SYSCOMMAND, #SC_HOTKEY, hWndnr)
  
Else
  ;Debug "Datei existiert nicht!"
  If OpenWindow(0, 0, 0, 1010, 250, "App Info:", #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_SizeGadget)
    TextGadget(1, 5, 5, 1000, 20, "RightClick to select app to be focused", #PB_Text_Center)
    ListIconGadget(0, 5, 30, 1000, 190, "Title", 235, #PB_ListIcon_FullRowSelect | #PB_ListIcon_AlwaysShowSelection | #PB_ListIcon_GridLines)
    ;AddGadgetColumn(0, 1, "Class", 200)
    ;AddGadgetColumn(0, 2, "Handle", 60)
    AddGadgetColumn(0, 3, "App", 235)
    AddGadgetColumn(0, 4, "Path", 500)
    ButtonGadget(2, 455, 225, 100, 20, "Refresh")
    EnumChildWindows_(FindWindow_("ToolbarWindow32",0),@ListWindows(),0)
    
    Repeat
      Select WaitWindowEvent()
        Case #PB_Event_CloseWindow
          Break
        Case #PB_Event_Gadget
          If EventGadget() = 0 And EventType() = #PB_EventType_RightClick
            ;Debug GetGadgetItemText(0, GetGadgetState(0), 2)
            If MessageRequester("Selected App", GetGadgetItemText(0, GetGadgetState(0), 1) + Chr(13) + Chr(13) + "will be focused and setting will be saved to:" + Chr(13) + Chr(13) + "AppForFocus.ini" + Chr(13) + Chr(13) + "To reset the setting - just delete " + Chr(34) + "AppForFocus.ini" + Chr(34), #PB_MessageRequester_YesNo | #PB_MessageRequester_Info)  = #PB_MessageRequester_Yes
              
              If CreateFile(0, "AppForFocus.ini")
                WriteString(0, GetGadgetItemText(0, GetGadgetState(0), 1))
                CloseFile(0)
              Else
                MessageRequester("Information","Couldn't write .ini file!")
              EndIf
              SendMessage_(GetForegroundWindow_(), #WM_SYSCOMMAND, #SC_HOTKEY, FindWindow_(0, GetProcessWindowText(GetGadgetItemText(0, GetGadgetState(0), 1))))
              End
            Else
            EndIf 
          EndIf
          If EventGadget() = 2 And EventType() = #PB_EventType_LeftClick
            RunProgram(ProgramFilename())
            End
          EndIf
      EndSelect
    ForEver
  EndIf
EndIf
PureBasic 6.00 | Windows 10 pro (x64)
Benutzeravatar
Kiffi
Beiträge: 10621
Registriert: 08.09.2004 08:21
Wohnort: Amphibios 9

Re: Warum funktioniert der Code im Compiler und nicht als ex

Beitrag von Kiffi »

Eine INI, die wir bei Dir ohne Pfadangabe geschrieben/gelesen wird, wird dort erwartet, wo auch Dein Programm läuft.

Wenn Dein Programm mit Debugger gestartet wird (und Du es nicht anders eingestellt hast), dann wird eine temporäre EXE nach Namensschema "PureBasic_Compilation[Nummer].exe" im Temp-Ordner erstellt und gestartet. Dort wird dann auch Deine INI gelesen/geschrieben.

Solltest Du Dein Programm als EXE erstellen und starten, dann wird die INI in dem Pfad, wo Du die kompilierte EXE erstellt hast, gelesen/geschrieben.

Kurzum: Mach mal ein Häkchen in den Compiler-Optionen bei "Temporäres Executable im Quellcode-Verzeichnis erstellen":

Bild
Hygge
Benutzeravatar
Zerosurf
Beiträge: 131
Registriert: 11.10.2005 15:46

Re: Warum funktioniert der Code im Compiler und nicht als ex

Beitrag von Zerosurf »

Die ini Datei wird schon am richtigen Platz erstellt - ich hab es auch mit einer absoluten Pfadangabe probiert - D:\AppForFocus.ini - im Purebasic Compiler funktionert alles wie gewollt, nur bei der exe haut es dann nicht hin! :-(
PureBasic 6.00 | Windows 10 pro (x64)
Benutzeravatar
Kiffi
Beiträge: 10621
Registriert: 08.09.2004 08:21
Wohnort: Amphibios 9

Re: Warum funktioniert der Code im Compiler und nicht als ex

Beitrag von Kiffi »

Funktioniert bei mir (mit fester Pfadangabe zur INI). Sowohl im Debugger als auch als kompilierte Exe.
Hygge
Benutzeravatar
Zerosurf
Beiträge: 131
Registriert: 11.10.2005 15:46

Re: Warum funktioniert der Code im Compiler und nicht als ex

Beitrag von Zerosurf »

Kiffi hat geschrieben:Funktioniert bei mir (mit fester Pfadangabe zur INI). Sowohl im Debugger als auch als kompilierte Exe.
OK, habs jetzt nochmal überprüft - die exe funktioniert nur, wenn ich sie als Administrator ausführe! (Egal ob mit oder ohne Pfadangabe)

Wie kann ich es einstellen, daß die auch ohne Administrator funktioniert?
PureBasic 6.00 | Windows 10 pro (x64)
Benutzeravatar
Mijikai
Beiträge: 754
Registriert: 25.09.2016 01:42

Re: Warum funktioniert der Code im Compiler und nicht als ex

Beitrag von Mijikai »

Evtl. mal die Virtualisierung ausschalten und überprüfen ob das Programm nicht doch geschützte Pfade verwendet.
Den Code habe ich nicht getestet da zu wenig Errorhandling.
Benutzeravatar
mk-soft
Beiträge: 3700
Registriert: 24.11.2004 13:12
Wohnort: Germany

Re: Warum funktioniert der Code im Compiler und nicht als ex

Beitrag von mk-soft »

Einstellung Dateien gehören in den User Ordner %ProgramData%. Bei allen anderen Ordner kann es zu Berechtigungsfehlern führen.
In dem Ordner muss man noch ein Ordner für die Company und Application anlegen.

Beispiel für Programm Daten und Projekt Daten als XML. Finde ich besser als INI-Dateien und können direkt mit ein Befehl geladen oder gespeichert werden. Einfach nur die Struktur udtProgramData anpassen.

Code: Alles auswählen

;-TOP ProgramData and CheckWindowPosition, by mk-soft, v0.6

EnableExplicit

; Change names
#CompanyName = "mk-soft"
#ApplicationName = "MyApp"

Structure udtWindowPosition
  x.i
  y.i
  Width.i
  Height.i
  State.i
EndStructure

Structure udtProgramData
  Window.udtWindowPosition
  DataPath.s
  LastPath.s
  List LastFiles.s()
EndStructure

Structure udtProjectData
  Version.i
  Date.s
  ; Data
  ;TODO
  List Text.s() 
EndStructure

Global ProgramData.udtProgramData
Global ProjectData.udtProjectData

; ----

Enumeration
  #MainWindow
EndEnumeration

Enumeration
  #MainMenu
EndEnumeration

Enumeration
  #MainMenuItem_Exit
  #MainMenuItem_LoadProject
  #MainMenuItem_SaveProject
EndEnumeration

Enumeration
  #MainStatusBar
EndEnumeration

; ----

Procedure GetWindowPosition(Window)
  With ProgramData\Window
    ; Get window state mode 
    \State = GetWindowState(Window)
    ; Set window state to normal
    SetWindowState(Window, #PB_Window_Normal)
    ; Get window postion and size
    \x = WindowX(Window)
    \y = WindowY(Window)
    \Width = WindowWidth(Window)
    \Height = WindowHeight(Window)
  EndWith
EndProcedure

Procedure SetWindowPosition(Window)
  Protected cnt, i
  
  With ProgramData\Window
    ; Check the position and size of the program is aviable
    If \Width <= 0 Or \Height <= 0
      ProcedureReturn #False
    EndIf
    ; Checks that the position and size of the program fits on the available desktop.
    cnt = ExamineDesktops()
    For i = 0 To cnt - 1
      If \x >= DesktopX(i) And \x < DesktopX(i) + DesktopWidth(i)
        If \y >= DesktopY(i) And \y < DesktopY(i) + DesktopHeight(i)
          If \x - DesktopX(i) + \Width <= DesktopWidth(i) And \y - DesktopY(i) + \Height <= DesktopHeight(i)
            ResizeWindow(Window, \x, \y, \Width, \Height)
            SetWindowState(Window, \State)
            ProcedureReturn #True
          EndIf
        EndIf
      EndIf
    Next
    ProcedureReturn #False
  EndWith
EndProcedure

; ----

Procedure LoadProgramData(FileName.s = "ProgramData.xml")
  Protected basepath.s, subpath.s, datapath.s, filepath.s, xml
  
  CompilerIf #PB_Compiler_OS = #PB_OS_Linux
    basepath = GetHomeDirectory()
    subpath = basepath + "." + #CompanyName + #PS$
  CompilerElse
    basepath = GetUserDirectory(#PB_Directory_ProgramData)
    subpath = basepath + #CompanyName + #PS$
  CompilerEndIf
  datapath = subpath  + #ApplicationName + #PS$
  filepath = datapath + FileName
  If FileSize(filepath) > 0 Or 1
    xml = LoadXML(#PB_Any, filepath)
    If xml And XMLStatus(xml) = #PB_XML_Success
      ExtractXMLStructure(MainXMLNode(xml), @ProgramData, udtProgramData, #PB_XML_NoCase)
      FreeXML(xml)
      ProgramData\DataPath = datapath
      ProcedureReturn #True
    EndIf
  EndIf
  ProgramData\DataPath = ""
  ProcedureReturn #False
EndProcedure

; ----

Procedure SaveProgramData(FileName.s = "ProgramData.xml")
  Protected basepath.s, subpath.s, datapath.s, filepath.s, xml
  
  CompilerIf #PB_Compiler_OS = #PB_OS_Linux
    basepath = GetHomeDirectory()
    subpath = basepath + "." + #CompanyName + #PS$
  CompilerElse
    basepath = GetUserDirectory(#PB_Directory_ProgramData)
    subpath = basepath + #CompanyName + #PS$
  CompilerEndIf
  datapath = subpath  + #ApplicationName + #PS$
  If FileSize(datapath) <> -2
    If FileSize(subpath) <> -2
      CreateDirectory(subpath)
    EndIf
    If FileSize(datapath) <> -2
      CreateDirectory(datapath)
    EndIf
  EndIf
  filepath = datapath + FileName
  xml = CreateXML(#PB_Any)
  If xml
    If InsertXMLStructure(RootXMLNode(xml), @ProgramData, udtProgramData)
      FormatXML(xml, #PB_XML_ReFormat)
      SaveXML(xml, filepath)
    EndIf
    FreeXML(xml)
  EndIf
EndProcedure

; ----

Procedure LoadProjectData(FileName.s, *ProjectData.udtProjectData)
  Protected xml
  
  If FileSize(FileName) > 0
    xml = LoadXML(#PB_Any, FileName)
    If xml And XMLStatus(xml) = #PB_XML_Success
      ExtractXMLStructure(MainXMLNode(xml), *ProjectData, udtProjectData, #PB_XML_NoCase)
      FreeXML(xml)
      ProcedureReturn #True
    EndIf
  EndIf
  ProcedureReturn #False
EndProcedure

; ----

Procedure SaveProjectData(FileName.s, *ProjectData.udtProjectData)
  Protected r1, xml
  
  xml = CreateXML(#PB_Any)
  If xml
    *ProjectData\Version = 101
    *ProjectData\Date = FormatDate("%YYYY-%MM-%DD %HH.%II.%SS", Date())
    If InsertXMLStructure(RootXMLNode(xml), *ProjectData, udtProjectData)
      FormatXML(xml, #PB_XML_ReFormat)
      If SaveXML(xml, FileName)
        r1 = #True
      Else
        r1 = #False
      EndIf
    EndIf
    FreeXML(xml)
  EndIf
  ProcedureReturn r1
EndProcedure

; ----

Procedure Main()
  Protected state, file.s
  
  LoadProgramData()
  
  #MainStyle = #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget | #PB_Window_Invisible
  
  OpenWindow(#MainWindow, #PB_Ignore, #PB_Ignore, 800, 600, "Program-Data", #MainStyle)
    
  SetWindowPosition(#MainWindow)
  
  CreateMenu(#MainMenu, WindowID(#MainWindow))
  MenuTitle("&File")
  MenuItem(#MainMenuItem_LoadProject, "&Load Project")
  MenuItem(#MainMenuItem_SaveProject, "&Save Project")
  MenuBar()
  MenuItem(#MainMenuItem_Exit, "E&xit")
  
  CreateStatusBar(#MainStatusBar, WindowID(#MainWindow))
  AddStatusBarField(#PB_Ignore)
  StatusBarText(#MainStatusBar, 0, "ProgramDataPath: " + ProgramData\DataPath)
  
  HideWindow(#MainWindow, #False)
  
  Repeat
    Select WaitWindowEvent()
      Case #PB_Event_Menu
        Select EventMenu()
          CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
          Case #PB_Menu_Quit
            Break
          CompilerEndIf
          
        Case #MainMenuItem_LoadProject
          file = OpenFileRequester("Load Project", ProgramData\LastPath, "", 0)
          If file
            If Not LoadProjectData(file, @ProjectData)
              MessageRequester("Error", "Load Projekt" + #LF$ + file)
            Else
              ProgramData\LastPath = GetFilePart(file)
            EndIf
          EndIf
          
        Case #MainMenuItem_SaveProject
          file = SaveFileRequester("Save Project", ProgramData\LastPath + "project.xml", "", 0)
          If file
            If Not SaveProjectData(file, @ProjectData)
              MessageRequester("Error", "Save Projekt" + #LF$ + file)
            Else
              ProgramData\LastPath = GetFilePart(file)
            EndIf
          EndIf
          
        Case #MainMenuItem_Exit
          Break
          
      EndSelect
      
      Case #PB_Event_CloseWindow
        Break
    EndSelect
  ForEver
  
  GetWindowPosition(#MainWindow)
  
  SaveProgramData()
  
EndProcedure : Main()
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Re: Warum funktioniert der Code im Compiler und nicht als ex

Beitrag von ts-soft »

Hier mal meine Version:

Code: Alles auswählen

Procedure.s GetPrefsFile(AppName.s, FileName.s = "AppForFocus.ini", Publisher.s = "Zerosoft")
  Protected Path.s, slash.s
  
  CompilerSelect #PB_Compiler_OS
    CompilerCase #PB_OS_Windows
      slash = "\"
      Path = GetEnvironmentVariable("APPDATA") + "\"
    CompilerDefault
      slash = "/"
      Path = GetHomeDirectory() + "."    
  CompilerEndSelect
  If Publisher
    Path + Publisher + slash
    If Not FileSize(Path) = - 2
      CreateDirectory(Path)
    EndIf
  EndIf
  Path + AppName + slash
  If Not FileSize(Path) = - 2
    CreateDirectory(Path)
  EndIf
  If FileSize(Path) = -2
    ProcedureReturn Path + FileName
  EndIf
EndProcedure
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Benutzeravatar
HeX0R
Beiträge: 2958
Registriert: 10.09.2004 09:59
Computerausstattung: AMD Ryzen 7 5800X
96Gig Ram
NVIDIA GEFORCE RTX 3060TI/8Gig
Win10 64Bit
G19 Tastatur
2x 24" + 1x27" Monitore
Glorious O Wireless Maus
PB 3.x-PB 6.x
Oculus Quest 2
Kontaktdaten:

Re: Warum funktioniert der Code im Compiler und nicht als ex

Beitrag von HeX0R »

slash ist mittlerweile #PS$
Benutzeravatar
Zerosurf
Beiträge: 131
Registriert: 11.10.2005 15:46

Re: Warum funktioniert der Code im Compiler und nicht als ex

Beitrag von Zerosurf »

Könnt ihr mir bitte Feedback geben, ob der Code bei euch so funktioniert?

Code: Alles auswählen

EnableExplicit

Define Title$, hWndnr, App$

Global PID
Global MODULEENTRY32.MODULEENTRY32
Global Snapshot

Procedure ListWindows(hwnd,lParam)
  Protected.s title = Space(1000),class = Space(1000)
  If GetWindowLong_(hwnd,#GWL_EXSTYLE) ! #WS_EX_TOOLWINDOW And GetWindowLong_(hwnd,#GWL_STYLE) & #WS_VISIBLE
    GetClassName_(hwnd,class,1000)
    GetWindowText_(hwnd,title,1000)
    If title <> ""
      MODULEENTRY32\dwSize = SizeOf(MODULEENTRY32)
      GetWindowThreadProcessId_(FindWindow_(0,title), @PID)
      Snapshot = CreateToolhelp32Snapshot_(#TH32CS_SNAPMODULE, PID)
      If Module32First_(Snapshot, MODULEENTRY32)
        ;Debug PeekS(@MODULEENTRY32\szExePath)
        ;Debug "Title: "+title+" | Class: "+class+" | Handle: "+Str(hwnd)+" | App: "+GetFilePart(PeekS(@MODULEENTRY32\szExePath))+" | Path: "+PeekS(@MODULEENTRY32\szExePath)
        ;AddGadgetItem (0, -1, title+Chr(10)+class+Chr(10)+Str(hwnd)+Chr(10)+GetFilePart(PeekS(@MODULEENTRY32\szExePath))+Chr(10)+PeekS(@MODULEENTRY32\szExePath)) 
        AddGadgetItem (0, -1, title+Chr(10)+GetFilePart(PeekS(@MODULEENTRY32\szExePath))+Chr(10)+PeekS(@MODULEENTRY32\szExePath)) 
      EndIf
      CloseHandle_(Snapshot)
    EndIf
  EndIf
  ProcedureReturn #True
EndProcedure

Procedure.I GetSelectedColumn(ListIconID.I)
  Protected CursorLocation.POINT
  Protected HitInfo.LVHITTESTINFO
  GetCursorPos_(CursorLocation)
  MapWindowPoints_(0, GadgetID(ListIconID), CursorLocation, 1)             
  Hitinfo\pt\x = CursorLocation\x
  HitInfo\pt\y = CursorLocation\y
  SendMessage_(GadgetID(ListIconID), #LVM_SUBITEMHITTEST, 0, HitInfo)
  ProcedureReturn HitInfo\iSubItem 
EndProcedure

Procedure.s GetProcessWindowText(Process.s)
  Protected handle.i
  Protected pid.i
  Protected proc.PROCESSENTRY32
  Protected buffer.s
  Protected check.i
  handle = CreateToolhelp32Snapshot_(#TH32CS_SNAPPROCESS,#Null);<- snapshot handle holen
  If Not handle = #INVALID_HANDLE_VALUE                        ;<- wenn das handle ok ist weitermachen
    proc\dwSize = SizeOf(PROCESSENTRY32)                       ;<- um die struktur benutzen zu können muss die größe übergeben werden
    If Process32First_(handle,@proc)                           ;<- den ersten eintrag in der prozess liste holen
      Repeat
        If PeekS(@proc\szExeFile) = Process;<- schauen ob der eintrag der gesuchte ist (string vergleich)
          pid = proc\th32ProcessID         ;<- wenn der eintrag der gesuchte ist die process id auslesen
          Break                            ;<- die suche abbrechen da die process id gefunden wurde
        EndIf
      Until Process32Next_(handle,@proc) = #False;<- falscher eintrag? dann weitersuchen
    EndIf
    CloseHandle_(handle);<- handle wieder freigeben
    If pid              ;<- wurde die process id gefunden?
      handle = GetWindow_(GetDesktopWindow_(),#GW_CHILD);<- das erste fenster handle holen (erstes fenster is immer das 'child' des desktops)
      If handle                                         ;<- gibt es ein fenster weitermachen
        Repeat
          GetWindowThreadProcessId_(handle,@check);<- process id des fensters ermitteln
          If check = pid And IsWindowVisible_(handle);<- wenn das fenster sichtbar (reicht meist um das richtige fenster zu bekommen *) ist und die process id die gesuchte ist weitermachen
            check = GetWindowTextLength_(handle)     ;<- die länge des fenster titels ermitteln (in chars)
            If check                                 ;<- gibt es eine länge weitermachen
              buffer = Space(check)                  ;<- speicher für den titel reservieren
              If GetWindowText_(handle,@buffer,check + 1) = check;<- den titel auslesen (wichtig die api will einen char mehr! - siehe msdn)
                ProcedureReturn buffer                           ;<- den titel zurückgeben
              EndIf
            EndIf
          EndIf
          handle = GetWindow_(handle,#GW_HWNDNEXT);<- falsches fenster - weitersuchen
        Until handle = #Null
      EndIf
    EndIf
  EndIf
  ProcedureReturn #Null$;<- nichts wurde gefunden
EndProcedure

Procedure.s GetPrefsFile(AppName.s, FileName.s = "AppForFocus.ini", Publisher.s = "DeepBlueMind")
  Protected Path.s, slash.s
  
  CompilerSelect #PB_Compiler_OS
    CompilerCase #PB_OS_Windows
      slash = "\"
      Path = GetEnvironmentVariable("APPDATA") + "\"
    CompilerDefault
      slash = "/"
      Path = GetHomeDirectory() + "."   
  CompilerEndSelect
  If Publisher
    Path + Publisher + slash
    If Not FileSize(Path) = - 2
      CreateDirectory(Path)
    EndIf
  EndIf
  Path + AppName + slash
  If Not FileSize(Path) = - 2
    CreateDirectory(Path)
  EndIf
  If FileSize(Path) = -2
    ProcedureReturn Path + FileName
  EndIf
EndProcedure

If FileSize(GetPrefsFile("FocusApp", "AppForFocus.ini", "DeepBlueMind")) => 0
  ReadFile(0, GetPrefsFile("FocusApp", "AppForFocus.ini", "DeepBlueMind"))
  App$ = ReadString(0)
  CloseFile(0)
  Title$ = GetProcessWindowText(App$)
  ;Debug Title$
  hWndnr = FindWindow_(0, Title$)
  ;Debug hWndnr
  SendMessage_(GetForegroundWindow_(), #WM_SYSCOMMAND, #SC_HOTKEY, hWndnr)
  
Else
  ;Debug "Datei existiert nicht!"
  If OpenWindow(0, 0, 0, 1010, 250, "App Info:", #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_SizeGadget)
    TextGadget(1, 5, 5, 1000, 20, "RightClick to select app to be focused", #PB_Text_Center)
    ListIconGadget(0, 5, 30, 1000, 190, "Title", 235, #PB_ListIcon_FullRowSelect | #PB_ListIcon_AlwaysShowSelection | #PB_ListIcon_GridLines)
    ;AddGadgetColumn(0, 1, "Class", 200)
    ;AddGadgetColumn(0, 2, "Handle", 60)
    AddGadgetColumn(0, 3, "App", 235)
    AddGadgetColumn(0, 4, "Path", 500)
    ButtonGadget(2, 455, 225, 100, 20, "Refresh")
    EnumChildWindows_(FindWindow_("ToolbarWindow32",0),@ListWindows(),0)
    
    Repeat
      Select WaitWindowEvent()
        Case #PB_Event_CloseWindow
          Break
        Case #PB_Event_Gadget
          If EventGadget() = 0 And EventType() = #PB_EventType_RightClick
            ;Debug GetGadgetItemText(0, GetGadgetState(0), 2)
            If MessageRequester("Selected App", GetGadgetItemText(0, GetGadgetState(0), 1) + Chr(13) + Chr(13) + "will be focused and setting will be saved to:" + Chr(13) + Chr(13) + "AppForFocus.ini" + Chr(13) + Chr(13) + "To reset the setting - just delete " + Chr(34) + "AppForFocus.ini" + Chr(34), #PB_MessageRequester_YesNo | #PB_MessageRequester_Info)  = #PB_MessageRequester_Yes
              ;If Not FileSize(GetEnvironmentVariable("APPDATA") + #PS$ + "FocusApp") = - 2
              ;CreateDirectory(GetEnvironmentVariable("APPDATA") + #PS$ + "FocusApp")
              ;EndIf
              If FileSize(GetPrefsFile("FocusApp", "AppForFocus.ini", "DeepBlueMind")) = -1
                CreateFile(0, GetPrefsFile("FocusApp", "AppForFocus.ini", "DeepBlueMind"))
                WriteString(0, GetGadgetItemText(0, GetGadgetState(0), 1))
                CloseFile(0)
              Else
                MessageRequester("Information","Couldn't write .ini file!")
              EndIf
              SendMessage_(GetForegroundWindow_(), #WM_SYSCOMMAND, #SC_HOTKEY, FindWindow_(0, GetProcessWindowText(GetGadgetItemText(0, GetGadgetState(0), 1))))
              End
            Else
            EndIf 
          EndIf
          If EventGadget() = 2 And EventType() = #PB_EventType_LeftClick
            RunProgram(ProgramFilename())
            End
          EndIf
      EndSelect
    ForEver
  EndIf
EndIf
PureBasic 6.00 | Windows 10 pro (x64)
Antworten