Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   DLL Side-by-side registration & redirection (https://www.delphipraxis.net/196811-dll-side-side-registration-redirection.html)

Der schöne Günther 21. Jun 2018 17:47

DLL Side-by-side registration & redirection
 
Herzlich Willkommen zu einem spannenden Thema :roteyes:

Warnung: Ich kenne mich nicht wirklich aus. Ich will noch nicht einmal alles verstehen, ich möchte nur etwas hinbekommen.


Eine Delphi-Anwendung verwendet eine ActiveX-Komponente. Bisher musste man hingehen und auf jedem PC mit Adminrechten einmal mit
Delphi-Quellcode:
regsvr32 someLib.dll
diese DLL "registrieren". Und die musste auch an diesem Pfad bleiben!

Ich möchte nun diese tolle "Side-by-side" registration nutzen: Ich kann mir diesen ganzen Registrierungsvorgang komplett sparen wenn ich
  • Der DLL
    Delphi-Quellcode:
    someLib.dll
    in ihrem Manifest eine
    Delphi-Quellcode:
    assemblyIdentity
    (sowie ein paar weitere Infos) gebe
  • Der Anwendung in ihrem Manifest eine
    Delphi-Quellcode:
    assemblyIdentity
    gebe
  • Der Anwendung
    Delphi-Quellcode:
    myApp.exe
    ins Manifest gebe dass sie die DLL
    Delphi-Quellcode:
    someLib.dll
    (genau spezifiziert mit Versionsnummer und allem) verwendet

Fortan brauche ich keine Registrierung mehr. Tolle Sache, das funktioniert wirklich :thumb:


Mich stören die Beschränkungen dass die DLL im gleichen Verzeichnis wie die .exe-Datei liegen muss. Es gibt ein paar weitere Regeln wo sie auch liegen darf, aber ich mag die alle nicht:

Zitat:

The first time side-by-side searches for a private assembly, it determines whether a language-specific subfolder exists in the application's directory structure. If no language-specific subfolder exists, side-by-side searches for the private assembly in the following locations using the following sequence.
Side-by-side searches the WinSxS folder.
\\<appdir>\<assemblyname>.DLL
\\<appdir>\<assemblyname>.manifest
\\<appdir>\<assemblyname>\<assemblyname>.DLL
\\<appdir>\<assemblyname>\<assemblyname>.manifest
Quelle: MSDN: About Isolated Applications and Side-by-side Assemblies > Assembly Searching Sequence


Meine Frage: Gibt es eine Möglichkeit dass ich z.B. die .exe unter
Delphi-Quellcode:
.\myApp.exe
haben kann und die DLL unter
Delphi-Quellcode:
.\fancyLibraries\someDll.dll
oder ist das nicht möglich?

KodeZwerg 21. Jun 2018 18:01

AW: DLL Side-by-side registration & redirection
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1405470)
Meine Frage: Gibt es eine Möglichkeit dass ich z.B. die .exe unter
Delphi-Quellcode:
.\myApp.exe
haben kann und die DLL unter
Delphi-Quellcode:
.\fancyLibraries\someDll.dll
oder ist das nicht möglich?

Wenn ich das richtig verstehe wäre die Antwort:
Zitat:

It is important to remember that Windows has a strict rule regarding loading DLLs: if the DLL name passed to any of the LoadLibrary* APIs contains a path, even a partial path, Windows will not search for the DLL. It will try the path as requested and quit. If the DLL name contains no path, Windows will try the activation context first then the standard Windows places (application directory, system directories, path etc.)

Der schöne Günther 21. Jun 2018 18:15

AW: DLL Side-by-side registration & redirection
 
Danke für die Antwort.

Da ist mein Problem dass ich ja im Endeffekt gar nichts mit
Delphi-Quellcode:
LoadLibrary
mache, das tun wohl irgendwelche Delphi-Automatismen im Hintergrund. Wenn ich den Absatz richtig verstehe dann greift die ganze Side-by-side-Geschichte sowieso nicht wenn ich explizit einen Pfad angebe? Wäre schön das auch auf einer offiziellen Microsoft-Seite zu lesen.

