Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2007.02.04;
Скачать: CL | DM;

Вниз

Получение имён файлов   Найти похожие ветки 

 
SerjVasiljev   (2007-01-16 20:19) [0]

Здравствуйте, интересует вопрос.
Есть программа (плеер), нашёл код, который не даёт запустить вторую копию программы http://read.excode.ru/art4055p1.html.
Мне нужно получать список имён файлов которые я выделил в проводнике и после выбрал в попап меню проводника Открыть в "Имя моего плеера". Тоесть как сделать так, что бы моя программа принимала названия файлов так же как и WinAmp.
 У меня получилось реализовать это используя вышеуказанный код, но работает очень медленно (пока откроется каждая копия программы, передастся параметр и т.д.).
 Есть предположение, что винамп каким-то образом сразу загружает весь список песен которые пользователь выбрал в проводнике. Если я прав, как это реализовать? Как мне решить проблемму?

P.S.
  Перепробовал множество примеров закрытия второй копии программы. Скорость одна и таже при передаче параметров. Рациональнее передавать сразу все файлы в прогу, как это сделать?


 
tesseract ©   (2007-01-16 22:20) [1]


>  Есть предположение, что винамп каким-то образом сразу загружает
> весь список песен которые пользователь выбрал в проводнике.
>  Если я прав, как это реализовать? Как мне решить проблемму?
>


См мультивыбор, winamp одной строкой все файлы кидает.


 
SerjVasiljev   (2007-01-16 22:28) [2]

Где смотреть? Можно пример? Пожалуйста.


 
clickmaker ©   (2007-01-17 11:23) [3]


> передавать сразу все файлы в прогу, как это сделать?

ParamStr(1) .. ParamStr(N) если аргументы командной строки разделены пробелами (имена файлов с пробелами должны быть в кавычках)
StringList.CommaText := ParamStr(1) если аргументы через запятую,
потом StringList.Strings[i]


 
SerjVasiljev   (2007-01-17 15:42) [4]

У меня получалось за одно открытие программы передать только один параметр (так как программу открывает первый файл выделенных песен, а потом второй и тд). Тоесть сколько бы мы не выбрали песен, каждая пытается открыть свой плеер и мы можем отловить только одно имя.
 Нужно сто-то другое, не через ParamStr. :(


 
clickmaker ©   (2007-01-17 15:49) [5]


> Тоесть сколько бы мы не выбрали песен, каждая пытается открыть
> свой плеер и мы можем отловить только одно имя

тогда программа эта должна проверять, а не запущена ли она уже. Если да, то активизировать окно своего клона (SetForegroundWindow) и передавать ему имя файла, например с помощью WM_COPYDATA


 
SerjVasiljev   (2007-01-17 18:46) [6]

Пожалуйста, можно пример? Очень прошу.


 
SerjVasiljev   (2007-01-17 20:08) [7]

Разобрался с WM_COPYDATA. Есть ещё другие варианты??? Скорость также мала.


 
Rial ©   (2007-01-17 20:15) [8]

Создай небольшую программу (как это сделано и в WinAMP), и именно
с этой программой ассоциируй свой тип файлов.
При запуске эта маленькая программа будет смотреть,
если ли уже запущенная "большая" программа. Если есть,
то передаешь ей имя файла. Если нет - то создаешь новый
процесс и передаешь ему имя файла.
Только "маленькую" программу лучше сделать вообще без
окон, и, конечно же, без VCL.


 
SerjVasiljev   (2007-01-17 20:35) [9]

Спасибо, попробую ;)


 
SerjVasiljev   (2007-01-17 21:07) [10]

Минимизировал прогу как мог.


program Project1;

uses
 Forms, Windows, Messages, SysUtils, Controls;

{$R *.res}

var
  aCopyData: TCopyDataStruct;
  hTargetWnd: HWND;

begin
 Application.Initialize;

  with aCopyData do
  begin
    dwData := 0;
    cbData := StrLen(PChar(ParamStr(1))) + 1;
    lpData := PChar(ParamStr(1));
  end;
  hTargetWnd := FindWindowEx(0, 0, nil, PChar("Form1"));
  SendMessage(hTargetWnd, WM_COPYDATA, Longint(Application.Handle), Longint(@aCopyData));

 Application.Run;
end.


Запускаю через неё песни, а потом передаю плееру, но скорость таже, тоесть песни передаются по одной. Надо как-нибудь по другому, только как?


 
Rial ©   (2007-01-17 21:45) [11]

