myCSharp.de - DIE C# und .NET Community
Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 
 | Suche | FAQ

» Hauptmenü
myCSharp.de
» Startseite
» Forum
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Suche
» Regeln
» Wie poste ich richtig?
» Forum-FAQ

Mitglieder
» Liste / Suche
» Wer ist wo online?

Ressourcen
» openbook: Visual C#
» openbook: OO
» Microsoft Docs

Team
» Kontakt
» Übersicht
» Wir über uns

» myCSharp.de Diskussionsforum
Du befindest Dich hier: Community-Index » Diskussionsforum » Entwicklung » Rund um die Programmierung » Wie kann ich aus einer gescannten Datei das Gerät auslesen/ändern, das diese Datei gescannt hat?
Letzter Beitrag | Erster ungelesener Beitrag Druckvorschau | Thema zu Favoriten hinzufügen

Antwort erstellen
Zum Ende der Seite springen  

Wie kann ich aus einer gescannten Datei das Gerät auslesen/ändern, das diese Datei gescannt hat?

 
Autor
Beitrag « Vorheriges Thema | Nächstes Thema »
OXO
myCSharp.de-Mitglied

Dabei seit: 04.06.2020
Beiträge: 17


OXO ist offline

Wie kann ich aus einer gescannten Datei das Gerät auslesen/ändern, das diese Datei gescannt hat?

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo zusammen,

in "Windows Fax- und Scan" sehe ich nach dem Scannen eines Dokumens/Bilds in der Spalte "Qulle" den Scanner, der diese Datei gescannt hat.

Irgendwo muss diese Information in der Datei auch ausgelesen bzw. gesetzt werden können.

Wie kann ich dies aus der Datei nachträglich per C# auslesen bzw. abändern?
04.06.2020 22:11 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
MrSparkle MrSparkle ist männlich
myCSharp.de-Team

avatar-2159.gif


Dabei seit: 16.05.2006
Beiträge: 5.404
Herkunft: Leipzig


MrSparkle ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Das wird sicherlich ein Eintrag in den  EXIF-Daten des Bildes sein. Du kannst dir die Einträge anschauen, indem du mit der rechten Maustaste auf die Datei klickst, und dann unter "Eigenschaften" die "Details"-Seite aufrufst. Zum Auslesen mit C# gibt es fertige Bibliotheken.
05.06.2020 13:41 Beiträge des Benutzers | zu Buddylist hinzufügen
OXO
myCSharp.de-Mitglied

Dabei seit: 04.06.2020
Beiträge: 17

Themenstarter Thema begonnen von OXO

OXO ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Leider sehe ich schon keine Informationen in Windows, die diese Information enthalten.