Bernhard Geyer 21. Jun 2018 21:49

AW: DLL Side-by-side registration & redirection
 
SideBySide macht doch nur wirklich Sinn wenn man selbst die DLLs mitliefert und nicht eine DLL nimmt die irgendwo liegt.

Der schöne Günther 21. Jun 2018 22:38

AW: DLL Side-by-side registration & redirection
 
Tue ich doch. Ich hätte nur immer gerne im Stammverzeichnis nichts außer der .exe-Datei und die .DLL-Dateien alle in einem separaten Unterordner gesammelt. Mehr ist das nicht.

Wahrscheinlich einfach nur Spinnerei, aber ich würde mich trotzdem freuen wenn es geht.

KodeZwerg 21. Jun 2018 22:44

AW: DLL Side-by-side registration & redirection
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1405475)
Da ist mein Problem dass ich ja im Endeffekt gar nichts mit
Delphi-Quellcode:
LoadLibrary
mache, das tun wohl irgendwelche Delphi-Automatismen im Hintergrund.

Nur eine Überlegung, in was auch immer für Unterordner, was passiert wenn Du dann RegSvr32/TRegSvr darauf loslässt?
Also SxS so wie Du es bereits machst nur die Typbibliothekregistrierung umverfrachten.

edit
Wobei, wenn ich das aus meinem Link da oben richtig verstehe, der Unterordner sich im %PATH% befinden sollte.

EWeiss 21. Jun 2018 23:03

AW: DLL Side-by-side registration & redirection
 
Zitat:

Mich stören die Beschränkungen dass die DLL im gleichen Verzeichnis wie die .exe-Datei liegen muss. Es gibt ein paar weitere Regeln wo sie auch liegen darf, aber ich mag die alle nicht:
Keine DLL muss im EXE Pfad liegen wenn du es nicht willst.
Vorausgesetzt man macht es richtig.

Was hier abgeht ist letztendlich nur Raten und ein Glücksspiel, geht dies geht das.
Wenn ich ein DLL außerhalb meines Anwendungspfad verwenden will dann setze ich die Umgebung und gut ist.

Zitat:

Wahrscheinlich einfach nur Spinnerei, aber ich würde mich trotzdem freuen wenn es geht.
Klar geht das wenn du wie schon gesagt die Umgebung setzt. (setzen kannst)

Ist das gleiche wie mit der Bass.dll da wird auch immer gesagt sie muss sich im EXE Pfad befinden das ist aber absoluter quatsch.
Sie darf nur nicht in den System Pfad verlegt werden weil sich die Versionen unterscheiden und andere Anwendungen dann nicht mehr laufen.
Auch meine DLL Bass_Vis lege ich nicht im Anwendungspfad genauso wenig wie im Pfad der Bass.DLL

MeinPfad\Player.exe
MeinPfad\Bass_Lib\Bass.dll
MeinPfad\Bass_ADDOn\Bass_Vis.dll
MeinPfad\Bass_ADDOn\bass_fx.dll

Du siehst also ich habe auch eine Struktur angelegt wo ich meine DLL's ablege.
Ich mag es genauso wenig wie du wenn alles im Anwendungspfad geklatscht wird.
Also du bist der Boss deiner Anwendung und legst selber fest wo sich deine DLL's befinden sollen.

gruss

KodeZwerg 22. Jun 2018 01:13

AW: DLL Side-by-side registration & redirection
 
Emil, er benutzt nicht LoadLibrary() wie Du mit Bass.dll. Was er beschreibt ordne ich eher .OCX (ActiveX) zu.

EWeiss 22. Jun 2018 01:21

AW: DLL Side-by-side registration & redirection
 
Zitat:

Zitat von KodeZwerg (Beitrag 1405495)
Emil, er benutzt nicht LoadLibrary() wie Du mit Bass.dll. Was er beschreibt ordne ich eher .OCX (ActiveX) zu.

