Otwieranie jednej instancji programu zewnętrznego (ShellExecute)

Odpowiedz Nowy wątek
2013-08-21 18:56
0

Program obsługuje bazę efektów dźwiekowych.
Kiedy użytkownik chce przesłuchać wybrany efekt, klika pozycję na liście. Program sam określa, który program ma dany dźwięk otworzyć. Problem polega na tym, że kiedy uruchamiam wybrany program poleceniem:

exename:=VlcAppPath; // ścieżka do aplikacji odwarzającej; tu: VLC Media player
Parms:=Filename;
res:=ShellExecute(MainF.handle,'open',PChar(exename+''),PChar('"'+Parms+'"'),'',sw_ShowNormal);

za każdym uruchomieniem otwiera sie nowe okno odtwarzacza. Niekiedy daje to niezły efekt mieszania dźwięku, ale w podstawowym trybie wolałbym, żeby w chwili kolejnego wywołania program odtwarzający przeerywał odtwarzanie bieżącego dźwięku i zaczynał własnie kliknięty (w tej samej instancji odtwarzacza). Dokładnie tak, jak to robi eksplorator Windows, kiedy nie czekając na koniec poprzedniego dźwięku kliknę kolejny plik *.flv;
Próbowałem różnych parametrów wywołania (nShowCmd), ale żadne nie powoduje opisanego dzialania.
Przeszukałem 4programerz.net i delphi.about.com (wiele sie przy tym nauczyłem), ale nie napotkałem odpowiedzi. Może ktoś cos wie na ten temat?


aps
Panowie.... Nie wszyscy naraz!!! Nie spodziewałem się tak błyskawicznej reakcji i takiego zalewu informacji. Nigdy dotąd nie korzystałem z forów internetowych dla rozwiązania napotkanych problemów, toteż jestem zaszokowany... Serdecznie wszystkim dziękuję i biorę się za wykorzystywanie tego wszystkiego w praktyce - vroobell13 2013-08-23 15:53

Pozostało 580 znaków

2013-08-21 19:22
0

Poczytaj o komunikatach...
To dość proste, bierzesz podczas uruchamiania appki sprawdzasz czy nie ma już uruchomionej jgko kopii jeżeli jest to wysyłasz do niej ścieżkę do pliku który chcesz otworzyć i zamykasz tą instancję, a tamta odbiera wiadomość i wykonuje stosowne akcje.

Pozostało 580 znaków

2013-08-21 19:24
0

Jeżeli dobrze zrozumiałem, to kiedy chcesz osiągnąc efekt jak dla Exploratora. To należało by wywoływać plik, a nie program i parametr. O ile w ogóle VLC Player działa ok. Ponieważ nawet kiedy w WinAMPie ustawiłem opcję aby uruchamiał się w wielu instancjach i zrobiłem taki kod programu, jak widać poniżej. To WinAMP nie wywołał mi się dwa razy. A klikałem przyciski naprzemiennie. Może jeszcze jakieś dodatkowe wpisy akurat dla niego w rejestrze o tym decydują, ale wątpie. To ważne jak program chyba jest stworzony. Na przykład czy nie tworzy Mutex i nie obsługuje nowych parametrów przy podaniu kiedy jest już uruchomiony.

//...
procedure TForm1.Button1Click(Sender : TObject);
begin
  ShellExecute(Handle, 'open', PChar('C:\PROGRAM FILES\WINAMP\winamp.exe'), PChar('"' + 'C:\PROGRAMY\MP3\Weekend - Ona Tanczy Dla Mnie.mp3' + '"'), '', SW_SHOWNORMAL);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  ShellExecute(Handle, 'open', PChar('C:\PROGRAM FILES\WINAMP\winamp.exe'), PChar('"' + 'C:\PROGRAMY\MP3\Sobota & Weekend - Ona Tanczy Dla Mnie (2sty Blend).mp3' + '"'), '', SW_SHOWNORMAL);
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
  ShellExecute(Handle, 'open', PChar('"' + 'C:\PROGRAMY\MP3\Weekend - Ona Tanczy Dla Mnie.mp3' + '"'), '', '', SW_SHOWNORMAL);
end;

procedure TForm1.Button4Click(Sender: TObject);
begin
  ShellExecute(Handle, 'open', PChar('"' + 'C:\PROGRAMY\MP3\Sobota & Weekend - Ona Tanczy Dla Mnie (2sty Blend).mp3' + '"'), '', '', SW_SHOWNORMAL);
