Autor Beitrag
Seven of Nine
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 132
Erhaltene Danke: 1

Win XP, Win Vista HomePro
Delphi 2009
BeitragVerfasst: Fr 26.06.09 11:32 
Folgender Code hat unter Delphi 7 und einer älteren BASS-Version einwandfrei funktioniert um Music-Module (MODS) aus einem kompilierten ResourcenFile zu laden.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
 //Init Sound Modules
  modc      := 3;
  for i:= 1 to modc do
    begin
      case i of
        1:  begin
              MyResource  :=FindResource(HInstance, 'RES7', RT_RCDATA);
            end;
        2:  begin
              MyResource  :=FindResource(HInstance, 'RES8', RT_RCDATA);
            end;
        3:  begin
              MyResource  :=FindResource(HInstance, 'RES9', RT_RCDATA);
            end;
      end; //of case

      MyGlobal := LoadResource(HInstance,MyResource);
      pResource:= LockResource(MyGlobal);
      mods[i]  := BASS_MusicLoad(True, pResource, 0, 0, BASS_MUSIC_RAMP OR BASS_UNICODE,0);
      FreeResource(MyGlobal);
    end;


Unter Delphi 2009 lässt sich der Code zwar ebenfalls compilieren (das BASS_UNICODE Flag ist mit gesetzt) allerdings werden die Sound-Module nicht ordnungsgemäß geladen
- Handle auf modc steht nach dem laden weiter auf 0
- der Bass ErrorCode steht auf -1 / unknown Error
- Das Modul ist nicht abspielbar

Interessanterweise funktionieren einige fast identische Codezeile mit BASS/samples" (BASS_SampleLoad) einwandfrei

was mache ich hier falsch? was muss ich ändern?

lG Martin
Sinspin
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1340
Erhaltene Danke: 120

Win 10
RIO, CE, Lazarus
BeitragVerfasst: Fr 26.06.09 12:51 
Haben sich die Resourcen geändert, so das du nun Unicode verwenden musst? Wenn du die resfile nicht geändert hast müssten die doch noch gleich sein.
Zudem sind Mods doch eh Binärdateien. Wenn ich mich nicht irre ist Unicode doch nur für die Strings von nöten.
Berichtigt mich wenn ich falsch liege.

_________________
Wir zerstören die Natur und Wälder der Erde. Wir töten wilde Tiere für Trophäen. Wir produzieren Lebewesen als Massenware um sie nach wenigen Monaten zu töten. Warum sollte unser aller Mutter, die Natur, nicht die gleichen Rechte haben?
Seven of Nine Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 132
Erhaltene Danke: 1

Win XP, Win Vista HomePro
Delphi 2009
BeitragVerfasst: Fr 26.06.09 13:55 
Die Idee das es daran liegt, dass sich das *.res File durch D2009 geändert hat, hatte ich auch schon.
habe es daraufhin mit dem Compiler der D2009 beiliegt erneut kompiliert.
Funktioniert leider trotzdem nicht.

lG Martin

---Moderiert von user profile iconNarses: Beiträge zusammengefasst---

Ich habe gerade einen Tipp vom Programmierer der Komponente bekommen.
-> Die neuen Versione von BASS benötigen jetzt auch die Angabe der Länge des MOD-Files
geänderter Sourcode der funktioniert anbei

lG Martin

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
 //Init Sound Modules
  modc      := 3;
  for i:= 1 to modc do
    begin
      case i of
        1:  begin
              MyResource  :=FindResource(HInstance, 'RES7', RT_RCDATA);
            end;
        2:  begin
              MyResource  :=FindResource(HInstance, 'RES8', RT_RCDATA);
            end;
        3:  begin
              MyResource  :=FindResource(HInstance, 'RES9', RT_RCDATA);
            end;
      end; //of case

      MyGlobal := LoadResource(HInstance,MyResource);
      pResource:= LockResource(MyGlobal);
      ResSize  := SizeOfResource(HInstance,MyResource);
      mods[i]  := BASS_MusicLoad(True, pResource, 0, ResSize, BASS_MUSIC_RAMP OR BASS_UNICODE,0);
      FreeResource(MyGlobal);
    end;
FinnO
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1331
Erhaltene Danke: 123

