2010-04-12 17 views
17

Me gustaría crear un fondo de escritorio animado para Windows 7 con DirectX. Estoy usando C#, SlimDX y un par de importaciones de P/Invoke de funciones API de Windows. No soy brillante con la programación nativa de Windows, pero he tenido un poke en línea y creo que lo que tengo que hacer es:DirectX Desktop

1) Encuentre el tirador de la ventana que contiene el fondo de pantalla de dekstop, conéctelo a un dispositivo DirectX y dibujar en él.

2) Cree una nueva ventana de salida e insértela encima del fondo de escritorio, pero debajo de los iconos del escritorio.

He intentado ambos, pero ninguno parece funcionar. Si navego por la jerarquía de ventanas comenzando desde el identificador devuelto por GetDesktopWindow(), puedo ir a Escritorio -> Trabajador W -> SHELLDLL_DefView -> SysListView32. Si conecto un dispositivo DirectX a este controlador, puedo dibujar sobre todo el escritorio, pero también cubre los íconos. Si creo un formulario de Windows, establezco su padre en SHELLDLL_DefView usando SetParent() y luego uso SetWindowPos para jugar con su orden Z, parece que solo puedo hacer que vaya detrás del fondo de escritorio o delante de los íconos de escritorio.

Parece que el fondo de escritorio está en segundo plano en la vista de carpeta que contiene los iconos, y por lo tanto, lo que intento hacer no puede funcionar. La única solución sería no usar el escritorio para los iconos, o buscar alguna alternativa, p. sobrescribiendo el escritorio y luego superponiendo una ventana transparente que contiene una vista del contenido de alguna carpeta.

¿Alguien tiene alguna idea de lo que debería hacer, o incluso si lo que quiero hacer es posible? Parece que puedes dibujar en el fondo del escritorio usando el GDI (como creo que lo hace el programa wxSnow), y he visto algo similar a lo que quiero hacer con VLC Media Player en Windows XP con su modo de fondo de pantalla DirectX (curiosamente, parece que no puedo activar esta opción en mi sistema).

Gracias!

+0

Wow, ni siquiera me había dado cuenta de que DreamScene había sido eliminado de 7. ¡Me gustó un poco la función de Vista! Aquí hay una publicación en el blog sobre cómo recuperarla http://www.mydigitallife.info/2009/01/14/how-to-install-and-enable-dreamscene-in-windows-7/ (esto, por supuesto, le permite animar su escritorio sin necesidad de escribir un programa para hacerlo, para aquellos que leen esta pregunta esperando simplemente animar su escritorio y no tener que escribir un programa para hacerlo). – Ricket

+1

Sería mejor que hicieras tu desarrollo en C++, ya que creo que DirectX 9 era la última versión con una API de DirectX administrada. –

+1