Habe noch mit der WindowsAPICodePack-ShellExtension Informationen ausgelesen, aber leider findet sich diese auch nicht bei den ganzen DeviceInformationen. Zumindest finde ich sie dort nirgends :(
05.06.2020 19:38 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
MrSparkle MrSparkle ist männlich
myCSharp.de-Team

avatar-2159.gif


Dabei seit: 16.05.2006
Beiträge: 5.404
Herkunft: Leipzig


MrSparkle ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Wenn die Infos nicht in der Datei stehen, kannst du sie auch nicht auslesen oder ändern.

Wenn beim nächsten Öffnen der Datei die Werte wieder angezeigt werden, sind sie aber wohl doch darin gespeichert.

Kannst du mal erklären, was du eigentlich vor hast? Um was für Dateien handelt es sich hier? Was willst du damit erreichen? Deine anderen Beiträge ( [gelöst] SendMessage an ListView in anderem Prozess und  Message Hook für andere Anwendungen) deuten irgendwie auf eine sehr unüberlegte Herangehensweise hin.
07.06.2020 16:41 Beiträge des Benutzers | zu Buddylist hinzufügen
OXO
myCSharp.de-Mitglied

Dabei seit: 04.06.2020
Beiträge: 17

Themenstarter Thema begonnen von OXO

OXO ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Mein Vater nutzt "Windows-Fax- und -Scan" zum Scannen. Dort werden die Dateinamen für jeden neuen Scan erst einmal benannt mit "Bild". Ist diese Datei bereits vorhanden, wird ein neuer Scan "Bild (2)", "Bild (3)" etc. genannt. Löscht man z.B. "Bild (2)", wird für einen nächsten Scan diese Lücke gefüllt und es entsteht nicht "Bild (4)", sondern "Bild (2)".

Mein Vater möchte die Dateien gerne durchnummiert haben.

Ich habe ihm daher ein Tool mit einem FileSystemWatcher geschrieben, der diese neuen Dateien umbenennt, sobald sie in dem Verzeichnis nach dem Scannen erzeugt wurden.

Es gab bei ihm aber mehrere Umstände, die ich gerne aus Anwendersicht glatt gezogen hätte. So kamen nach und nach bei der Lösungsfindung neue fragen auf. Natürlich nicht nur bezogen auf dieses Problem, sondern auch allgemeiner Natur, weil ich mich zwischendurch gefragt habe, wie sowas gehen könnte.

Bei ihm war es so, dass z.B. der FileSystemWatcher immer 2x angesprungen ist, obwohl ich die Message in der CallBack-Funktion des OnCreated-Events auf "Created" abgefragt habe. Ich vermute, dass der Scanner-Treiber erst temporär eine Datei aufmacht und am Ende hab ich dann 2x das Event. Dann war die Feststellung, dass im ListView 2 Dateien auftauchen, die gescannte und meine neu benannte Datei. Nur, meine umbenannte Datei hatte die Information in der Spalte "Quelle" verloren. Diese stand als eine unbekannte Quelle bei der Datei im ListView. Die Original-Datei vom Scanner nach dem Scan, hatte diese Information aber dran. Dann wollte ich das zuerst von der alten Datei auslesen und in meine neue Datei übernehmen. Bin aber auch wieder davon abgekommen, da das ListView eh einen falschen Namen hatte.

Dann bin ich zwischenzeitlich zu dem Entschluss gekommen, dass ich mit meinem Umkopieren doch solange warte, bis der Scanner-Treiber seine Datei wirklich fertig erzeugt hat und ich erst dann umkopieren kann. Das hab ich dann gemacht, damit war aber das ListView nicht mehr Up-to-Date und hat die Datei so angezeigt, wie sie ursprünglich nach dem Scannen benannt war und nicht, wie ich sie neu genannt hab. Dafür stand aber die Information mit der Scanner-Quelle drin.

Somit war mein nächster Ansatz, ob ich nicht das ListView entsprechend umbenennen könnte nach der Umkopier-Aktion. Ich hatte gesehen, dass das ListView nicht neu initialisiert wird, egal was für Refresh-Aktionen ich da per API versucht hatte. Alles natürlich auch unter dem "Forschungsgedanken" wie macht man x oder y ganz generell. Da das mit dem ListView, wie Du aus den anderen Threads raus gelesen hast, etwas tricky war, kamen mehrere Überlegungen rein.


Zwischendrin dachte ich mir auch, gut vielleicht könnte ich mich auch einfach an die Nachrichten des ListView dran hängen und vor dem Einfügen den Eintrag manipulieren. Jetzt ließ sich das Problem ja anderweitig über das TreeView lösen, aber wie man die Nachrichten von anderen Controls abfängt und wie man sich rein hängen könnte, interessiert mich trotzdem noch, auch wenn das nicht als Lösung genommen wird :)
07.06.2020 17:46 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
MrSparkle MrSparkle ist männlich
myCSharp.de-Team

avatar-2159.gif


Dabei seit: 16.05.2006
Beiträge: 5.404
Herkunft: Leipzig


MrSparkle ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Wow. So viel Arbeit, um die Dateireihenfolge von einem 30 Jahre altem Programm zu ändern, für das du nichtmal den Quellcode hast. In der Zeit hättest du ein eigenes Scan-Tool schreiben können.

Da wird dir wohl niemand weiterhelfen können.

Deinem Vater würde ich ein moderneres Tool zum Scannen empfehlen, bei dem man die Dateinamen selbst festlegen kann.
07.06.2020 18:12 Beiträge des Benutzers | zu Buddylist hinzufügen
OXO
myCSharp.de-Mitglied

Dabei seit: 04.06.2020
Beiträge: 17

Themenstarter Thema begonnen von OXO

OXO ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Rein unter mit einer Aufwand <-> Nutzen Brille gebe ich Dir völlig Recht.
Allerdings sehe ich das auch unter dem Lern-Aspekt und das war ne interessante und teils lehrreiche Reise bis hierhin :)

