Beiträge von chesstiger

    Dann ist TimerInit/TimerDiff nicht das richtige für dich. Speichere dir einen Timestamp (entweder a la "yyyy-mm-dd hh:ii:ss" oder als UNIX-Timestamp) und berechne die Differenz zu jetzt mit den Date*-Funktionen.

    Korrekt, beim Namen liegt ein großes Problem der Sache. Ich habe einige PDF-Drucker getestet, bekomme als Originaldokumententitel allerdings immer "PDF.js" (der Name des Chrome-internen PDF-Viewers). Daher die Notlösung, mit pdftotext im Dateiinhalt zu schauen.


    Andy

    Eine Automatisierung des ERP-Systems ist grundsätzlich möglich, klar. Allerdings handelt es sich um ein Rolling-Release-System (mehrere Updates pro Woche), welches auch noch beim Anbieter gehostet wird. Das heißt, ich habe praktisch keine Möglichkeit, Updates zu verhindern. Eine Automatisierung der Oberfläche bedeutet daher extrem viel Wartungsaufwand. Der Aufwand als solches hält sich bei uns allerdings in Grenzen. Mitarbeiterin steht im Lieferschein, klickt auf das kleine Drucker-Icon => PDf-Vorschau des Beleges wird angezeigt, Systemdruckdialog plopt automatisch auf. Wenn der richtige Drucker bereits ausgewählt ist, reduziert sich der Aufwand also auf 2 Klicks, was ich für okay halte.


    BugFix

    Ja, unsere Damen sind an dem Punkt auch sehr verwöhnt. IBM AS/400 und textbasierte Warenwirtschaft lässt grüßen. Bisher haben die Damen den entsprechenden Druckbefehl eingegeben (bspw. drucke LS 5344 oder drucke alle noch nicht gedruckten Rechnungen), dann hat das System selber entschieden, welchen der Drucker es angesteuert hat (Nadeldrucker für LS, Nadeldrucker für RE, Laserdrucker für Protokolle). Die meisten unserer Bürodamen empfinden die manuelle Druckerauswahl also als extremen Rückschritt.

    Generell haben wir auch ein Problem damit, herauszufinden, ob ein Beleg wirklich gedruckt worden ist. In der AS/400 wusste das System genau, ob der Job schon an den Drucker weitergeleitet worden ist (Ansteuerung über TwinAx-Kabel). Im neuen ERP geht das natürlich nicht, der Browser bekommt ja keine Rückmeldung. Und wenn eine Dame sich beeilen wollte und u.U. den Druckdialog NACH Erzeugung der PDF abgebrochen hat, wird der Beleg trotzdem als gedruckt markiert. Da verliert man bei >400 Lagerbelegen am Tag schon mal die Übersicht, dann geht auch was verloren. Dafür habe ich auch noch keine elegante Lösung.

    Hi,


    ich hatte das Thema in der SB ja schon mal angeschnitten, aber es wohl wirklich zu umfangreich, um dort geklärt zu werden. Daher nochmal hier.


    Mein Problem

    Wir benutzen seit dem 24.09.2018 ein neues ERP-System, welches komplett im Browser (bei uns generell Chrome) läuft und beim Anbieter gehostet wird. Das heißt, Modifikationen direkt am ERP-System sind nicht möglich. In diesem ERP-System erzeugen wir sämtliche Belege als PDF-Dateien, also (u.A.) Auftragsbestätigungen, Lagerbelege (Kommissionierzettel), Lieferscheine und Rechnungen. Da wir aber keine klare Trennung zwischen unseren Büroabteilungen haben, nimmt eigentlich jeder Mitarbeiter Aufträge telefonisch entgegen und schreibt auch gleichzeitig Lieferscheine und Rechnungen. Die Problematik liegt jetzt beim Drucken der so erzeugten Belege. Alle Rechnungen und Lieferscheine werden auf Drucker A im Büro gedruckt, bestückt mit unserem Briefbogen. Alle Lagerbelege werden auf Drucker B im Lager gedruckt, damit die Kommissionierer diese direkt von dort bearbeiten können. Und - wie sollte es anders sein - wird natürlich regelmäßig vergessen, den richtigen Drucker zu wählen.


    Bisheriger Lösungsansatz

    Aus eigenem Antrieb und auf Anraten einiger User hier habe ich versucht, den Umweg über einen PDF-Drucker zu nehmen (in meinem Fall 7-PDF). Das sollte wie folgt funktionieren: Die Damen drucken IMMER auf dem PDF-Drucker, dieser schmeißt den Ausdruck als PDF immer ins selbe Verzeichnis. Dieses Verzeichnis wird dauerhaft von einem AutoIt-Skript überwacht, welches anhand des Dateinamens den Druck auf dem richtigen Drucker anstößt. Das ist schon relativ umständlich, finde ich. Erschwert wird das ganze noch durch die Tatsache, dass der PDF-Drucker nicht den Original-Dateinamen weitergeben kann. Ich habe also im Moment folgende (lauffähige) Konstruktion: ERP -> PDF-Drucker -> AutoIt-Skript -> xpdfs pdftotext (Rausfinden des Belegtypes) -> Sumatra-PDF (stilles Drucken). Das sind also alleine schon drei externe Softwarekomponenten PLUS mein Skript. Ich hätte da gerne eine standsicherere und elegantere Lösung, um ehrlich zu sein.


    Vom Wunschdenken her wäre ein Dummy-Druckertreiber das Mittel der Wahl. Oder ein Chrome-Plugin, welches den Drucker passend wählt. Oder, oder, oder... Es gibt sicherlich einige Möglichkeiten. Aber ich habe noch nichts anderes realisiert bekommen, mal von der bereits genannnten Lösung abgesehen. Fällt noch jemandem was ein?

    Das ist so ziemlich eins der ersten Sachen im Kapitel GUI-Programmierung in jedem Tutorial lernt. Zu sagen, das man nichts passendes gefunden hat kann ich da nicht glauben.

    Ist jetzt zwar etwas Off-Topic, aber: Jeder lernt anders. Ich schreibe zwar gerne Tutorials, aber selber welche lesen? Fehlanzeige. Lieber rumprobieren und so dazu lernen. Copy&Paste aus dem Netz, dann Zeilen oder Parameter verändern, beobachten, was passiert etc... Wenn ich mich richtig erinnere, war meine erste Frage in diesem Forum, wie man die Id eines Controls bekommt. Auch nicht viel besser. ^^

    Man könnte auch den direkten Weg gehen. Im Header einer ausführbaren Datei ist vermerkt, für welchen Prozessortyp sie gedacht ist. Das kann man einfach aus einer Office-Datei auslesen. Dann pfuscht einem auch nicht diese SysWOW64-Redirect-Geschichte da rein.


    Müsste so eigentlich gehen.

    Ok, sortieren wir das mal. Du hast i Eingabedateien, für jede Eingabedatei sollen j Queries ausgeführt werden. Normalerweise würde man das im Datenbankkontext mit Prepared Statements lösen, aber ich denke, AdoDB bzw. MS Access können das nicht. Daher behelfen wir uns mit StringFormat, um unsere Queries zu bauen. Außerdem habe ich einfach mal die For-To-Next-Schleifen durch For-In-Next-Schleifen ersetzt, das lässt sich für dich vielleicht leichter lesen. Damit spart man sich den Indexzugriff auf das Array. In jedem Durchlauf der inneren Schleife wird der Query neu zusammengesetzt. Kannst du das nachvollziehen?


    Ich möchte aber auch anmerken, dass du, sollte es wirklich nur um fünf SELECTs gehen, die auch in einem Query ausführen kannst.


    Ich hab dein Skript auch mal grob aufgeräumt, sonst finde ich mich selber da nicht zurecht.


    Du kannst auch einfach WM_DROPFILES überwachen. Das Drop-Event in WParam enthält einerseits alle Dateinamen, andererseits auch die Koordinaten des "Loslassens". Über ChildWindowFromPoint kannst du dir dann das entsprechende Control-Handle holen und schauen, ob es deine Toolbar ist.


    Wie soll Zeile 27 denn auch funktionieren? $test = "$query"&$j - Lass dir sowas zum Debuggen einfach mal in der Konsole ausgeben. Das "$query" ist kein Variablenzugriff, sondern nur ein Text (durch die Anführungszeichen). In $test steht also nach dem ersten Durchlauf $query1.


    Und gerade in dem Moment, in dem ich das schreibe, verstehe ich, was du vor hast. Du willst so direkt auf die jeweilige Variable (Z. 20 bis 24) zugreifen, richtig? Oh je, dein ganzes Skript ist etwas durcheinander... Probier es mal mit folgendem Grundaufbau: Du benutzt nur EINE For-Schleife, welche durch das Array $array_tagaktuelle iteriert (ACHTUNG! Nicht von 1 bis 5, sondern von 0 bis 4!). In dieser setzt du den jeweiligen Query aus dem Basisquery select A_Nr, Afo from tmp_abf1 where wert_ist= und deinem jeweiligen Array-Element $array_tagaktuelle[$i] zusammen. Dann direkt ausführen und Ergebnisse verarbeiten. Dann im nächsten For-Schleifendurchlauf der nächste Query.

    "Nicht möglich" - Das gibt es bei uns nicht! :D


    Windows kennt mehrere Desktops, wobei ein Desktop intern eine Art "Ansicht" darstellt, also nicht die Schreibtischanalogie mit Icons meint. Diese Desktops sind auch mit verschiedenen Zugriffsrechten versehen.

    Standardmäßig gibt es drei Stück davon, nämlich einmal den normalen User-Desktop, auf dem alle normalen Programme ausgeführt werden. Dann gibt es noch den ScreenSaver-Desktop, der mit seiner Existenz verhindern soll, dass über den Bildschirmschoner auf die laufenden Programme zugegriffen wird. Und zu guter letzt bleibt noch der Winlogon-Desktop, unser Sperrbildschirm (noch dazu läuft über diesen Desktop jeder UAC-Dialog). Auch diese Trennung dient eigentlich dazu, die Programme, die im User-Desktop-Kontext laufen, vor Zugriff zu schützen.


    Prinzipiell kann ich bei dem Starten eines Prozesses (Win32 CreateProcess) über die STARTUPINFO-Struktur einen Desktop angeben, auf dem der Prozess gestartet wird. Allerdings darf ein normaler Benutzer nicht auf die beiden gesicherten Desktops ScreenSaver und Winlogon zugreifen. Interessanterweise darf dies nicht mal der Administrator-Account, egal ob lokal oder aus der Domäne. In einem Absatz im MSDN wird nur nebenbei erwähnt, dass nur ganz wenige Benutzer auf Winlogon Zugriff haben, der einzige namentlich genannte ist der "LocalSystem account". Dabei handelt es sich um den lokalen Standard-Benutzer "SYSTEM". Ich habe es nicht getestet, aber ich nehme an, solche Benutzer wie TrustedInstaller haben auch Zugriff.

    Zitat von MSDN

    The Winlogon desktop's security descriptor allows access to a very restricted set of accounts, including the LocalSystem account. Applications generally do not carry any of these accounts' SIDs in their tokens and therefore cannot access the Winlogon desktop or switch to a different desktop while the Winlogon desktop is active.


    Die erste Aufgabe besteht also darin, meinen Prozess als SYSTEM auszuführen. wraithdu aus dem EN-Forum hat dafür eine sehr schöne und elegante Lösung gefunden, die ohne Zusatzprogramme wie PsExec auskommt. Dabei registriert sich das Au3-Programm selber als Dienst, welcher als SYSTEM ausgeführt wird. Etwas tricky, aber funktioniert wunderbar. Wohlgemerkt nur bei einem kompilierten AutoIt-Skript. Sobald mein Programm also unter dem SYSTEM-Account läuft, kann ich einen Prozess starten, der als Desktop Winlogon nutzt. Was dieses Programm dann macht, ist komplett dem Programmierer überlassen.


    Ich habe mal exemplarisch eine kleine Uhr programmiert, die auf dem Sperrbildschirm angezeigt wird. Im Anhang sind alle Binärdateien und Skriptdateien enthalten. LogonMsgStarter ist letztendlich wraithdus Skript, welches am Ende einfach nur LogonMsg im Systemkontext auf dem Winlogon-Desktop startet. LogonMsg selber ist letztendlich nichts anderes als eine stinknormale AutoIt-Anwendung, da ist nix dabei. Getestet habe ich das ganze unter Windows 10, funktioniert einwandfrei. Lediglich der "Sperrbildschirm-Schoner", also das Bild, was die Anmeldemaske verdeckt, liegt über meiner GUI. Und die GUI wird auch im Hintergrund von UAC-Dialogen angezeigt. :D

    Prinzipiell (vereinfacht) funktioniert ein Website-Aufruf wie folgt:

    Client: GET /index.html

    Server: 200 OK <Inhalt der Seite>


    Die 200 ist dabei der Statuscode und heißt konkret "Anfrage OK, Content folgt". Ein Webserver kann natürlich auch andere Codes schicken. Ein relevantes Beispiel wäre 303 (See other). Das ist nichts anderes als deine Weiterleitung. Du müsstest also nix anderes machen, als einen Raw HTTP Request (bspw. per TCP-Funktionen) senden und dann schauen, welcher Statuscode zurückkommt.

    Naja, eine verschlüsselte, ausführbare Datei im Ressourcenfeld zu haben, ist ja (verständlicherweise) irgendwie verdächtig. Aber von den großen Scannern schlägt ja nichts an, unser Panda in der Firma auch nicht.

    Zum Thema Sicherheit an sich habe ich auch noch eine kleine Idee, das muss ich aber erst selber testen...

    Okay, das habe ich hiermit erledigt. Daher will ich meine Idee jetzt mal etwas ausführen.

    Was ist das gefährliche an einer "normalen" Zugangskontrolle? Man kann disassemblieren und die Sicherheitsabfrage einfach "überspringen", grob erklärt. Oder sogar noch einfacher: Man könnte sogar mit einem einfachen Texteditor alle hartkodierten Strings aus einer ausführbaren Datei auslesen, wo dann auch Benutzername und Passwort bei wären. Man müsste also eine Situation schaffen, in der die Sicherheitsabfrage obligatorisch für den Betrieb des Programmes ist. Man könnte also hergehen, und die eigentliche ausführbare Datei verschlüsseln. Der Schlüssel besteht dann aus dem Benutzername und dem Passwort. So liegt in dem ausgelieferten Skript keine Information über die richtigen Zugangsdaten vor. Wenn man sie falsch eingibt, wird trotzdem entschlüsselt, nur das Ergebnis ist unbrauchbar.


    Ich habe die Idee mal in einem Beispiel umgesetzt. Dabei wird aus Benutzername:Passwort zunächst ein SHA256-Hash gebildet. Dieser wird dann als Schlüssel für eine AES256-Verschlüsselung genutzt. Damit wird das eigentliche Skript in kompilierter Form verschlüsselt. Die verschlüsselte EXE wird dann per FileInstall in das Zugangskontrollprogramm gepackt. Dieses fragt beim Start Zugangsdaten ab, packt das eigentliche Skript aus, entschlüsselt es mit den eingegebenen Daten und überprüft dann nur kurz, ob eine ausführbare Datei entstanden ist. Wenn ja => Ausführen. Wenn nein => Fehlermeldung. Nach Ausführung werden dann wieder alle temporären Daten gelöscht.


    Natürlich krankt auch diese Idee an ein, zwei Punkten. Nach der korrekten Eingabe der Zugangsdaten kann man theoretisch innerhalb der Laufzeit der Software einfach die entschlüsselte Datei sichern und nachher separat starten. Eine EXE direkt aus dem Prozessspeicher auszuführen, dürfte etwas komplexer sein. Soweit ich weiß, sieht Windows keine Standardfunktion dafür vor, man müsste also selber einen PE-Loader basteln... Ansonsten sollte das aber schon halbwegs sicher sein.


    Im Beispiel enthalten sind 4 Dateien:

    - acl.au3: Enthält die Passwortabfrage und die Entschlüsselungsroutinen.

    - script.au3: Das eigentliche Skript, welches geschützt werden soll. Beliebiger Inhalt.

    - mkau3.au3: Dieses Skript baut aus den anderen beiden die endgültige Datei.

    - myprogram.exe: Beispieldatei zum rumprobieren, kann durch ./mkau3.au3 neu erzeugt werden.

    Ich würde die Werte mal als grob realistisch einstufen. Das ist eine Class 10 Karte, was bedeutet, dass die Schreibgeschwindigkeit bei mindestens 10 MB/s liegt.

    Habe aber ansonsten nicht so viel mit der Materie zutun, meine einzigen SD-Karten sind zur Multitrack-Aufnahme im X32. :D

    Zum Thema Sicherheit an sich habe ich auch noch eine kleine Idee, das muss ich aber erst selber testen...


    Ansonsten hab ich aber noch einen schönen Dialog für einen Login gehabt und eben mal in eine passende Funktion gepackt:

    Zunächst: Wirklich sicher ist das natürlich nicht. So eine simple Abfrage lässt sich mit einem Disassembler (bzw. Debugger) relativ leicht umgehen, im Falle von AutoIt reicht auch ein Decompiler und ein anschließendes Entfernen der Abfrage, da der Code im Klartext vorliegt. Jedoch wird es wohl für den simplen Zweck, Kollegen am Rumschnüffeln zu hindern, reichen. Wobei es da wohl einfacher wäre, bei Verlassen des Arbeitsplatzes den Rechner kurz mit Win+L zu sperren... Aber gut, davon mal abgesehen ist das ganze simpel umsetzbar.


    Am schönsten liest es sich vermutlich, wenn du deine ganze Zugangskontrolle in eine Funktion packst. Abhängig vom Erfolg der Benutzerdatenabfrage gibst du dann einfach True (bei korrekten Daten) oder False (bei inkorrekten Daten oder Abbruch) zurück. Dann kannst du direkt am Anfang des Skriptes einfach so eine Zeile einfügen:

    Code
    If Not ZugangsKontrolle() Then Exit

    Liest sich sehr angenehm und ist eigentlich selbsterklärend für den Code-Leser. Wenn die Zugangskontrolle nicht erfolgreich ist, terminiert das Skript an dieser Stelle. Wenn sie erfolgreich ist, läuft es ab diesem Punkt einfach normal weiter.


    Edit:

    Zwecks Kapselung und Wiederverwendbarkeit würde ich ALLES, was mit der Authentifizierung zutun hat, in diese eine Funktion packen, inklusive GUI-Erstellung.