Mac OSX, Arch
TypeScript (Webstorm), Kotlin, Clojure (IDEA), Golang (VSCode)
BeitragVerfasst: Fr 26.06.09 14:27 
Moderiert von user profile iconNarses: Komplett-Zitat des letzten Beitrags entfernt.

also irgendwie verstehe ich nicht warum du immer wieder MyResource überschreibst. In der Schleife wird 3 schließlich immer erreicht, es sollte also jedes mal MyResource = FindResource(HInstance,'RES9',RT_RCDATA); sein. :scratch:
Seven of Nine Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 132
Erhaltene Danke: 1

Win XP, Win Vista HomePro
Delphi 2009
BeitragVerfasst: Fr 26.06.09 15:14 
ich verstehe nicht ganz was du meinst.
- MyResource verweist bei unterschiedlicher Zählernummer jeweils auf ein anders MOD-File innerhalb des Resourcenfiles (RES7 -> RES8 -> RES9)
- Die Zuweisung, Längenermitllung und das finale Laden des Modules wird dann außerhalb von case bearbeitet um ein paar Zeilen Code zu sparen
...sollte doch ok so sein oder?

btw: das in der case anweisung noch begin/end; mit drinsteht ist so natürlich nicht nötig. In meinem Code stehen da allerdings jeweils noch weitere Codezeilen die ich aber entfernt habe um das Bsp. hier nicht zu verkomplizieren

lG Martin
FinnO
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1331
Erhaltene Danke: 123

Mac OSX, Arch
TypeScript (Webstorm), Kotlin, Clojure (IDEA), Golang (VSCode)
BeitragVerfasst: Fr 26.06.09 16:02 
ja funktionieren wirds, aber wenn eine Schleife von 1-3 durchgeht und dann je durchlauf eine unterschiedliche Aktion macht, kann man dann nicht die Aktionen ohne Schleife untereinander setzen?
Seven of Nine Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 132
Erhaltene Danke: 1

Win XP, Win Vista HomePro
Delphi 2009
BeitragVerfasst: Fr 26.06.09 16:09 
Die Schleife macht je bewusst bei jedem Durchlauf "eine andere Funktion", nämlich das laden eines weiteren Sound-Moduls. Das solange bis alle Module geladen sind.
Aber vlt. "stehe ich auch nur auf dem Schlauch" was du mir sagen möchtest. :)

lG Martin
FinnO
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1331
Erhaltene Danke: 123

Mac OSX, Arch
TypeScript (Webstorm), Kotlin, Clojure (IDEA), Golang (VSCode)
BeitragVerfasst: Fr 26.06.09 16:23 
ich meine:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
for i := 1 to 3 do 
case i of 
  1: 
  begin
   //dosomething
  end;
  2: 
  begin
  //dosomethingelse
  end;
  3: 
  begin
  //dosomethingdifferent
  end;
end;


bewirkt nichts anderes als
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
procedure Dosomething;
begin
  //dosomething
  //dosomethingelse
  //dosomethingdifferent
end;
Gausi
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 8554
Erhaltene Danke: 481

Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
BeitragVerfasst: Fr 26.06.09 16:27 
Ja, aber in der for-Schleife ist ja nicht nur die case-Anweisung drin. ;-)

_________________
We are, we were and will not be.
Seven of Nine Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 132
Erhaltene Danke: 1

Win XP, Win Vista HomePro
Delphi 2009
BeitragVerfasst: Fr 26.06.09 16:29 
ok, jetzt habe ich dich verstanden !Danke für die Geduld.

der Grund für die Schleife bei mir liegt darin das ich (wie schon erwähnt) in der Case Anweisung noch zusätzlich Codezeilen habe welche die Schleifenvariable (i) dazu verwenden ein bestimmte Arrays mit Daten zu füllen.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
case i of
 1:  begin
       MyResource  :=FindResource(HInstance, 'RES7', RT_RCDATA);
       ModPlayTime[i] := (3*60 + 39) * 1000 ; //3:39
       ModText[i]     := 'Title: XTC     Artist: Sat';
     end;


Aber auch das kann man natürlich anders machen. Auf diese Weise ist aber die Case-Anweisung (...die hat bei mir im Code auch deutlich mehr Zeilen..) schneller erstellt gewesen -> Copy & Paste. Notwendig für den Code ist das natürlich nicht.

