¿Hay alguna funcion para evitar que un archivo se cierre?

Iniciado por scott_, 8 Abril 2015, 09:07 AM

0 Miembros y 2 Visitantes están viendo este tema.

scott_

Muy buenas hermanos.

Como dice le titulo, ¿hay alguna funciona para que no se pueda finalizar un proceso?
He estado invesigando pero no se si es correcto:

e.CloseReason = CloseReason.TaskManagerClosing
"o agregar":
e.CloseReason = CloseReason.TaskManagerClosing OrElse e.CloseReason = CloseReason.WindowsShutDown

Si alguien me explica estaría muy agradecido.
Muchas Gracias por su tiempo y Saludos.
Si no intentas salvar una vida, jamás salvarás la de nadie más

Eleкtro

#1
Buenas

Cita de: owl-eyes en  8 Abril 2015, 09:07 AM¿hay alguna funciona para que no se pueda finalizar un proceso?

No, no es posible, por motivos obvios de seguridad un proceso no puede evitar su terminación incondicional, pero al menos puedes controlar el cierre voluntario por parte del usuario.

Aplicaciones cómo por ejemplo el Administrador de tareas (taskmgr) llaman a la función TerminateProcess para matar incondicionalmente un proceso, repito, incondicionalmente:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms686714.aspx?f=255&MSPPError=-2147217396

Dicha función no "pregunta" al proceso si puede ser cerrado y no necesita el permiso del proceso para cerrarlo, por algo puedes matar procesos que no estén respondiendo.




Cita de: owl-eyes en  8 Abril 2015, 09:07 AMHe estado invesigando pero no se si es correcto:

e.CloseReason = CloseReason.TaskManagerClosing

La propiedad e.CloseReason que has mostrado se usa en la plataforma .Net, ¿debemos suponer que estás intentando hacerlo en VB.Net o C#?, especifica que lenguaje utilizas al menos.

CloseReason.TaskManagerClosing es simplemente un valor de una enumeración para determinar el motivo del cierre, nada más:
https://msdn.microsoft.com/en-us/library/system.windows.forms.closereason.aspx?f=255&MSPPError=-2147217396

La ventana recibe el mensaje de windows WM_CLOSE (0x10) para solictar la terminación de la aplicación:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms632617%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396

Te muestro un ejemplo escrito en Vb.Net de cómo puedes interceptar el mensaje recibido y cancelarlo:

Código (vbnet) [Seleccionar]
   ''' <summary>
   ''' Specifies A Windows Message Identifier.
   ''' </summary>
   Public Enum WindowsMessages As Integer

       WM_CLOSE = &H10

   End Enum

   ''' <summary>
   ''' Invokes the default window procedure associated with this window to process messages.
   ''' </summary>
   ''' <param name="m">
   ''' A <see cref="T:System.Windows.Forms.Message"/> that is associated with the current Windows message.
   ''' </param>
   Protected Overrides Sub WndProc(ByRef m As Message)

       If m.Msg = WindowsMessages.WM_CLOSE Then
          ' Do Nothing
       Else
           MyBase.WndProc(m)

       End If

   End Sub


Pero eso solo sirve cuando "el usuario cierra la aplicación",
el evento de cierre no se puede cancelar una vez que la terminación incondicional del proceso ha sido enviada,
puedes comprobarlo tu mismo con el código de arriba y también con el siguiente código, verás que el código del interior del bloque de la condicional jamás se llegará a procesar (ni el evento a cancelar, claro está) si matas la aplicación desde el administrador de tareas puesto que la ejecución termina de forma inminente:

Código (vbnet) [Seleccionar]
   ''' <summary>
   ''' Handles the FormClosing event of the Form1 control.
   ''' </summary>
   ''' <param name="sender">The source of the event.</param>
   ''' <param name="e">The <see cref="FormClosingEventArgs"/> instance containing the event data.</param>
   Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As FormClosingEventArgs) _
   Handles Me.FormClosing

       If e.CloseReason <> CloseReason.UserClosing Then
           e.Cancel = True
           IO.File.Create("C:\Test.txt").Dispose()
       End If

   End Sub





Cita de: owl-eyes en  8 Abril 2015, 09:07 AMSi alguien me explica estaría muy agradecido.

Hay dos soluciones viables:

· Mantener dos procesos distintos en ejecución, el segundo proceso podría ser un servicio de windows que monitorizase el estado del primer proceso para detectar el cierre y volver a ejecutar una nueva instancia del proceso después de haber sido cerrado. Obviamente esto no evita que ambos procesos puedan ser matados incondicionalmente.

· Hookear la API TerminateProcess y opcionalmente ExitProcess para interceptar las llamadas a dicha función, y cancelarlas. Aparte de estar controlando adicionalmente el cierre voluntario en tu aplicación.

