Laden...

Forenbeiträge von SirFoldabit Ingesamt 66 Beiträge

04.11.2011 - 17:15 Uhr

Hi lukasS,

Ich hab das ähnlich implementiert wie du, allerdings brauchst du doch das "Clone()" gar nicht oder?
Dann müsstest du auch "DestroyIcon()" nicht benutzen, denn es handelt sich hierbei wohl sowieso um "Shared Icons".
Kannst also eigentlich...


icFileIcon = (Icon)Icon.FromHandle(shinfo.hIcon).Clone();

...zu...


icFileIcon = Icon.FromHandle(shinfo.hIcon);

...machen.

So habe ich das implementiert:


SHFILEINFO shFileInfo = new SHFILEINFO(); //Neue SHFILEINFO-Struktur anlegen
Icon smallIcon = null; //Das Icon in 16x16
            
/*** Dateinamen in DGV anzeigen ***/
foreach (string filepath in filepaths)
{
    extension = Path.GetExtension(filepath); //Extension mit '.'
    
    /*** Wenn der Key schon vorhanden ist, wird das Icon aus der Hashtable geladen ***/            
    if (iconHashtable.ContainsKey(extension))
    {
        smallIcon = (Icon)iconHashtable[extension];
    }
    /*** Wenn der Key noch nicht vorhanden ist, wird das Icon über "SHGetFileInfo" geholt ***/
    else
    {
        ShellIcon.SHGetFileInfo(filepath, FILE_ATTRIBUTE_NORMAL, ref shFileInfo, (uint)Marshal.SizeOf(shFileInfo),
                                SHGFI_USEFILEATTRIBUTES | SHGFI_ICON | SHGFI_SMALLICON);
                    
        try
        {
            smallIcon = Icon.FromHandle(shFileInfo.handleIcon); //Icon zuweisen...
            iconHashtable.Add(extension, smallIcon); //...danach zur Hashtable hinzufügen
        }
        catch (Exception exc)
        {
            //MessageBox.Show(exc.Message);
        }
    }
    ...
    ...
    ...
}

MfG SirFoldabit

03.11.2011 - 23:43 Uhr

Brauchst dich nicht entschuldigen, das ist doch kein Problem.
Also wegen mir darfst du deine Lösung noch gerne posten.
Mir hat dein Stichwort der Hashtable allerdings schon gereicht. Hab das jetzt auch so umgesetzt.
Funktioniert prima und ich kann keine Geschwindigkeitseinbußen feststellen.

Ich hab aber auch für dich noch nen kleinen Tipp um das Ganze noch zu beschleunigen.
Wenn du "SHGetFileInfo" so benutzt...


SHGetFileInfo(filepath, 0, ref shFileInfo, (uint)Marshal.SizeOf(shFileInfo), SHGFI_ICON | SHGFI_SMALLICON);

...dann wird für jede Datei nochmals überprüft, ob diese auch existiert. D.h. es geht unnötige Zeit verloren.
Implementiere "SHGetFileInfo" stattdessen einfach so...


private const int FILE_ATTRIBUTE_NORMAL = 0x80; //Normales Dateiattribut (Wenn kein Directory vorkommt sondern nur Dateien)
private const int SHGFI_USEFILEATTRIBUTES = 0x10; //Muss gesetzt sein, wenn ein Dateiattribut angegeben wurde

SHGetFileInfo(filepath, FILE_ATTRIBUTE_NORMAL, ref shFileInfo, (uint)Marshal.SizeOf(shFileInfo), SHGFI_USEFILEATTRIBUTES | SHGFI_ICON | SHGFI_SMALLICON);

...und schon geht alles wesentlich schneller, denn jetzt wird einfach angenommen, dass die Datei, mit dem entsprechendem Attribut existiert.
"FILE_ATTRIBUTE_NORMAL" geht natürlich nur, wenn es sich NUR um Dateien handelt und kein Ordner mit dabei ist.
Wenn auch Ordner dabei sein können, muss halt noch auf "FILE_ATTRIBUTE_DIRECTORY" überprüft werden.

Ich danke dir auf jeden Fall recht herzlich für deine Hilfe.

MfG SirFoldabit

03.11.2011 - 00:23 Uhr

Hi lukasS,

Ich bin genau auf dasselbe Problem gestoßen wie du.
Ich habe in meinem Projekt auch eine "dataGridView" in der die Icons von Dateien angezeigt werden.
Da der User die Dateien eines beliebigen Ordners anzeigen lassen kann, können dies natürlich auch mal locker mehrere Tausend sein.
Die Icons hole ich mir ebenfalls über "SHGetFileInfo" und auch bei mir kommt dann an ca. der 3300. Stelle:> Fehlermeldung:

Der an Icon übergebene Win32-Handle ist ungültig oder hat den falschen Typ.

Ich hab mich dann ein bissl schlau gemacht und gelesen, dass "FileIconInit" wohl die Lösung des Problems sei, denn "FileIconInit" aktualisiert die "System Image List".
Das Ganze klang dann auch sehr logisch für mich, da die Fehlermeldung ja fast immer an derselben Stelle auftritt.
Ich hab dann gegoogelt und diese Dokumentation zur FileIconInit function gefunden.
Dort steht, dass man "FileIconInit" bei Start des Prozesses und bei Vorkommen von "WM_SETTINGCHANGE" bei gesetztem "SPI_SETNONCLIENTMETRICS"-Flag aufrufen muss.
Hab das also in die "WndProc" und in meinen Konstruktor der Form eingefügt, nur leider kommt diese Nachricht NIE vor und deshalb habe ich nun immernoch dasselbe Problem.
Habs auch schon mit "CloseHandle" und "DestroyIcon" probiert aber das hat auch nicht geholfen.
Falls du es selbst probieren möchtest (vielleicht hab ichs einfach net geblickt), "FileIconInit" muss folgendermaßen importiert werden:


/// <summary>
/// Aktualisiert den "System Image List Cache".
/// Der Cache muss beim Start des Prozesses und bei "WM_SETTINGCHANGE", wenn das "SPI_SETNONCLIENTMETRICS"-Flag gesetzt ist, aktualisiert werden.
/// </summary>
/// <param name="restoreCache">Gibt an, ob der Cache aktualisiert werden soll.</param>
/// <returns>"True" bei Erfolg, andernfalls "false."</returns>
[DllImport("Shell32.dll", EntryPoint = "#660")]
public static extern bool FileIconInit(bool restoreCache);