lG Martin
FinnO
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1331
Erhaltene Danke: 123

Mac OSX, Arch
TypeScript (Webstorm), Kotlin, Clojure (IDEA), Golang (VSCode)
BeitragVerfasst: Fr 26.06.09 16:30 
@GAUSI:die könnte man dann aber aus Zeitgründen vor die for-schleife setzten ;)

Was ich jetzt immer noch nicht verstanden habe:

MyResource verwendest du wozu? Weil du der ja sofort wieder einen anderen Wert zuweist, ohne sie zu benutzen. (es sei denn, du enthälst uns noch Code vor)
Seven of Nine Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 132
Erhaltene Danke: 1

Win XP, Win Vista HomePro
Delphi 2009
BeitragVerfasst: So 28.06.09 05:04 
MyResource enthält ja jedesmal ein anderes Handle das gleich darauf benötigt wird (siehe zB 1.tes Codeschnipsel).
Aber, wie schon erwähnt, man könnte das ganze natürlich auch ohne die for-Schleife machen, dann wäre es "offensichtlicher".

Momentan kämpfe ich mit einem weiteren Problem.
Die Applikation wurde bisher mit einer alten bass.dll installiert die vom Installer im InstallationsDir gepeichert wird.
Die neue Version meiner Applikation braucht wegen D2009 aber unbedingt eine neuere bass.dll.
Ich liefere im neuen Installer-Paket dann einfach die nuee bass.dll mit..soweit alles bestens. ABER

Meine Applikation hat eine Autoudate-Funktion. Bereits installierte Versionen "haben" mur die alte "bass.dll", Wird diese aufgerufen gibt es ein Problem, denn die "neue Applikation" braucht ja die "neue" bass.dll.
Nach dem Auto-Update würde es also bei diesen Usern zu Fehlern kommen, deswegen kann ich diese Version noch nicht releasen, sondern muss zuerst das Problem lösen.

Hier mein bisheriger Lösungsansatz, der leider noch nicht funktioniert
- "Neue" bass.dll wird als Resource der Applikation beigegeben
- Beim Start der Applikation wird in FormCreate des Hauptformulars die Version der bass.dll geprüft. Ist diese zu alt, soll sie mit der neueren aus der Resource überschrieben werden (mittels ResourceStream ... Res.SavetoFile).

soweit kein Problem...dachte ich... ABER das gestaltet sich nicht so einfach. Dadurch das die Funktionen der DLL ja in Uses referenziert sind, wird die DLL von der Applikation benützt. Ich kann sie also, vor dem extrahieren der neuen DLL-Version, nicht so einfach löschen. Zusätlich dazu befindet sie sich auch noch im Windows ProgramFiles Ordner wo die UAC auch noch hinzukommt.

Henne vs Ei Problematik ??
kennt jemand einen besseren Ansatz?

lG Martin
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19346
Erhaltene Danke: 1754

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: So 28.06.09 09:16 
Benenne die DLL beim Update einfach um (das geht mit Exen und DLLs, wenn sie gerade laufen) und kopiere die neue an deren Stelle. Danach startest du die eigene Anwendung neu und gibst den Parameter zum Löschen mit.

Ich bin gerade dabei eine entsprechende Updateklasse für Delphiprojekte zu entwickeln. Wegen den notwendigen Rechten passiert das mehrstufig. Ich habe das Ablaufdiagramm (eigene Notation :D) einmal als PDF angehängt.
Vorteile des Verfahrens: das vorher und nachher laufende Programm hat keine Adminrechte, diese werden angefordert ohne eine zusätzliche Exe oder DLL und eine recht gute Fortschrittsanzeige ist auch möglich.
Einloggen, um Attachments anzusehen!
Seven of Nine Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 132
Erhaltene Danke: 1

Win XP, Win Vista HomePro
Delphi 2009
BeitragVerfasst: Di 30.06.09 19:32 
@Sebastian: Lässt sich eine Datei (DLL)
a) wenn sie gerade verwendet wird und gleichzeitig
b) im Windows-ProgramFiles Ordner liegt
mit RenameFile(Oldfilename,Newfilename) wirklich bei allen Win-OS-Versionen aus dem aktuell laufenden Programm heraus umbenennen?