Vor allem die Erkenntnis, dass die Pointer ja irgendwie in fremdem Speicher liegen müssen und da die Dinge adressieren.

Vieles ist mir aber noch unklar, wie z.B. wo ich diese ganzen Werte für die Konstanten und auch die Strukturen für die API-Funktionen alle für C# nachschlagen kann? In der MSDN stehen die im C++ Code und teils mit Unterstrukturen und Pointern darauf. Mir ist immer noch nicht ganz klar, wo ich diese Informationen alle richtig für C# her bekomme und wie ich die richtig zusammenbasteln muss, damit die alle richtig versorgt sind.
07.06.2020 20:10 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Th69
myCSharp.de-Poweruser/ Experte

avatar-2578.jpg


Dabei seit: 01.04.2008
Beiträge: 3.643
Entwicklungsumgebung: Visual Studio 2015/17


Th69 ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Für WinAPI ist es das einfachste, du installierst im VS zusätzlich C++ (und damit das  Windows SDK) - in den Headerdateien (u.a. <windows.h> oder z.B. <commctrl.h>) stehen dann die Deklarationen der Funktionen mit den Strukturen etc.

Ansonsten finden sich viele Funktionen und Strukturen auch bei  PInvoke.net (wofür es auch ein VS Add-In gibt).

Und teilweise einfach bei konkreten Namen von Typen, Strukturen oder Konstanten/Enums im Internet danach suchen (leider fehlen die internen Werte von Konstanten/Enums in der offiziellen MS-Doku).

Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von Th69 am 07.06.2020 20:26.

07.06.2020 20:25 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
OXO
myCSharp.de-Mitglied

Dabei seit: 04.06.2020
Beiträge: 17

Themenstarter Thema begonnen von OXO

OXO ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Zitat von Th69:
Für WinAPI ist es das einfachste, du installierst im VS zusätzlich C++ (und damit das  Windows SDK) - in den Headerdateien (u.a. <windows.h> oder z.B. <commctrl.h>) stehen dann die Deklarationen der Funktionen mit den Strukturen etc.

Was hältst Du davon, das gleich in einer C++ Datei in der eigenen C#-Anwendung zu realisieren? Oder macht es die Problematik dann von dieser zurück in die C#-Anwendung zu kommen nicht kleiner als direkt die Funktionen in C# anzusprechen und alle Typen zu recherchieren?

Zitat von Th69:
Ansonsten finden sich viele Funktionen und Strukturen auch bei  PInvoke.net (wofür es auch ein VS Add-In gibt).

Und teilweise einfach bei konkreten Namen von Typen, Strukturen oder Konstanten/Enums im Internet danach suchen (leider fehlen die internen Werte von Konstanten/Enums in der offiziellen MS-Doku).

So habe ich das jetzt auch gemacht, aber das ist schon ne recht mühsame Recherche hatte ich den Eindruck. Irgendwie kenne ich die MSDN von früher noch, wo ich auch hin und wieder noch in VB vor .NET-Zeiten API-Calls gemacht hab. Da kam mir das in der MSDN transparenter vor und die Werte der Konstanten waren genauer beschrieben, so zumindest meine Erinnerung.

Nehmen wir gleich mal als Parade-Beispiel die  SetWindowsHookExA-Beschreibung aus der MSDN. Da sind gleich mehrere Parameter, bei denen ich mich frag, wie ich die in die C#-Welt übertrage und richtig abbilde? HHOOK, HOOKPROC, HINSTANCE. Genauso bestimmte Pointer-Typen

C#-Code:
HHOOK SetWindowsHookExA(
  int       idHook,
  HOOKPROC  lpfn,
  HINSTANCE hmod,
  DWORD     dwThreadId
);

Gibt es ne gute Einstiegsseite, bei der ich die generellen Grundprinzipien zum Umgang mit Pointern, Marshal etc. für Win API-Aufrufe erklärt sind?
07.06.2020 21:07 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Th69
myCSharp.de-Poweruser/ Experte

avatar-2578.jpg


Dabei seit: 01.04.2008
Beiträge: 3.643
Entwicklungsumgebung: Visual Studio 2015/17


Th69 ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Du meinst eine eigene C++/CLI Assembly im Projekt zu verwenden (anstatt P/Invoke)? Aber auch dort mußt du ja dann C#-Datentypen zur Übergabe benutzen, die man ersteinmal wissen muß.

