Помощь - Поиск - Пользователи - Календарь
Полная версия: Плеер
Форум «Всё о Паскале» > Современный Паскаль и другие языки > Делфи
Артемий
Вожусь с плеером.Ктонибудь не подскажет одну вещь: допустим я использую свой плеер по умолчанию (
  if not ('' = System.ParamStr(1)) then
with MediaPlayer1 do
begin
try
Filename := System.ParamStr(1);
{Ну и так далее...}
) Так вот когда я не закрывая первого экземпляра плеера открываю другой муз. файл, то открывается второй экземпляр плеера и там играет вторая мелодия. А я хочу чтобы 2-я мелодия играла в первом экземпляре.
hiv
Алгоритм такой:
1) Проверяешь при старте программы (onCreateForm) не запущен ли еще один экземпляр твоего плеера. Как сделать смотри Получение списка запущенных приложений
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
Артемий
Примерно что-то вроде этого думал, но не знал как сделать. Спасибо. good.gif
Артемий
Цитата
2) Если экземпляр есть, то шли сообщение ему (PostMessage), в котором указано имя нового файла для воспроизведения и завершай работу программы (только не первого экземпляра ;) ).

Извиняюсь за тормоз! А как именно приложению отправить это имя? В смысле в PostMessage не разбираюсь.. mega_chok.gif (отписался и забыл про эту тему,теперь вспомнил)
hiv
Цитата(Артемий @ 22.08.2007 17:26) *
В смысле в PostMessage не разбираюсь..
Вот так посылать сообщения:
PostMessage(hWnd, WM_FILEREADY, 0, MusicFileName);
Close;
где hWnd - хендлер уже запущенного твоего плеера (как его найти я давал ссылку вверху).
Close - означает выход из текущего плеера...
Bokul
Как я понимаю на этапе использования PostMessage, ты уже уверен что твое приложение запущенно. А значит можешь идентифицировать его, например, по названию оконного заголовка или класса окна. Для этого в WinApi есть функция FindWindow. Первый параметр - название класса окна, второй - название заголовка окна. Есть возможность искать только по одному из параметров (в случае когда второй неизвестен), подставляя под значение другого nil, но гарантия нахождения именно твоего окна увеличивается при задании сразу двух параметров. Результат этой функции, в случае успешного выполнения, вернет handle твоего окна (того, что стартовало первым). Именно за этим мы использовали FindWindow, ибо первый аргумент функции PostMessage и есть handle окна, которому ты хочешь отправить сообщение. В качестве Msg можешь указать WM_ADD_IN_PLAYLIST (из поста hiv'a), а полезную нагрузку будут выполнять два оставшихся параметра. Вернее в нашем случае понадобиться только один. Тип каждого из них это DWord, который занимает 4 байта. Как раз как и pointer или pChar... Т.е. ты просто приводишь свою строку к DWord и передаешь получившиеся как аргумент в функцию.
Артемий
Цитата
Т.е. ты просто приводишь свою строку к DWord

А как привести строку к dword?
Bokul
dword(PChar). Хотя правильнее будет WPARAM(PChar) или LPARAM (PChar), в соответствии с типом аргумента в котором ты захочешь передавать данные.
Артемий
Пасибо ребят! (если будут вопросы - отпишусь smile.gif ) а пока - +1 Bokul и +1 hiv! Вы реально помогли! good.gif
volvo
Цитата
1) Проверяешь при старте программы (onCreateForm) не запущен ли еще один экземпляр твоего плеера. Как сделать смотри Получение списка запущенных приложений

Гораздо надежнее было бы использовать CreateMutex с заранее сгенерированным GUID-ом в качестве третьего параметра для отлова второй копии приложения...

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

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

mailslots никто не отменял: Ассоциированные файлы и предотвращение запуска второй копии приложения
Артемий
Блин, при компиляции программы 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
Ну, во-первых, ты где прописал 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
Артемий
Ага,я понял.Спасибо за помощь!
Артемий
Это опять я. !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
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;
...
Артемий
Теперь ошибка происходит в этой строке:
s := StrPas(PChar(Msg.lParam));


Добавлено через 2 мин.
Дело еще в том,что значение lParam(d) в процедуре FormCreate одно, а в процедуре AppMessage Msg.lParam значение другое..я сравнил...
volvo
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;

- все отработало...
Артемий
В смысле как передаю? System.ParamStr(1)?

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

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, чтоб не было утечки)
Артемий
Кажется я понял проблему...
Смотри,так работает:
d := StrNew(PChar('D:\1.mp3'));

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

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

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

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

Добавлено через 3 мин.
Вообще,я понял что ParamStr с PostMessage не катит,да? mega_chok.gif
volvo
Цитата
Вообще,я понял что 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
Цитата(Артемий @ 24.08.2007 22:24) *
Ну а привести тогда код любого из этих путей можешь?
Вот пример создания каналов.
Первый запуск приложения приведет к созданию именованного канала, последующие запуски будут просто отсылать первому приложению данные.
Артемий
2volvo
Ты крууут! smile.gif give_rose.gif good.gif good.gif good.gif
Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.