En una de las entradas anteriores, justamente en los comentarios de «Primeros pasos tras el curso…», AROJAS comentaba:
Buenos Días, dime tendrias alguna DLL hecha que sirva para llamar el cuadro de diálogo Buscar y Seleccionar Carpeta de Windows, como para que funcione en VELNEO, desde ya gracias
Veamos a ver que podemos hacer… ummmm 🙂
En este caso concreto, no tiene mucho sentido desde la perspectiva de Delphi tener esta función dentro de una librería. Sin embargo, desde la perspectiva de Velneo la cosa cambia y posiblemente sí que nos interese incluirla, ya que al necesitar inicializar estructuras para invocar la función, puesto que recibe como parámetro un puntero a la estructura TBrowseInfo, no lo vamos a poder hacer desde Velneo. Solución: Abrimos nuestro editor de Delphi (otros compañeros sustituiran este entorno por otro cualquiera que nos permita generar la libreria) y no queda más que escribir unas lineas de código.
Vamos a necesitar la función del API de Windows, SHBrowseForFolder que se encuentra ya declarada en el modulo ShlObj.pas de Delphi, lo que nos ahorra tiempo y problemas. De no ser así, deberiamos declararla y traducir los tipos originales de C que necesita la función a los de nuestro entorno.
Básicamente, lo que hacemos es inicializar la estructura TBrowseInfo con los valores adecuados y una vez hecho esto, entregamos un puntero al registro como parámetro de entrada de la función ShBrowseForFolder. La respuesta de la función es similar a otras funciones de la Shell del mismo ámbito. Nos devuelve un puntero a una estructura (PItemIdList). Finalmente, liberamos mediante la interfaz IMalloc la asignación de memoria que hizo el sistema en su respuesta, según reza la documentación técnica.
Descargar el codigo fuente y el mapa para testear la función
Lo que ya dejo un poco a gusto de vosotros es modificar los parámetros de entrada de la función MostrarCuadroCarpetas para que muestre determinadas opciones, o por el contrario no las muestre. Podriamos querer que se visualizase un botón para permitirnos crear una nueva carpeta, mostrar solo los directorios del sistema, mostrar solo los equipos o solo las impresoras. Existen bastantes posibilidades y parece razonable que no nos sean necesarias siempre por lo que he preferido no complicar innecesariamente este pequeño ejemplo. En todo caso, una gran parte de ellas van a depender del valor que tome el campo ulFlags y convendría conocer los distintos valores de las constantes que pueden ser usadas.
BIF_RETURNONLYFSDIRS = $0001;
BIF_DONTGOBELOWDOMAIN = $0002;
BIF_STATUSTEXT = $0004;
BIF_RETURNFSANCESTORS = $0008;
BIF_EDITBOX = $0010;
BIF_VALIDATE = $0020;
BIF_NEWDIALOGSTYLE = $0040;
BIF_USENEWUI = BIF_NEWDIALOGSTYLE or BIF_EDITBOX;
BIF_BROWSEINCLUDEURLS = $0080;
BIF_UAHINT = $100;
BIF_NONEWFOLDERBUTTON = $200;
BIF_NOTRANSLATETARGETS = $400;
BIF_BROWSEFORCOMPUTER = $1000;
BIF_BROWSEFORPRINTER = $2000;
BIF_BROWSEINCLUDEFILES = $4000;
BIF_SHAREABLE = $8000;
Si quisieramos por ejemplo que además de las carpetas nos mostrara los archivos para poder seleccionar cualquiera de ellos, bastaría hacer la asignación:
ulFlags:= BIF_STATUSTEXT or BIF_BROWSEINCLUDEFILES;
Así de fácil. 😉
function MostrarCuadroCarpetas(ACaption: PChar; ACallBack: Boolean): PChar; stdcall;
var
fres: Array[0..MAX_PATH] of Char;
fName: Array[0..MAX_PATH] of Char;
IDList: PItemIDList;
BrowseInfo: TBrowseInfo;
Malloc: IMalloc;
begin
//rellenamos la estructura con los datos deseados
with BrowseInfo do begin
hwndOwner:= 0; //en nuestro caso no existe handle y
//se mostrara de forma no modal
pidlRoot:= nil; //no existe origen predefinido
pszDisplayName:= fName; //Nombre de la carpeta
lpszTitle:= ACaption; //Titulo de la ventana
//se podria parametrizar desde Velneo para mostrar opciones distintas
//en este caso solo hemos seleccionado la posibilidad de mostrar el
//texto a traves del mensaje en la función callback
{
Ver la unidad ShlObj para obtener una lista de todas las constantes
disponibles.
}
ulFlags:= BIF_STATUSTEXT;
//si no queremos ejecutar el callback para modificar la ventana de exploracion
if ACallBack then
lpfn:= @BrowseCallBackProc
else lpfn:= nil;
lParam:= 0;
end;
//Invocamos la funcion del API SHBrowseForFolder pasando como parámetro la
//estructura que hemos inicializado
IDList:= SHBrowseForFolder(BrowseInfo);
//Obtenemos la ruta
ShGetPathFromIDList(IDList, @fres);
//segun la documentación de windows sería necesario liberar la memoria
//que windows reserva para la estructura IDList. Nosotros seguimos la
//mecanica aconsejada y hacemos uso de la interfaz IMalloc para ello.
//El metodo Free libera la memoria asignada
//Previamente comprobamos que podemos obtener un handle a la interfaz
//para hacer uso de las funciones.
if Succeeded(SHGetMalloc(Malloc)) then begin
Malloc.Free(IDList);
end;
Result:= fres;
end;
{$R *.res}
exports
BrowseCallBackProc,
MostrarCuadroCarpetas;
begin
end.
Muy buen ejemplo!!!
Y muchas gracias.
Saludos,
Fran Varona
Me gustaMe gusta