Die Abfrage der "WndProc" habe ich wie folgt eingebunden:


protected override void WndProc(ref Message m)
{
    switch (m.Msg)
    {
        case WM_SETTINGCHANGE:                   
            if ((int)m.WParam == SPI_SETNONCLIENTMETRICS)
            {
                FileIconInit(true);
            }
            break;
    }
    base.WndProc(ref m);
}

Mich würde aber auf jeden Fall deine alternative Lösung für dieses Problem interessieren, denn mir fällt leider momentan nichts mehr dazu ein.
Ich würde mich sehr freuen, wenn du mir weiterhelfen könntest, bzw. vielleicht hast du dieses Problem ja mittlerweile behoben oder vielleicht
habe ich dir wenigstens einen Denkanstoß in die richtige Richtung gegeben.

MfG SirFoldabit

02.09.2011 - 15:54 Uhr

Hi,

die einfachste Lösung die mir auf die Schnelle einfällt, wäre:
Ändere den Button-Style mit der Property "FlatStyle" auf "Flat". Ein Feld darüber gibt es die "FlatAppearance".
Dort musst du nur noch die Properties "BorderColor, BorderSize, MouseDownBackColor und MouseOverBackColor" so anpassen,
dass beim Überfahren der Maus z.B. die MouseOverBackColor dieselbe ist, wie deine Hintergrundfarbe des Controls oder der Form, auf der der Button sitzt.

Andere Möglichkeit wäre noch, dass du deinen Button selbst zeichnest oder du
könntest z.B. ein Bild des Standardbuttons machen und das auf deine Oberfläche setzen.
Dann müsstest du in den Events "MouseClick, MouseDown, MouseEnter, Mouseleave..." etc. das Aussehen deines "Buttons"
entsprechend ändern und die entsprechenden Aktionen durchführen, die z.B. beim Klick auf deinen Button durchgeführt werden sollen.

MfG

SirFoldabit

27.08.2011 - 12:41 Uhr

@Cat: Hab das mit ner anderen Taste probiert und festgestellt, dass es egal ist, ob man "Remove" oder "RemoveAt" benutzt.
Das heißt, dass wohl "Remove" bzw. "RemoveAt" immer auch den aktuellen Text im Textfeld der ComboBox löscht.

27.08.2011 - 02:36 Uhr

Gute Idee Lynix aber das funktioniert leider nicht.

Ich glaube langsam irgendwie, dass das nicht geht, denn es wird sogar die Eingabe gelöscht, obwohl sie nicht markiert war.
D.h. auch wenn ich einen neuen Text im Textfeld der ComboBox eingebe, dann die Dropdownliste öffne und einen Eintrag selektiere,
ist die Eingabe im Textfeld der ComboBox nicht markiert und dennoch wird sie gelöscht, wenn ich ein Element der Dropdownliste lösche.

Code zum Löschen:


private void comboBox1_KeyDown(object sender, KeyEventArgs e)
{
    if (e.KeyCode == Keys.Delete && comboBox1.DroppedDown && comboBox1.Items.Count > 1)
    {
        e.Handled = true;
        comboBox1.Items.RemoveAt(comboBox1.SelectedIndex);
    }
}

26.08.2011 - 13:22 Uhr

Hi Thorus,

füge doch in deiner 2. Form einfach


this.Hide();
Application.OpenForms["NameDeinerErstenForm"].Show();

ein und schon sollte es deinen gewünschten Effekt erzielen.

EDIT: Du solltest auf jeden Fall aufpassen, dass du nicht immer wieder eine neue Instanz deiner 2. Form erzeugst und diese dann nur mit "this.Hide()" versteckst.
Je nachdem was du machen möchtest solltest du auch hier z.B. "Application.Openforms" benutzen oder dir besser gleich das hier

Im übrigen ist das auch ein Fall für
>
mal genauer anschauen.

MfG

SirFoldabit

25.08.2011 - 03:18 Uhr

Also mir ist gerade eine andere Möglichkeit eingefallen, wie ich meinen gewünschten Effekt erzielen könnte.
Ich könnte z.B. einfach ein ContextMenuStrip anzeigen, welches einen Delete-Eintrag enthält.
Ich habe das eben auch mal getestet allerdings erscheint das ContextMenu dann nur, wenn ich mit der Maus
einen Rechtsklick auf den Texteingabebereich der ComboBox mache.

Ich bräuchte das dann aber wenn man mit der Maus ein Element in der Liste der ComboBox selektiert
und dann per Rechtsklick das ContextMenu aufruft...das funktioniert aber leider nicht.

25.08.2011 - 00:01 Uhr

Ich habe gerade auch nochmal kurz ein Testprojekt erstellt um das zu verdeutlichen.
Also, wenn ich etwas eintippe, das noch nicht zur ComboBoxListe hinzugefügt wurde, ist alles OK.
Das Bild zeigt aber, dass der Text in der ComboBox immer mitselektiert wird, wenn sich kein Text in der ComboBox befindet, der noch nicht zur Liste hinzugefügt wurde.
Wenn ich dann in diesem Fall das Item "String1" löschen möchte (durch Drücken von "Entf"), wird der Text "ABCDEF" in der ComboBox automatisch mit entfernt.
Genau das möchte ich aber gerne verhindern. Ich hoffe, dass es jetzt etwas verständlicher ist (Hab das im oberen Beitrag noch etwas fälschlich dargestellt, SRY).

Zur Vollständigkeit, ich verwende VS 2010 Ultimate, .NET 4.0 und Win7x64 Ultimate.

24.08.2011 - 21:13 Uhr

Hi Leute,

ich habe eine ComboBox, die der User mit Werten befüllen kann.
Natürlich dürfen diese Werte auch wieder vom User zur Laufzeit gelöscht werden.
Es kann nun z.B. sein, dass der User gerade einen Text eingegeben hat und der Wert aber noch nicht gespeichert wurde, da noch keine Aktion ausgeführt wurde.
Wenn der User jetzt auf den DropDown-Pfeil klickt, wird automatisch der Text in der ComboBox mit selektiert.
Das ist aber sehr unpraktisch, denn wenn der User einen Eintrag in der DropDownListe löschen möchte, dann wird der zuvor eingegebene Text mit gelöscht, da er ja auch selektiert ist.