Bei mir funktioniert das irgendwie nicht, RenameFile gibt mir als Ergebnis "False" zurück, obwohl die Notation stimmen müsste.

Aber ich würde das ganze ganz gerne ohne den von Dir in deinem Ablaufdiagramm beschriebenen Zusatzweg über eine 2.te Instanz der Anwendung machen. Möglich?

lG Martin
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19346
Erhaltene Danke: 1754

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Di 30.06.09 19:38 
Ohne zweite Instanz geht das wegen den Rechten schon normalerweise nicht. Das Umbenennen selbst sollte nicht das Problem sein, das geht sogar mit Windows-Systemdateien. So kann man die ersetzen obwohl Windows sie benutzt.

Ich werde das Umbenennen gleich nochmal kurz testen.

// EDIT:
Es funktioniert wie ich mir schon dachte bereits ab Windows 2000.
Seven of Nine Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 132
Erhaltene Danke: 1

Win XP, Win Vista HomePro
Delphi 2009
BeitragVerfasst: Di 30.06.09 20:46 
Ok hier ist mal ein Teil meines Codes. Das ist sicher nicht besonders elegant aber es funktioniert hiermit. Evtl. hilft es mal jemandem mit einem ähnlichen Problem.

Eins Vorab: RenameFile(Oldfilename,Newfilename); funktionierte bei mir leider NICHT.
Was aber funktiert ist folgende Funktion (Anmerkugn: sie ist nicht von mir; Autor ist mir derzeit nicht bekannt)
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
function RenameFileEx(const AOldName, ANewName: string; ARenameCheck: boolean = false): boolean;
var
  sh: TSHFileOpStruct;