end;

Jeżeli jednak Explorator zachowuje się ok to myślę, że powinno pomóc wywołanie pliku. Ponieważ kiedy robisz dwuklik na pliku, to o ile się orientuje robisz właśnie tak jakbyś wywoływał sam plik jako program, a parametr pusty. Ewentualnie zobacz w Rejestrze czy wywołanie plików .flv przez VLC nie odbywa się z jakimis dodatkowymi parametrami i tym podobne. Jeżeli to i reinstall nie pomoże to nie wiem jak można by jeszcze kombinować. Nie mam zamiaru instalować VLC na chwile i psuć sobie skojarzenia dla plików filmów. Natomiast przedwczesne jest raczej "wytaczanie takich dział" jak próba napisania wrappera dll (o ile taki da się łatwo napisac, bo VLC obsluguje jakąś udokumentowaną dllkę systemową przez małą ilośc eksportów), co jest moją jedną z moich ulubionych metod i w miarę łatwych do zaimplementowania. Jeżeli oczywiście chcemy łatwo ingerować w zachowanie kodu oryginalnego programu bez jego ręcznego patchowania albo inwazyjnego injectowania dllek. Wtedy takim wrapperem można by spróbować najprościej tworzyć Mutex o unikalnej nazwie. Tylko kwestia, co zrobić jeżeli on by istniał. Jak przekazać nowy plik do VLC. Chyba tylko symulacją komunikatu o przeciąganiu pliku na okno, ewentualnie mechanizmem DDE jeżeli jest obsługiwany i udokumentowany dla tego playera. W ostateczności można szukać pomocy w supporcie VLC.


edytowany 2x, ostatnio: olesio, 2013-08-21 19:27

Pozostało 580 znaków

2013-08-21 19:25
0

Obawiam się że takiego czegoś nie uzyskasz gdyż to zależy w jaki sposób dany program który ma odtwarzać jest napisany czyli to program musi pozwalać się otworzyć tylko w jednej instancji i odtwarzać podany jako parametr plik (jeżeli jest już otarty to przerywać odtwarzanie poprzedniego a odtwarzać ten nowy). Jeżeli dany odtwarzacz ma udostępnia API (jak np Winamp) to mógłbyś spróbować sterować nim poprzez to API (oczywiście o ile jest taka możliwość bo nie zajmowałem się w zabawy z API Winampa ale raczej powinno się dać).


Nie odpowiadam na PW w sprawie pomocy programistycznej.
Pytania zadawaj na forum, bo:
od tego ono jest ;) | celowo nie zawracasz gitary | przeczyta to więcej osób a więc większe szanse że ktoś pomoże.
Winampa można sterować message'ami. - marogo 2013-08-21 19:31
@marogo: mowa i tak o VLC, a sterowanie jeżeli chodzi o zapodawanie nazw plików to z komunikatów nie wiem czy może się odbywać. Raczej ewentualnie przez zasymulowanie przerzucenia plików komunikatem WM_DROPFILES, ale nigdy się tak nie bawiłem. Nie miałem potrzeby. A i nie wiem czy WM_DROPFILES da się łatwo zasymulować. - olesio 2013-08-21 19:34
Dla Winampa, nie działa, po podstawieniu za "Wnd" uchwytu okna Winampa lub jego playlist-y. - marogo 2013-08-21 20:07
@marogo: zadziała, ale trzeba użyć PostMessage. Doczytałem to na: http://us.generation-nt.com/a[...]es-message-help-57315072.html - olesio 2013-08-21 20:39
@marogo: zobacz EDIT #3 w moim, ostatnim póki co postcie, bo jednak powyższy kod nie działał dla więcej niż jednego pliku pomimo zmiany na PostMessage. Dopiero elegancko działa kod z: http://www.delphi-zone.com/20[...]ther-program-by-auto-dragdrop - podejrzewam, że to kwestia złego tworzenia danych do wysłania we wcześniejszym kodzie. Jak dodawałem do długości Run + 1, to działalo ale potrafiło za pierwszym razem wieszać WinAMP. Teraz po wielu testach jest ok. - olesio 2013-08-21 21:35

Pozostało 580 znaków

2013-08-21 19:27
0