Te muestro un ejemplo de API hooking escrito en VB.Net, utilizo la librería Deviare (también puedes utilizar Microsoft Detours en C++), el hook se adjunta al proceso activo taskmgr.exe para evitar que éste pueda terminar ningún proceso, interceptando las llamadas que dicho proceso hace a la función TerminateProcess para cancelarlo (en la pre-llamada):

Código (vbnet) [Seleccionar]
Imports Nektra.Deviare2

Public NotInheritable Class Form1

   Public WithEvents SpyMgr As NktSpyMgr
   Public Hook As NktHook

   ' TerminateProcess API reference:
   ' https://msdn.microsoft.com/es-es/library/windows/desktop/ms686714%28v=vs.85%29.aspx
   ReadOnly libName As String = "kernel32.dll"
   ReadOnly funcName As String = "TerminateProcess"
   ReadOnly hookFlags As eNktHookFlags = eNktHookFlags.flgOnlyPreCall ' Or eNktHookFlags.flgAutoHookChildProcess

   ' Processes to attach the hook.
   ReadOnly processesToAttach As IEnumerable(Of Process) =
       Process.GetProcessesByName("taskmgr")

   Private Sub Test() Handles MyBase.Load

       If Me.processesToAttach.Count = 0 Then
           MsgBox("No se encontró ningún proceso al que adjuntar.")

       Else
           Me.SpyMgr = New NktSpyMgr()
           Me.SpyMgr.Initialize()

           Me.Hook = SpyMgr.CreateHook(String.Format("{0}!{1}", libName, funcName), hookFlags)
           Me.Hook.Hook(sync:=True)

           For Each proc As Process In processesToAttach
               Debug.WriteLine("Attaching to: " & proc.ProcessName)
               Me.Hook.Attach(procOrId:=proc.Id, sync:=True)
           Next proc

       End If

   End Sub

   <MTAThread>
   Private Sub OnTerminateProcess_Called(ByVal hook As NktHook,
                                         ByVal proc As NktProcess,
                                         ByVal callInfo As NktHookCallInfo) Handles SpyMgr.OnFunctionCalled

       ' Signature params.
       Dim hProcessParam As NktParam = DirectCast(callInfo.Params(0), NktParam)
       Dim uExitCodeParam As NktParam = DirectCast(callInfo.Params(1), NktParam)

       Dim hProcessValue As IntPtr = New IntPtr(CInt(hProcessParam.Value))
       Dim uExitCodeValue As UInteger = CUInt(uExitCodeParam.Value)

       Trace.WriteLine(String.Format("hProcess : '{0}'", hProcessValue))
       Trace.WriteLine(String.Format("uExitCode: '{0}'", uExitCodeValue))

       If callInfo.IsPreCall Then ' Skip precall. Avoid process termination.
           callInfo.Result.Value = 1
           callInfo.SkipCall()
       End If

   End Sub

End Class


PD: El primer parámetro de TerminateProcess especifica el handle del proceso que se va a matar, con eso puedes determinar que proceso es, pero lee bien la documentación de MSDN que te he dejado arriba por que me parece que es más complicado que una simple verificación de handles... quizás puedas necesitar la siguiente enumeración para la verificación:

Código (vbnet) [Seleccionar]
   Public Enum ProcessAccessFlags As UInteger
       All = &H1F0FFF
       Terminate = &H1
       CreateThread = &H2
       VirtualMemoryOperation = &H8
       VirtualMemoryRead = &H10
       VirtualMemoryWrite = &H20
       DuplicateHandle = &H40
       CreateProcess = &H80
       SetQuota = &H100
       SetInformation = &H200
       QueryInformation = &H400
       QueryLimitedInformation = &H1000
       Synchronize = &H100000
   End Enum


Saludos








scott_

#2
He tratado de desarrollarlo en C#, pero con el informe que me has dado y los ejemplos mostrados en VB, pues he observado que el archivo no se puede cerrar, ni tampoco eliminar sin usar taskmgr. El típico proceso que no se cierra porque se esta ejecutando. Y pues para lo que estoy probando me es mas que suficiente.

Pero me entro otra duda. Sobre El Drag Drop desde .bat del anterior tema.
copy "%UserProfile%\AppData\Roaming\File.exe" "%ProgramData%\Microsoft\Windows\Start Menu\Programs\Startup"

¿Y me gustara saber como lo puedo hacer para ejecutar un Drag Drop al abrir un archivo, el que sea en VB o en (batch).bat?
Es decir que lo copie el mismo archivo en cualquier directorio, cuando se abra.

Gracias por tomarte la molestia de responder.
Te agradezco mucho.
Gracias y Saludos.
Si no intentas salvar una vida, jamás salvarás la de nadie más

Eleкtro