begin
  sh.Wnd := Application.Handle;
  sh.wFunc := fo_Move;
  sh.pFrom := PChar(AOldName + #0);
  sh.pTo := PChar(ANewName + #0);
  sh.fFlags := fof_Silent or fof_MultiDestFiles;
  if ARenameCheck then
    sh.fFlags := sh.fFlags or fof_RenameOnCollision;
  Result:=ShFileOperation(sh)=0;
end;



Der folgende Code
- fragt ab ob ein Update notwendig ist (anhand des ermittelten datums der bass.dll auf dem PC und dem "Soll-Versions-Datum" das im Code als "Const" definiert ist.
Erforderlich = Ja, kein problem...weiter im Takt...starten
Erforderlich = Nein. Die Routine zum updaten wird gestartet.
- IsBassLoaded gibt an ob die bass.dll aktuell ist.
Falls Nein wird KEINE der Bass Funktione im Programm aufgerufen (-> exit)
und bei Application.terminate wird die Bass.dll aus dem Speicher freigegeben nicht freigegeben
(ansonsten würde es zu Fehlermedlungen kommen)
- Die Codezeilen fürs Updaten der Bass.dll selbst sind halbwegs kommentiert


Anbei ebenso noch die benötigte Funktion CopyFileEx (Autor siehe oben)

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
function TMainForm.CopyFileEx(const ASource, ADest: string;ARenameCheck: boolean = false): boolean;
var
  sh: TSHFileOpStruct;
  ABool: Boolean;
  ACount:Integer;
begin
  ACount := 0;
  If ARenameCheck = False
    then If FileExists(ADest)
      then begin
            ABool := DeleteFile(ADest);
            while (ABool = False) AND (ACount < 40)
              do begin
                   Inc(ACount);
                   sleep(50); //wait for function
                 end;
           end;
  //-------------------
  sh.Wnd := Application.Handle;
  sh.wFunc := FO_COPY;
  // String muss mit #0#0 Terminiert werden, um das Listenende zu setzen
  sh.pFrom := PChar(ASource + #0);
  sh.pTo := PChar(ADest + #0);
  sh.fFlags := fof_Silent or fof_MultiDestFiles;
  if ARenameCheck then
    sh.fFlags := sh.fFlags or fof_RenameOnCollision;
  Result:=ShFileOperation(sh)=0;
end;



und hier der Code der die Updates durchführt

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
  //Bass-Sound System
  //Check if recent version installed
  AFileName := PathExeFile + '\' + FNameBassDLL;
  DateBassResource  := MyDecodeDate(VerDate_Bassdll);
  DateBassPC        := MyDecodeDate(FormatDateTime('dd.mm.yyyy', GetFileModifyDate(AFileName)));

  if (DateBassResource > DateBassPC)
    then begin // Programm is about to Update Bass.dll
           IsBassLoaded  := False;
           Screen.Cursor := crHourglass;


           //Define Files Names for later use
           AFileName    := PathExeFile + '\' + FNameBassDLL;      // Original Filename to replace
           AFileNameBak := PathExeFile + '\' + FNameBassDLLBak;   // File with another Name (= Backup)
           AFileTemp    := PathSave    + '\' + FNameBassDLL;

           //step-0: Inform User to confirm the question form Windows OS (UAC)
           showmessage('TrainIt wird nun ein Update des Sound-Modules (bass.dll) ausführen'+ #13+#10+
                       'Bestätigen sie dazu evtl. stattfindende Abfragen Ihres Windows-Betriebsystemes');

           //step-1: Rename the File in Program Dir
           If FileExists(AFileNameBak) then DeleteFile(AFileNameBak); //Delete new Filename, so that it doesn't exist for ReName
           RenameFileEx(AFileName,AFileNameBak,False);

           //step-2: Extract new File from within program resource into a TempDir
           If FileExists(AFileTemp) then DeleteFile(AFileTemp); //Delete File in TempPath before
           Res := TResourceStream.Create(Hinstance, 'Music_DLL', RT_RCDATA);
           try
            Res.SavetoFile(AFileTemp);  // extract from resource file
           finally
            Res.Free;
           end;

           //step-3: Copy file from temp-Path to Program Dir
               CopyFrom := AFileTemp;
               CopyTo   := AFileName;
               If FileExists(CopyFrom)
                 then begin
                        copyfileEx(CopyFrom, CopyTo);
                        DeleteFile(CopyFrom);
                        end;


           Screen.Cursor := crDefault;
           showmessage('Update durchgeführt. Bitte starten Sie TrainIt nun erneut');
           Application.Terminate;
           exit;
         end

  //----------------------
  else begin
         Load_BASSDLL(AFileName);
         if not BASS_Init(-1, 44100, 0, Handle, nil)
           then  begin
                  Showmessage('Error initializing audio!');
                  IsBassLoaded  := False;
                end
            else IsBassLoaded  := True;
       end;


..wie gesagt, sicher nicht besonders schön, aber effizient.

lG Martin
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19346
Erhaltene Danke: 1754

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Di 30.06.09 20:49 
Wobei du ja anbieten kannst die Exe mit Adminrechten zu starten, wenn du beim Update merkst, dass du keine Schreibrechte hast in dem Verzeichnis.
Seven of Nine Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 132
Erhaltene Danke: 1

Win XP, Win Vista HomePro
Delphi 2009
BeitragVerfasst: Di 30.06.09 20:52 
Ja, das könnte ich.
Aber ob das "Otto-Nomaluser" versteht ???

wobei das natürlcih schon gut wäre weil die UAC (Vista) 2 x zuschlägt (beim rename, und beim Copy)
oder gibt es eine Möglichkeit innerhalb einer Anwendung nachträglich auf "als Admin ausführen" umzuschalten?

lG Martin
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19346
Erhaltene Danke: 1754

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Di 30.06.09 20:58 
user profile iconSeven of Nine hat folgendes geschrieben Zum zitierten Posting springen:
oder gibt es eine Möglichkeit innerhalb einer Anwendung nachträglich auf "als Admin ausführen"
Nein, das ist aus Sicherheitsgründen nicht möglich. Die Rechte werden beim Start zugeteilt und können danach nicht mehr verändert werden.

Es gibt nur zwei Möglichkeiten:
Die eigene oder eine zweite Exe mit Adminrechten starten.
Oder ein COM-Server, was aber eine mit Adminrechten (z.B. beim Setup) registrierte DLL voraussetzt.
Seven of Nine Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 132
Erhaltene Danke: 1

Win XP, Win Vista HomePro
Delphi 2009
BeitragVerfasst: Mi 01.07.09 04:32 
Ok, danke dir Sebastian !

lG Martin