Pregunta

Mike Lischke subclases TThemeServices Application.Handle, de modo que pueda recibir notificaciones de radiodifusión a partir de Windows (es decir WM_THEMECHANGED) cuando tematización cambios.

subclases de la ventana del objeto Application:

FWindowHandle := Application.Handle;
if FWindowHandle <> 0 then
begin
 // If a window handle is given then subclass the window to get notified about theme changes.
 {$ifdef COMPILER_6_UP}
    FObjectInstance := Classes.MakeObjectInstance(WindowProc);
 {$else}
    FObjectInstance := MakeObjectInstance(WindowProc);
 {$endif COMPILER_6_UP}
 FDefWindowProc := Pointer(GetWindowLong(FWindowHandle, GWL_WNDPROC));
 SetWindowLong(FWindowHandle, GWL_WNDPROC, Integer(FObjectInstance));
end;

El procdure ventana subclase entonces lo hace, ya que se supone que, WM_DESTROY mensaje, y eliminar de subclase, y luego pasar el mensaje WM_DESTROY en:

procedure TThemeServices.WindowProc(var Message: TMessage);
begin
  case Message.Msg of
     WM_THEMECHANGED:
        begin
               [...snip...]
        end;
     WM_DESTROY:
        begin
          // If we are connected to a window then we have to listen to its destruction.
          SetWindowLong(FWindowHandle, GWL_WNDPROC, Integer(FDefWindowProc));
          {$ifdef COMPILER_6_UP}
             Classes.FreeObjectInstance(FObjectInstance);
          {$else}
             FreeObjectInstance(FObjectInstance);
          {$endif COMPILER_6_UP}
          FObjectInstance := nil;
        end;
  end;

  with Message do
     Result := CallWindowProc(FDefWindowProc, FWindowHandle, Msg, WParam, LParam);
end;

El objeto TThemeServices es un singleton, destruido durante unidad de finalización:

initialization
finalization
  InternalThemeServices.Free;
end.

Y que todo funciona bien -. Siempre y cuando TThemeServices es el mango de la solicitud única persona que alguna vez subclases

tengo una biblioteca Singleton similares, que también quiere conectar Application.Handle para que pueda recibir emisiones:

procedure TDesktopWindowManager.WindowProc(var Message: TMessage);
begin
case Message.Msg of
WM_DWMCOLORIZATIONCOLORCHANGED: ...
WM_DWMCOMPOSITIONCHANGED: ...
WM_DWMNCRENDERINGCHANGED: ...
WM_DESTROY:
    begin
        // If we are connected to a window then we have to listen to its destruction.
        SetWindowLong(FWindowHandle, GWL_WNDPROC, Integer(FDefWindowProc));
        {$ifdef COMPILER_6_UP}
        Classes.FreeObjectInstance(FObjectInstance);
        {$else}
        FreeObjectInstance(FObjectInstance);
        {$endif COMPILER_6_UP}
        FObjectInstance := nil;
    end;
end;

with Message do
    Result := CallWindowProc(FDefWindowProc, FWindowHandle, Msg, WParam, LParam);

y mi Singleton se elimina de manera similar cuando la unidad finaliza:

initialization
   ...
finalization
    InternalDwmServices.Free;
end.

Ahora llegamos al problema. No puedo garantizar el orden en que alguien podría optar por ThemeServices acceso o DWM, cada uno de los cuales se aplica la subclase. Tampoco puedo saber el orden en que Delphi finalizará unidades.

Las subclases se están eliminando en el orden equivocado, y hay un accidente al cerrar la aplicación.

Cómo corregir? ¿Cómo puedo asegurar que sigo mi método de subclases el tiempo suficiente hasta que el otro chico se hace después de mí que se hace? (I no quiero perder memoria, después de todo)

Ver también


Actualización: i ver Delphi 7 soluciona los errores reescribiendo TApplication. > <

procedure TApplication.WndProc(var Message: TMessage);
...
begin
   ...
   with Message do
      case Msg of
      ...
      WM_THEMECHANGED:
          if ThemeServices.ThemesEnabled then
              ThemeServices.ApplyThemeChange;
      ...
   end;
   ...
end;

Grrrr

En otras palabras: tratar de TApplication subclase era un error, que Borland fija cuando adoptaron TThemeManager de Mike.

Esto muy bien puede significar que no hay manera de eliminar las subclases de TApplication en orden inverso. Alguien puso que en la forma de una respuesta, y lo aceptaré.

¿Fue útil?

Solución

Cambiar su código de llamada SetWindowSubclass , y cuando el artículo se ha vinculado a la asesora. Pero eso sólo funciona si todo el mundo utiliza la misma API, por lo gestor de parches tema use la misma técnica. La API se introdujo en Windows XP, por lo que no hay peligro de que no está disponible en los sistemas en los que se necesitarían.

No debe haber ningún problema con parches Administrador de temas. Está diseñado para soportar Windows XP, que Microsoft no soporta más, y para apoyar Delphi 4 a 6, que Borland no soporta más. Dado que el desarrollo ha dejado en todos los productos pertinentes, es seguro para su tenedor el proyecto Administrador de temas sin riesgo de quedarse atrás debido a las actualizaciones futuras.

usted no está realmente la introducción de una dependencia. Por el contrario, usted está fijando un error que está presente sólo cuando ambas bibliotecas ventana en la apariencia están en uso al mismo tiempo. Los usuarios de la biblioteca no necesita tener Administrador de temas para el suyo para trabajar, pero si desean utilizar tanto, tienen que utilizar Administrador de temas con los parches aplicados. Debe haber pocas objeciones a que puesto que ya tienen la versión base, por lo que no es como ellos estarían instalando una nueva biblioteca. Ellos acababan de estar aplicando un parche y volver a compilar.

Otros consejos

En lugar de crear subclases de la ventana TApplication, tal vez usted puede utilizar AllocateHWnd () en lugar de recibir los mismos transmisiones por separado, ya que es una ventana de nivel superior de su cuenta.

Creo que haría lo siguiente:

  • Ponga una referencia a ThemeServices en la sección de inicialización de ThemeSrv.pas.
  • Ponga una referencia a DwmServices en la sección de inicialización de DwmSrv.pas (soy adivinar el nombre de su unidad).

Dado que las unidades que se finalicen en el orden inverso del orden de inicialización, el problema será resuelto.

¿Por qué no sólo tiene que utilizar los ApplicationEvents y hacerse con él. No hay necesidad de jugar un poco con la subclasificación. La otra forma es crear una subclase sola y crear multi-notificar eventos y suscribirse a todos los que así lo desea.

Saludos

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top