Sprawdź, czy uruchamiany player ma w ustawieniach (włączoną) opcję w stylu "Uruchamiaj tylko jedną instancję" lub wyłączoną opcję w stylu "Pozwól na wiele instancji" lub też poszukaj w helpie playera, czy można go uruchomić z określonym parametrem, który pozwala mu działać tylko w jednej instancji.

Pozostało 580 znaków

2013-08-21 19:31
0

Propozycja @hzmzp jest według mnie za bardzo inwazyjna, bo zamykamy i otwieramy ponownie program co może potrwać. Natomiast @kAzek napisał o WinAMPie albo sugerując się jego działaniem albo moim kodem. Natomiast pytanie jest o VLC. Który może faktycznie działać inaczej. Chociaż jeżeli przez dwuklik z exploratora jest ok. To podejrzewał bym albo wywoływanie z odpowiednimi parametrami poza nazwą pliku. Albo inną domyślną czynnośc niż open. Albo obsługę DDE. Niestety w nowszych Windowsach o ile się orientuje skopano względem XP trochę ustawianie i podgląd skojarzonych rozszerzeń. Także takie operacje jak podgląd albo zmiana domyślnej czynności i innych ustawień najlepiej dokonać w Rejetrze - konkretnie dla HKEY_CLASSES_ROOT\.FLV, a później dla klucza, który jest w nazwie domyślnej oczywiście.

EDIT: o - poniżej elegancki kod na zasymulowanie przerzucenia plików. Trzeba sobie tylko ustalić uchawyt okna VLC za pewne. Bo chyba obsługuje ono Drag and Drog. To może będzie to jakieś rozwiązanie: http://www.vbforums.com/showt[...]with-SendMessage-WM_DROPFILES o ile się nie uda inaczej.

EDIT #2: zgodnie z informacją zawartą w treści wątku na: http://us.generation-nt.com/a[...]es-message-help-57315072.html - powyższy kod na symulowanie WM_DROPFILES zadziała, tylko trzeba użyć PostMessage zamiast SendMessage.

EDIT #3: powyższe kombinacje jednak źle działają dla więcej niż jednego pliku, a dodawanie do długości zmiennej Run nawet +1 powoduje obsługe ok po pierwszym uruchomieniu WinAMP'a. Nie analizowałem zmian, ale ten kod, który pochodzi ze strony: http://www.delphi-zone.com/20[...]ther-program-by-auto-dragdrop sprawdza się znakomicie, a i ma ten plus, że jest już przyszłościowo pod kątem WinAMP ;) Oczywiście nie problem prxerobić go na skorzystanie z TStringList i VCL. Poniżej przykład dla szybkich testów. Zakładam, że takie pliki jak ja macie w media. Przynajmniej pod siódemką takowe są.

//...
uses
  ShellApi;

function MakeDrop(const FileNames : array of string) : THandle;
var
  P : PChar;
  Data : PDragInfoA;
  I, Size : Integer;
begin
  Size := SizeOf(TDragInfoA) + 1;
  for I := 0 to High(FileNames) do
  begin
    Inc(Size, Length(FileNames[I]) + 1);
  end;
  Result := GlobalAlloc(GHND or GMEM_SHARE, Size);
  if Result <> 0 then
  begin
    Data := GlobalLock(Result);
    if Data <> nil then
      try
        Data.uSize := SizeOf(TDragInfoA);
        P := PChar(@Data.grfKeyState) + 4;
        Data.lpFileList := P;
        for I := 0 to High(FileNames) do
        begin
          Size := Length(FileNames[I]);
          Move(Pointer(FileNames[I])^, P^, Size);
          Inc(P, Size + 1);
        end;
      finally
        GlobalUnlock(Result);
      end
    else
    begin
      GlobalFree(Result);
      Result := 0;
    end;
  end;
end;

procedure TForm1.FormCreate(Sender : TObject);
begin
  Application.Title := Caption;
end;

procedure TForm1.Button1Click(Sender : TObject);
var
  H : HWND;
  Drop : HDrop;
begin
  H := FindWindow('Winamp v1.x', nil);
  if H > 0 then
  begin
    Drop := MakeDrop
      (['C:\WINDOWS\MEDIA\flourish.mid',
      'C:\WINDOWS\MEDIA\town.mid',
        'C:\WINDOWS\MEDIA\chord.wav']);
    if Drop <> 0 then
    begin
      PostMessage(H, WM_DropFiles, Drop, 0);
    end;
    GlobalFree(Drop);
  end;