Ich verwende kein LoadLibrary wer sagt dir das? ;)

Das einzige Problem das er haben könnte wenn er die Umgebung setzt das der seltsame Compiler von Delphi die DLL selber lädt bevor er die Umgebung setzen kann.
Wenn also die DLL dann nicht gefunden wird startet das Programm erst gar nicht.
VB zum Beispiel tut das nicht.

Beispiel:
Delphi-Quellcode:
var
  MeinDLLPath: string;

begin

  MeinDLLPath := ExtractFilePath(ParamStr(0)) + 'Meine_Lib';
  SetEnvironmentVariable(PWideChar('Path'), PWideChar(MeinDLLPath));
  if not FileExists(ExtractFilePath(ParamStr(0)) + 'Meine_Lib\Meinelib.dll') then
    Halt;
end;
Ich befürchte aber das es trotz meiner Aussage bedingt durch den Compiler von Delphi nicht funktionieren wird wenn es keinen Schalter gibt
der verhindert das die Anwendung sich beendet wenn die DLL nicht gefunden wird bevor man die Umgebung setzen kann.

Zumindest unter VB gibt es diesbezüglich keine Probleme ohne LoadLibrary.
Vielleicht kann man das umgehen wenn man vorher eine Batchdatei erstellt. (nicht getestet)

gruss

EWeiss 22. Jun 2018 01:46

AW: DLL Side-by-side registration & redirection
 
Hier ein Beispiel in Sharp..
Von meinem BassVis Example in C# (Sharp) :lol:

