Версия для печати темы

Нажмите сюда для просмотра этой темы в обычном формате

Форум «Всё о Паскале» _ Делфи _ Плеер

Автор: Артемий2 2.12.2006 21:26

Вожусь с плеером.Ктонибудь не подскажет одну вещь: допустим я использую свой плеер по умолчанию (

  if not ('' = System.ParamStr(1)) then
with MediaPlayer1 do
begin
try
Filename := System.ParamStr(1);
{Ну и так далее...}
) Так вот когда я не закрывая первого экземпляра плеера открываю другой муз. файл, то открывается второй экземпляр плеера и там играет вторая мелодия. А я хочу чтобы 2-я мелодия играла в первом экземпляре.

Автор: hiv 5.12.2006 19:56

Алгоритм такой:
1) Проверяешь при старте программы (onCreateForm) не запущен ли еще один экземпляр твоего плеера. Как сделать смотри http://forum.pascal.net.ru/index.php?showtopic=11847&hl=%F1%EF%E8%F1%EE%EA+%E7%E0%E4%E0%F7
2) Если экземпляр есть, то шли сообщение ему (PostMessage), в котором указано имя нового файла для воспроизведения и завершай работу программы (только не первого экземпляра ;) ).
3) Организуй обработку своего события (т.н. сообщения - например const WM_ADD_IN_PLAYLIST = WM_USER + 1010; ) как это сделать - пример из стандартного хелпа:

//The following code handles a custom message that the application sends to itself when a file is ready for reading.

const
WM_FILEREADY = WM_USER + 2000;
procedure TForm1.FormCreate(Sender: TObject);

begin
Application.OnMessage := AppMessage;
end;

procedure TForm1.AppMessage(var Msg: TMsg; var Handled: Boolean);
begin
if Msg.message = WM_FILEREADY then
begin
Memo1.Lines.LoadFromFile(StrPas(PChar(Msg.lParam)));
Handled := True;

end;

{ for all other messages, Handled remains False }
{ so that other message handlers can respond }
end;

Удачи smile.gif

Автор: Артемий2 5.12.2006 22:25

Примерно что-то вроде этого думал, но не знал как сделать. Спасибо. good.gif

Автор: Артемий 22.08.2007 20:26

Цитата
2) Если экземпляр есть, то шли сообщение ему (PostMessage), в котором указано имя нового файла для воспроизведения и завершай работу программы (только не первого экземпляра ;) ).

Извиняюсь за тормоз! А как именно приложению отправить это имя? В смысле в PostMessage не разбираюсь.. mega_chok.gif (отписался и забыл про эту тему,теперь вспомнил)

Автор: hiv 22.08.2007 21:10

Цитата(Артемий @ 22.08.2007 17:26) *
В смысле в PostMessage не разбираюсь..
Вот так посылать сообщения:
PostMessage(hWnd, WM_FILEREADY, 0, MusicFileName);
Close;
где hWnd - хендлер уже запущенного твоего плеера (как его найти я давал ссылку вверху).
Close - означает выход из текущего плеера...

Автор: Bokul 22.08.2007 21:10

Как я понимаю на этапе использования PostMessage, ты уже уверен что твое приложение запущенно. А значит можешь идентифицировать его, например, по названию оконного заголовка или класса окна. Для этого в WinApi есть функция http://msdn2.microsoft.com/en-us/library/ms633499.aspx. Первый параметр - название класса окна, второй - название заголовка окна. Есть возможность искать только по одному из параметров (в случае когда второй неизвестен), подставляя под значение другого nil, но гарантия нахождения именно твоего окна увеличивается при задании сразу двух параметров. Результат этой функции, в случае успешного выполнения, вернет handle твоего окна (того, что стартовало первым). Именно за этим мы использовали FindWindow, ибо первый аргумент функции http://msdn2.microsoft.com/en-us/library/ms644944.aspx и есть handle окна, которому ты хочешь отправить сообщение. В качестве Msg можешь указать WM_ADD_IN_PLAYLIST (из поста hiv'a), а полезную нагрузку будут выполнять два оставшихся параметра. Вернее в нашем случае понадобиться только один. Тип каждого из них это DWord, который занимает 4 байта. Как раз как и pointer или pChar... Т.е. ты просто приводишь свою строку к DWord и передаешь получившиеся как аргумент в функцию.

Автор: Артемий 22.08.2007 21:17

Цитата
Т.е. ты просто приводишь свою строку к DWord

А как привести строку к dword?

Автор: Bokul 22.08.2007 21:19

dword(PChar). Хотя правильнее будет WPARAM(PChar) или LPARAM (PChar), в соответствии с типом аргумента в котором ты захочешь передавать данные.

Автор: Артемий 22.08.2007 21:24

Пасибо ребят! (если будут вопросы - отпишусь smile.gif ) а пока - +1 Bokul и +1 hiv! Вы реально помогли! good.gif

Автор: volvo 22.08.2007 23:00