#3
Cita de: owl-eyes en  9 Abril 2015, 08:50 AMme gustara saber como lo puedo hacer para ejecutar un Drag Drop al abrir un archivo

¿Puedes intentar ser más específico?, no entendí lo que pretendes decir con "ejecutar un drag drop al abrir un archivo".

¿Te refieres a añadir capacidad Drag&Drop (arrastrar y soltar) de archivos en un Form?...

...En ese caso primero debes activar la propiedad 'AllowDrop' del Form/Control y suscribirte a los eventos 'DragEnter' y 'DragDrop' de dicho Form/Control, el primer evento se dispara al arrastrar y el segundo evento al soltar.

Te muestro un ejemplo con un TextBox:

Código (vbnet) [Seleccionar]
   ''' <summary>
   ''' Handles the DragEnter event of the Textbox1 control.
   ''' </summary>
   ''' <param name="sender">The source of the event.</param>
   ''' <param name="e">The <see cref="System.Windows.Forms.DragEventArgs"/> instance containing the event data.</param>
   Private Sub Textbox1_DragEnter(ByVal sender As Object, ByVal e As DragEventArgs) _
   Handles TextBox1.DragEnter

       If e.Data.GetDataPresent(DataFormats.FileDrop) AndAlso
          DirectCast(e.Data.GetData(DataFormats.FileDrop), IEnumerable(Of String)).
                     All(Function(path As String) IO.File.GetAttributes(path).HasFlag(IO.FileAttributes.Archive)) Then

           e.Effect = DragDropEffects.All

       Else
           e.Effect = DragDropEffects.None

       End If

   End Sub

   ''' <summary>
   ''' Handles the DragDrop event of the Textbox1 control.
   ''' </summary>
   ''' <param name="sender">The source of the event.</param>
   ''' <param name="e">The <see cref="DragEventArgs"/> instance containing the event data.</param>
   Private Sub Textbox1_DragDrop(ByVal sender As Object, ByVal e As DragEventArgs) _
   Handles TextBox1.DragDrop

       If e.Data.GetDataPresent(DataFormats.FileDrop) Then

           Dim paths As IEnumerable(Of String) =
              From path As String In DirectCast(e.Data.GetData(DataFormats.FileDrop), IEnumerable(Of String))
              Order By path Ascending

           Me.TextBox1.Text = String.Join("; ", paths)

       End If

   End Sub


Traducción online a C#:
Código (csharp) [Seleccionar]
/// <summary>
/// Handles the DragEnter event of the Textbox1 control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.Windows.Forms.DragEventArgs"/> instance containing the event data.</param>
private void Textbox1_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.FileDrop) && ((IEnumerable<string>)e.Data.GetData(DataFormats.FileDrop)).All((string path) => IO.File.GetAttributes(path).HasFlag(IO.FileAttributes.Archive))) {

e.Effect = DragDropEffects.All;

} else {
e.Effect = DragDropEffects.None;
}
}

/// <summary>
/// Handles the DragDrop event of the Textbox1 control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="DragEventArgs"/> instance containing the event data.</param>
private void Textbox1_DragDrop(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.FileDrop)) {

IEnumerable<string> paths = from path in (IEnumerable<string>)e.Data.GetData(DataFormats.FileDrop) orderby path ascending;
this.TextBox1.Text = string.Join("; ", paths);
}
}

//=======================================================
//Service provided by Telerik (www.telerik.com)
//=======================================================


PD: No te rebajes a utilizar Batch pudiendo manejarte en un lenguaje de alto nivel.

Saludos








scott_

Me parece excelente la traducción en C#, pero no es lo que busco exactamente, me refiero a que un ejecutable se abra y se copie en un directorio.
El ejemplo te lo dejo aqui:
http://www.mediafire.com/download/8md4ra7iz6rir3q/File.rar

Voy a tomar en cuenta el script que me dejaste.

Te agradezco por tu tiempo.
Gracias y Saludos.
Si no intentas salvar una vida, jamás salvarás la de nadie más

Eleкtro

Cita de: owl-eyes en 10 Abril 2015, 00:03 AMme refiero a que un ejecutable se abra y se copie en un directorio.

Código (vbnet) [Seleccionar]
Imports System.IO

Dim destFilePath As String =
    Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
                 Path.GetFileName(Application.ExecutablePath))

File.Copy(sourceFileName:=Application.ExecutablePath,
          destFileName:=destFilePath)


¿Eso dices?

Saludos








scott_

Si ese es el código que busco.

En mi caso en C#:
Código (csharp) [Seleccionar]
using System.IO;
string destFilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), Path.GetFileName(Application.ExecutablePath));
File.Copy(Application.ExecutablePath, destFilePath);


No me queda que agradecerte por tu tiempo invertido.
Muchas Gracias y Saludos.
Si no intentas salvar una vida, jamás salvarás la de nadie más

Eleкtro