Título: Ejecutar un archivo externo y esperar a que termine para eliminarlo Publicado por: ThunderCls en 4 Marzo 2011, 16:31 pm Un saludo a todos los amigos del foro y ti que lees este post.
Vamos a ver, tengo esta aplicacion cuyo objetivo es el de ejecutar un archivo externo (.txt, .pdf, etc) con ShellExecute, ahora, lo que quiero es que, una vez ejecutado y cerrado dicho archivo, se borre del HD sin mas. Lo que quiero es algo asi como un fichero temporal, suponiendo que sea un txt, pues que una vez mi aplicacion lo abra con el bloc de notas y luego el usuario lo cierre, que este se elimine. La cuestion esta en que, como muchos pensaran, podria programar un DeleteFile justo antes de salir de mi aplicacion y listo, pero lo que quiero hacer es lo siguiente: Variante#1 ======== 1- Ejecuto mi aplicacion 2- Mi aplicacion ejecuta el archivo (txt, pdf, doc, etc) 3- Mi aplicacion se cierra 4- Se continua abriendo el archivo con su programa predeterminado 5- Se termina de trabajar con el archivo abierto y se cierra 6- El archivo se elimina automaticamente Ahora, otra variante que pudiera hacer seria moviendo el punto 3: Variante#2 ======== 1- Ejecuto mi aplicacion 2- Mi aplicacion ejecuta el archivo (txt, pdf, doc, etc) 3- Se continua abriendo el archivo con su programa predeterminado 4- Se termina de trabajar con el archivo abierto y se cierra 5- Mi aplicacion sabe que se cerro el archivo y lo elimina 6- Mi aplicacion se cierra Ahora, la cosa se complica al no ser un .exe el que se ejecuta, sino cualquier tipo de archivo que depende de una segunda aplicacion para abrirse, por lo que no puedo hacer nada con WaitForSingleObject o cualquier API para el trabajo con procesos y su monitoreo (corriganme si estoy equivocado). Variante#1 ======== Para esto que quiero he estado investigando un poco las API's CreateFile y ShellExecuteEx. En cuanto a la primera, he visto un parametro muy interesante, me refiero a: Código
especificamente en la bandera: FILE_FLAG_DELETE_ON_CLOSE: The system deletes a file immediately after all of its handles are closed, which includes the specified handle and any other open or duplicated handles. If there are existing open handles to a file, the call fails unless they were all opened with the FILE_SHARE_DELETE share mode. Subsequent open requests for the file fail, unless the FILE_SHARE_DELETE share mode is specified. Y yo tengo esto: Código
Como ven eso es justo lo que necesito, pero aqui viene el otro problema, y es que una vez tomado el handle del archivo con estos valores, no tengo acceso permitido a el por una segunda aplicacion al no ser para eliminarlo, por lo que las llamadas con ShellExecute sobre el mismo daran error de acceso al intentar abrirlo. Variante#2 ======== Para la segunda variante, he investigado sobre la API ShellExecuteEx, exactamente hay un valor interesante en la estructura de parametro SHELLEXECUTEINFO, me refiero al valor: Código
Handle to the newly started application. This member is set on return and is always NULL unless fMask is set to SEE_MASK_NOCLOSEPROCESS. Even if fMask is set to SEE_MASK_NOCLOSEPROCESS, hProcess will be NULL if no process was launched. For example, if a document to be launched is a URL and an instance of Microsoft Internet Explorer is already running, it will display the document. No new process is launched, and hProcess will be NULL. Note ShellExecuteEx does not always return an hProcess, even if a process is launched as the result of the call. For example, an hProcess does not return when you use SEE_MASK_INVOKEIDLIST to invoke IContextMenu. Y yo tengo esto: Código
Pero por lo que dicen de el, vemos que no seria confiable para esto, ademas que lo he intentado con el si exito alguno. Perdon por este post tan largo, y gracias por el simple hecho de haber llegado hasta aqui (si es que llegaste...jeje), pero aqui es donde estoy detenido, y es que no se de que forma lograr lo que quiero,...si es con alguna combinacion exacta de valores en los parametros de CreateFile o en ShellExecuteEx que me permitan alguna de las dos variantes que expuse al principio. Bueno, no doy mas lata...ya esta...alguien tiene alguna idea o me puede guiar a lo que quiero??? Saludos y gracias de antemano Título: Re: Ejecutar un archivo externo y esperar a que termine para eliminarlo Publicado por: ThunderCls en 7 Marzo 2011, 22:18 pm Bueno, ya que nadie aporta, me respondo yo mismo y de paso aporto tambien para alguien con el mismo problema que encuentre este post en la red. Por ahora lo he solucionado por la variante#2, aunque no estoy 100% conforme, pero bueno, es lo que hay, aun asi seguire investigando en la variante#1 y si logro algo lo posteo aqui tambien.
Variante#2 - Metodo1 ================ Esta variante la he sacado de dos formas distintas. La primera es de un post parecido a este que encontre en el foro de VB el codigo lo pueden ver aqui: http://foro.elhacker.net/programacion_visual_basic/problemas_con_ejecutar_cualquier_archivo_y_esperar_a_que_termine-t205423.0.html Asi que lo que hice fue pasarlo a CBuilder6 y aqui esta el codigo resultante: Código
Ahora, con respecto a este metodo, es de aclarar que no siempre es 100% efectivo, y me explico. Supongamos que vamos a probar el codigo que he puesto, el cual abre el archivo "test.doc", pero antes de hacerlo ya teniamos con anterioridad una instancia del "WORD.EXE" abierta, y luego de haber ejecutado una que otra aplicacion mas (Winrar, AdobeReader, etc), probamos nuestro codigo y...veremos que abre el "test.doc", pero aun al cerrarlo, nuestra aplicacion no se termina. Esto es debido a que el codigo anterior se basa en hacer un listado de todos los procesos que se ejecutan en la PC, tomando como referencia el ultimo proceso creado, como el proceso de nuestro archivo, y por este sera por el que esperara a que termine. Ahora en el ejemplo que puse anteriormente, ya teniamos una instancia del "WORD.EXE" abierta, por lo que al lanzar el documento no se crea ningun nuevo proceso y se tomara como referencia el ultimo proceso de la lista, no siendo este el correcto. Variante#2 - Metodo2 ================ El segundo metodo que utilizo es el que comentaba en el primer post, y es haciendo uso de las API's ShellExecuteEx y WaitForSingleObject, aqui esta: Código
Este metodo al igual que el primero, tiene sus "contras", algo bien parecido a lo que sucede con el primer codigo. A pesar de estos inconvenientes que he expuesto para cada metodo, el que mejores resultados da de los dos es el primero, asi que gracias a cobein del foro de VB por ese codigo que posteo hace unos años. Como dije al principio, seguire investigando en la primera variante que expuse, de seguro sale algo interesante. Título: Re: Ejecutar un archivo externo y esperar a que termine para eliminarlo Publicado por: yqueseyo en 11 Marzo 2012, 15:33 pm Hola
Es muy probable que este solucionado pero quizas te sirva mejor que el otro metodo. No lo pude hacer fallar por el momento ;) Estaba haciendo un programa para que ejecute cualquier cosa: Accesos directos, .bat, .msu(actualizaciones del seven) etc. etc . y que espere que finalice el programa para continuar. Al final lo pude resolver Buscando desesperado encontre este post; no es lo que buscaba pero lo tome como un desafio. En base a lo que tenia lo modifique y lo adapte a la Variante#1 Salio esto y funciona tambien aunque el word este abierto lo borra sin problemas (el archivo que queremos abrir tiene que estar cerrado ;D) Bueno vamos con el codigo Agregar al form: un Command1 y un Text1(en este va la ruta completa de lo que se quiere abrir y borrar) Código: Private Declare Function GetShortPathName Lib "kernel32" Alias "GetShortPathNameA" _ Lo que hace esto es crear un bat en la carpeta temp. Este bat queda haciendo un bucle para tratar de borrar el archivo que acaba de abrir, como le da error sigue intentando eliminarlo. Cuando se cierra la aplicacion que lo utiliza ej el word lo logra eliminar y se borra así mismo usa el comando ping como temporizador Saludos Título: Re: Ejecutar un archivo externo y esperar a que termine para eliminarlo Publicado por: ThunderCls en 11 Marzo 2012, 21:57 pm Hola, pues al final lo que hice fue lo siguiente...
1- Ejecutar el archivo con su aplicacion predeterminada (ShellExecuteEx) 2- Verificar el campo hProcess: if (hProcess != NULL) tenemos un handle ;-) 2.1 - Si no hay handle es que ya habia una instancia de la aplicacion encargada de abrir el archivo u otra razon, por lo que se marca el fichero para que sea borrado al reinicio del sistema (MoveFileEx con la bandera MOVEFILE_DELAY_UNTIL_REBOOT) 3- Esperar a que termine el hilo que abrio el archivo (WaitForSingleObject) 4- Borrar el archivo La variante del uso del batch ya la habia visto por ahi, pero no me gusta mucho (aunque resuelve sin dudas el problema :silbar:) Saludos ;) |