SlimDX (http://slimdx.org/) es un contenedor para DirectX que, a diferencia de MDX, se actualiza regularmente para admitir las últimas versiones de DirectX. Tienes razón, probablemente debería estar desarrollándome en C++, pero me gusta C# demasiado para eso. – Jonathan

Respuesta

1

Supongo que puede obtener bastantes fotogramas por segundo al generar dinámicamente mapas de bits y establecerlos constantemente como fondo de escritorio. Sin embargo, esto suena innecesariamente (casi estúpidamente) pesado para la CPU. Actualización: Ahora que lo pienso (era tarde cuando escribí esto), el principal problema con este enfoque es que necesita escribir y leer bitmaps desde el disco duro cada vez que se va a mostrar un nuevo marco. Esto no es factible

¿Realmente está usando el escritorio para los iconos? En Windows 7, la función de búsqueda del menú de inicio y la nueva barra de tareas me han hecho no utilizar el escritorio para los iconos.

Sólo una idea

Se podría ser posible alterar la ventana del escritorio, mediante SendMessage (GetDesktopWindow, WM_SOME_MESSAGE, wParam, lParam), por lo que se puede lograr lo que quiere. Podría investigar esto más mañana (actualmente a las 3 a.m., hora local).

+0

Gracias. Como dices, creo que usar el GDI o configurar el fondo de pantalla con funciones de API probablemente mataría a la CPU, que desafortunadamente es la razón principal por la que quiero usar DirectX en lugar de DreamScene. Creo que he visto algunas referencias al uso de SendMessage() para hacer lo que quiero, pero por el momento esta parte de la API de Windows me supera un poco. Si parece prometedor, iré a leerlo. De lo contrario, seguiré su consejo y dejaré de usar mi escritorio como una tienda de basura al azar. – Jonathan

5

Parece que esto podría no ser posible.Vea este enlace:

http://social.msdn.microsoft.com/Forums/en-US/winforms/thread/69839cec-3424-4300-9ac3-486b8c2fe492

Si usted tiene que dibujar algunos controles entre el fondo de escritorio y los iconos del escritorio, un paso alternativo es a continuación:

  1. Crear el control de usuario en una biblioteca de control de windows.
  2. Incruste el control de usuario en un control ActiveX.
  3. Incruste el control ActiveX en una página web.
  4. Habilite el escritorio activo y configure la página web como su fondo de escritorio .

Esto solo se puede hacer en XP desde Vista no es compatible con el escritorio activo.

Otra publicación sugiere que podría hacer esto con el fondo de una ventana del explorador, si puede obtener el control de la ventana que lo constituye. Por supuesto, si eso es posible, entonces también es posible obtener el control de la ventana del escritorio detrás de los íconos.

Actualización: Bueno, hasta ahora lo único que he encontrado que podría "funcionar" es simplemente crear archivos Bitmap y cambiar el fondo de pantalla una y otra vez (sospecho que esto sería lento, como usted mencionó) .

Esa imagen de pantalla completa debe residir en la memoria en alguna parte, pero puede que no haya forma de acceder a ella sin una grave piratería de memoria de bajo nivel. Voy a seguir buscando.

Actualización 2: Esto podría funcionar, pero no estoy seguro:

http://social.msdn.microsoft.com/forums/en-US/vcgeneral/thread/4af734fb-d2c1-414b-a9f1-759b76692802

La carne de la misma es la siguiente:

HWND p = FindWindow("ProgMan", NULL); 
HWND s = FindWindowEx(p, NULL, "SHELLDLL_DefView", NULL); 
HWND dtw = FindWindowEx(s, NULL, "SysListView32", NULL); 
HDC hdc = GetDC(dtw); 

Básicamente, se está comenzando con la Ventana de ProgMan y exploración desde allí hasta el fondo de escritorio ("SysListView32", supongo). Voy a probar esto.

Actualización 3: No va - el código anterior obtiene el DC del escritorio, pero está por encima de los iconos, por lo que BitBlt se dibuja sobre ellos. Sin embargo, no está dibujando en la pantalla porque puedo dibujar debajo de una forma abierta sin cubrirla, así que eso es progreso al menos.

Supongo que hay alguna ventana disponible que no sea "SysListView32" que es el escritorio detrás de los iconos, o hay más de una ventana "SysListView32".

Actualización 4: Estoy bastante seguro de algo con esto funcionaría:

http://msdn.microsoft.com/en-us/library/bb761155(v=VS.85).aspx http://msdn.microsoft.com/en-us/library/bb774742(v=VS.85).aspx

Básicamente, es un método de API que se llama, pasando de una estructura que incluye un mango de mapa de bits . Si la llamada es exitosa, ese mapa de bits se convierte en el escritorio.

¿DirectX expone las tramas como controladores de mapa de bits (compatibles con GDI), o solo expone la CC? En mi caso, mi animación ya es una matriz de mapas de bits compatibles con GDI, así que no tendría problemas para utilizar este enfoque. Si esta es la única ruta, y DirectX no expone los identificadores de mapa de bits (y no creo que lo hagan), entonces para cada fotograma debería crear un nuevo mapa de bits GDI, lo que desaceleraría bastante las cosas.

En realidad, podría haber una manera más fácil, aunque no estoy seguro de que funcione. Una vez que obtenga el identificador del mapa de bits real del fondo de pantalla, puede seleccionarlo en un contexto de dispositivo usando SelectObject, y luego simplemente usar ese contexto de dispositivo como el destino de BitBlt. Sin embargo, es posible que tenga que enviar una instrucción de repintado al escritorio, lo que podría hacer que los íconos se vuelvan a pintar cada vez.

¿Qué tal si trabajas aquí? :)

+0

Gracias por el enlace. Como mencioné en mi respuesta a la publicación anterior, usar el GDI para animación parece tomar demasiada potencia de CPU. wxSnow utiliza un método similar a la sugerencia en el foro para pintar mapas de bits de copos de nieve sobre el escritorio, y, además de consumir un 20% de CPU por sí mismo, enloquece Desktop Window Manager y Windows Explorer y hace que ocupen el mejor parte del otro 80%. – Jonathan

+1

GDI (BitBlt etc.) no tiene ningún problema de rendimiento intrínseco. Lo uso para una animación rápida a pantalla completa (> 30 fps), que requiere mucho menos CPU que el enfoque DirectX/DirectShow correspondiente. De hecho, la principal limitación de la animación con GDI es que no hay manera de lidiar con los efectos de "desgarro", porque GDI no tiene conciencia de la posición de la línea de exploración de su monitor. DirectX tiene un método semi confiable para hacer esto, aunque todavía es un dolor usarlo para prevenir el desgarro. – MusiGenesis

+0

Sí, uso GDI para animaciones (> 30 fps) también. Pero solo para simples animaciones 2D. Si está trabajando con 3D, necesita usar la GPU.Pero tenga en cuenta que usar GDI en lugar de DirectX no resolvería el problema. Cuando escribe en el CD obtenido de GetDC (GetDesktopWindow), sobrescribirá los iconos en el escritorio. –

1

He hecho some animation of alpha blended windows que siempre están en la parte superior del Z-Order. Una idea sería ignorar el intento de modificar el mapa de bits del escritorio y simplemente dibujar sus cosas como layered window, pero administre ZOrder de alguna manera, de modo que siempre sea la ventana que no está en el escritorio (quizás llamando estratégicamente al Form.SendToBack() o algo así en el momento adecuado)

Dependiendo de lo que esté intentando hacer, esto puede darle el mismo efecto de animar el escritorio.