Ich möchte nun also, dass z.B. beim Klick auf den DropDown-Pfeil sich ganz normal die Liste mit den vorhandenen Einträgen öffnet... aber der Text in der ComboBox nicht automatisch mitselektiert wird.
(Die Einträge der ComboBox werden über das KeyDown-Event gelöscht, wenn "Entf" gedrückt wurde)

Ich habe es wie folgt probiert (Ohne Erfolg):


private void comboBox1_DropDown(object sender, EventArgs e)
{
    comboBox1.SelectionStart = comboBox1.Text.Length;
}

private void comboBox1_Enter(object sender, EventArgs e)
{
    comboBox1.SelectionStart = comboBox1.Text.Length;
}

Bei Textboxen funtkioniert das anscheinend so...bei meiner ComboBox jedenfalls nicht.
Hat jemand ne Idee???

LG SirFoldabit

04.08.2011 - 14:14 Uhr

Wieso erzeugst du nicht einfach dein EigenesObject außerhalb der Schleife?
Ich denke dadurch sollte dieses Problem schnell behoben sein.


EigenesObject eo = new EigenesObject();

for(i = 0; i < viel; i++){
  errors.append(eo.macheVieles(para1, para2, para3));
  eo = null;
}

02.08.2011 - 23:33 Uhr

Die 1. Zeile wird automatisch selektiert, sobald du eine Zeile hinzufügst.
Ich würd's mal hiermit probieren:


for (int i = 0; i < dgvRubrik.Rows.Count; i++)
{
   if (dgvRubrik.Rows[i].Cells["ID"].Value.ToString().Equals(rubrik.ID.ToString()))
   {
      dgvRubrik.ClearSelection(); //Aktuelle Auswahl löschen
      dgvRubrik.Rows[i].Selected = true; //Danach die Auswahl neu setzen
      dgvRubrik.FirstDisplayedScrollingRowIndex = i;
      break;
   }
}

02.08.2011 - 23:18 Uhr

Also ich hab jetzt alles probiert und ich bekomme beim Debuggen einfach nix raus.
Der String wird korrekt übergeben und wenn keiner was andres weiß, dann muss des wohl n Bug sein,
denn ich habe fast genau die gleiche Funktion um das Modul aus dem fremden Prozess wieder zu entladen,
sprich es wird eben anstatt "Loadlibrary" "Freelibrary" aufgerufen und das funktioniert auch ohne Probleme.

Ich bin somit wirklich am Ende meines Lateins...Weiß hier keiner Abhilfe oder hat schon mal Ähnliches festgestellt?

29.07.2011 - 16:03 Uhr

@zommi, der Zielprozess kann 32-Bit als auch 64-Bit sein, das spielt keine Rolle.
Ich habe es mehrmals mit beidem getestet und bekomme immer denselben Fehler.

Also Aufruf wie folgt: 64-Bit-C#-App importiert 64-Bit-C++-DLL welche Loadlibrary ausführt um eine 32-Bit-DLL in einen Zielprozess (32-/64-Bit) zu injizieren.

29.07.2011 - 04:23 Uhr

Also wenn ihr wollt, dass Adminrechte zur Verfügung gestellt werden sollen bzw. dass das Programm nur mit Adminrechten läuft, dann kann man das doch ganz einfach über das Manifest machen.

Das ist der Standard (normaler User):
<requestedExecutionLevel level="asInvoker" uiAccess="false" />

So kann die Anwendung nur mit Adminrechten starten:
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />

Einfach im Manifest umändern und natürlich unter Projekt->Eigenschaften->Anwendung->Symbol und Manifest das abgeänderte Manifest auswählen. Neu kompilieren...und fertig.

Dann passiert sowas...

Beispiel:

-->User 'Peter' startet Programm mit Adminrechten
-->Programm prüft nun den angemeldeten User ob er Administrator ist : Nein
-->Programm läuft nicht/fehlerhaft

...auch nicht mehr.

Die Anwendung kann dann allerdings nur noch als Admin ausgeführt werden und das Ganze funktioniert auch erst ab Windows Vista.
Naja, ich hoffe trotzdem, dass ich weiterhelfen konnte.

28.07.2011 - 23:31 Uhr

Hi,

Ich habe eine 64-Bit-C#-Anwendung, in der ich ein paar Funktionen aus meiner 64-Bit-Unmanaged-C-DLL per DllImport einbinde.
Eine dieser Funktionen soll eine 32-Bit-Unmanaged-C
-DLL in einen Zielprozess injizieren.
Soweit so gut. Mein Problem ist, dass "LoadLibrary()" immer "0" zurückgibt und "GetLastError()" den Fehlercode "87" ausspuckt.
Errorcode "87" ist "ERROR_INVALID_PARAMETER". Diesen Fehler kann ich mir nur leider überhaupt nicht erklären, da ich an "LoadLibrary()"
schließlich nur meinen Modulpfad übergebe und der stimmt definitiv. Ich habe das auch anhand einer Ausgabe in der DLL überprüft.

Hier mal die ganze Funktion:


extern "C" DLL_EXPORT HMODULE InjectModule(unsigned int PID, char *modulePath)
{
	HANDLE hProcess, hRemoteThread;
	DWORD dwModule = NULL, dwMemSize = (DWORD)strlen(modulePath) + 1;
	LPVOID lpvRemoteMemory, lpvLoadLibrary;
	
	/*** Prozess mit All Access öffnen ***/
    if ((hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, PID)) != NULL)
	{
        /*** Speicher allokieren um den Pfad zur DLL im Speicher des anderen Prozesses zu halten ***/
		if ((lpvRemoteMemory = VirtualAllocEx(hProcess, NULL, dwMemSize, MEM_COMMIT, PAGE_READWRITE)) != NULL)
		{
			/*** Den Pfad der DLL in den gerade erstellten Speicherblock schreiben ***/
			if (WriteProcessMemory(hProcess, lpvRemoteMemory, (LPCVOID)modulePath, dwMemSize, NULL) == TRUE)
			{
				lpvLoadLibrary = (LPVOID)GetProcAddress(GetModuleHandleA("kernel32"), "LoadLibraryA");

				/*** Die Funktion "LoadLibrary()" im anderen Prozess ausführen ***/
				if ((hRemoteThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)lpvLoadLibrary, lpvRemoteMemory, 0, NULL)) != NULL)
				{
					WaitForSingleObject(hRemoteThread, INFINITE); //Warten bis Remotethread beendet wurde
					GetExitCodeThread(hRemoteThread, &dwModule); //Modulhandle holen
					VirtualFreeEx(hProcess, lpvRemoteMemory, dwMemSize, MEM_RELEASE); //Den erstellten Speicher im anderen Prozess freigeben
					CloseHandle(hRemoteThread);
				}
			}
		}
		CloseHandle(hProcess);
	}
	
    return (HMODULE)dwModule; //Modulhandle zurückgeben, welches dann wieder zum entladen der DLL benötigt wird
}