У тебя всю беда в коде.
С каких "маленькое" приложение весит 400 КБ ?
Это нехорошо.

Забудь ты про этот Application !!
И про модули Forms и Controls тоже. И будет тебе счастье
размером в 40КБ и скоростью запуска в 1 раз выше.


 
SerjVasiljev   (2007-01-17 22:16) [12]

А как тогда Application.Handle и т.д. ? Может дело не в коде, дело в методе передачи параметров?


 
SerjVasiljev   (2007-01-17 22:56) [13]

Вот уменьшил


program Project1;

uses
 Windows, Messages, SysUtils;

{$R *.res}

var
  aCopyData: TCopyDataStruct;
  hTargetWnd: HWND;

begin
  with aCopyData do
  begin
    dwData := 0;
    cbData := StrLen(PChar(ParamStr(1))) + 1;
    lpData := PChar(ParamStr(1));
  end;
  hTargetWnd := FindWindowEx(0, 0, nil, PChar("Form1"));
  SendMessage(hTargetWnd, WM_COPYDATA, 0, Longint(@aCopyData));
end.


Но результат почти не изменился. Нужен другой метод :(


 
TRUNK ©   (2007-01-17 23:05) [14]

Привожу исходники своей программы (вернее DLL). Оставил основной каркас и добавил комментарии.
За основу был взят файл ContextM.pas в папке Delphi6\Demos\ActiveX\ShellExt.

Пришлось разбить текст на части :(

// 1-я часть:

library CntxtHandler;
uses
 ComServ,
 CntxtUnit in "CntxtUnit.pas";
exports
 DllGetClassObject,
 DllCanUnloadNow,
 DllRegisterServer,
 DllUnregisterServer;
{$R *.RES}
begin
end.

unit CntxtUnit;
{$WARN SYMBOL_PLATFORM OFF}
interface
uses
 Windows,ActiveX,Classes,ComObj,ShlObj;
type
 TContextMenuHandler = class(TComObject,IShellExtInit,IContextMenu)
 private
   FFileCount: Cardinal;
   FFileNames: array of string;
   FidCmdFirst,FidCmdLast: Cardinal;
 protected
   function IShellExtInit.Initialize = SEIInitialize;
   function SEIInitialize(pidlFolder: PItemIDList; lpdobj: IDataObject; hKeyProgID: HKEY): HResult; stdcall;
   function QueryContextMenu(Menu: HMENU; indexMenu,idCmdFirst,idCmdLast,uFlags: Cardinal): HResult; stdcall;
   function InvokeCommand(var lpici: TCMInvokeCommandInfo): HResult; stdcall;
   function GetCommandString(idCmd,uType: Cardinal; pwReserved: PCardinal;
                             pszName: PChar; cchMax: Cardinal): HResult; stdcall;
 end;
const
 Class_ContextMenuHandler: TGUID = "{CEF775AF-336C-4EAD-80FE-1D17EE1EFC90}";


 
TRUNK ©   (2007-01-17 23:06) [15]

// 2-я часть:

implementation
uses
 ComServ, SysUtils, ShellApi;
(*****************************************************************************)
(* Вызывается перед созданием контекстного меню и указывает выбранные файлы; *)
(* По типам файлов здесь можно решить - добавлять свои пункты в меню или нет *)
function TContextMenuHandler.SEIInitialize(pidlFolder: PItemIDList; lpdobj: IDataObject; hKeyProgID: HKEY): HResult;
// pidlFolder -> Specifies the parent folder
// lpdobj     -> Spefifies the set of items selected in that folder
// hkeyProgID -> Specifies the type of the focused item in the selection
var
i: Integer;
StrBuf: PChar;
BufSize,StrLength: Cardinal;
StgMedium: TStgMedium;
FormatEtc: TFormatEtc;
begin
if (lpdobj = nil) then
 begin
 Result := E_INVALIDARG;
 Exit;
 end;
with FormatEtc do
 begin
 cfFormat := CF_HDROP;
 ptd := nil;
 dwAspect := DVASPECT_CONTENT;
 lindex := -1;
 tymed := TYMED_HGLOBAL;
 end;
// Render the data referenced by the IDataObject pointer
// to an HGLOBAL storage medium in CF_HDROP format
Result := lpdobj.GetData(FormatEtc,StgMedium);
if Failed(Result) then
 Exit;
// Извлекаем кол-во выбранных файлов
FFileCount := DragQueryFile(StgMedium.hGlobal,$FFFFFFFF,nil,0);
SetLength(FFileNames,FFileCount);
// Копируем их имена
StrBuf := nil;
BufSize := 4096;
ReallocMem(StrBuf,BufSize);
for i := 0 to FFileCount-1 do
 begin
 StrLength := DragQueryFile(StgMedium.hGlobal,i,StrBuf,BufSize);
 FFileNames[i] := Copy(StrBuf,1,StrLength);
 end;
ReallocMem(StrBuf,0);
ReleaseStgMedium(StgMedium);
Result := NOERROR;
end;


 
TRUNK ©   (2007-01-17 23:07) [16]

// 3-я часть:

(*************************************************************************)
(* Вызывается, когда Explorer создаёт контекстного меню для файла;       *)
(* данный пример добавляет пункт "Пункт 0" с 2-мя вложенными подпунктами *)
function TContextMenuHandler.QueryContextMenu(Menu: HMENU; indexMenu,idCmdFirst,idCmdLast,uFlags: Cardinal): HResult;
// Menu       -> Handle of the menu
// indexMenu  -> Location to insert first menu item
// idCmdFirst -> Minimum value for a menu item identifier
// idCmdLast  -> Maximum value for a menu item identifier
// uFlags     -> Specifies zero or more status values
var
ItemName: string;
SBM: HMENU;
MII: TMenuItemInfo;
begin
Result := 0;
if ((uFlags and $0000000F) = CMF_NORMAL)or((uFlags and CMF_EXPLORE) <> 0) then
 begin
 SBM := CreatePopupMenu;
 ItemName := "Подпункт 1";
 MII.cbSize := SizeOf(MII);
 MII.fMask := MIIM_TYPE or MIIM_STATE or MIIM_ID or MIIM_CHECKMARKS;
 MII.fType := MFT_STRING;
 MII.fState := MFS_ENABLED or MFS_UNCHECKED;
 MII.wID := idCmdFirst+1; // индекс, к-рый идентифицирует этот пункт;
                          // индекс задаётся произвольно при условии,
                          // что idCmdFirst <= индекс <= idCmdLast
 MII.hSubMenu := 0;
 MII.hbmpChecked := 0;
 MII.hbmpUnchecked := 0;
 MII.dwItemData := 0;
 MII.dwTypeData := PChar(ItemName);
 MII.cch := Length(ItemName);
 MII.hbmpItem := 0;
 InsertMenuItem(SBM,0,true,MII);
 ItemName := "Подпункт 2";
 MII.cbSize := SizeOf(MII);
 MII.fMask := MIIM_TYPE or MIIM_STATE or MIIM_ID or MIIM_CHECKMARKS;
 MII.fType := MFT_STRING;
 MII.fState := MFS_ENABLED or MFS_UNCHECKED;
 MII.wID := idCmdFirst+2; // индекс, к-рый идентифицирует этот пункт
 MII.hSubMenu := 0;
 MII.hbmpChecked := 0;
 MII.hbmpUnchecked := 0;
 MII.dwItemData := 0;
 MII.dwTypeData := PChar(ItemName);
 MII.cch := Length(ItemName);
 MII.hbmpItem := 0;
 InsertMenuItem(SBM,1,true,MII);
 ItemName := "Пункт 0";
 MII.cbSize := SizeOf(MII);
 MII.fMask := MIIM_TYPE or MIIM_STATE or MIIM_ID or MIIM_SUBMENU or MIIM_CHECKMARKS;
 MII.fType := MFT_STRING;
 MII.fState := MFS_ENABLED or MFS_UNCHECKED;
 MII.wID := idCmdFirst; // индекс, к-рый идентифицирует этот пункт
 MII.hSubMenu := SBM;
 MII.hbmpChecked := 0;
 MII.hbmpUnchecked := 0;
 MII.dwItemData := 0;
 MII.dwTypeData := PChar(ItemName);
 MII.cch := Length(ItemName);
 MII.hbmpItem := 0;
 // Добавляем в контекстное меню
 InsertMenuItem(Menu,indexMenu,true,MII);
 // Возвращаем кол-во добавленных пунктов меню
 Result := 3;
 FidCmdFirst := idCmdFirst;
 FidCmdLast := idCmdLast;
 end;
end;


 
TRUNK ©   (2007-01-17 23:08) [17]

// 4-я часть:

(**********************************************************)
(* Вызывается при выборе нашего пункта в контекстном меню *)
function TContextMenuHandler.InvokeCommand(var lpici: TCMInvokeCommandInfo): HResult;
var
i: Integer;
begin
// Убеждаемся, что не вызваны приложением
if (HiWord(Integer(lpici.lpVerb)) <> 0) then
 begin
 Result := E_FAIL;
 Exit;
 end;
// Убеждаемся, что вызваны одним из наших пунктов меню
if (LoWord(lpici.lpVerb) > 2) then // 2 - это максимальный индекс наших пунктов меню
 begin
 Result := E_INVALIDARG;
 Exit;
 end;
case LoWord(lpici.lpVerb) of
 1: DoAction_1; // выбран пункт меню с индексом 1
 2: DoAction_2; // выбран пункт меню с индексом 2
end;
Result := NOERROR;
end;

function TContextMenuHandler.GetCommandString(idCmd,uType: Cardinal; pwReserved: PCardinal;
                                             pszName: PChar; cchMax: Cardinal): HResult;
begin
// Проверяем, что у нас запрашивается строка с подсказкой
if (uType <> GCS_HELPTEXT) then
 begin
 Result := E_FAIL;
 Exit;
 end;
// Выдаём строку с подсказкой для пункта меню
// с индексом idCmd (показывается в StatusBar"е Explorer"а)
case idCmd of
 0: StrCopy(pszName,"Подсказка для пункта 0");
 1: StrCopy(pszName,"Подсказка для пункта 1");
 2: StrCopy(pszName,"Подсказка для пункта 2");
else
 Result := E_FAIL;
 Exit;
end;
Result := NOERROR;
end;

initialization

TComObjectFactory.Create(ComServer,TContextMenuHandler,Class_ContextMenuHandler,
                        "ContextMenuHandler","",ciMultiInstance,tmApartment);
end.


После компиляции DLL нужно зарегистрировать (Run->Register ActiveX Server).
Также в реестре прописать для каких типов файлов будет использоваться:
HKEY_CLASSES_ROOT\расширение_файла\shellex\ContextMenuHandlers\GUID_этого_CntxtH andler
например:
HKEY_CLASSES_ROOT\.mp3\shellex\ContextMenuHandlers\{CEF775AF-336C-4EAD-80FE-1D17EE1EFC90}

Остаётся только открыть программу и передать в неё список файлов.


 
SerjVasiljev ©   (2007-01-17 23:13) [18]

Класс :) . Буду разбираться, спасибо ;)


 
SerjVasiljev ©   (2007-01-17 23:21) [19]

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


 
SerjVasiljev ©   (2007-01-17 23:21) [20]

