I have a program that shows previews of jpgs in small pictureboxes. The loading of these images is slow, and takes almost a second for each. That is because the images are big (8/9 mB). I would need to load them quickly, for example by loading a thumb of the picture. I would like to avoid putting all into the memory since there could be hundreds of pictures.
what is your advice on this?
THanks
You need to resize the pictures in advance.
Creating tumbnails would be equally slow because you need to read the whole file, before you can even start making the tumbnail.
What you could do is, just like windows, create a tumbnail 'data base', where you store the tumbs for each picture. And only use the full size picture if needed.
So if you have like,
picture001.jpg
picture002.jpg
picture003.jpg
Create tumbs for each one;
picture001.jpg
picture001_tumb.jpg
picture002.jpg
picture002_tumb.jpg
picture003.jpg
picture003_tumb.jpg
So in the loading of the picuters detect, if the _tumb.jpg is there, if not create and store it. Which ofcourse, needs to be done in a background worker, because you need your main app to responsive...
You can also use this code, to request the icon from the windows shell;
Imports System.Runtime.InteropServices
Imports System
Imports System.Drawing
Imports System.Drawing.Imaging
Imports System.Collections.Generic
Imports System.Text
' http://www.vbforums.com/showthread.php?617626-How-do-I-extract-a-256X256-image-out-of-an-icon&highlight=IShellItemImageFactory
Module GetShellIcon
<Flags()> _
Public Enum SIIGBF
SIIGBF_RESIZETOFIT = 0
SIIGBF_BIGGERSIZEOK = 1
SIIGBF_MEMORYONLY = 2
SIIGBF_ICONONLY = 4
SIIGBF_THUMBNAILONLY = 8
SIIGBF_INCACHEONLY = 16
End Enum
Public Enum SIGDN As UInteger
NORMALDISPLAY = 0
PARENTRELATIVEPARSING = &H80018001UI
PARENTRELATIVEFORADDRESSBAR = &H8001C001UI
DESKTOPABSOLUTEPARSING = &H80028000UI
PARENTRELATIVEEDITING = &H80031001UI
DESKTOPABSOLUTEEDITING = &H8004C000UI
FILESYSPATH = &H80058000UI
URL = &H80068000UI
End Enum
<ComImportAttribute(), GuidAttribute("bcc18b79-ba16-442f-80c4-8a59c30c463b"), InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)> _
Public Interface IShellItemImageFactory
Sub GetImage(ByVal size As SIZE, ByVal flags As SIIGBF, ByRef phbm As IntPtr)
End Interface
<ComImport()> <Guid("43826d1e-e718-42ee-bc55-a1e261c37bfe")> <InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> _
Public Interface IShellItem
Sub BindToHandler(ByVal pbc As IntPtr, <MarshalAs(UnmanagedType.LPStruct)> ByVal bhid As Guid, <MarshalAs(UnmanagedType.LPStruct)> ByVal riid As Guid, ByRef ppv As IntPtr)
Sub GetParent(ByRef ppsi As IShellItem)
Sub GetDisplayName(ByVal sigdnName As SIGDN, ByRef ppszName As IntPtr)
Sub GetAttributes(ByVal sfgaoMask As UInt32, ByRef psfgaoAttribs As UInt32)
Sub Compare(ByVal psi As IShellItem, ByVal hint As UInt32, ByRef piOrder As Integer)
End Interface
<DllImport("shell32.dll", CharSet:=CharSet.Unicode, PreserveSig:=False)> _
Public Sub SHCreateItemFromParsingName(<MarshalAs(UnmanagedType.LPWStr)> ByVal pszPath As String, ByVal pbc As IntPtr, <MarshalAs(UnmanagedType.LPStruct)> ByVal riid As Guid, <MarshalAs(UnmanagedType.Interface, IidParameterIndex:=2)> ByRef ppv As IShellItem)
End Sub
<StructLayout(LayoutKind.Sequential)> _
Public Structure SIZE
Public cx As Integer
Public cy As Integer
Public Sub New(ByVal cx As Integer, ByVal cy As Integer)
Me.cx = cx
Me.cy = cy
End Sub
End Structure
Public Function GetShellIcon(ByVal Path As String, MySIIGBF As SIIGBF, Optional ByVal Width As Integer = 256, Optional ByVal Height As Integer = 256) As Bitmap
Dim ppsi As IShellItem = Nothing
Dim hbitmap As IntPtr = IntPtr.Zero
Dim uuid As New Guid("43826d1e-e718-42ee-bc55-a1e261c37bfe")
Dim bs As Bitmap
SHCreateItemFromParsingName(Path, IntPtr.Zero, uuid, ppsi)
DirectCast(ppsi, IShellItemImageFactory).GetImage(New SIZE(Width, Height), MySIIGBF, hbitmap)
bs = System.Drawing.Bitmap.FromHbitmap(hbitmap)
bs.MakeTransparent(Color.Black)
Return bs
End Function
End Module
Related
I made some research, but I can't find something really "interesting". I tried my best to find any kind of documentation or questions that are closest to my case as following:
How to find main window title name of application
how to get the window title of a process
How to get the Title Bar Text by its Process Id
getting the name of a process
How do I get list of Process Names running
Check to see if process is running
How To Get Process Owner ID
How to get the title/name of the last active window?
Get Process ID from Window Title
and also
Process.GetProcessesByName Method
The code I am using to open the process window
Private Async Function ParentMethod() As Task
Dim filePath As String = Await Task.Run(
Function()
Return Directory.EnumerateFiles(My.Settings.Cartellasalvataggio, titolo & ".mp3",
SearchOption.AllDirectories).FirstOrDefault()
End Function)
If Not String.IsNullOrEmpty(filePath) Then
LinkLabel1.Text = "File exist already"
LinkLabel1.Visible = True
PictureBox7.Visible = True
Else
MsgBox("it doesn't exist")
End If
End Function
and the helper class
Imports System.IO
Imports System.Runtime.InteropServices
Public Class NativeMethods
<DllImport("shell32.dll", SetLastError:=True)>
Private Shared Function SHOpenFolderAndSelectItems(
pidlFolder As IntPtr, cidl As UInteger,
<[In], MarshalAs(UnmanagedType.LPArray)> apidl As IntPtr(),
dwFlags As UInteger) As Integer
End Function
<DllImport("shell32.dll", SetLastError:=True)>
Private Shared Sub SHParseDisplayName(
<MarshalAs(UnmanagedType.LPWStr)> name As String,
bindingContext As IntPtr, <Out> ByRef pidl As IntPtr,
sfgaoIn As UInteger, <Out> ByRef psfgaoOut As UInteger)
End Sub
Public Shared Sub OpenFolderAndSelectFile(filePath As String)
Dim dirPath As String = Path.GetDirectoryName(filePath)
Dim fileName As String = Path.GetFileName(filePath)
OpenFolderAndSelectFile(dirPath, fileName)
End Sub
Public Shared Sub OpenFolderAndSelectFile(dirPath As String, fileName As String)
Dim nativeFolder As IntPtr
Dim psfgaoOut As UInteger
SHParseDisplayName(dirPath, IntPtr.Zero, nativeFolder, 0, psfgaoOut)
If nativeFolder = IntPtr.Zero Then
' Log error, can't find folder
Return
End If
Dim nativeFile As IntPtr
SHParseDisplayName(Path.Combine(dirPath, fileName),
IntPtr.Zero, nativeFile, 0, psfgaoOut)
Dim fileArray As IntPtr()
If nativeFile = IntPtr.Zero Then
' Open the folder without the file selected if we can't find the file
fileArray = New IntPtr(-1) {}
Else
fileArray = New IntPtr() {nativeFile}
End If
SHOpenFolderAndSelectItems(nativeFolder, CUInt(fileArray.Length), fileArray, 0)
Marshal.FreeCoTaskMem(nativeFolder)
If nativeFile <> IntPtr.Zero Then
Marshal.FreeCoTaskMem(nativeFile)
End If
End Sub
End Class
then calling it with
NativeMethods.OpenFolderAndSelectFile(filepath,filename & "extension"))
Since I am opening the process this way and NOT with Process class, almost all of them are not suitable to be considered for my case as many of them refer to notepad, while I think the explorer window title and ID changes for every file ( obviously), while "notepad" process, stay "notepad".
I also tried BringToFront, but this latter moves a control in front of other controls, but in this case Explorer is not a control, right?
The least I want to do is to
Get a list of active windows & their process names
as It will waste memory and time usage for no reason as I will need to "filter" process to find my process.
Hope we can find a solution to this, Thanks in advance.
Mattia
This is the solution to it using FindWindowW e SetWindowPos Api.
It is showing Explorer folder on top of top most form.
<DllImport("user32.dll", EntryPoint:="FindWindowW")>
Public Shared Function FindWindowW(<MarshalAs(UnmanagedType.LPTStr)> ByVal lpClassName As String, <MarshalAs(UnmanagedType.LPTStr)> ByVal lpWindowName As String) As IntPtr
End Function
<DllImport("user32.dll")>
Shared Function SetWindowPos(ByVal hWnd As IntPtr, ByVal hWndInsertAfter As IntPtr, ByVal X As Integer, ByVal Y As Integer, ByVal cx As Integer, ByVal cy As Integer, ByVal uFlags As UInteger) As Boolean
End Function
Shared ReadOnly HWND_TOPMOST As IntPtr = New IntPtr(-1)
Const SWP_NOSIZE As UInt32 = &H1
Const SWP_NOMOVE As UInt32 = &H2
Const SWP_SHOWWINDOW As UInt32 = &H40
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
Dim inptr = FindWindowW("CabinetWClass", Nothing)
SetWindowPos(inptr, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE Or SWP_NOSIZE Or SWP_SHOWWINDOW)
End Sub
I have implemented the IOleDropTarget interface and am also using the IDropTargetHelper interface to show the system icon of the file being dragged.
Part of my DragEnter code looks like this
Public Function OleDragEnter(<[In]> <MarshalAs(UnmanagedType.Interface)> pDataObj As Object, <[In]> <MarshalAs(UnmanagedType.U4)> grfKeyState As Integer, <[In]> <MarshalAs(UnmanagedType.U8)> pt As Long, <[In]> <Out> ByRef pdwEffect As Integer) As Integer Implements IOleDropTarget.OleDragEnter
Dim x As Integer = CInt(pt And &H7FFFFFFF)
Dim y As Integer = CInt((pt >> 32) And &H7FFFFFFF)
Dim winPT As Win32Point
winPT.x = CInt(pt And &H7FFFFFFF)
winPT.y = CInt((pt >> 32) And &H7FFFFFFF)
ddHelper.DragEnter(hwnd, CType(pDataObj, NativeMethods.IDataObject), winPT, 0)
End Function
The cast of the pDataObj to an IDataObject works for every kind of object I can drag except for an Outlook email attachment. An email itself works fine but not an attachment. The error is Invalid FORMATETC structure (Exception from HRESULT: 0x80040064 (DV_E_FORMATETC)
Where do I start to work out what I am doing wrong? What code should I show?
my IDataObject interface looks like this
<ComImport, Guid("0000010E-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
Interface IDataObject
<PreserveSig>
Function GetData(
<[In]> ByRef format As FORMATETC, <Out> ByRef medium As STGMEDIUM) As Integer
<PreserveSig>
Function GetDataHere(
<[In]> ByRef format As FORMATETC, ByRef medium As STGMEDIUM) As Integer
<PreserveSig>
Function QueryGetData(
<[In]> ByRef format As FORMATETC) As Integer
<PreserveSig>
Function GetCanonicalFormatEtc(
<[In]> ByRef formatIn As FORMATETC, <Out> ByRef formatOut As FORMATETC) As Integer
<PreserveSig>
Function SetData(
<[In]> ByRef formatIn As FORMATETC,
<[In]> ByRef medium As STGMEDIUM,
<MarshalAs(UnmanagedType.Bool)> ByVal release As Boolean) As Integer
<PreserveSig>
Function EnumFormatEtc(ByVal direction As ComTypes.DATADIR, <Out> ByRef ppenumFormatEtc As System.Runtime.InteropServices.ComTypes.IEnumFORMATETC) As Integer
<PreserveSig>
Function DAdvise(
<[In]> ByRef pFormatetc As FORMATETC, ByVal advf As ComTypes.ADVF, ByVal adviseSink As ComTypes.IAdviseSink, <Out> ByRef connection As Integer) As Integer
<PreserveSig>
Function DUnadvise(ByVal connection As Integer) As Integer
<PreserveSig>
Function EnumDAdvise(<Out> ByRef enumAdvise As ComTypes.IEnumSTATDATA) As Integer
End Interface
and FORMATETC structure like this
<StructLayout(LayoutKind.Sequential)>
Public NotInheritable Class FORMATETC
Public cfFormat As UShort
Public dummy As Short
Public ptd As IntPtr
Public dwAspect As Integer
Public lindex As Integer
Public tymed As Integer
End Class
UPDATED
ddHelper is an instance of my class cast from the IDropTargetHelper interface.
Private ddHelper As IDropTargetHelper = CType(New DragDropHelper(), IDropTargetHelper)
class and interface look like this
<StructLayout(LayoutKind.Sequential)>
Public Structure Win32Point
Public x As Integer
Public y As Integer
End Structure
<ComImport>
<Guid("4657278A-411B-11d2-839A-00C04FD918D0")>
Public Class DragDropHelper
End Class
<ComVisible(True)>
<ComImport>
<Guid("4657278B-411B-11D2-839A-00C04FD918D0")>
<InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
Interface IDropTargetHelper
Sub DragEnter(
<[In]> ByVal hwndTarget As IntPtr,
<[In], MarshalAs(UnmanagedType.[Interface])> ByVal dataObject As NativeMethods.IDataObject,
<[In]> ByRef pt As Win32Point,
<[In]> ByVal effect As Integer)
Sub DragLeave()
Sub DragOver(
<[In]> ByRef pt As Win32Point,
<[In]> ByVal effect As Integer)
Sub Drop(
<[In], MarshalAs(UnmanagedType.[Interface])> ByVal dataObject As NativeMethods.IDataObject,
<[In]> ByRef pt As Win32Point,
<[In]> ByVal effect As Integer)
Sub Show(
<[In]> ByVal show As Boolean)
End Interface
And the error looks like this.
So I have this code
Imports System.Runtime.InteropServices
Imports System.Text
Public Class Form1
Const PROCESS_WM_READ As Integer = &H10
<DllImport("kernel32.dll")>
Public Shared Function OpenProcess(dwDesiredAccess As Integer, bInheritHandle As Boolean, dwProcessId As Integer) As IntPtr
End Function
<DllImport("kernel32.dll")>
Public Shared Function ReadProcessMemory(hProcess As Integer, lpBaseAddress As Integer, lpBuffer As Byte(), dwSize As Integer, ByRef lpNumberOfBytesRead As Integer) As Boolean
End Function
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim notepadProcess As Process = Process.GetProcessesByName("GeometryDash")(0)
Dim processHandle As IntPtr = OpenProcess(PROCESS_WM_READ, False, notepadProcess.Id)
Dim bytesRead As Integer = 0
Dim buffer As Byte() = New Byte(23) {}
'The address in this line is hard-coded. Use whatever is appropriate for your situation.
ReadProcessMemory(CInt(processHandle), 117317672, buffer, buffer.Length, bytesRead)
MsgBox(Encoding.Unicode.GetString(buffer))
End Sub
End Class
It outputs 2 or 3 weird Japanese characters, the address "117317672" is "06FE2028" in decimal. I think it's not liking how I'm giving it the address, how should I put in the address?
I am using the following code to make a connection with a network path to get the list of files.
The network path is defiantly correct, and it is possible for me to map a drive manually with the same credentials. Just when running this code, the error: "53" is displayed which means "The network path was not found.".
The error happens suddenly which suggests to me that even the connection is not being made.
Dim nr As New NETRESOURCE
nr.dwType = RESOURCETYPE_DISK
nr.lpRemoteName = "\\fileserver.ourserver.com\"
MessageBox.Show(WNetAddConnection2(nr, "Password", "ourserver.com\User", 0))
The other code is:
Imports System.Runtime.InteropServices
Imports System
Imports System.IO
Public Class Form1
<StructLayout(LayoutKind.Sequential)> _
Private Structure NETRESOURCE
Public dwScope As UInteger
Public dwType As UInteger
Public dwDisplayType As UInteger
Public dwUsage As UInteger
<MarshalAs(UnmanagedType.LPTStr)> _
Public lpLocalName As String
<MarshalAs(UnmanagedType.LPTStr)> _
Public lpRemoteName As String
<MarshalAs(UnmanagedType.LPTStr)> _
Public lpComment As String
<MarshalAs(UnmanagedType.LPTStr)> _
Public lpProvider As String
End Structure
Private Const NO_ERROR As Long = 0
Private Const RESOURCETYPE_DISK As UInteger = 1
<DllImport("mpr.dll", CharSet:=CharSet.Auto)> _
Private Shared Function WNetAddConnection2(ByRef lpNetResource As NETRESOURCE, <[In](), MarshalAs(UnmanagedType.LPTStr)> ByVal lpPassword As String, <[In](), MarshalAs(UnmanagedType.LPTStr)> ByVal lpUserName As String, ByVal dwFlags As UInteger) As UInteger
End Function
<DllImport("mpr.dll", CharSet:=CharSet.Auto)> _
Private Shared Function WNetCancelConnection2(<[In](), MarshalAs(UnmanagedType.LPTStr)> ByVal lpName As String, ByVal dwFlags As UInteger, <MarshalAs(UnmanagedType.Bool)> ByVal fForce As Boolean) As UInteger
End Function
End Class
Is there a reason you are using an interop class to list your files, you could use the .net Framework to DiriectoryInfo class to do the same.
Unsure why, but adding /IPC$ to the server path now lets me use it again.
Does anyone know how to change the kerning (space between characters) in vb.net? For example, i would like to change "STRING" to "S T R I N G". If possible i would like to be able to create my own font where i can specify the kerning as i wish! Thanks in advance!
The only way I found is to P/Invoke. Assumming a generic form with a generic button this code will work.
Imports System.Runtime.InteropServices
Public Class Form1
Declare Function SetTextCharacterExtra Lib "gdi32" Alias "SetTextCharacterExtra" (ByVal hDC As Integer, ByVal nCharExtra As Integer) As Integer
<DllImport("gdi32")> _
Private Shared Function TextOut(ByVal hdc As IntPtr, ByVal x As Integer, ByVal y As Integer, ByVal textstring As String, ByVal charCount As Integer) As Boolean
End Function
<DllImport("gdi32")> _
Private Shared Function SelectObject(ByVal hdc As IntPtr, ByVal hgdiobj As IntPtr) As IntPtr
End Function
<DllImport("gdi32")> _
Private Shared Function DeleteObject(ByVal objectHandle As IntPtr) As Boolean
End Function
<DllImport("gdi32")> _
Private Shared Function SetBkColor(ByVal hdc As IntPtr, ByVal crColor As Integer) As UInt32
End Function
<DllImport("gdi32")> _
Private Shared Function SetTextColor(ByVal hdc As IntPtr, ByVal crColor As Integer) As UInt32
End Function
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Using G = Graphics.FromHwnd(Me.Handle)
Using myFont As New System.Drawing.Font("Arial", 20, FontStyle.Regular, GraphicsUnit.Pixel)
'Regular Way
Dim LeftEdge = 20
G.DrawString("Hello", myFont, Brushes.Red, LeftEdge, 40)
'If you want kerning
Dim Kerning As Integer = 6 'I think this is twips
Dim Hdc As IntPtr
Dim FontPtr As IntPtr
Try
'Grab the Graphic object's handle
Hdc = G.GetHdc()
'Set the current GDI font
FontPtr = SelectObject(Hdc, myFont.ToHfont())
'Set the drawing surface background color
SetBkColor(Hdc, ColorTranslator.ToWin32(Me.BackColor))
'Set the text color
SetTextColor(Hdc, ColorTranslator.ToWin32(Color.Red))
'Set the kerning
SetTextCharacterExtra(Hdc, Kerning)
Dim Text = "Hello"
'Draw the text at (20,60), Kerning will be applied so reset the left edge to half of kerning
TextOut(Hdc, LeftEdge + (Kerning \ 2), 60, Text, Text.Length)
Catch ex As Exception
Finally
'Release the font
DeleteObject(FontPtr)
'Release the handle on the graphics object
G.ReleaseHdc()
End Try
End Using
End Using
End Sub
End Class
You can use CSS.
I usually set the letter-spacing style attribute in my aspx page.