Code:
private void BassInit()
{
  string BassPath;
  string BassVisPath;
  BASS_DEVICEINFO info;

  BassPath = Path.Combine(Application.StartupPath, "BassLib");
  Win32Api.SetEnvironmentVariable("Path", BassPath);

  // check the correct BASS was loaded
  if (Win32Api.HiWord(Bass.BASS_GetVersion()) != Bass.BASSVERSION)
  {
    MessageBox.Show("BASS_Vis.DLL existiert nicht!", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
    Application.Exit();
  }

  //Set Path to AddOns
  BassVisPath = Path.Combine(Application.StartupPath, "BassADDOn");

  Win32Api.SetEnvironmentVariable("Path", BassVisPath);

  //Check "bass_Vis.dll" exist

  string visDll = Path.Combine(Application.StartupPath, @"BassADDOn\bass_Vis.dll");

  if (!File.Exists(visDll))
  {
    MessageBox.Show("BASS_Vis.DLL failed to load!", "BASS_Vis.DLL", MessageBoxButtons.OK, MessageBoxIcon.Error);
    Application.Exit();
  }

  // setup recording and output devices (using default devices)
  if ((Bass.BASS_RecordInit(-1) == false) || (Bass.BASS_Init(-1, 44100, 0, Handle, Guid.Empty) == false))
  {
    MessageBox.Show("Can\'t initialize device", "BASS.DLL", MessageBoxButtons.OK, MessageBoxIcon.Error);
    Application.Exit();
  }
  else
  {
    input_ = 0;
    info = new BASS_DEVICEINFO();
    while (Bass.BASS_RecordGetDeviceInfo(input_, info))
    {
      Bass.BASS_RecordGetDeviceInfo(input_, info);
      cmbInputs.Items.Add(info.name);
      input_++;
    }
    cmbInputs.SelectedIndex = 0;
  }

  Text = "Bass_Vis Example for C# VS2012: BassVis Version: " + BassVis.BASSVIS_GetVersion();
  Width = 498;
}

#endregion BassInit()
Ich setze die Umgebung nur für diese Anwendung nicht global von außen kann das also niemand sehen.
Die Anwendung startet ohne zu murren und die DLL's werden gefunden.

Und nein die DLL's werden nicht dynamisch geladen.
Ich glaube aber das Problem ist Delphi in dem Fall.
Zitat:

das tun wohl irgendwelche Delphi-Automatismen im Hintergrund.
gruss

Der schöne Günther 22. Jun 2018 07:40

AW: DLL Side-by-side registration & redirection
 
Zitat:

Zitat von EWeiss (Beitrag 1405491)
Also du bist der Boss deiner Anwendung und legst selber fest wo sich deine DLL's befinden sollen.

Wie schon eingangs geschrieben geht es nicht um eine simple DLL sondern eine ActiveX-Komponente die meines Wissens nach entweder fest im System registriert werden muss oder halt direkt über diese lustige Side-by-side registration eingebunden werden kann.

EWeiss 22. Jun 2018 14:50

AW: DLL Side-by-side registration & redirection
 
Zitat:

geht es nicht um eine simple DLL sondern eine ActiveX-Komponente
Ach so und du denkst die wären was besonderes? Was ist da soviel anders?
Wie viele ActiveX DLL's möchtest du haben die ich schon selbst geschrieben habe?

Aber da du diese nicht mit LoadLibrary in den Speicher laden willst vergiss es
denn das ist eine der Voraussetzungen um ActiveX dll's während der Laufzeit zu registrieren und auszuführen.
Wie gesagt im welchen Pfad diese sich befinden ist wurscht.

gruss

Der schöne Günther 22. Jun 2018 15:02

AW: DLL Side-by-side registration & redirection
 
Ich halte mich an das was der Hersteller sagt.

Beispiel:
Zitat:

Prior to Windows XP, an ActiveX control had to be registered on the system before it could be used by an application. This registration creates a few issues among which:
Registering a control requires administrative rights on a system.
Registering a control affects multiple applications as the same DLL is shared among all applications using the same version of the control (some developers refer to this issue as the DLL hell.)
An application that unregisters a control will prevent all other applications from using it.
The solution to these issues is to use side-by-side activation, or registration-free components; a concept that is very similar to what was introduced with .NET.
When side-by-side registration is used, two things happen:
scvncctrl.dll can be placed in each application's folder and is not shared with other applications.
The ActiveX control is not registered in the system wide registry but each application acts as if it had its own registered component.
https://support.s-code.com/Knowledge...m-registration

Heißt: Es muss entweder registriert werden oder man nutzt "side-by-side".

EWeiss 22. Jun 2018 15:07

AW: DLL Side-by-side registration & redirection
 
Kenne die DLL nicht.
Zitat:

Heißt: Es muss entweder registriert werden oder man nutzt "side-by-side".
Oder LoadLibrary.

Ich mache es so.. mit LoadLibrary von meinem Plugin System.

Code:
Private Sub CheckVisPlugin()

    VisPlugin = GetSetting(App.EXEName, "Option", "PluginVisual", vbNullString)
    If Right$(VisPlugin, 4) = ".dll" Then
        RegServe VisPlugin, True
        VisPlugin = GetFileName(VisPlugin)
        PluginName = Left$(VisPlugin, Len(VisPlugin) - 4)
        Set PluginVis = CreateObject(PluginName & ".clsMain")
        msgPlg.Visual = True
        PluginVis.ToolBarVisible = frmToolbar.Visible = True
        PluginVis.EQVisible = frmEqualizer.Visible = True
        PluginVis.SkinChange sOldSkinName

        If Me.WindowState = vbMinimized Then
            PluginVis.PlayerVisible = False
        Else
            PluginVis.PlayerVisible = Me.Visible
        End If

        If stndPlayList = 1 Then
            PluginVis.PlaylistVisible = True
            PluginVis.PlaylistPos frmPlayList.Left, frmPlayList.Top, frmPlayList.Width, frmPlayList.Height
        Else
            PluginVis.PlaylistVisible = False
        End If
        PluginVis.Execute FrmMain_Hwnd
    End If

End Sub
Code:
Public Function RegServe(ByVal Path As String, _
                         ByVal mode As Boolean) As Boolean

Dim insthLib As Long
Dim lpLibAdr As Long
Dim hThd    As Long
Dim lpExCode As Long
Dim procName As String
Dim Result  As Long
Dim okFlag  As Boolean
'### DLL in den Speicher laden

    insthLib = LoadLibrary(Path)
    '### Aktion wählen
    If insthLib Then
        If mode Then
            procName = "DllRegisterServer"
        Else
            procName = "DllUnregisterServer"
        End If
        '### Adresse der DLL im Speicher
        lpLibAdr = GetProcAddress(insthLib, procName)
        If lpLibAdr <> 0 Then
            '### Aktion starten
            hThd = CreateThread(ByVal 0, 0, ByVal lpLibAdr, ByVal 0&, 0&, 0&)
            If hThd Then
                '### Maximal 5 sec warten
                Result = WaitForSingleObject(hThd, 5000)
                If Result = STATUS_WAIT_0 Then
                    '### Vorgang erfolgreich in 5 sec beendet
                    Call CloseHandle(hThd)
                    okFlag = True
                Else
                    '### 5 sek. überschritten -> Thread schließen
                    Call GetExitCodeThread(hThd, lpExCode)
                    Call ExitThread(lpExCode)
                    Call CloseHandle(hThd)
                End If
            End If
        End If
        '### Speicher wieder freigeben
        Call FreeLibrary(insthLib)
    End If
   
    If Not okFlag Then
        MsgBox ("Fehler! Der Vorgang wurde abgebrochen.")
    Else
        'MsgBox ("Der Vorgang war erfolgreich!")
    End If
   
    RegServe = okFlag
   
End Function
Nur damit du siehst das ich dir nicht nur was erzähle sondern weis wie es geht.

gruss

Der schöne Günther 22. Jun 2018 15:27

AW: DLL Side-by-side registration & redirection
 
Und das funktioniert ohne Adminrechte?

Denn regsvr32.exe macht ja im Endeffekt auch genau das was der obige Quellcode tut. Ich bin sehr ungläubig, aber ich probiere es bei Gelegenheit aus.


MSDN: ActiveX-DLLs und OCX-Dateien per Quellcode registrieren und deregistrieren

EWeiss 22. Jun 2018 15:35

AW: DLL Side-by-side registration & redirection
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1405554)
Und das funktioniert ohne Adminrechte?

