zoukankan      html  css  js  c++  java
  • Shell extension

    unit uGetResList;

    {$WARN SYMBOL_PLATFORM OFF}

    interface

    uses
      Windows, ActiveX, Classes, Sysutils, Messages, ComObj, ShellAPI, ShlObj,
      Math, Graphics, JPEG, Registry;

    type
      TGetResList = class(TComObject, IShellExtInit, IContextMenu, IContextMenu3)
      private
        FFileList: TStrings;
        FGraphic: TGraphic;
      protected
        //IShellExtInit
        function IShellExtInit.Initialize = SEInitialize;
        function SEInitialize(pidlFolder: PItemIDList; lpdobj: IDataObject;
          hKeyProgID: HKEY): HResult; stdcall;
        //IContextMenu
        function QueryContextMenu(Menu: HMENU;
          indexMenu, idCmdFirst, idCmdLast, uFlags: UINT): HResult; stdcall;//before popup
        function InvokeCommand(var lpici: TCMInvokeCommandInfo): HResult; stdcall;//onclick
        function GetCommandString(idCmd, uType: UINT; pwReserved: PUINT;
          pszName: LPSTR; cchMax: UINT): HResult; stdcall;//hint when move over
        //IContextMenu2
        function HandleMenuMsg(uMsg: UINT; WParam, LParam: Integer): HResult; stdcall;
        //IContextMenu3
        function HandleMenuMsg2(uMsg: UINT; wParam, lParam: Integer;
          var lpResult: Integer): HResult; stdcall;
      public
        procedure Initialize; override;
        destructor Destroy; override;
      end;

      TGetResListFactory = class(TComObjectFactory)
      public
        procedure UpdateRegistry(Register: Boolean); override;
      end;

    const
      Class_GetResList: TGUID = '{AAE1817E-34EA-4892-B6A7-8D5738BA3074}';

      //menu type
      mfString    = MF_STRING or MF_BYPOSITION;
      mfOwnerDraw = MF_OWNERDRAW or MF_BYPOSITION;
      mfSpearator = MF_SEPARATOR or MF_BYPOSITION;

      //menu ID
      idCopyAnyWhere = 0;//copy(move)
      idRegister = 5;   //registerActiveX
      idUnregister = 6; //unregisterActiveX
      idImagePreview = 10;//preview picture
      idMenuRange = 90; //

    resourcestring
      //menu item name
      sCopyAnyWhere = 'Copy any where...';
      sCopyAnyWhereTip = '可将选定的文件复制到任何路径下';
      sRegister = '注册...';
      sRegisterTip = '注册GetResList插件库';
      sUnregister = '取消注册...';
      sUnregisterTip = '取消注册GetResList插件库';
      sImagePriview = '预览图片文件';
      sImagePriviewTip = '预览图片文件';

    function GetFileListFromDataObject(lpdobj: IDataObject; sl: TStrings): HResult;
    function IsActiveLib(const FileName: string): Boolean;
    procedure RegisterActiveLib(Wnd: HWND; const FileName: string);
    procedure UnregisterActiveLib(Wnd: HWND; const FileName: string);
    procedure ReportWin32Error(Wnd: HWND; const Prefix: string; dwError: DWORD);
    function IsImageFile(const FileName: string): Boolean;
    function ImageFromFile(const FileName: string): TGraphic;
    function ExecuteFile(Wnd: HWND; const FileName: string): THandle;
    procedure DrawGraphic(adc: HDC; rc: TRect; State: Integer; Graphic: TGraphic);
    function ImageInfoToStr(Graphic: TGraphic): string;

    function Make_HResult(sev, fac, code: Word): DWORD;
    procedure DoCopyAnyWhere(Wnd: HWND; sl: TStrings);


    implementation

    uses ComServ;

    //* 根据图片对象,得到图片相关的信息
    function ImageInfoToStr(Graphic: TGraphic): string;
    begin
      Result := Format('%d * %d', [Graphic.Width, Graphic.Height]);
      if Graphic is TIcon then
        Result := Result + ' 图标';
      if Graphic is TBitmap then
      begin
        case TBitmap(Graphic).PixelFormat of
          pfDevice: Result := Result + ' DDB';
          pf1bit: Result := Result + ' 2色';
          pf4bit: Result := Result + ' 16色';
          pf8bit: Result := Result + '256色';
          pf15bit, pf16bit: Result := Result + ' 16位色';
          pf24bit: Result := Result + ' 24位色';
          pf32bit: Result := Result + ' 32位色';
          pfCustom: Result := Result + ' 自定义色';
        end;
        Result := Result + '位图';
      end;
      if Graphic is TMetafile then
      begin
        Result := Result + Format('(%d*%d) 元文件', [TMetafile(Graphic).MMWidth div 100,
          TMetafile(Graphic).MMHeight div 100]);
      end;
      if Graphic is TJPEGImage then
      begin
        case TJPEGImage(Graphic).PixelFormat of
          jf24Bit: Result := Result + ' 24位色 JPEG';
          jf8Bit: Result := Result + ' 8位色 JPEG';
        end;
      end;
    end;

    //* 画图像
    procedure DrawGraphic(adc: HDC; rc: TRect; State: Integer; Graphic: TGraphic);
    var
      rcImage, rcText, rcStretch: TRect;
      Canvas: TCanvas;
      nSaveDC: Integer;
      x, y: Integer;
      xScale, yScale, Scale: Double;
      xStretch, yStretch: Integer;
    begin
      rcImage.Left := rc.Left + 10;
      rcImage.Right := rc.Right - 10;
      rcImage.Top := rc.Top + 10;
      rcImage.Bottom := rc.Bottom - 30;

      rcText.Left := rc.Left + 10;
      rcText.Right := rc.Right - 10;
      rcText.Top := rc.Bottom - 20;
      rcText.Bottom := rc.Bottom;

      Canvas := TCanvas.Create;
      nSaveDC := 0;
      try
        nSaveDC := SaveDC(adc);
        Canvas.Handle := adc;

        if not Assigned(Graphic) then
        begin
          Canvas.Rectangle(rcImage);
          Canvas.MoveTo(rcImage.Left, rcImage.Top);
          Canvas.LineTo(rcImage.Right, rcImage.Bottom);
          Canvas.MoveTo(rcImage.Right, rcImage.Top);
          Canvas.LineTo(rcImage.Left, rcImage.Bottom);
          DrawText(Canvas.Handle, '未知图像', -1, rcImage, DT_SINGLELINE or DT_CENTER or DT_VCENTER);
        end
        else
        begin
          if (Graphic.Width < rcImage.Right - rcImage.Left)
            and (Graphic.Height < rcImage.Bottom - rcImage.Top) then
          begin
            x := rcImage.Left + (rcImage.Right - rcImage.Left - Graphic.Width) div 2;
            y := rcImage.Top + (rcImage.Bottom - rcImage.Top - Graphic.Height) div 2;
            Canvas.Draw(x, y, Graphic);
          end
          else
          begin
            xScale := Graphic.Width / (rcImage.Right - rcImage.Left);
            yScale := Graphic.Height / (rcImage.Bottom - rcImage.Top);
            Scale := Max(xScale, yScale);
            xStretch := Trunc(Graphic.Width / Scale);
            yStretch := Trunc(Graphic.Height / Scale);
            x := rcImage.Left + (rcImage.Right - rcImage.Left - xStretch) div 2;
            y := rcImage.Top + (rcImage.Bottom - rcImage.Top - yStretch) div 2;
            rcStretch := Rect(x, y, x + xStretch, y + yStretch);
            Canvas.StretchDraw(rcStretch, Graphic);
          end;
          Windows.FillRect(Canvas.Handle, rcText, GetSysColorBrush(COLOR_MENU));
          SetTextColor(Canvas.Handle, GetSysColor(COLOR_MENUTEXT));
          SetBkColor(Canvas.Handle, GetSysColor(COLOR_MENU));
          DrawText(Canvas.Handle, PChar(ImageInfoToStr(Graphic)), -1, rcText,
            DT_SINGLELINE or DT_CENTER or DT_VCENTER);
        end;
      finally
        Canvas.Handle := 0;
        FreeAndNil(Canvas);
        RestoreDC(adc, nSaveDC);
      end;
    end;

    //* 打开文件
    function ExecuteFile(Wnd: HWND; const FileName: string): THandle;
    var
      Path: string;
    begin
      Path := ExtractFilePath(FileName);
      Result := ShellExecute(Wnd, 'open', PChar(FileName), nil, PChar(Path), SW_SHOW);
    end;

    //* 图片从文件载入(其实也是判断文件是否是真正的图片文件。如果是,则能正常载入)
    function ImageFromFile(const FileName: string): TGraphic;
    var
      Ext: string;
    begin
      Ext := UpperCase(ExtractFileExt(FileName));
      Result := nil;
      if not IsImageFile(FileName) then
        Exit;
      try
        if (Ext = '.ICO') then
          Result := TIcon.Create
        else if Ext = '.BMP' then
          Result := TBitmap.Create
        else if (Ext = '.EMF') or (Ext = '.WMF') then
          Result := TMetafile.Create
        else if (Ext = '.JPG') or (Ext = '.JPEG') then
          Result := TJPEGImage.Create;
        Result.LoadFromFile(FileName);
      except
        if Assigned(Result) then
          FreeAndNil(Result);
      end;
    end;

    //* 判断是否是图片文件
    function IsImageFile(const FileName: string): Boolean;
    var
      Ext: string;
    begin
      Ext := UpperCase(ExtractFileExt(FileName));
      Result := (Ext = '.ICO') or (Ext = '.BMP') or (Ext = '.EMF') or (Ext = '.WMF')
        or (Ext = '.JPG') or (Ext = '.JPEG');
    end;

    //* 错误报告
    procedure ReportWin32Error(Wnd: HWND; const Prefix: string; dwError: DWORD);
    //var
    //  szError: array[0..399] of char;
    //  str: string;
    begin
      OutputDebugString(PChar(Prefix));
    //  FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, nil, dwError,
    //    Make_LangID(LANG_NEUTRAL, SUBLANG_DEFAULT), szError, SizeOf(szError), nil);
    //  str := Format('%s: %s', [Prefix, StrPas(szError)]);
    //  MessageBox(Wnd, PChar(str), '错误', MB_ICONEXCLAMATION);
    end;

    //* 取消注册AcitveX库
    procedure UnregisterActiveLib(Wnd: HWND; const FileName: string);
    var
      hLib: THandle;
      fn: TDLLUnregisterServer;
      hr: HRESULT;
    begin
      hLib := LoadLibrary(PChar(FileName));
      if hLib = 0 then
      begin
        ReportWin32Error(Wnd, '装载文件失败', GetLastError);
        Exit;
      end;
      try
        fn := TDLLUnregisterServer(GetProcAddress(hLib, 'DllUnregisterServer'));
        if not Assigned(fn) then
        begin
          MessageBox(Wnd, '定位函数入口点 DllUnregisterServer 失败', '错误', MB_ICONEXCLAMATION);
          Exit;
        end;
        hr := fn();
        if Failed(hr) then
        begin
          ReportWin32Error(Wnd, '取消注册动态库失败', hr);
          Exit;
        end;
        MessageBox(Wnd, '取消注册成功', '成功', MB_ICONINFORMATION);
      finally
        FreeLibrary(hLib);
      end;
    end;

    //* 注册ActiveX库
    procedure RegisterActiveLib(Wnd: HWND; const FileName: string);
    var
      hLib: THandle;
      fn: TDLLRegisterServer;
      hr: HRESULT;
    begin
      hLib := LoadLibrary(PChar(FileName));
      if hLib = 0 then
      begin
        ReportWin32Error(Wnd, '装载文件失败', GetLastError);
        Exit;
      end;
      try
        fn := TDLLRegisterServer(GetProcAddress(hLib, 'DllRegisterServer'));
        if not Assigned(fn) then
        begin
          MessageBox(Wnd, '定位函数入口点 DllRegisterServer 失败', '错误', MB_ICONEXCLAMATION);
          Exit;
        end;
        hr := fn();
        if Failed(hr) then
        begin
          ReportWin32Error(Wnd, '注册动态库失败', hr);
          Exit;
        end;
        MessageBox(Wnd, '注册成功', '成功', MB_ICONINFORMATION);
      finally
        FreeLibrary(hLib);
      end;
    end;

    //* 检查指定的文件是否是ActiveX文件
    function IsActiveLib(const FileName: string): Boolean;
    var
      Ext: string;
      hLib: THandle;
    begin
      Result := False;
      Ext := UpperCase(ExtractFileExt(FileName));
      if (Ext <> '.EXT') and (Ext <> '.DLL') and (Ext <> '.OCX') then
        Exit;
      hLib := LoadLibrary(PChar(FileName));
      if hLib = 0 then Exit;
      try
        Result := GetProcAddress(hLib, 'DllRegisterServer') <> nil;
      finally
        FreeLibrary(hLib);
      end;
    end;

    procedure DoCopyAnyWhere(Wnd: HWND; sl: TStrings);
    begin
      //some code here.
    end;

    function Make_HResult(sev, fac, code: Word): DWORD;
    begin
      Result := (sev shl 31) or (fac shl 16) or code;
    end;

    function GetFileListFromDataObject(lpdobj: IDataObject; sl: TStrings): HResult;
    var
      fe: FormatEtc;
      sm: StgMedium;
      i, iFileCount: Integer;
      FileName: array[0..MAX_PATH - 1] of char;
    begin
      Assert(lpdobj <> nil);
      Assert(sl <> nil);
      sl.Clear;

      fe.cfFormat := CF_HDROP;
      fe.ptd := nil;
      fe.dwAspect := DVASPECT_CONTENT;
      fe.lindex := -1;
      fe.tymed := TYMED_HGLOBAL;

      sm.tymed := TYMED_HGLOBAL;

      Result := lpdobj.GetData(fe, sm);
      if (FAILED(Result)) then Exit;
      iFileCount := DragQueryFile(sm.hGlobal, $FFFFFFFF, nil, 0);
      if iFileCount <= 0 then
      begin
        ReleaseStgMedium(sm);
        Result := E_INVALIDARG;
        Exit;
      end;
      for i := 0 to iFileCount - 1 do
      begin
        DragQueryFile(sm.hGlobal, i, FileName, Sizeof(FileName));
        sl.Add(FileName);
      end;
      ReleaseStgMedium(sm);
      Result := S_OK;
    end;

    { TGetResListFactory }

    procedure TGetResListFactory.UpdateRegistry(Register: Boolean);
      procedure DeleteRegValue(const Path, ValueName: string; Root: DWORD = HKEY_CLASSES_ROOT);
      var
        reg: TRegistry;
      begin
        reg := TRegistry.Create;
        try
          reg.RootKey := Root;
          if reg.OpenKey(Path, False) then
          begin
            if reg.ValueExists(ValueName) then
              reg.DeleteValue(ValueName);
            reg.CloseKey;
          end;
        finally
          FreeAndNil(reg);
        end;
      end;
    const
      RegPath = '*\shellex\ContextMenuHandlers\GetResList';
      ApprovedPath = 'Software\Microsoft\Windows\CurrentVersion\ShellExtensions\Approved';
    var
      strGUID: string;
    begin
      inherited;
      strGUID := GUIDToString(Class_GetResList);
      if Register then
      begin
        CreateRegKey(RegPath, '', strGUID);
        CreateRegKey(ApprovedPath, strGUID, 'GetResList的外壳扩展', HKEY_LOCAL_MACHINE);
      end
      else
      begin
        DeleteRegKey(RegPath);
        DeleteRegValue(ApprovedPath, strGUID, HKEY_LOCAL_MACHINE);
      end;
    end;

    { TGetResList }

    destructor TGetResList.Destroy;
    begin
      OutputDebugString('TGetResList::Destroy'#13#10);
      if Assigned(FGraphic) then
        FreeAndNil(FGraphic);
      FreeAndNil(FFileList);
      inherited;
    end;

    function TGetResList.GetCommandString(idCmd, uType: UINT;
      pwReserved: PUINT; pszName: LPSTR; cchMax: UINT): HResult;
    var
      strTip: string;
      wstrTip: WideString;
    begin
      strTip := '';
      Result := E_INVALIDARG;
      if (uType and GCS_HELPTEXT) <> GCS_HELPTEXT then Exit;
      case idCmd of
        idCopyAnyWhere: strTip := sCopyAnyWhereTip;
        idRegister: strTip := sRegisterTip;
        idUnregister: strTip := sUnregisterTip;
        idImagePreview: strTip := sImagePriviewTip;
      end;
      if strTip <> '' then
      begin
        if (uType and GCS_UNICODE) = 0 then
        begin//Ansi
          lstrcpynA(pszName, PChar(strTip), cchMax);
        end
        else
        begin//Unicode
          wstrTip := strTip;
          lstrcpynW(PWideChar(pszName), PWideChar(wstrTip), cchMax);
        end;
        Result := S_OK;
      end;
    end;

    function TGetResList.HandleMenuMsg(uMsg: UINT; WParam,
      LParam: Integer): HResult;
    var
      Ret: Integer;
    begin
      Ret := 0;
      Result := HandleMenuMsg2(uMsg, WParam, LParam, Ret);
    end;

    function TGetResList.HandleMenuMsg2(uMsg: UINT; wParam, lParam: Integer;
      var lpResult: Integer): HResult;
    var
      pmis: PMeasureItemStruct;
      pdis: PDrawItemStruct;
    begin
      Result := S_OK;
      case uMsg of
        WM_MEASUREITEM:
          begin
            pmis := PMeasureItemStruct(lParam);
            if not Assigned(FGraphic) then
            begin
              pmis.itemWidth := 120;
              pmis.itemHeight := 120;
              Exit;
            end;
            //如果图片小于120 * 120,则按实际显示,否则缩放到120*120
            if (FGraphic.Width <= 120) and (FGraphic.Height <= 120) then
            begin
              pmis.itemWidth := FGraphic.Width;
              pmis.itemHeight := FGraphic.Height;
            end;
          end;
        WM_DRAWITEM:
          begin
            pdis := PDrawItemStruct(lParam);
            DrawGraphic(pdis.hDC, pdis.rcItem, pdis.itemState, FGraphic);
          end;
      end;
    end;

    procedure TGetResList.Initialize;
    begin
      OutputDebugString('TGetResList::Initialize'#13#10);
      inherited;
      FFileList := TStringList.Create;
      FGraphic := nil; 
    end;

    function TGetResList.InvokeCommand(
      var lpici: TCMInvokeCommandInfo): HResult;
    begin
      Result := E_INVALIDARG;
      if HiWord(Integer(lpici.lpVerb)) <> 0 then Exit;
      case LoWord(Integer(lpici.lpVerb)) of
        idCopyAnyWhere: DoCopyAnyWhere(lpici.hwnd, FFileList);
        idRegister: RegisterActiveLib(lpici.hwnd, FFileList[0]);
        idUnregister: UnregisterActiveLib(lpici.hwnd, FFileList[0]);
        idImagePreview: ExecuteFile(lpici.hwnd, FFileList[0]);
      end;
      Result := NOERROR;
    end;

    function TGetResList.QueryContextMenu(Menu: HMENU; indexMenu, idCmdFirst,
      idCmdLast, uFlags: UINT): HResult;
    var
      Added: UINT;
      hbmReg, hbmUnreg: HBITMAP;
    begin
      if (uFlags and CMF_DEFAULTONLY) = (CMF_DEFAULTONLY) then
      begin
        Result := Make_HResult(SEVERITY_SUCCESS, FACILITY_NULL, 0);
        Exit;
      end;
      Added := 0;
      //加入CopyAnyWhere菜单项
      InsertMenu(Menu, indexMenu, mfSpearator, 0, nil);
      InsertMenu(Menu, indexMenu, mfString, idCmdFirst + idCopyAnyWhere, PChar(sCopyAnyWhere));
      InsertMenu(Menu, indexMenu, mfSpearator, 0, nil);
      Inc(Added, 3);

      if FFileList.Count = 1 then
      begin//单一文件
        if IsActiveLib(FFileList[0]) then
        begin
          InsertMenu(Menu, indexMenu + Added, mfSpearator, 0, nil);
          InsertMenu(Menu, indexMenu + Added, mfString, idCmdFirst + idUnregister, PChar(sUnregister));
          InsertMenu(Menu, indexMenu + Added, mfString, idCmdFirst + idRegister, PChar(sRegister));
          InsertMenu(Menu, indexMenu + Added, mfSpearator, 0, nil);
          Inc(Added, 4);
          hbmReg := LoadImage(HInstance, MakeIntResource(101), IMAGE_BITMAP, 0, 0, LR_LOADMAP3DCOLORS);
          hbmUnreg := LoadImage(HInstance, MakeIntResource(102), IMAGE_BITMAP, 0, 0, LR_LOADMAP3DCOLORS);
          SetMenuItemBitmaps(Menu, idCmdFirst + idRegister, MF_BYCOMMAND, hbmReg, hbmReg);
          SetMenuItemBitmaps(Menu, idCmdFirst + idUnregister, MF_BYCOMMAND, hbmUnreg, hbmUnreg);
        end;
        if {IsImageFile(FFileList[0])} False then
        begin//图片文件
          FGraphic := ImageFromFile(FFileList[0]);
          if Assigned(FGraphic) then
          begin
            InsertMenu(Menu, indexMenu + Added, mfSpearator, 0, nil);
            InsertMenu(Menu, indexMenu + Added, mfOwnerDraw, idCmdFirst + idImagePreview, nil);
            InsertMenu(Menu, indexMenu + Added, mfSpearator, 0, nil);
            //Inc(Added, 3);
          end;
        end;
      end
      else
        Result := Make_HResult(SEVERITY_SUCCESS, FACILITY_NULL, idMenuRange);

      Result := Make_HResult(SEVERITY_SUCCESS, FACILITY_NULL, idMenuRange);
    end;

    function TGetResList.SEInitialize(pidlFolder: PItemIDList;
      lpdobj: IDataObject; hKeyProgID: HKEY): HResult;
    begin
      Result := GetFileListFromDataObject(lpdobj, FFileList);
    end;

    initialization
      TComObjectFactory.Create(ComServer, TGetResList, Class_GetResList,
        'GetResList', 'Get Select File List Main Unit', ciMultiInstance, tmApartment);
    end.

  • 相关阅读:
    Servlet和Filter的url匹配
    iterator的用法
    python学习笔记
    python的序列之列表
    java开发实战学习笔记3
    java学习笔记4
    Java Java集合
    Struts2中的几个符号
    DbHelper.cs
    做word,excel时需要引用com
  • 原文地址:https://www.cnblogs.com/tongy0/p/tongy0.html
Copyright © 2011-2022 走看看