Für die Erzeugung der P/Invoke-Schnittstelle in C# aus C heraus kannst du den  PInvoke Interop Assistant benutzen (ich kenne zwar nur die Vorgängerversion, die dort verlinkt ist, aber optisch und benutzertechnisch war diese doch sehr gewöhnungsbedürftig - und das hat sich hoffentlich geändert). Jedoch habe ich dort direkt keine EXE (bzw. Installer) gesehen, so daß man das Projekt wohl selber bauen muß.
Evtl. dann doch die ältere Version verwenden: auf  CodePlex Archive: clrinterop "download archive" nutzen und das gesamte Archiv (~35MB) herunterladen. Die Anwendung heißt "winsiggen.exe" (und dort dann den 3. Tab "SigImp Translate Snippet" benutzen).

Edit: Ich habe noch eine Doku dazu gefunden:  P/Invoke Interop Assistant - Overview

Außerdem gibt es wohl noch andere Tools:  Re-inventing the p/invoke generator

Und wenn man sucht, dann findet man noch mehr:  P/Invoke (eine Umsetzung der meisten System-DLLs, wenn auch nicht vollständig).

Noch ein Edit:
Ich habe selber mal den Source-Code (C#) vom "PInvoke Interop Assistant" heruntergeladen und erfolgreich kompiliert (Projektdatei ist für VS 2015).
Es gibt nur noch 2 Tabs: "SigImp Search" und "SigImp Translate Snippet" - und das Generieren von P/Invoke-Deklarationen klappt immer noch. ;-)

Dieser Beitrag wurde 5 mal editiert, zum letzten Mal von Th69 am 08.06.2020 17:10.

08.06.2020 08:48 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
OXO
myCSharp.de-Mitglied

Dabei seit: 04.06.2020
Beiträge: 17

Themenstarter Thema begonnen von OXO

OXO ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Mir sind auch noch ein paar interessante Links untergekommen. Zum einen mit Grundlagen für das Marshaling und auch noch mit Datentypen, die man häufig in den C/C++ Deklarationen in der MSDN zu den Funktionen findet und was für ein Managed-Datentyp das ist. Vielleicht interessant für das eigene Erstellen der Strukturen:

 Interop-Marshalling

 Standard-Marshalling Verhalten

 Marshallen von Daten mit Platformaufruf

 Zuordnen von HRESULT Werten und Ausnahmen
08.06.2020 23:10 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
OXO
myCSharp.de-Mitglied

Dabei seit: 04.06.2020
Beiträge: 17

Themenstarter Thema begonnen von OXO

OXO ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hab mich jetzt mit dem Thema Hooking herum geschlagen und experimentiert.

Ist schon sehr aufwändig, aber ich hab es hinbekommen und es wird jetzt eine C++-DLL verwendet, mit der ich einen Hook setzen kann (z.B.

C#-Code:
WH_CALLWNDPROC

). Von dort aus verzweigt es dann auch zurück in ein C# Progrogramm. Hier kann ich einige Messages sehen und bin auch soweit gekommen, dass ich eine

C#-Code:
LVM_INSERTITEMW

verändere und den Text hierüber im Ziel-ListView des anderen Prozesses austausche.

Eine ganz interessante Erfahrung war, dass man Speicher für die Pointer zu den Strings immer im Ziel-Prozess allokieren muss und von der Managed-Welt dort hin rüber schieben muss. Eigentlich logisch, aber trotzdem gewöhnungsbedürftig. Ebenfalls, dass ich noch den lparam aus dem

C#-Code:
CWPSTRUCT

wieder auspacken muss, um dann bei den Messages auf ein

C#-Code:
LVM_INSERTITEMW

reagieren kann. Danach noch den lparam in ein

C#-Code:
LV_ITEM

-Struct pressen. Also schon alles mit viel Aufwand verbunden.
Hattet Ihr mich nicht schon gewarnt? :P

Beim Lesen bzw. auch beim Anlegen der Strings muss man immer eine size mit angeben. Da ist mir ehrlich gesagt bis jetzt noch nicht klar, wie viel ich denn hierfür reservieren muss bzw. woher ich z.B. beim Lesen weiß, wie viel ich reservieren soll? Genauso beim Schreiben/Anlegen der Strings hatte ich den Eindruck, ich muss auf meine str.Length noch eine Konstante oben drauf hauen muss, um eine größere size zu reservieren, damit es funktioniert.