Не получается соединить модули, постоянно ошибки. Не могли бы залить весь проект куда-нибуть? Пожалуйста.


 
SerjVasiljev ©   (2007-01-17 23:26) [21]

Совсем запутался :(


 
TRUNK ©   (2007-01-17 23:27) [22]


> Не получается соединить модули, постоянно ошибки


Что за ошибки? И куда залить?


 
SerjVasiljev ©   (2007-01-17 23:38) [23]

Вообщем я создал новую dll, вставил туда все куски кода, в папку вложил файл ContexM (Переименовал в CntxtUnit, как понял). Когда запускаю dll много ошибок. Наверное что-то не допонял.
 Можете отправить весь проект (рабочий) на serjpochta@mail.ru ? Было бы здорово, я новичок, мне тяжело в таких кодах разбираться, извеняюсь :(


 
TRUNK ©   (2007-01-18 00:19) [24]

OK, вышлю проект. Он будет несколько отличаться от приведённого, т.к. здесь я описал всего лишь обобщённый вариант, к-рый ничего полезного не делает :)

P.S. Прочитай приложенный ReadMe



Страницы: 1 вся ветка

Текущий архив: 2007.02.04;
Скачать: CL | DM;

Наверх




Память: 0.54 MB
Время: 0.048 c
15-1168582732
NLex
2007-01-12 09:18
2007.02.04
Развитие в области...


3-1163579842
kulkse
2006-11-15 11:37
2007.02.04
Если сервер отключен (как обработать ошибку)


15-1168795976
Рамиль
2007-01-14 20:32
2007.02.04
Посмотрел тут "Апокалипсис"..


2-1169063960
Pasha L
2007-01-17 22:59
2007.02.04
overload или ещё чт-то нужно?


2-1168785827
Lamer666
2007-01-14 17:43
2007.02.04
DBEDIT