Achja, nicht ganz unwichtig ist denke ich, dass ich das Ganze unter Windows 7 Ultimate 64-Bit teste.
An der zu injizierenden DLL kanns auch nicht liegen, denn wenn ich diese z.B. in meine C#-Anwendung einbinde, wird "DllMain()" ohne Probleme ausgeführt.
Ich hoffe ganz stark, dass mir hier jemand weiterhelfen kann, denn wenn ich das nicht gebacken bekomme, dann funktioniert höchstwahrscheinlich ein großes Feature meiner Anwendung nicht.
Ich bin für jeden Lösungsvorschlag offen.

08.07.2011 - 20:09 Uhr

Ja klar, das denke ich auch aber mam muss eben wissen WER WAS tut.
Dann ist das Ganze überhaupt kein Problem. 😃

07.07.2011 - 21:08 Uhr

Bitte gewöhn dir nicht gleich die schlechteste aller Möglichkeiten an.
In .NET ist DataBinding viel besser als in allen anderen Systemen, weshalb man die Daten nicht mehr in UI Elemente frickeln muss.

Ich habe mich nur auf

ich habe bisher keine methode oder eigenschaft zum direkten ansprechen der zellen gefunden. bezogen...

DataBinding ist natürlich eleganter aber auch nicht immer für jeden wünschenswert.

07.07.2011 - 20:40 Uhr

Hi fh2k10,

also wenn du eine Zelle einer DGV direkt ansprechen willst, dann kannst du das z.B. so tun:
Für die Veranstaltung z.B.:


dataGridView1[Columnindex, Rowindex].Value = textBox1.Text;

Für die Note z.B.:


dataGridView1[Columnindex, Rowindex].Value = comboBox1.SelectedItem;

Du musst natürlich noch den richtigen Spalten- und Reihenindex angeben und jedes Mal, wenn du eine Zelle befüllt hast, den index um 1 erhöhen.

07.07.2011 - 20:03 Uhr

Hast du denn jetzt auch mal den
>
ausprobiert?

Haaaaaa, Cat du bist ein Schatz...
Daran hab ich überhaupt nicht gedacht, ich hab immer nur mit den Graphics-Methoden rumgespielt.
Der TextRenderer hat das Problem behoben. Es liegt also daran, dass ein Wert, der in der DGV per Value Eigenschaft zugewiesen wurde,
mit dem TextRenderer gezeichnet wird und nicht mit Graphics.DrawString(). Daher die Unterschiede...
Gut zu wissen für die Zukunft. 😃

@Blacal: Das wäre die letzte Option gewesen, die ich dann wohl hätte ergreifen müssen aber zum Glück haben wir das Problem gefunden.

Ich danke euch Allen für die schnelle und kompetente Hilfe. --> Thread kann als gelöst angesehen werden.

07.07.2011 - 15:52 Uhr

sollte normalerweise nicht sein. Schon mal versucht, die alle Zellen auch mit den gleichen Einstellungen beim Graphics-Objekt zu zeichen (Antialiasing, Qualitätsstufe, usw.)..
bzw.. du zeichnest alle Zellen selbst, oder?

Hi Roland, ich zeichne hier nur die Zellen in der Spalte "Handle" selbst. Die Spalte der "PID" enthält kein Bild sondern nur eine Zahl, daher kann dies vom System gemacht werden.

...(wenn z.B. eine Null 4,5 Pixel breit dargestellt werden müsste), dann kommt es je nach Position der des Buchstabens im gesamten Text
und den Breiten der vorangegangene Buchstaben dazu, dass die Breite auf- oder abgerundet werden muss...

EDIT: Sry@gfoidl, ich hab nen ziemlich großen Monitor, da war das Zitat sehr klein...

Hi herbivore, das wäre eine Erklärung und würde Sinn machen aber warum betrifft, das dann immer nur die Spalte "Handle", die von mir gezeichnet wird und nie die Spalte "PID", die vom System gezeichnet wird? Ich habe auch probiert in der von mir gezeichneten Spalte die Schrift etwas nach Hinten zu versetzen um zu schaun, ob du Recht hast. Die Ziffern blieben aber immer gleich groß.

Ich habe auch eben alle TextRenderingHints durchprobiert... hat nichts geändert, also es wird auf jeden Fall richtig gerendert bis auf das Phänomen, dass eben manche Ziffern einen Pixel zu schmal sind.

06.07.2011 - 23:49 Uhr

Hi Leute,

mir ist vorher etwas sehr Komisches an 2 benachbarten Zellen meiner DGV aufgefallen.
Beide Zellen enthalten einen integer-Wert. Hier einmal eine ProcessID und ein zugehöriges Dateihandle.
Da hier bei beiden zufällig die letzten beiden Ziffern übereinstimmen, konnte ich beobachten, dass diese sich von der Schriftart unterscheiden. (s. Anhang)
Der Wert der PID wird per dataGridView1[e.ColumnIndex, e.RowIndex].Value gesetzt.
Der Wert des Dateihandles wird in CellPainting mit e.Graphics.DrawString() gezeichnet.
In der ganzen DGV ist überall derselbe Font eingestellt und natürlich verwendet auch e.Graphics.DrawString() denselben Font.
Warum unterscheiden sich also diese beiden Zahlenwerte? Liegt es vielleicht daran, dass ein anderes Aliasing der Schrift bei e.Graphics.DrawString()
durchgeführt wird wie beim normalen Setzen von dataGridView1[e.ColumnIndex, e.RowIndex].Value?

Ich bitte um Hilfe, wenns um die Optik bei mir geht, dann muss das auf den Pixel genau stimmen, da bin ich sehr penibel.

P.S. Hab das Bild im Anhang auf 800% vergrößert und die Ziffern rot umrahmt, so sieht man auf Anhieb was ich meine.