end;

edytowany 4x, ostatnio: olesio, 2013-08-21 21:38
Na Winampie działa :) - marogo 2013-08-22 10:24

Pozostało 580 znaków

2013-08-22 00:24
0

Program obsługuje bazę efektów dźwiekowych.
Kiedy użytkownik chce przesłuchać wybrany efekt, klika pozycję na liście.
No ok, ale po co do tego zewnętrzny program przez ShellExecute, zamiast odtworzyć dźwięk wewnątrz programu, dowolnym działającym sposobem?

Pozostało 580 znaków

2013-08-22 00:50
0

@Azarien: jakby to był typowy format i chodzilo tylko o dźwięk to wiadomo, że chyba najprościej o najlepiej było by posiłkować się bass.dll. Ja jednak kiedy widzę flv i chęć użycia VLC Playera, to podejrzewam że może chodzić również o wyświetlenie ruchomego obrazu. A z pokazywaniem video poza TMediaPlayer i avi osobiście nie mam doświadczenia w Delphi. Wydaje mi się też, że chyba nie ma łatwego do ogarnięcia rozwiązania w postaci dllka, wyświetlenie na oknie o podanym handle i wygodna nawigacja. Czyli bez kombinowania z kodekami i tym podobnymi. Co nie oznacza, że używanie zewnętrznego programu do tego co można spróbować zrobić samodzielnie jest rozwiązaniem godnym polecenia. Bo można inaczej, także jeżeli pytającemy na pewno chodzi tylko o dźwięk to najlepiej przekonwertować flv na mp3, ponazywać sensownie. I albo wrzucić do podkatalogu jako dane i ogarnąć bass.dll albo ewentualnie jeżeli chcemy mieć wszystko w postaci jednego exeka to polecam bass.dll i moduł dllloader.pas z funkcją FindExport. Wpakować wszystko w zasób, ewentualnie mp3ki też jako zasoby tylko wczytywane i zapisywane po ID odpowiednim konstruktorem dla TResourceSream (czyli w pliku *.rc # i liczba jako nazwa zasobu). Wczytywanie po ID zgodnie z tym co piszą w helpie do Delphi, ma znaczenie nie tyle jeżeli chodzi o wielkość sumaryczną zasobów co ewentualną ich ilośc ponad kilkaset sztuk w jednym exeku. Oczywiście można jeszcze kombinować z dllką jako pliko zasobem zewnętrznym. Ale jeśli chcemy sobie zrobić ładny i zgrabny program wszystko w jednym to faktycznie chyba tak najlepiej. Anyway, już pytający otrzymał w tym wątku tyle konkretnych rad, że na pewno spokojnie można siąść i zakować coś porządnego bez "męczenia" VLC do dźwięku :)


edytowany 1x, ostatnio: olesio, 2013-08-22 00:57
ja bym użył po prostu DirectShow, obsłuży wszystkie kodeki i formaty zainstalowane w systemie. podczepienie wideo pod uchwyt okna też jest proste. nie używałem co prawda DShow nigdy pod Delphi. - Azarien 2013-08-22 02:23

Pozostało 580 znaków

2013-08-22 08:49
0

W pomocy programu VLC media player-a: https://wiki.videolan.org/VLC_command-line_help jest opisany parametr dotyczący uruchamiania pojedynczej instancji: --one-instance , co przekłada się na takie wywołanie ShellExecute:

ShellExecute(MainF.handle, 'open', PChar(exename), PChar('--one-instance "'+Parms+'"'),'',sw_ShowNormal);
Jeśli pliki multimedialne o określonych rozszerzeniach byłyby skojarzone z różnymi playerami, to przed otwarciem danego typu pliku należałoby sprawdzać w rejestrach (HKEY_CLASSES_ROOT) z jakim playerem jest skojarzony i odpowiednio podawać parametr pozwalający na uruchomienie tylko jednej instancji. Niestety wiąże się to z tym, że program musiałby mieć taką tablicę (bądź mini bazę) przechowującą nazwę tego parametru dla wszystkich popularnych playerów, które oczywiście maja możliwość odpalenia tylko w pojedynczej instancji. - marogo 2013-08-22 09:09

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0