Ver Mensaje Individual
  #7  
Antiguo 08-11-2004
Avatar de roman
roman roman is offline
Moderador
 
Registrado: may 2003
Ubicación: Ciudad de México
Posts: 20.269
Reputación: 10
roman Es un diamante en brutoroman Es un diamante en brutoroman Es un diamante en bruto
Cita:
Empezado por Nil
Lo que mas me urge es el tema de mover mediante código la posición de los iconos del escritorio.
Luego de una búsqueda en los grupos de noticias de Borland me he percatado de que esto es más difícil de lo que en principio hubiera pensado.

La situación es la siguiente:

Visualmente, el escritorio no es más que un ListView cuyo identificador puedes obtner fácilmente con:

Código Delphi [-]
function SysListView: HWnd;
begin
  Result := FindWindow('Progman', nil);
  Result := FindWindowEx(Result, 0, 'SHELLDLL_DefView', nil);
  Result := FindWindowEx(Result, 0, 'SysListView32', nil);
end;

con lo que en pricipio podrías mandarle el mensaje LVM_SETITEMPOSITION:

Código Delphi [-]
var
  ItemPos: TPoint;
 
begin
  ItemPos.X := 200;
  ItemPos.Y := 300;
 
  SendMessage(SysListView, LVM_SETITEMPOSITION, Index, Cardinal(@ItemPos));
end;

El problema es que ItemPos se localiza en el espacio de memoria asignado a tu aplicación y el ListView del escritorio espera los datos en su propio espacio de memoria. Dicho de otra forma, no puedes acceder a datos de la memoria de otra aplicación.

Para resolver esto he visto que usan varias técnicas dependiendo del sistema operativo. En Windows 9x parece que puedes usar Memory Mapped Files pero no en Windows NT (XP, 2000) en donde o bien usan una DLL o bien funciones especiales de la API para obtener memoria en el espacio de otra aplicación.

Michael Winters, en un hilo de los grupos de noticias de Borland, proporciona un ejemplo muy completo para interactuar con el ListView del escritorio.

La unidad que a continuación te pongo es una versión sumamente simplificada de su código que sirve únicamente para el caso de Windows NT (XP, 2000).

Código Delphi [-]
unit VMem;
 
interface
 
uses
  Windows, SysUtils;
 
type
  TVMemory = class
  private
    FProcess: Cardinal;
 
  public
    constructor Create(Pid: Cardinal);
    destructor Destroy; override;
    function AllocMem(Size: Cardinal): Pointer;
    procedure FreeMem(P: Pointer);
    procedure Read(Source: Pointer; var Dest; Size: Cardinal);
    procedure Write(const Source; Dest: Pointer; Size: Cardinal);
  end;
 
implementation
 
{ TVMemory }
constructor TVMemory.Create(Pid: Cardinal);
const
  Flags = PROCESS_VM_OPERATION or PROCESS_VM_READ or PROCESS_VM_WRITE;
 
begin
  FProcess := OpenProcess(Flags, false, Pid);
  if FProcess = 0 then RaiseLastOSError;
end;
 
destructor TVMemory.Destroy;
begin
  CloseHandle(FProcess);
  inherited;
end;
 
function TVMemory.AllocMem(Size: Cardinal): Pointer;
begin
  Result := VirtualAllocEx(FProcess, nil, Size, MEM_COMMIT, PAGE_READWRITE);
end;
 
procedure TVMemory.FreeMem(P: Pointer);
begin
  VirtualFreeEx(FProcess, P, 0, MEM_RELEASE);
end;
 
procedure TVMemory.Write(const Source; Dest: Pointer; Size: Cardinal);
var
  BytesWritten: Cardinal;
 
begin
  if not WriteProcessMemory(FProcess, Dest, @Source, Size, BytesWritten) then
    RaiseLastOSError;
end;
 
procedure TVMemory.Read(Source: Pointer; var Dest; Size: Cardinal);
var
  BytesRead: Cardinal;
 
begin
  if not ReadProcessMemory(FProcess, Source, @Dest, Size, BytesRead) then
    RaiseLastOSError;
end;
 
end.

Para usarla tienes que crear una instancia de TVMemory pasándole el identificador del proceso de la aplicación que contiene al ListView:

Código Delphi [-]
var
  Pid: Cardinal;
 
begin
  GetWindowThreadProcessId(SysListView, @Result);
  VMemory := TVMemory.Create(Pid);
end;

Para establecer la posición de un icono harías algo así:

Código Delphi [-]
var
  ItemPos: TPoint;
  PItemPos: PPoint;
 
begin
  ItemPos.X := 200;
  ItemPos.Y := 300;
 
  PItemPos := VMemory.AllocMem(SizeOf(ItemPos));
  VMemory.Write(ItemPos, PItemPos, SizeOf(ItemPos));
  SendMessage(SysListView, LVM_SETITEMPOSITION, Index, Cardinal(PItemPos));
  VMemory.FreeMem(PItemPos);
end;

donde Index será el índice del icono que desees cambiar. Cómo obtienes este índice dependerá de cómo pretendas manipular los iconos pero quizá podrías obtener de entrada la posición e índice de todos ellos usando LVM_GETNEXTITEM y LVM_GETITEMPOSITION. Para el útlimo tendrías que usar VMemory con Read en lugar de Write.

// Saludos
Responder Con Cita