Цитата
1) Проверяешь при старте программы (onCreateForm) не запущен ли еще один экземпляр твоего плеера. Как сделать смотри Получение списка запущенных приложений

Гораздо надежнее было бы использовать http://msdn2.microsoft.com/en-us/library/ms682411.aspx с заранее сгенерированным GUID-ом в качестве третьего параметра для отлова второй копии приложения...

P.S. С цитатой сначала промахнулся... Исправил...

Автор: Bokul 22.08.2007 23:21

Цитата
P.S. С цитатой сначала промахнулся... Исправил...

А если вернуться к первоначальной, как повысить надежность нахождения нужного окна? На ум приходит только явное сохранение handle в заданном месте, например в файле или атоме..

Автор: volvo 22.08.2007 23:41

Ага, сейчас прямо... Все дела забросим и будем файлы плодить smile.gif

mailslots никто не отменял: http://www.delphikingdom.ru/asp/viewitem.asp?catalogid=904

Автор: Артемий 23.08.2007 1:57

Блин, при компиляции программы FindWindow сразу находит первый экземпляр..Что не так?

procedure TForm1.FormCreate(Sender: TObject);
var
d: PChar;
h: hwnd;
begin
Application.OnMessage := AppMessage;
d := PChar(System.ParamStr(1));
h := FindWindow(nil,'MP3 1.8.0.7');
if h<>0 then begin
PostMessage(h,WM_ADD_TO_PLAYLIST,0,lparam(d));
Application.Terminate;
end;
end;

Автор: volvo 23.08.2007 4:10

Ну, во-первых, ты где прописал Caption формы? В Object Inspector-е? Надо бы здесь:

begin
Application.OnMessage := AppMessage;
d := PChar(System.ParamStr(1));
h := FindWindow(nil,'MP3 1.8.0.7'); // <--- Здесь ищешь именно первое приложение
if h<>0 then begin
PostMessage(h,WM_ADD_TO_PLAYLIST,0,lparam(d));
Application.Terminate;
end;

// Вот тут, уже после FindWindow, можно менять Caption формы...
Form1.Caption := 'MP3 1.8.0.7';
...


Должно работать... А если у тебя Caption прописан в Инспекторе, то получишь то, что получаешь smile.gif

Автор: Артемий 23.08.2007 12:43

Ага,я понял.Спасибо за помощь!

Автор: Артемий 24.08.2007 22:49

Это опять я. !low.gif !low.gif Сообщение от второго экзэмпляра первому передается,только первое нифига нормально обработать не может:

procedure TForm1.FormCreate(Sender: TObject);
var
d: PChar;
h: hwnd;
begin
Application.OnMessage := AppMessage;
d := PChar(System.ParamStr(1));
h := FindWindow(nil,'MP3 1.8.0.7');
if (h<>0) then begin
PostMessage(h,WM_ADD_TO_PLAYLIST,0,lparam(d));
Application.Terminate;
end;
end;

procedure TForm1.AppMessage(var Msg: TMsg; var Handled: Boolean);
begin
if Msg.message = WM_ADD_TO_PLAYLIST then
begin
MediaPlayer1.FileName := StrPas(PChar(Msg.lParam)); {<-------- Вот тут произходит ошибка!!!!!}
MediaPlayer1.Open;



Эскизы прикрепленных изображений
Прикрепленное изображение

Автор: volvo 24.08.2007 23:08

procedure TForm1.AppMessage(var Msg: TMsg; var Handled: Boolean);
var s: string;
begin
if Msg.message = WM_ADD_TO_PLAYLIST then
begin
s := StrPas(PChar(Msg.lParam));
MediaPlayer1.FileName := s; // Вот так ошибка не произойдет, если передано правильное имя файла
MediaPlayer1.Open;
...

Автор: Артемий 24.08.2007 23:13

Теперь ошибка происходит в этой строке:

s := StrPas(PChar(Msg.lParam));


Добавлено через 2 мин.
Дело еще в том,что значение lParam(d) в процедуре FormCreate одно, а в процедуре AppMessage Msg.lParam значение другое..я сравнил...

Автор: volvo 24.08.2007 23:15

blink.gif У меня не происходит... Покажи, как ты передаешь имя файла, может там проблема...

Добавлено через 4 мин.
А, у тебя берется параметр командной строки... Я сделал вот так:


var
d: PChar; // Глобально !!!

procedure TForm1.FormCreate(Sender: TObject);
var h: hwnd;
begin
Application.OnMessage := AppMessage;
d := PChar(ExtractFilePath(ParamStr(0)) + 'sound.wav');
h := FindWindow(nil,'MP3 1.8.0.7');
if h<>0 then begin
PostMessage(h,WM_ADD_TO_PLAYLIST,0,lparam(d));
Application.Terminate;
end;
Form1.Caption := 'MP3 1.8.0.7';
...
end;

const
WM_ADD_TO_PLAYLIST = WM_USER + 1010;

procedure TForm1.AppMessage(var Msg: TMsg; var Handled: Boolean);
var s: string;
begin
if Msg.message = WM_ADD_TO_PLAYLIST then
begin