Denn regsvr32.exe macht ja im Endeffekt auch genau das was der obige Quellcode tut. Ich bin sehr ungläubig, aber ich probiere es bei Gelegenheit aus.


MSDN: ActiveX-DLLs und OCX-Dateien per Quellcode registrieren und deregistrieren

Also mein Player benötigt keine Adminrechte von daher ;)
Aber ich habe nebenbei aus Sicherheitsgründen das noch zu meinem Manifest addiert.
Du hättest es nicht extra nochmal verlinken müssen denn hier steht doch wie es geht.

Code:
  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
    <security>
      <requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
        <!-- UAC Manifest Options
             If you want to change the Windows User Account Control level replace the
             requestedExecutionLevel node with one of the following.

        <requestedExecutionLevel level="asInvoker" uiAccess="false" />
        <requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
        <requestedExecutionLevel level="highestAvailable" uiAccess="false" />

            Specifying requestedExecutionLevel element will disable file and registry virtualization.
            Remove this element if your application requires this virtualization for backwards
            compatibility.
        -->
        <requestedExecutionLevel level="asInvoker" uiAccess="false" />
      </requestedPrivileges>
    </security>
  </trustInfo>
Wie gesagt ich kann alle meine DLL's zur Laufzeit registrieren und unregistrieren wo sich der Pfad zur DLL befindet ist dabei zu vernachlässigen.
Und im übrigen alle Dll's die mit VB erstellt werden sind ActiveX Dll's (denn hier gibt es keine "normalen" Dll's)

Ich verwende kein regServ32 sondern erstelle das Objekt selbst wenn LoadLibrary erfolgreich war.
Siehe!
CreateObject(PluginName & ".clsMain")

clsMain ist der Einsprungs punkt der geladenen DLL.
Diese Classe muss in jeder DLL vorhanden sein.

gruss


Alle Zeitangaben in WEZ +1. Es ist jetzt 08:51 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz