Archive
Open Existing Android Project in Eclipse
I downloaded sample android applications from http://code.google.com/p/apps-for-android/. Coming from a .NET development background and using Visual Studio as IDE, it took me several minutes to figure out to open a sample app in Eclipse. To open an existing project, click on File > Import… menu item.
Select “Existing Projects into Workspace” and click the Next button. Select the root directory where the samples are located. Eclipse will search for existing projects in the said folder. Although there are a lot of samples in the folder, I think Eclipse will only load samples that have .project and .classpath files.
Afterwards, select the project that you want to import. You can optionally copy the project to your workspace. Click the Finish button and you should already see the imported projects in the package explorer. In my case, I get the following error:
[2011-06-26 11:20:12 - WebViewDemo] /WebViewDemo/gen already exists but is not a source folder. Convert to a source folder or rename it.
Just delete the gen directory in the package explorer and Eclipse will automatically regenerate it. That will clear the error.
Getting Started with Android Development Using Eclipse
I wanted to learn programming in Android, and might as well create an app that could generate extra income. I wanted to blog my experience with Android development and I hope that someone else find my posts helpful. Anyway, before I could create an Android program, I’ll need to install the tools to get started. I’ll be following the instructions laid out in http://developer.android.com/sdk/eclipse-adt.html. It’s been a long time since I used Eclipse because I use Visual Studio at work. I think it’s not required to use Eclipse for Android development but having an IDE would certainly make life easier.
First, we need to download and install the Android SDK. You can download it in http://developer.android.com/sdk/index.html. Select the appropriate version for your operating system. The installer will first check if you have a Java Development Kit (JDK) installed. If it is not yet installed, it won’t continue so just download the JDK and install it first. Afterwards, run the SDK manager to download packages. In my case, I just downloaded the packages checked by default.
You can download the Eclipse IDE in http://www.eclipse.org/downloads/. I downloaded the Eclipse Classic version. It is a zipped file containing the binaries. Just unzip the file and put the contents in the directory you desire. There is no setup required. You may also want to create a shortcut on the desktop. Open up Eclipse and select the directory for your workspace. Go to the Help > Install New Software menu. It opens up the Install dialog. Click on the Add button to add the ADT Plugin repository like shown below.
Afterwards, select the ADT Plugin in the “Work with” combo box. Also select the items that show up on the list.
Continue with the wizard, accept the license agreements, and install the selected software. Restart the Eclipse IDE after. Go to Window > Preferences. Select Android from the list. The Android SDK location is not set yet. Set it to the Android SDK directory. On my machine, I set it to C:\Program Files\Android\android-sdk. Click on the Apply button and the list of SDK targets is refreshed.
To test if our setup is working perfectly, we can try running a sample included in the Android SDK. Check the C:\Program Files\Android\android-sdk\samples directory for the different samples. There are different folders for each API level. To use one, click on the File > New > Other… from the menu. It will show a dialog with different wizard choices. Choose the Android Project wizard. It will open the New Android Project dialog. Select the “Create project from existing sample” radio button. Select the build target and the sample you want to run. I chose the 2.3.3 build target in this example.
Click the Finish button. You can see the added project in the Package Explorer. Right-click on the project and select Run As > Android Application. You can also run the application by using the Run button in the toolbar. You may be prompted to add a new Android Virtual Device. Click Yes and the Android SDK and AVD Manager dialog will be shown. You can see the list of available virtual devices. Click on the New button to create a virtual device compatible with the desired build target.
Click on the Create AVD (Android Virtual Device) button. Run the application again and it should launch the emulator.
Get Processes Locking a File in VB .NET
I was in need of code for getting processes that are locking a file. After some searching, I found this question in Stack Overflow: How does one figure out what process locked a file using c#? There are several answers. In Windows Vista or later, the Restart Manager can be used. In Windows XP, we have to use Windows API functions like NtQuerySystemInformation and NtQueryObject. These functions may be changed or removed in future Windows releases.
I did a bit of a search on Restart Manager and saw this MSDN article: Restart Manager and Generic Method Compilation. There is already a complete method for getting processes locking a file and works perfectly on my machine. This is written in C# so I converted it into VB .NET by using Developer Fusion’s online converter. This method accepts multiple file paths as argument.
Imports System.ComponentModel
Imports System.Runtime.InteropServices
Public Class Util
<DllImport("rstrtmgr.dll", CharSet:=CharSet.Unicode)> _
Private Shared Function RmStartSession(ByRef pSessionHandle As UInteger, dwSessionFlags As Integer, strSessionKey As String) As Integer
End Function
<DllImport("rstrtmgr.dll")> _
Private Shared Function RmEndSession(pSessionHandle As UInteger) As Integer
End Function
<DllImport("rstrtmgr.dll", CharSet:=CharSet.Unicode)> _
Private Shared Function RmRegisterResources(pSessionHandle As UInteger, nFiles As UInt32, rgsFilenames As String(), nApplications As UInt32, <[In]()> rgApplications As RM_UNIQUE_PROCESS(), nServices As UInt32, _
rgsServiceNames As String()) As Integer
End Function
<DllImport("rstrtmgr.dll")> _
Private Shared Function RmGetList(dwSessionHandle As UInteger, ByRef pnProcInfoNeeded As UInteger, ByRef pnProcInfo As UInteger, <[In](), Out()> rgAffectedApps As RM_PROCESS_INFO(), ByRef lpdwRebootReasons As UInteger) As Integer
End Function
Private Const RmRebootReasonNone As Integer = 0
Private Const CCH_RM_MAX_APP_NAME As Integer = 255
Private Const CCH_RM_MAX_SVC_NAME As Integer = 63
<StructLayout(LayoutKind.Sequential)> _
Private Structure RM_UNIQUE_PROCESS
Public dwProcessId As Integer
Public ProcessStartTime As ComTypes.FILETIME
End Structure
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode)> _
Private Structure RM_PROCESS_INFO
Public Process As RM_UNIQUE_PROCESS
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=CCH_RM_MAX_APP_NAME + 1)> _
Public strAppName As String
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=CCH_RM_MAX_SVC_NAME + 1)> _
Public strServiceShortName As String
Public ApplicationType As RM_APP_TYPE
Public AppStatus As UInteger
Public TSSessionId As UInteger
<MarshalAs(UnmanagedType.Bool)> _
Public bRestartable As Boolean
End Structure
Private Enum RM_APP_TYPE
RmUnknownApp = 0
RmMainWindow = 1
RmOtherWindow = 2
RmService = 3
RmExplorer = 4
RmConsole = 5
RmCritical = 1000
End Enum
Public Shared Function GetProcessesUsingFiles(filePaths As IList(Of String)) As IList(Of Process)
Dim sessionHandle As UInteger
Dim processes As New List(Of Process)()
' Create a restart manager session
Dim rv As Integer = RmStartSession(sessionHandle, 0, Guid.NewGuid().ToString())
If rv <> 0 Then
Throw New Win32Exception()
End If
Try
' Let the restart manager know what files we’re interested in
Dim pathStrings As String() = New String(filePaths.Count - 1) {}
filePaths.CopyTo(pathStrings, 0)
rv = RmRegisterResources(sessionHandle, CUInt(pathStrings.Length), pathStrings, 0, Nothing, 0, _
Nothing)
If rv <> 0 Then
Throw New Win32Exception()
End If
' Ask the restart manager what other applications
' are using those files
Const ERROR_MORE_DATA As Integer = 234
Dim pnProcInfoNeeded As UInteger = 0, pnProcInfo As UInteger = 0, lpdwRebootReasons As UInteger = RmRebootReasonNone
rv = RmGetList(sessionHandle, pnProcInfoNeeded, pnProcInfo, Nothing, lpdwRebootReasons)
If rv = ERROR_MORE_DATA Then
' Create an array to store the process results
Dim processInfo As RM_PROCESS_INFO() = New RM_PROCESS_INFO(pnProcInfoNeeded - 1) {}
pnProcInfo = CUInt(processInfo.Length)
' Get the list
rv = RmGetList(sessionHandle, pnProcInfoNeeded, pnProcInfo, processInfo, lpdwRebootReasons)
If rv = 0 Then
' Enumerate all of the results and add them to the
' list to be returned
For i As Integer = 0 To pnProcInfo - 1
Try
processes.Add(Process.GetProcessById(processInfo(i).Process.dwProcessId))
' in case the process is no longer running
Catch generatedExceptionName As ArgumentException
End Try
Next
Else
Throw New Win32Exception()
End If
ElseIf rv <> 0 Then
Throw New Win32Exception()
End If
Finally
' Close the resource manager
RmEndSession(sessionHandle)
End Try
Return processes
End Function
End Class
For XP, I converted the C# code I got from Stack Overflow to VB .NET using the said online converter. I also manually edited the conversion results because it can’t properly convert anonymous methods and the var keyword. Also, there are some things that we still need to change to make it work. The line “nLength = objBasic.NameInformationLength” won’t work because NameInformationLength is always zero so I set nLength to &H1000. Also, a handle’s access may cause a call to NtQueryObject to hang forever so we have to check them first before continuing. I got the list of the access masks here. Lastly, we have to check the “Remove integer overflow checks” check box under the Project Properties > Compile > Advance Compile Options. Otherwise, a overflow exception might occur. I think integer overflow is not checked in C# by default.
Imports System.Collections.Generic
Imports System.Runtime.InteropServices
Imports System.Diagnostics
Imports System.Text
Imports System.Threading
Public Class Win32Processes
''' <summary>
''' Return a list of processes that hold on the given file.
''' </summary>
Public Shared Function GetProcessesLockingFile(filePath As String) As List(Of Process)
Dim procs = New List(Of Process)()
For Each process__1 In Process.GetProcesses()
Dim files = GetFilesLockedBy(process__1)
If files.Contains(filePath) Then
procs.Add(process__1)
End If
Next
Return procs
End Function
''' <summary>
''' Return a list of file locks held by the process.
''' </summary>
Public Shared Function GetFilesLockedBy(process As Process) As List(Of String)
Dim outp = New List(Of String)()
Dim ts As ThreadStart = New ThreadStart(
Sub()
Try
outp = UnsafeGetFilesLockedBy(process)
Catch
End Try
End Sub
)
Try
Dim t = New Thread(ts)
t.IsBackground = True
t.Start()
t.Join()
'If Not t.Join(250) Then
' Try
' t.Abort()
' Catch
' End Try
'End If
Catch
End Try
Return outp
End Function
#Region "Inner Workings"
Private Shared Function UnsafeGetFilesLockedBy(process As Process) As List(Of String)
Try
Dim [handles] = GetHandles(process)
Dim files = New List(Of String)()
For Each handle In [handles]
Dim file = GetFilePath(handle, process)
If file IsNot Nothing Then
files.Add(file)
End If
Next
Return files
Catch
Return New List(Of String)()
End Try
End Function
Const CNST_SYSTEM_HANDLE_INFORMATION As Integer = 16
Const STATUS_INFO_LENGTH_MISMATCH As UInteger = &HC0000004UI
Private Shared Function GetFilePath(sYSTEM_HANDLE_INFORMATION As Win32API.SYSTEM_HANDLE_INFORMATION, process As Process) As String
If sYSTEM_HANDLE_INFORMATION.GrantedAccess = &H12019F OrElse
sYSTEM_HANDLE_INFORMATION.GrantedAccess = &H1A019F OrElse
sYSTEM_HANDLE_INFORMATION.GrantedAccess = &H120189 OrElse
sYSTEM_HANDLE_INFORMATION.GrantedAccess = &H100000 Then
Return Nothing
End If
Dim m_ipProcessHwnd As IntPtr = Win32API.OpenProcess(Win32API.ProcessAccessFlags.All, False, process.Id)
Dim ipHandle As IntPtr = IntPtr.Zero
Dim objBasic = New Win32API.OBJECT_BASIC_INFORMATION()
Dim ipBasic As IntPtr = IntPtr.Zero
Dim objObjectType = New Win32API.OBJECT_TYPE_INFORMATION()
Dim ipObjectType As IntPtr = IntPtr.Zero
Dim objObjectName = New Win32API.OBJECT_NAME_INFORMATION()
Dim ipObjectName As IntPtr = IntPtr.Zero
Dim strObjectTypeName As String = ""
Dim strObjectName As String = ""
Dim nLength As Integer = 0
Dim nReturn As Integer = 0
Dim ipTemp As IntPtr = IntPtr.Zero
If Not Win32API.DuplicateHandle(m_ipProcessHwnd, sYSTEM_HANDLE_INFORMATION.Handle, Win32API.GetCurrentProcess(), ipHandle, 0, False, _
Win32API.DUPLICATE_SAME_ACCESS) Then
Return Nothing
End If
ipBasic = Marshal.AllocHGlobal(Marshal.SizeOf(objBasic))
Win32API.NtQueryObject(ipHandle, CInt(Win32API.ObjectInformationClass.ObjectBasicInformation), ipBasic, Marshal.SizeOf(objBasic), nLength)
objBasic = DirectCast(Marshal.PtrToStructure(ipBasic, objBasic.[GetType]()), Win32API.OBJECT_BASIC_INFORMATION)
Marshal.FreeHGlobal(ipBasic)
ipObjectType = Marshal.AllocHGlobal(objBasic.TypeInformationLength)
nLength = objBasic.TypeInformationLength
While CUInt(InlineAssignHelper(nReturn, Win32API.NtQueryObject(ipHandle, CInt(Win32API.ObjectInformationClass.ObjectTypeInformation), ipObjectType, nLength, nLength))) = Win32API.STATUS_INFO_LENGTH_MISMATCH
Marshal.FreeHGlobal(ipObjectType)
ipObjectType = Marshal.AllocHGlobal(nLength)
End While
objObjectType = DirectCast(Marshal.PtrToStructure(ipObjectType, objObjectType.[GetType]()), Win32API.OBJECT_TYPE_INFORMATION)
If Is64Bits() Then
ipTemp = New IntPtr(Convert.ToInt64(objObjectType.Name.Buffer.ToString(), 10) >> 32)
Else
ipTemp = objObjectType.Name.Buffer
End If
strObjectTypeName = Marshal.PtrToStringUni(ipTemp, objObjectType.Name.Length >> 1)
Marshal.FreeHGlobal(ipObjectType)
If strObjectTypeName <> "File" Then
Return Nothing
End If
'nLength = objBasic.NameInformationLength
nLength = &H1000
ipObjectName = Marshal.AllocHGlobal(nLength)
While CUInt(InlineAssignHelper(nReturn, Win32API.NtQueryObject(ipHandle, CInt(Win32API.ObjectInformationClass.ObjectNameInformation), ipObjectName, nLength, nLength))) = Win32API.STATUS_INFO_LENGTH_MISMATCH
Marshal.FreeHGlobal(ipObjectName)
ipObjectName = Marshal.AllocHGlobal(nLength)
End While
objObjectName = DirectCast(Marshal.PtrToStructure(ipObjectName, objObjectName.[GetType]()), Win32API.OBJECT_NAME_INFORMATION)
If Is64Bits() Then
ipTemp = New IntPtr(Convert.ToInt64(objObjectName.Name.Buffer.ToString(), 10) >> 32)
Else
ipTemp = objObjectName.Name.Buffer
End If
If ipTemp <> IntPtr.Zero Then
Dim baTemp As Byte() = New Byte(nLength - 1) {}
Try
Marshal.Copy(ipTemp, baTemp, 0, nLength)
strObjectName = Marshal.PtrToStringUni(If(Is64Bits(), New IntPtr(ipTemp.ToInt64()), New IntPtr(ipTemp.ToInt32())))
Catch generatedExceptionName As AccessViolationException
Return Nothing
Finally
Marshal.FreeHGlobal(ipObjectName)
Win32API.CloseHandle(ipHandle)
End Try
End If
Dim path As String = GetRegularFileNameFromDevice(strObjectName)
Try
Return path
Catch
Return Nothing
End Try
End Function
Private Shared Function GetRegularFileNameFromDevice(strRawName As String) As String
Dim strFileName As String = strRawName
For Each strDrivePath As String In Environment.GetLogicalDrives()
Dim sbTargetPath As New StringBuilder(Win32API.MAX_PATH)
If Win32API.QueryDosDevice(strDrivePath.Substring(0, 2), sbTargetPath, Win32API.MAX_PATH) = 0 Then
Return strRawName
End If
Dim strTargetPath As String = sbTargetPath.ToString()
If strFileName.StartsWith(strTargetPath) Then
strFileName = strFileName.Replace(strTargetPath, strDrivePath.Substring(0, 2))
Exit For
End If
Next
Return strFileName
End Function
Private Shared Function GetHandles(process As Process) As List(Of Win32API.SYSTEM_HANDLE_INFORMATION)
Dim nStatus As UInteger
Dim nHandleInfoSize As Integer = &H10000
Dim ipHandlePointer As IntPtr = Marshal.AllocHGlobal(nHandleInfoSize)
Dim nLength As Integer = 0
Dim ipHandle As IntPtr = IntPtr.Zero
While (InlineAssignHelper(nStatus, Win32API.NtQuerySystemInformation(CNST_SYSTEM_HANDLE_INFORMATION, ipHandlePointer, nHandleInfoSize, nLength))) = STATUS_INFO_LENGTH_MISMATCH
nHandleInfoSize = nLength
Marshal.FreeHGlobal(ipHandlePointer)
ipHandlePointer = Marshal.AllocHGlobal(nLength)
End While
Dim baTemp As Byte() = New Byte(nLength - 1) {}
Marshal.Copy(ipHandlePointer, baTemp, 0, nLength)
Dim lHandleCount As Long = 0
If Is64Bits() Then
lHandleCount = Marshal.ReadInt64(ipHandlePointer)
ipHandle = New IntPtr(ipHandlePointer.ToInt64() + 8)
Else
lHandleCount = Marshal.ReadInt32(ipHandlePointer)
ipHandle = New IntPtr(ipHandlePointer.ToInt32() + 4)
End If
Dim shHandle As Win32API.SYSTEM_HANDLE_INFORMATION
Dim lstHandles As New List(Of Win32API.SYSTEM_HANDLE_INFORMATION)()
For lIndex As Long = 0 To lHandleCount - 1
shHandle = New Win32API.SYSTEM_HANDLE_INFORMATION()
If Is64Bits() Then
shHandle = DirectCast(Marshal.PtrToStructure(ipHandle, shHandle.[GetType]()), Win32API.SYSTEM_HANDLE_INFORMATION)
ipHandle = New IntPtr(ipHandle.ToInt64() + Marshal.SizeOf(shHandle) + 8)
Else
ipHandle = New IntPtr(ipHandle.ToInt64() + Marshal.SizeOf(shHandle))
shHandle = DirectCast(Marshal.PtrToStructure(ipHandle, shHandle.[GetType]()), Win32API.SYSTEM_HANDLE_INFORMATION)
End If
If shHandle.ProcessID <> process.Id Then
Continue For
End If
lstHandles.Add(shHandle)
Next
Return lstHandles
End Function
Private Shared Function Is64Bits() As Boolean
Return If(Marshal.SizeOf(GetType(IntPtr)) = 8, True, False)
End Function
Friend Class Win32API
<DllImport("ntdll.dll")> _
Public Shared Function NtQueryObject(ObjectHandle As IntPtr, ObjectInformationClass As Integer, ObjectInformation As IntPtr, ObjectInformationLength As Integer, ByRef returnLength As Integer) As Integer
End Function
<DllImport("kernel32.dll", SetLastError:=True)> _
Public Shared Function QueryDosDevice(lpDeviceName As String, lpTargetPath As StringBuilder, ucchMax As Integer) As UInteger
End Function
<DllImport("ntdll.dll")> _
Public Shared Function NtQuerySystemInformation(SystemInformationClass As Integer, SystemInformation As IntPtr, SystemInformationLength As Integer, ByRef returnLength As Integer) As UInteger
End Function
<DllImport("kernel32.dll")> _
Public Shared Function OpenProcess(dwDesiredAccess As ProcessAccessFlags, <MarshalAs(UnmanagedType.Bool)> bInheritHandle As Boolean, dwProcessId As Integer) As IntPtr
End Function
<DllImport("kernel32.dll")> _
Public Shared Function CloseHandle(hObject As IntPtr) As Integer
End Function
<DllImport("kernel32.dll", SetLastError:=True)> _
Public Shared Function DuplicateHandle(hSourceProcessHandle As IntPtr, hSourceHandle As UShort, hTargetProcessHandle As IntPtr, ByRef lpTargetHandle As IntPtr, dwDesiredAccess As UInteger, <MarshalAs(UnmanagedType.Bool)> bInheritHandle As Boolean, _
dwOptions As UInteger) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function
<DllImport("kernel32.dll")> _
Public Shared Function GetCurrentProcess() As IntPtr
End Function
Public Enum ObjectInformationClass As Integer
ObjectBasicInformation = 0
ObjectNameInformation = 1
ObjectTypeInformation = 2
ObjectAllTypesInformation = 3
ObjectHandleInformation = 4
End Enum
<Flags()> _
Public Enum ProcessAccessFlags As UInteger
All = &H1F0FFF
Terminate = &H1
CreateThread = &H2
VMOperation = &H8
VMRead = &H10
VMWrite = &H20
DupHandle = &H40
SetInformation = &H200
QueryInformation = &H400
Synchronize = &H100000
End Enum
<StructLayout(LayoutKind.Sequential)> _
Public Structure OBJECT_BASIC_INFORMATION
' Information Class 0
Public Attributes As Integer
Public GrantedAccess As Integer
Public HandleCount As Integer
Public PointerCount As Integer
Public PagedPoolUsage As Integer
Public NonPagedPoolUsage As Integer
Public Reserved1 As Integer
Public Reserved2 As Integer
Public Reserved3 As Integer
Public NameInformationLength As Integer
Public TypeInformationLength As Integer
Public SecurityDescriptorLength As Integer
Public CreateTime As System.Runtime.InteropServices.ComTypes.FILETIME
End Structure
<StructLayout(LayoutKind.Sequential)> _
Public Structure OBJECT_TYPE_INFORMATION
' Information Class 2
Public Name As UNICODE_STRING
Public ObjectCount As Integer
Public HandleCount As Integer
Public Reserved1 As Integer
Public Reserved2 As Integer
Public Reserved3 As Integer
Public Reserved4 As Integer
Public PeakObjectCount As Integer
Public PeakHandleCount As Integer
Public Reserved5 As Integer
Public Reserved6 As Integer
Public Reserved7 As Integer
Public Reserved8 As Integer
Public InvalidAttributes As Integer
Public GenericMapping As GENERIC_MAPPING
Public ValidAccess As Integer
Public Unknown As Byte
Public MaintainHandleDatabase As Byte
Public PoolType As Integer
Public PagedPoolUsage As Integer
Public NonPagedPoolUsage As Integer
End Structure
<StructLayout(LayoutKind.Sequential)> _
Public Structure OBJECT_NAME_INFORMATION
' Information Class 1
Public Name As UNICODE_STRING
End Structure
<StructLayout(LayoutKind.Sequential, Pack:=1)> _
Public Structure UNICODE_STRING
Public Length As UShort
Public MaximumLength As UShort
Public Buffer As IntPtr
End Structure
<StructLayout(LayoutKind.Sequential)> _
Public Structure GENERIC_MAPPING
Public GenericRead As Integer
Public GenericWrite As Integer
Public GenericExecute As Integer
Public GenericAll As Integer
End Structure
<StructLayout(LayoutKind.Sequential, Pack:=1)> _
Public Structure SYSTEM_HANDLE_INFORMATION
' Information Class 16
Public ProcessID As Integer
Public ObjectTypeNumber As Byte
Public Flags As Byte
' 0x01 = PROTECT_FROM_CLOSE, 0x02 = INHERIT
Public Handle As UShort
Public Object_Pointer As Integer
Public GrantedAccess As UInt32
End Structure
Public Const MAX_PATH As Integer = 260
Public Const STATUS_INFO_LENGTH_MISMATCH As UInteger = &HC0000004UI
Public Const DUPLICATE_SAME_ACCESS As Integer = &H2
End Class
Private Shared Function InlineAssignHelper(Of T)(ByRef target As T, value As T) As T
target = value
Return value
End Function
#End Region
End Class






