PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : IShellLink mit C#


Tom Servo
2003-06-23, 21:47:12
Hi,

kennt sich hier jemand mit C# aus?

Ich möchte Shell Links in C#/.NET erzeugen. Habe es einmal mit WSH probiert, was einwandfrei funktioniert.

Da WSH nicht überall installiert ist, würde ich gerne stattdessen ISHellLink benutzen, was aber immer eine Runtime-Fehlermeldung "COM Object mit CLSID {...} not valid or registered" bringt.


Shell32.IShellLinkDual sl = new Shell32.ShellLinkObjectClass();


Ist das ein lösbares Problem?
Mit C++ (unmanaged) funktioniert ISHellLink problemlos.



Was anderes. Wenn ich eine Funktion mit DLLImport importiere, welche einen Pointer auf ein struct erwartet, ist mir nicht klar, wie ich der Funktion einen NULL Pointer übergeben kann.
(Im konkreten Fall, konnte man das Problem auch anders lösen)



[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct DEVMODE
{
...
}
class c {
[DllImport("user32.dll", CharSet=CharSet.Auto)]
static extern int ChangeDisplaySettings([In] ref DEVMODE dm, int flags);

public void f()
{
// ChangeDisplaySettings(DEVMODE *dm, int n)
// we need a NULL pointer for a value type
ChangeDisplaySettings(null, 0); //Fehlermeldung }
}

Demirug
2003-06-24, 12:11:38
Original geschrieben von Tom Servo
Hi,

kennt sich hier jemand mit C# aus?

Ich möchte Shell Links in C#/.NET erzeugen. Habe es einmal mit WSH probiert, was einwandfrei funktioniert.

Da WSH nicht überall installiert ist, würde ich gerne stattdessen ISHellLink benutzen, was aber immer eine Runtime-Fehlermeldung "COM Object mit CLSID {...} not valid or registered" bringt.


Shell32.IShellLinkDual sl = new Shell32.ShellLinkObjectClass();


Ist das ein lösbares Problem?
Mit C++ (unmanaged) funktioniert ISHellLink problemlos.

Wie hast du den den Wrapper erzeugt?

Ist unter dem GUID den die Fehlermeldung enthält in der Registry etwas eingetragen?

Was anderes. Wenn ich eine Funktion mit DLLImport importiere, welche einen Pointer auf ein struct erwartet, ist mir nicht klar, wie ich der Funktion einen NULL Pointer übergeben kann.
(Im konkreten Fall, konnte man das Problem auch anders lösen)



[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct DEVMODE
{
...
}
class c {
[DllImport("user32.dll", CharSet=CharSet.Auto)]
static extern int ChangeDisplaySettings([In] ref DEVMODE dm, int flags);

public void f()
{
// ChangeDisplaySettings(DEVMODE *dm, int n)
// we need a NULL pointer for a value type
ChangeDisplaySettings(null, 0); //Fehlermeldung }
}


Das hat mich auch mal einiges an Nerven gekostet. Ist aber ganz einfach zu lösen.

Man darf keine struktur benutzten sondern muss eine Klasse verwenden. In diesem Fall muss dann natürlich das ref weg.

Also:



[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public class DEVMODE
{
...
}
class c {
[DllImport("user32.dll", CharSet=CharSet.Auto)]
static extern int ChangeDisplaySettings(DEVMODE dm, int flags);

Tom Servo
2003-06-24, 15:24:36
Hallo Demirug,

danke für deine Hilfe.

Beim Nullpointer hätte nicht gedacht, dass man eine Klasse bei solchen Lowlevel Sachen benutzen darf. Die Wrapper habe ich nicht selber geschrieben (hätte ich auch nicht gekonnt als C# Anfänger).


Die GUID ist nicht in meiner Registry eingetragen. Aber in einem C++ Programm funtkioniert es wie gesagt, müsste dann die GUID nicht irgendwo doch existieren?

Aber ich glaube ich habe die Lösung nun doch mit Google gefunden. Hatte gestern zwar sehr viel gesucht, aber keine Lösung gefunden. Habe jetzt einfach mal direkt nach dem GUID gesucht und das ist scheinbar die Lösung:

http://groups.google.com/groups?selm=3b82647f.438120233%40msnews.microsoft.com&output=gplain

Vorher hatte ich mal ein Testprojekt erstellt, aber das ist jetzt wohl überflüssig.


// COM Referenz "Microsoft Shell Control And Automation" %windir%\System32\Shell32.dll
// mit VS7 hinzugefügt. VS7 erzeugt die Datei Interop.Shell32.dll im Programm-Directory
// ab jetzt sollte Shell32 im C# Programm nutzbar sein.

namespace test_shell32
{
class Class1
{
[System.STAThread]
static void Main()
{
try
{
new Shell32.ShellLinkObjectClass();
}
catch (System.Exception ex)
{
//ex.Message => "Das COM-Objekt mit der CLSID
// {11219420-1768-11D1-95BE-00609797EA4F}
// ist ungültig oder wurde nicht registriert."

throw ex; //Breakpoint
}
}
}
}


http://home.tiscalinet.de/bertw/proj/tdprof/misc/test_shell32.zip

Tom Servo
2003-06-25, 19:20:26
Hallo Demirug,

obwohl ich das mit class statt struct nun sogar nochmal auf einer Webseite zum Thema gelesen habe, scheint da irgendwie der Wurm drin zu sein.

Ich habe es mal zum Test mit EnumDisplayDevices() getestet und mit struct funktionierts, aber mit class liefert die Funktion success, aber es sind keine Daten in dd eingetragen. Da die Funktion ja success liefert, sollten doch die Daten bei der Funktion angekommen sein (also der size Member).

Kann es sein, dass wegen class irgendwie nur eine Kopie zum Aufruf verwendet wird und die Original-Struktur dann bei Rückkehr nicht upgedated wird. Mit struct gehts aber. Dann würden sich Klassen nicht als Out Parameter eignen.

Falls das kein bekanntes Problem ist, dann könnnte ich auch mal ein kurzes Testprogramm schreiben.

Demirug
2003-06-25, 19:39:37
Mein Fehler. Ich habe nicht daran gedacht das die Funktion ja in der "Struktur" Daten zurück gibt.


[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public class DEVMODE
{
...
}

class c
{
[DllImport("user32.dll", CharSet=CharSet.Auto)]
static extern int ChangeDisplaySettings([In, Out]DEVMODE dm, int flags);
}


Die Attribute sind notwending damit das System weiss das es nach dem Aufruf die Daten wieder zurück kopieren muss.

Tom Servo
2003-06-25, 20:06:55
Danke, es funktioniert damit.

Ich hatte sogar selber mal [In] und [Out] probiert, aber das [In, Out] ist wohl nötig, weil ja der Size Member als Input dient. Mit [Out] gibts eine Exception.

War aber nicht dein Fehler. Die Funktion ChangeDisplaySettings() wofür ich momentan den Nullpointer brauche, war ja eine, die wirklich das Objekt nur als Input verlangt.