s := StrPas(PChar(Msg.lParam));
MediaPlayer1.FileName := S;
MediaPlayer1.Open;
Handled := True;

end;
end;

- все отработало...

Автор: Артемий 24.08.2007 23:21

В смысле как передаю? System.ParamStr(1)?

Добавлено через 8 мин.
Все равно пишет ошибку! (сволочь (извините))

Автор: volvo 24.08.2007 23:38

Правильнее будет - так:

var
d: PChar;

procedure TForm1.FormCreate(Sender: TObject);
var
h: hwnd;
begin
Application.OnMessage := AppMessage;
d := StrNew(PChar(System.ParamStr(1))); // Выделяем память под строку !!!
h := FindWindow(nil,'MP3 1.8.0.7');
if (h<>0) then begin
PostMessage(h,WM_ADD_TO_PLAYLIST,0,lparam(d));
Application.Terminate;
end;
end;

procedure TForm1.AppMessage(var Msg: TMsg; var Handled: Boolean);
var s: string;
begin
if Msg.message = WM_ADD_TO_PLAYLIST then
begin
s := StrPas(PChar(Msg.lParam));
MediaPlayer1.FileName := s;
MediaPlayer1.Open;
...


Попробуй, что ЭТОТ вариант тебе выдаст? (не забудь потом удалить D, чтоб не было утечки)

Автор: Артемий 25.08.2007 0:51

Кажется я понял проблему...
Смотри,так работает:

d := StrNew(PChar('D:\1.mp3'));

А так нет:
  d := StrNew(PChar(System.ParamStr(1)));

То есть я понял,что гвоздь в этом System.ParamStr!Теперь тупик еще более противен!

Добавлено через 15 мин.
Да,твой вариант работает,но как показал выше.^

Автор: hardcase 25.08.2007 1:08

Хм.... Может глупость...
А что если открыть сокет на 127.0.0.1 (т.е. локально) и слушать его на поступление имен файлов, которые нужно проиграть.

Автор: Артемий 25.08.2007 1:14

Нет,нужно именно через Post или SendMessage

Автор: hardcase 25.08.2007 1:18

Цитата(Артемий @ 24.08.2007 22:14) *
Нет,нужно именно через Post или SendMessage
Дело в том, что в случае с именами файлов будет проблема с выделением памяти. Послать сообщение элементарно. Но сообщение может вместить лишь 2 DWORD'а. А строка обычно длинная, если это полный путь к имени файла. Выделяя память в одном процессе ты не сможешь передать этот указатель в другой. В этом случае нужно организовывать передачу информации через общую память (filemap), интерфейс-петлю (127.0.0.1) или программные каналы (pipes).

В случае с программными каналами тебе даже не придется искать, запущен ли твой плеер уже или нет.
При старте программы, она пытается открыть pipe, если получилось, значит один экземпляр плеера уже запущен, потому просто пишем туда имя файла. Если открыть не получилось - мы первые, потому создаем канал и слушаем его.

Автор: Артемий 25.08.2007 1:24

Ну а привести тогда код любого из этих путей можешь?..я с этим не работал.

Добавлено через 3 мин.
Вообще,я понял что ParamStr с PostMessage не катит,да? mega_chok.gif

Автор: volvo 25.08.2007 2:37

Цитата
Вообще,я понял что ParamStr с PostMessage не катит,да?

Получите, распишитесь smile.gif


const
WM_ADD_TO_PLAYLIST = WM_USER + 1010;

procedure TForm1.AppMessage(var Msg: TMsg; var Handled: Boolean);
var
s: string;
begin
if Msg.message = WM_ADD_TO_PLAYLIST then
begin
SetLength(S, MSG.lParam + 1);
GlobalGetAtomName(MSG.wParam, PChar(S), MSG.LParam + 1);

MediaPlayer1.FileName := S;
MediaPlayer1.Open;

Handled := True;

end;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
h: hwnd;
s: string;
myAtom: TAtom;
begin
Application.OnMessage := AppMessage;
s := ParamStr(1);
h := FindWindow(nil,'MP3 1.8.0.7');
if h <> 0 then begin
myAtom := GlobalAddAtom(PChar(s));
PostMessage(H, WM_ADD_TO_PLAYLIST, myAtom, Length(s));
GlobalDeleteAtom(myAtom);

Application.Terminate;
end;
Form1.Caption := 'MP3 1.8.0.7';


Автор: hardcase 25.08.2007 4:14

Цитата(Артемий @ 24.08.2007 22:24) *
Ну а привести тогда код любого из этих путей можешь?
Вот пример создания каналов.
Первый запуск приложения приведет к созданию именованного канала, последующие запуски будут просто отсылать первому приложению данные.



Прикрепленные файлы
Прикрепленный файл  PipeListener.zip ( 6.87 килобайт ) Кол-во скачиваний: 150

Автор: Артемий 25.08.2007 15:26

2volvo
Ты крууут! smile.gif give_rose.gif good.gif good.gif good.gif