03.07.2011 - 15:30 Uhr

Jo herbivore, hast recht...heute bin ich wohl n bissl "betriebsblind."
Naja, war auch lange auf...Klitschko-Kampf etc.
Kann man ja an der Erstellungszeit dieses Threads sehn... 😉

Ich danke dir trotzdem für deine Mühen. Ich wünsche noch einen schönen Sonntag und Thread kann geschlossen werden. 😃

03.07.2011 - 14:54 Uhr

Danke herbivore für die schnelle Hilfe.
Hab das Problem selbst gelöst...ich hatte noch irgendwo nen Zugriff, der nicht aus dem GUI-Thread kam...hatte einfach vergessen das zu entfernen.
Manchmal sieht man den Wald vor lauter Bäumen nicht..(.ALLERDINGS habe ich jetzt ein neues Problem.
Ich habe einen delegaten

private delegate void SetNewArgsCallback(string[] strArray);

und die InvokeRequired-Überprüfung in meiner Funktion

public void SetNewArgs(string[] strArray)
{
     if (this.InvokeRequired == true)
     {
          SetNewArgsCallback callback_delegate = new SetNewArgsCallback(SetNewArgs);
          this.Invoke(callback_delegate, new object[] { strArray });
     }
     dataGridView1.Rows.Add();
     ...
     ... //Restlicher Code der Methode
     ...
}

Das funktionirt auch, nur wird die Methode für jedes übergebene Argument 2 mal ausgeführt und zwar einmal mit Invoke und einmal ohne.
Ich sehe meinen Fehler hierbei gerade leider auch nicht... Ich bitte um Hilfe.

03.07.2011 - 03:51 Uhr

Hi Leute,

Ich hab da ein ganz fieses Problem, an dem ich nun schon eine ganze Weile festhänge und bestimmt schon ganz google und sämtliche Foren durchforstet habe aber zu keiner Lösung gelangt bin.

Zu meinem Problem:

Ich habe eine Anwendung, bei der per Argumentübergabe in der Main-Funktion ("static void Main(string[] strArray)") z.B. Dateipfade an meine Anwendung übergeben werden.
Diese werden dann in einer dataGridView angezeigt. Für jeden Dateipfad wird eine neue Row über "dataGridView1.Rows.Add()" programmatisch hinzugefügt.
Falls nun mehr Rows vorhanden sind, als im Clientbereich angezeigt werden können, soll eine vertikale ScrollBar angezeigt werden, mit der der User nach unten Scrollen kann.
Eigentlich kein Problem, allerdings friert mir die Form ein sobald die vertikale ScrollBar angezeigt wird.
Das Ganze ist sehr komisch, denn wenn ich z.B. nur soviele Dateipfade übergebe, dass noch keine ScrollBar notwendig ist und dann mit der Maus die Form "nach oben hin" verkleinere,
dann wird die vertikale ScrollBar ohne Probleme angezeigt und alles verläuft genau so, wie es sein sollte.

Zusätzliche Infos: Meine DGV enthält 4 DataGridViewImageColumns, welche am "Ende" jeder Row, also auf der rechten Seite, angezeigt werden.
Die ScrollBars der DGV sind auf "ScrollBars.Both" gesetzt und mit der horizontalen ScrollBar gibt es keinerlei Probleme.
Es liegt auch nicht, daran, dass ich die Rows aus einem anderem Thread heraus hinzufügen möchte, als aus dem, in dem sie erstellt wurden.
"dataGridView1.Rows.Add()" wird aus dem GUI-Thread heraus aufgerufen.

Kann mir hierbei bitte irgendjemand helfen? Bin echt am Verzweifeln...

26.12.2010 - 22:42 Uhr

So ein ähnliches Problem hatte ich auch mal. Windows hat einen Icon Cache, und verwendet vermutlich ein falsches/kein Icon für deine App.
Such mal im Internet wie man den Cache löscht.

THX A LOT!!!!
Genau das war das Problem. Hab unter "C:\Users[Username]\AppData\Local" die "IconCache.db" gelöscht und zusätzlich den Iconcache auf 8192 erhöht.
Alles funzt jetzt wieder so wie es sein sollte.

26.12.2010 - 21:44 Uhr

Hast du das Icon denn auch deiner Form zugewiesen?

Ja klar. Das komische ist, dass es gestern noch ging. Allerdings war noch ein älteres Icon in meiner Anwendung eingebunden und deshalb habe ich ein Neues gemacht und eingebunden. Seitdem wird in der von mir gezeigten Ansicht gar kein Icon mehr angezeigt. Starte ich ein komplett neues Projekt, dann funktioniert es wieder --> s. Anhang.

26.12.2010 - 21:08 Uhr

@talla:

Nein, das ist ja leider schon die anwendung direkt. Aus VS gestartet sieht das ja so aus:

26.12.2010 - 19:52 Uhr

Hi Leute,

hab da ein kleines Icon Problem. Hab ne Anwendung geschrieben und ganz normal ein Icon über die Projekteigenschaften in die ".exe" eingebunden. Das Icon is ne Icon-Collection mit 16x16 bis 256x256 Pixel Auflösung. Es wird überall richtig dargestellt unter Windows 7 außer: --> siehe Anhang (rot umrahmt).

Weiß da einer wie ich das Icon auch dort zur Anzeige bekomme?
Hab auch schon probiert ein neues Projekt zu starten und nochmals alles neu einzubinden...vergeblich.

EDIT: Die Ansicht im Anhang bekommt man, wenn man auf eine Anwendung in der Taskleiste rechtsklickt.

13.12.2009 - 16:41 Uhr

Hi, also ich habe jetzt mal eine Test-DLL in C++ geschrieben.
Diese wurde auch richtig kompiliert.
Nun habe ich aber folgendes Problem: Wie kann ich in meinem C#-Programm auf die Funktionen der DLL zugreifen??? Geht das auch über "[DLLImport]" oder muss ich eine Referenz hinzufügen? Wenn ja wie?

MfG

SirFoldabit

EDIT:

Hat sich erledigt. Lag daran, dass ich

static __declspec(dllexport) double Add(double a, double b);

in der "*.h" Datei hatte.
Nach Entfernen der Headerdatei und Verschieben von:

extern "C" __declspec(dllexport) double Add(double a, double b);

in die "*.cpp"-Datei, kann ich in meinem C#-Prog über:


[DllImport("NameDerDLL.dll")]
public static extern double Add(double a, double b);

auf die Funktion zugreifen. Wenn ich in der Headerdatei static zu extern "C" umbenenne, dann funktioniert es nicht... Verstehe ich zwar nicht warum es ohne Header geht und mit Header nicht aber OK...

11.12.2009 - 16:25 Uhr

Es gibt kein "Default ContextMenu" an das du dich hängen kannst. Fast jede Implementation von IShellFolder unterstützt das Interface IContextMenuCB. Das Kontextmenü wird immer! neu erstellt, wenn auf etwas rechts geklickt wird.

In der MSDN steht aber: "LPFNDFMCALLBACK Prototype:

Defines the prototype for the callback function that receives messages from the Shell's default context menu implementation."

und "DFM_INVOKECOMMAND:

Sent by the default context menu implementation to request LPFNDFMCALLBACK to invoke a menu command."

Ich weiß, dass das Kontextmenü jedes Mal neu erstellt wird...
Aber ich verstehe das so, dass ich das dann über diese Funktionen abfangen kann.
Also so wie das dort in der MSDN steht, sieht das für mich genau so aus.

11.12.2009 - 14:09 Uhr

Hmm ok aber ich möchte ja nur das "DFM_CMD_PASTE" des "DefaultContextMenu" abfangen.
"Einfügen" taucht im Default Kontextmenü ja sowieso nur auf, wenn sich Dateipfade im Clipboard befinden. D.h., dass ich doch dann dennoch an mein Ziel kommen sollte oder nicht?
Also nur mit .NET-Mitteln???

MfG

SirFoldabit

11.12.2009 - 12:19 Uhr

Ich möchte einfach die Befehle des normalen Kontextmenüs, bei Rechtsklick mit der Maus, abfangen und dann z.B. bei "Einfügen" eine eigene Methode bzw. Programm ausführen lassen.

Unter .NET darfst du unter keinen Umständen eine eigene Implementation von IContextMenuCB in der Shell registrieren.

D.h. dann, dass ich das in C++ machen und die fertige DLL in der Registry laden lassen muss, wenn der User einen Rechtsklick auf einen Ordner oder im Background des Ordners macht? (Nur dann möchte ich das Paste abfangen)

MfG

SirFoldabit

EDIT:

Hab hier bei Codeproject was gefunden. Dort wird IShellFolder mit C# instanziiert.
Die Methode "GetUIObjectOf" ist dort auch implementiert.
Hilft mir das weiter? Geht das dann doch? Wenn ja, wie komme ich jetzt an eine Instanz von IContextMenuCB ran?

10.12.2009 - 16:33 Uhr

Hallo liebe Forum-Gemeinde,

hab da nach langem Suchen diesen Artikel gefunden.
Dort ist der Prototyp "LPFNDFMCALLBACK" definiert, welcher in "shlobj.h" zu finden ist.
Über die Notification "DFM_INVOKECOMMAND" kann man z.B. auf "DFM_CMD_PASTE" reagieren.
Zusätzlich gibt es das Interface "IContextMenuCB" und eine "CallBack" Methode. Hier nachlesen. (Die Callback-Methode ist unter IContextMenuCB Members zu finden)
Dort steht : "Enables the callback function for a context menu."

Mein Frage ist nun: Wie benutze ich diese Callback-Funktion? Ich habe schon probiert das per Import zu machen...


[DllImport("shell32.dll")]
		public static extern Int32 Callback(
		    IShellFolder psf,
		    IntPtr hwnd,
		    IDataObject pdtobj,
		    uint uMsg,
		    IntPtr wParam,
		    IntPtr lParam);

... da kommt dann aber ne Fehlermeldung, dass der Einstiegspunkt in der DLL "shell32.dll" nicht gefunden werden konnte.
Muss ich das Ganze in einem C++-Projekt zusammenbasteln und dann als DLL kompilieren?
Wenn ja, was muss ich alles in der ".h" und der ".cpp" definieren???
Dass das Ganze dann erst ab Vista funktioniert ist mir klar. Das wäre aber nicht wirklich schlimm, da ich denke, dass mit Win7 XP bald abgelöst sein wird.
Bitte helft mir da irgendwie weiter. Am Besten Schritt für Schritt was ich machen muss.

MfG

SirFoldabit

30.11.2009 - 17:24 Uhr

Der explorer ruft intern unter xp SHFileOperation und unter Vista IFileOperation (Com) auf.

Das mit SHFileOperation hooken ginge problemlos mit dllinjection (siehe mein snippet) mit eincompaliertem Easyhook

  1. Danke für die Hinweise.
  2. Wie sieht es bei Windows 7 aus, welche FileOperation wird dort benutzt?
  3. Was fange ich mit dem EasyHook an? Da hab ich keine Dokumentation dazu gefunden und einfach die DLL's zu importieren bringt mir ja nichts, wenn ich nicht weiß welche Funktionen dort enthalten sind.

MfG SirFoldabit

EDIT:
@ujr: Er meint dieses Snippet.

30.11.2009 - 14:06 Uhr

[EDIT=herbivore]Threads zusammengefügt[/EDIT]

Hallo liebe Forum Gemeinde,

Mein Problem bezüglich diesem Thema ist immernoch nicht gelöst.
Ich bin mir (fast) sicher, dass mein Problem nur mit Hooks zu lösen sein wird.
Ich erkläre am Besten nochmals ganz genau, was ich möchte, sodass man mich nicht falsch versteht:
Ich möchte ein Programm à la "TeraCopy" schreiben.
D.h. für Dateikopier- und Verschiebeoperationen soll mein Programm "anspringen" und nicht der Windows Explorer. Die markierten Dateien, die der User markiert hat, die bekomme ich ganz easy übers Clipboard (ClipBoard.GetFileDroplist()). Nun weiß ich welche Dateien der User mit "Strg+c" oder rechte Maustaste "Kopieren" kopiert hat aber ich hab keine Ahnung wie ich an den "Einfügen-Befehl" der rechten Maustaste rankomme. Mein Programm soll ab Systemstart im Hintergrund laufen, es muss also irgendwie den Befehl oder das Event, welches bei "Einfügen" oder "Strg+v" ausgelöst wird, abfangen. Zusätzlich muss ich dann ja auch noch wissen in welchen Ordner die Dateien kopiert werden sollen (Der benötigte Zielpfad).
Wenn das Ganze doch irgendwie übers Clipboard funktionieren sollte, dann erklärt mir bitte wie. Wenn nicht (also wohl über Hooks), dann erklärt mir bitte ebenfalls wie, falls das überhaupt jemand weiß.

Ich denke, dass man über diese HookTypes zum gewünschten Ergebnis kommen könnte:


public enum HookType : int
{
    WH_JOURNALRECORD = 0,
    WH_JOURNALPLAYBACK = 1,
    WH_KEYBOARD = 2,
    WH_GETMESSAGE = 3,
    WH_CALLWNDPROC = 4,
    WH_CBT = 5,
    WH_SYSMSGFILTER = 6,
    WH_MOUSE = 7,
    WH_HARDWARE = 8,
    WH_DEBUG = 9,
    WH_SHELL = 10,
    WH_FOREGROUNDIDLE = 11,
    WH_CALLWNDPROCRET = 12,
    WH_KEYBOARD_LL = 13,
    WH_MOUSE_LL = 14
}

Die Frage ist nur welcher und wie sieht die enum-Liste für diesen Typ aus?
Ich hoffe wirklich sehr, dass mir jemand weiterhelfen kann.

MfG

SirFoldabit

27.11.2009 - 16:13 Uhr

Weiß das keiner oder antwortet keiner mehr, weil "gelöst" dran steht?
Wollte deshalb jetzt kein extra Thema starten...
Ich komm hier leider einfach nicht weiter...

MfG SirFoldabit

26.11.2009 - 15:44 Uhr

Hi Th69,

Sry, ich hatte vergessen zu sagen, dass ich das ganze natürlich global haben möchte, sprich es soll bei jeder anderen Anwendung auch funktionieren und nicht nur bei meiner eigenen. "FindHandle()" funktioniert ja soweit ich weiß nur für die eigene Anwendung... Korrigiert mich bitte falls das falsch sein sollte.

MfG

SirFoldabit

26.11.2009 - 11:53 Uhr

Hi dr4g0n76,

muss diesen Thread hier nochmal ausgraben. Hab mir dein Beispielprogramm angeschaut und festgestellt, dass es wunderbar funktioniert.
Allerdings leuchtet deine Form dann jede Sekunde ca. immer wieder auf. Da hast du wohl nen Timer drin oder (Hab mir nicht deinen gesamten SourceCode angeschaut)?
Naja jedenfalls habe ich ein Problem herauszufinden welches MenuItem gerade aktiviert wurde. Die ID des Menüs bekommt man ja durch dein Programm.
Wie kann ich jetzt aber z.B. die Methode "FindMenuItem(int type, IntPtr value);" benutzen? Ich habe danach gesucht aber auch bei Microsoft keine guten Infos dazu bekommen. "IntPtr value" ist mir klar, das ist der Wert des Menüs, bei deinem Programm wäre das "guiThreadInfo.hwndMenuOwner". Was aber bitte ist "type"???
Ist ja hier ein integer-Wert... In VB glaube ich ist "type" ein string und man kann direkt z.B. nach "Bearbeiten" suchen.
Kannst du mir da vllt weiterhelfen? Wäre echt super.
Natürlich darf mir auch gerne jeder andere behilflich sein. 😃

26.11.2009 - 00:11 Uhr

Wenn du es ganz sicher haben möchtest, dann benutze doch Onetime Pads.
Damit wird deine zu verschlüsselnde Nachricht wirklich unknackbar, weil der Schlüssel nach einmaliger Benutzung wieder gelöscht wird.
Falls es dich interressiert, dann google doch mal danach. Darüber wirst du sicherlich einiges finden.
Hab sogar noch ein passendes Beispiel für eine C#-Implementierung:
Hier Klicken.

MfG

SirFoldabit

25.11.2009 - 23:19 Uhr

Also wie das nun bei Firefox gelöst wird weiß ich nicht genau aber z.B. bei Windows ist das so gelöst, dass du ein Passwort eingibst und dieses dann, mithilfe eines praktisch nicht umkehrbaren Algorithmus (zu hoher Zeitaufwand), verschlüsselt wird.
Das verschlüsselte Passwort wird dann lokal auf der Platte abgespeichert. Wenn du dich jetzt anmeldest wird jedes Mal dein eingegebenes Passwort verschlüsselt und mit dem verschlüsselten Passwort auf deiner Platte verglichen...
Sind beide verschlüsselten Werte gleich, dann hast du das richtige Passwort eingegeben und dich erfolgreich angemeldet.
Man kann deshalb, um solche Passwörter zu knacken, auch nur Wörterbuchattacken verwenden.

MfG

SirFoldabit

25.11.2009 - 13:13 Uhr

Dankeschön @Th69 ich hab mir den SourceCode geholt und werd mir das mal anschaun. Ich hoffe ich finde was und wenn nicht, dann werd ich mir was einfallen lassen... 😃 oder euch hier im Forum wieder schön mit Fragen nerven. 😉

24.11.2009 - 20:44 Uhr

Doch kommen wir nun zu meiner Frage, ich möchte gerne wissen über welche Befehle ich das Event abfangen kann, welches ausgelöst wird, wenn der user Strg+c/Strg+v oder Rechtsklick und Kopieren/Ausschneiden/Einfügen klickt. Warum? Ich will dann mein Tool die Kopiervorgänge handlen lassen, an Stelle des Windows-Explorers.

Falls das noch nicht genau genug ist:

Mein Prog soll im Hintergund laufen und einfach alle Kopiervorgänge, welche sich auf Dateien oder Ordner beziehen, vom Explorer übernehmen.
Im Hintergund auch deshalb, sodass der User die Möglichkeit hat alle Kopiervorgänge "unsichtbar" ablaufen zu lassen mit zusätzlichen Einstellungen im Tray wie z.B. das Beenden der App.
Zusätzlich soll auch noch die Möglichkeit bestehen, dass die Kopiervorgänge ganz normal mit Progressbar etc. angezeigt werden.
Nach Beenden meiner App soll der Explorer wieder alle Kopieraufgaben übernehmen.
Ich dachte jetzt ich hätte die Lösung gefunden... Stichwort: Shell Extension und Copy Hook Handler... allerdings beziehen diese sich nur auf das Kopieren/Verschieben/Löschen etc. von Ordnern und nicht auch von Dateien.
D.h. die CopyCallback Methode kann ich dafür wohl auch nicht nutzen.
Das ist echt ärgerlich... jetzt bekomme ich alle Pfade+Dateinamen der files übergeben und weiß daher welche Dateien der User markiert bzw. kopiert hat, kann das aber beim Einfügen nicht nutzen, weil ich nicht weiß wohin der User einfügen möchte... Das kann doch nicht sein, das muss gehen. Bei TeraCopy geht das anscheinend auch... Hier geht's zur Page.
Dort steht unter anderem: "Shell integration. TeraCopy can completely replace Explorer copy and move functions, allowing you work with files as usual."

EDIT:
@Khalid: Drag & Drop ist erstmal nicht so wichtig, sollte aber nicht das Problem werden, wenn ich Obiges umsetzen könnte...

24.11.2009 - 18:15 Uhr

Und ich fänds auch für den Benutzer ehrlich gesagt etwas verwirrend, wenn er in dein Programm einfügt, aber der Zielort durch irgend ein Explorer-Fenster im Hintergrund bestimmt wird.

Da hast du mich dann falsch verstanden oder vllt. habe ich das Ganze auch nicht verständlich genug rübergebracht. Ich wollte/will mein Prog im Tray bei Systemstart laufen lassen und wenn der User kopiert bzw. einfügt soll mein Prog das Kopieren/Einfügen handhaben.

24.11.2009 - 17:01 Uhr

den Ursprungsort brauchst du doch gar nicht extra. Der ergibt sich aus dem Inhalt der Zwischenablage. Das Problem ist doch der Zielort. Und der ist soweit ich das sehen nicht bekannt. Im Prinzip ist das Ziel immer da, wo Ctrl-V gedrückt wird.

Genau, das Problem ist der Zielort...

Das sauberste wäre, wenn du in deiner Anwendung eine Möglichkeit schaffst, den Zielort auszuwählen, z.B. über einen FolderBrowserDialog.

Absolut richtig aber ich will es eigentlich ein bissl komfortabler gestalten, sodass der User eben nicht erst in meine Oberfläche rein muss um dort den Pfad auszuwählen.
Es wäre vllt erst einmal eine Notfalllösung oder eine aktzeptable Alternative aber so wirklich optimal wäre es nicht...

24.11.2009 - 16:47 Uhr

Hmm... also ich weiß nicht, wenn ich schon so an die Zwischenablage rankomme und die Msgs von Windows durch Überschreiben der WndProc bekomme....
Da nehme ich eigentlich schon an, dass ich dann auch an das Paste-Event rankomme und den dazugehörigen Ursprungsort bekomme. Notfalls durch Focusabfragen, welches Fenster gerade aktiv ist...
Wenn das nur über Shell Extensions geht... schön und gut aber wie mach ich das dann und warum sollte es nur so gehen? Ich muss dann da ja auch irgendwelche Ereignisabfragen o.Ä. machen...

MfG

SirFoldabit

24.11.2009 - 14:10 Uhr
  1. Danke @dr4g0n76, das hatte ich aber auch schon HIER gefunden.

  2. @Khalid: Die Pfade von den Dateien zu bekommen, die kopiert werden sollen, ist kein Problem. Das realisiere ich ja über GetFileDropList().
    Das Problem ist nur den Pfad/Ordner zu bekommen, wo die Dateien letzendlich hin sollen.
    Bsp.: Ich habe die Datei "C:\Test.txt", welche ich kopiere und dann bei "C:\Dokumente und Einstellungen\Username\Desktop" wieder einfügen möchte.
    Mein 1. Problem ist, dass die WM_PASTE irgendwie gar nicht ankommt und mein

  3. Problem ist, dass ich auch nicht weiß woher ich den Pfad bekomme bei dem eingefügt werden soll...
    Ich hoffe ihr versteht, was ich meine.

MfG

SirFoldabit

24.11.2009 - 10:54 Uhr

du meinst den Menüpunkt "Einfügen" des Standard-Kontextmenüs einer TextBox? Da müsstest du wohl in der WndProc der TextBox auf WM_PASTE (0x302) reagieren.

Jo, ich meine den Standard-Eintrag "Einfügen" des Windows Kontextmenüs bei einem Rechstklick mit der Maus auf den Desktop oder in einem Ordner.
Herbivore du bist echt Klasse, bei dir bekommt man sofort ne kompetente Antwort, die einen auf den richtigen Weg führt.
Jetzt sollte ich alles ohne Probleme implementieren können... Wobei... Eine Frage habe ich noch: Wenn ich auf WM_PASTE reagiere, bekomme ich dann auch den Pfad mitgeliefert? Ich muss ja schließlich wissen, wo dann eingefügt werden soll, also in welchem Ordner/Pfad.

23.11.2009 - 22:10 Uhr

Es geht doch um das Drücken von Strg-V in deiner Anwendung, oder? KeyDown/KeyPress/KeyUp, ggf. noch mit KeyPreview = true.

Jein... Einerseits ja, weil KeyDown Event is mir klar aber andererseits könnte der User ja auch über Rechtsklick->"Einfügen" die Dateien einfügen.
Das müsste ich ja ebenso abfangen... Ansonsten schon mal BIG THX für die schnelle und kompetente Hilfe.

MfG

SirFoldabit

23.11.2009 - 20:55 Uhr

Super herbivore, das ist genau das, was ich gesucht habe!
Nun habe ich aber ein kleines anderes Problem.
Nehmen wir an, mein Prog startet mit Systemstart und läuft im Hintergund.
Wie überprüfe ich nun ständig, ob sich Dateien in der Zwischenablage befinden???
Muss ja wohl ne Art Endlosschleife sein... in etwa so:


while (true)
{
	if (Clipboard.ContainsFileDropList())
	{
		stringcollection = Clipboard.GetFileDropList();
						
		for (int i=0; i<stringcollection.Count; i++)
		{
			MessageBox.Show(stringcollection[i].ToString()); //Oder eben die Werte in ein Array schreiben
		}
		Clipboard.Clear();
	}
}

Irgendnen Tipp für mich?

MfG

SirFoldabit

EDIT (Wichtig):

Ich hab mir jetzt die Pfade aus der Zwischenablage geholt. Wie bekomme ich jetzt aber mit, wenn der User auf "Einfügen" klickt oder "Strg+v" drückt???