Dann ist es so, dass man auch immer wieder mit

C#-Code:
OpenProcess/VirtualAlloc/WriteMemory

arbeiten muss. Kann es sein, dass ich auch einen Gegenpart zum OpenProcess und dem VirtualAlloc brauche, um alles wieder freizugeben? Ich wundere mich nämlich, dass alles recht träge wirkt. Weiß aber auch nicht, ob das nicht einfach so ist?

Auch das Freigeben des pszTextPtrForeign wäre vermutlich noch sinnvoll, aber dann kann ich das ja nicht mehr erfolgreich zurückgeben, wenn ich den Speicher für diesen Pointer schon freigegeben hab.

C#-Code:
public static IntPtr GetPtrToStringInProcessMemory(Process Process, string str)
{
    IntPtr ProcessHandle = OpenProcess(PROCESS_VM_WRITE | PROCESS_VM_OPERATION, false, Process.Id);

    const int stringMaxAddedSize = 128;
    int maxStringSize = 0;

    if (String.IsNullOrEmpty(str)) // not initialized
        str = new string('x', 32);

    int size = str.Length + stringMaxAddedSize;
    if (size > maxStringSize)
        maxStringSize = size;

    IntPtr pszTextPtrForeign = VirtualAllocEx(ProcessHandle, IntPtr.Zero, (uint)size, AllocationType.Commit, MemoryProtection.ReadWrite);
    IntPtr TextPtrLocal = Marshal.StringToHGlobalAuto(str);

    bool Ok = WriteProcessMemory(ProcessHandle, pszTextPtrForeign, TextPtrLocal, size, IntPtr.Zero);
    if (!Ok) { throw new Win32Exception(Marshal.GetLastWin32Error()); }

    Marshal.FreeHGlobal(TextPtrLocal);

    return pszTextPtrForeign;
}
26.06.2020 09:40 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Th69
myCSharp.de-Poweruser/ Experte

avatar-2578.jpg


Dabei seit: 01.04.2008
Beiträge: 3.643
Entwicklungsumgebung: Visual Studio 2015/17


Th69 ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Ja sicherlich mußt du jeweils die Gegenpart-Funktion aufrufen (Open/Close, Alloc/Free).
Am besten immer in die WinAPI-Doku schauen, also z.B.  OpenProcess:

Zitat:
When you are finished with the handle, be sure to close it using the  CloseHandle function.

Gleiches für  VirtualAlloc ->  VirtualFree.
26.06.2020 09:52 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
OXO
myCSharp.de-Mitglied

Dabei seit: 04.06.2020
Beiträge: 17

Themenstarter Thema begonnen von OXO

OXO ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Dachte ich mir schon, dass ich das noch nicht ganz richtig gemacht hab - Mist ;)
Bei Benutzung der Methode von oben ist es aber schwierig den sicheren Zeitpunkt für das Abräumen zu bestimmen.

Den Speicher für den pszTextPtrForeign kann ich z.B. in der Routine noch gar nicht frei geben, da der ja meinen Pointer im Prozess für den pszText das LV_ITEM repräsentiert. Genauso hab ich ein Problem mit dem allokierten Speicher, solange ich noch im Weiterleiten einer veränderten LVM_INSERTITEMW Message in meinem CallBack bin. Irgendwie darf ich das ja alles erst abräumen, wenn die komplette Nachricht am Ziel angekommen und verarbeitet ist.
Dazu ist im Hook-Callback eigentlich gar keine Möglichkeit.

Denke, zumindest das CloseHandle(...) auf den Prozess-Handle könnte ich noch in der Routine unterbringen, da dieser nach dem WriteProcessMemory(...) wohl nicht mehr gebraucht wird

Der Grund für das langsame Update des ListView nach dem Verändern meiner Hook-Message kann das aber nicht sein, oder könnte das eine Rolle spielen? Da kann man nämlich darauf warten, bis das ListView seine paar Einträge geladen hat.
26.06.2020 18:09 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Baumstruktur | Brettstruktur       | Top 
myCSharp.de | Forum Der Startbeitrag ist älter als ein Monat.
Antwort erstellen


© Copyright 2003-2020 myCSharp.de-Team | Impressum | Datenschutz | Alle Rechte vorbehalten. | Dieses Portal verwendet zum korrekten Betrieb Cookies. 11.07.2020 12:24