I would like to write a simple macro to lift all sheet protection at once. It work's fine. But i would like to make 2 options of it.
1st to use inputbox to write password. Simple
2nd where I need your help, is to use Windows User names to define which are allowed to unprotect it without password (password is in code already defined).
How to use Environ.user to define which user can use that macro?
For example user: 1st "hackla" and 2nd "klaud"
My basic code looks so:
Sub TabelleEntsperren()
Dim strPassw As String
Dim wSheet As Worksheet
strPassw = "Athens"
For Each wSheet In ActiveWorkbook.Worksheets
wSheet.Unprotect Password:=strPassw
Next wSheet
End Sub
Do you mean something like this?
Sub TabelleEntsperren()
Const strPassw As String = "yourPassword"
Const usr1 As String = "hackla"
Const usr2 As String = "klaud"
Dim wSheet As Worksheet
Dim isTrustedUser As Boolean
Dim currentUsr As String
currentUsr = Environ("username")
isTrustedUser = currentUsr = usr1 Or currentUsr = usr2
For Each wSheet In ActiveWorkbook.Worksheets
If isTrustedUser Then wSheet.Unprotect Password:=strPassw
Next wSheet
End Sub
Option Explicit
'Private API declarations
#If VBA7 And Win64 Then
Private Declare PtrSafe Function GetComputerName Lib "kernel32" Alias "GetComputerNameA" (ByVal lpBuffer As String, nSize As Long) As Long
Private Declare PtrSafe Function GetUserName Lib "advapi32.dll" Alias "GetUserNameA" (ByVal lpBuffer As String, nSize As Long) As Long
#Else
Private Declare Function GetComputerName Lib "kernel32" Alias "GetComputerNameA" (ByVal lpBuffer As String, nSize As Long) As Long
Private Declare Function GetUserName Lib "advapi32.dll" Alias "GetUserNameA" (ByVal lpBudffer As String, nSize As Long) As Long
#End If
'To get the computer name
Public Function getActiveComputerName() As String
Dim cn As String, ls As Long, res As Long
cn = String(1024, 0)
ls = 1024
res = GetComputerName(cn, ls)
If res <> 0 Then
getActiveComputerName = Mid$(cn, 1, InStr(cn, Chr$(0)) - 1)
Else
getActiveComputerName = ""
End If
End Function
'To get the identifier for the active user
Public Function getActiveUserName() As String
Dim cn As String, ls As Long, res As Long
cn = String(1024, 0)
ls = 1024
res = GetUserName(cn, ls)
If res <> 0 Then
getActiveUserName = Mid$(cn, 1, InStr(cn, Chr$(0)) - 1)
Else
getActiveUserName = ""
End If
End Function
Related
I am doing some automation work to do repeated copy paste work. Sometimes the server will be so slow. In that time i would be using the below code to wait until the cursor wait goes to normal
Option Explicit
Private Const IDC_WAIT As Long = 32514
Private Type POINT
x As Long
y As Long
End Type
Private Type CURSORINFO
cbSize As Long
flags As Long
hCursor As Long
ptScreenPos As POINT
End Type
Private Declare Function GetCursorInfo _
Lib "user32" (ByRef pci As CURSORINFO) As Boolean
Private Declare Function LoadCursor _
Lib "user32" Alias "LoadCursorA" _
(ByVal hInstance As Long, ByVal lpCursorName As Long) As Long
Public Function IsWaitCursor() As Boolean
' Get handle to wait cursor
Dim handleWaitCursor As Long
handleWaitCursor = LoadCursor(ByVal 0&, IDC_WAIT)
Dim pci As CURSORINFO
pci.cbSize = Len(pci)
' Retrieve information about the current cursor
Dim ret As Boolean
ret = GetCursorInfo(pci)
If ret = False Then
MsgBox "GetCursorInfo failed", vbCritical
Exit Function
End If
' Returns true when current cursor equals to wait cursor
IsWaitCursor = (pci.hCursor = handleWaitCursor)
End Function
The above code worked fine for me in MS Excel 2013 32-bit. But now I am using MS Excel 64-bit and the above code is not working. Someone please tell me what needs to be done
Private Const IDC_WAIT As Long = 32514
Private Type POINT
X As Long
Y As Long
End Type
Private Type CURSORINFO
cbSize As Long
flags As Long
hCursor As LongPtr
ptScreenPos As POINT
End Type
Private Declare PtrSafe Function GetCursorInfo _
Lib "User32" (ByRef pci As CURSORINFO) As Boolean
Private Declare PtrSafe Function LoadCursor Lib "User32" Alias "LoadCursorA" (ByVal hInstance As Long, ByVal lpCursorName As Long) As LongPtr
Public Function IsWaitCursor() As Boolean
' Get handle to wait cursor
Dim handleWaitCursor As LongPtr
handleWaitCursor = LoadCursor(ByVal 0&, IDC_WAIT)
Dim pci As CURSORINFO
pci.cbSize = Len(pci)
' Retrieve information about the current cursor
Dim ret As Boolean
ret = GetCursorInfo(pci)
If ret = False Then
MsgBox "GetCursorInfo failed", vbCritical
Exit Function
End If
' Returns true when current cursor equals to wait cursor
IsWaitCursor = (pci.hCursor = handleWaitCursor)
End Function
The above code worked for me. I changed the Long datatype to LongPtr
I cant belive this is so hard to find (or unexisting) but I would like to write a macro that would copy a file(word,pdf,txt) at predefined path and then I could right click with a mouse in folder and paste it.
So copying to windows clipboard.
Try this method:
https://social.msdn.microsoft.com/Forums/en-US/e624729a-e8bd-4d16-867f-6bd48000bbaa/copy-file-into-clipboard?forum=isvvba
You need to define the path at the end:
afile(0) = "c:\bdlog.txt" 'The file actually exists
The code to try:
Option Explicit
' Required data structures
Private Type POINTAPI
x As Long
y As Long
End Type
' Clipboard Manager Functions
Private Declare Function EmptyClipboard Lib "user32" () As Long
Private Declare Function OpenClipboard Lib "user32" (ByVal hWnd As Long) As Long
Private Declare Function CloseClipboard Lib "user32" () As Long
Private Declare Function SetClipboardData Lib "user32" (ByVal wFormat As Long, ByVal hMem As Long) As Long
Private Declare Function GetClipboardData Lib "user32" (ByVal wFormat As Long) As Long
Private Declare Function IsClipboardFormatAvailable Lib "user32" (ByVal wFormat As Long) As Long
' Other required Win32 APIs
Private Declare Function DragQueryFile Lib "shell32.dll" Alias "DragQueryFileA" (ByVal hDrop As Long, ByVal UINT As Long, ByVal lpStr As String, ByVal ch As Long) As Long
Private Declare Function DragQueryPoint Lib "shell32.dll" (ByVal hDrop As Long, lpPoint As POINTAPI) As Long
Private Declare Function GlobalAlloc Lib "kernel32" (ByVal wFlags As Long, ByVal dwBytes As Long) As Long
Private Declare Function GlobalFree Lib "kernel32" (ByVal hMem As Long) As Long
Private Declare Function GlobalLock Lib "kernel32" (ByVal hMem As Long) As Long
Private Declare Function GlobalUnlock Lib "kernel32" (ByVal hMem As Long) As Long
Private Declare Sub CopyMem Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
' Predefined Clipboard Formats
Private Const CF_TEXT = 1
Private Const CF_BITMAP = 2
Private Const CF_METAFILEPICT = 3
Private Const CF_SYLK = 4
Private Const CF_DIF = 5
Private Const CF_TIFF = 6
Private Const CF_OEMTEXT = 7
Private Const CF_DIB = 8
Private Const CF_PALETTE = 9
Private Const CF_PENDATA = 10
Private Const CF_RIFF = 11
Private Const CF_WAVE = 12
Private Const CF_UNICODETEXT = 13
Private Const CF_ENHMETAFILE = 14
Private Const CF_HDROP = 15
Private Const CF_LOCALE = 16
Private Const CF_MAX = 17
' New shell-oriented clipboard formats
Private Const CFSTR_SHELLIDLIST As String = "Shell IDList Array"
Private Const CFSTR_SHELLIDLISTOFFSET As String = "Shell Object Offsets"
Private Const CFSTR_NETRESOURCES As String = "Net Resource"
Private Const CFSTR_FILEDESCRIPTOR As String = "FileGroupDescriptor"
Private Const CFSTR_FILECONTENTS As String = "FileContents"
Private Const CFSTR_FILENAME As String = "FileName"
Private Const CFSTR_PRINTERGROUP As String = "PrinterFriendlyName"
Private Const CFSTR_FILENAMEMAP As String = "FileNameMap"
' Global Memory Flags
Private Const GMEM_FIXED = &H0
Private Const GMEM_MOVEABLE = &H2
Private Const GMEM_NOCOMPACT = &H10
Private Const GMEM_NODISCARD = &H20
Private Const GMEM_ZEROINIT = &H40
Private Const GMEM_MODIFY = &H80
Private Const GMEM_DISCARDABLE = &H100
Private Const GMEM_NOT_BANKED = &H1000
Private Const GMEM_SHARE = &H2000
Private Const GMEM_DDESHARE = &H2000
Private Const GMEM_NOTIFY = &H4000
Private Const GMEM_LOWER = GMEM_NOT_BANKED
Private Const GMEM_VALID_FLAGS = &H7F72
Private Const GMEM_INVALID_HANDLE = &H8000
Private Const GHND = (GMEM_MOVEABLE Or GMEM_ZEROINIT)
Private Const GPTR = (GMEM_FIXED Or GMEM_ZEROINIT)
Private Type DROPFILES
pFiles As Long
pt As POINTAPI
fNC As Long
fWide As Long
End Type
Public Function ClipboardCopyFiles(Files() As String) As Boolean
Dim data As String
Dim df As DROPFILES
Dim hGlobal As Long
Dim lpGlobal As Long
Dim i As Long
' Open and clear existing crud off clipboard.
If OpenClipboard(0&) Then
Call EmptyClipboard
' Build double-null terminated list of files.
For i = LBound(Files) To UBound(Files)
data = data & Files(i) & vbNullChar
Next
data = data & vbNullChar
' Allocate and get pointer to global memory,
' then copy file list to it.
hGlobal = GlobalAlloc(GHND, Len(df) + Len(data))
If hGlobal Then
lpGlobal = GlobalLock(hGlobal)
' Build DROPFILES structure in global memory.
df.pFiles = Len(df)
Call CopyMem(ByVal lpGlobal, df, Len(df))
Call CopyMem(ByVal (lpGlobal + Len(df)), ByVal data, Len(data))
Call GlobalUnlock(hGlobal)
' Copy data to clipboard, and return success.
If SetClipboardData(CF_HDROP, hGlobal) Then
ClipboardCopyFiles = True
End If
End If
' Clean up
Call CloseClipboard
End If
End Function
Public Function ClipboardPasteFiles(Files() As String) As Long
Dim hDrop As Long
Dim nFiles As Long
Dim i As Long
Dim desc As String
Dim filename As String
Dim pt As POINTAPI
Const MAX_PATH As Long = 260
' Insure desired format is there, and open clipboard.
If IsClipboardFormatAvailable(CF_HDROP) Then
If OpenClipboard(0&) Then
' Get handle to Dropped Filelist data, and number of files.
hDrop = GetClipboardData(CF_HDROP)
nFiles = DragQueryFile(hDrop, -1&, "", 0)
' Allocate space for return and working variables.
ReDim Files(0 To nFiles - 1) As String
filename = Space(MAX_PATH)
' Retrieve each filename in Dropped Filelist.
For i = 0 To nFiles - 1
Call DragQueryFile(hDrop, i, filename, Len(filename))
Files(i) = TrimNull(filename)
Next
' Clean up
Call CloseClipboard
End If
' Assign return value equal to number of files dropped.
ClipboardPasteFiles = nFiles
End If
End Function
Private Function TrimNull(ByVal sTmp As String) As String
Dim nNul As Long
'
' Truncate input sTmpg at first Null.
' If no Nulls, perform ordinary Trim.
'
nNul = InStr(sTmp, vbNullChar)
Select Case nNul
Case Is > 1
TrimNull = Left(sTmp, nNul - 1)
Case 1
TrimNull = ""
Case 0
TrimNull = Trim(sTmp)
End Select
Sub maaa()
'i = "c:\" & ActiveDocument.Name
'ActiveDocument.SaveAs i
Dim afile(0) As String
afile(0) = "c:\070206.excel" 'The file actually exists
MsgBox ClipboardCopyFiles(afile)
End Sub
I need to use FTP Command Function from wininet.dll to send some FTP command. It's working when I use QUIT command. But when I try to use for example LS or DIR I get response 0.
Private Declare Function FtpCommand Lib "wininet.dll" Alias "FtpCommandA" (ByVal hConnect As Long, ByVal fExpectResponse As Long, ByVal dwFlags As Long, ByVal lpszCommand As String, ByVal dwContext As Long, phFtpCommand As Long) As Long
Private Function test()
Dim Success As Long
Dim iRet As Integer
Dim lngInet As Long
Dim lngInetConn As Long
Dim sCommand As String
Dim test44 As Long
sCommand = "DIR"
Dim test5 As Long
Dim lError As Long
Dim strBuffer As String
Dim lBufferSize As Long
Dim retVal As Long
lngInet = InternetOpen("MyFTP Control", 1, vbNullString, vbNullString, 0) 'Open connection with fpt
If lngInet = 0 Then
iRet = MsgBox("bad")
Else
lngInetConn = InternetConnect(lngInet, Server.Value, 0, _
User.Value, Pass.Value, 1, 0, 0) 'Connect to server
If lngInetConn > 0 Then
Login = True
blnRC = FtpCommand(lngInetConn, True, FTP_TRANSFER_TYPE_ASCII, sCommand, test44, test5)
retVal = InternetGetLastResponseInfo(lError, strBuffer, lBufferSize)
Else
Login = False
LoginError
End If
End If
InternetCloseHandle (lngInet) 'Close Ftp I thnik is not necessary
InternetCloseHandle (lngInetConn) 'Close Connection I thnik is not necessary
End Function
There's no DIR or LS commands in FTP. There's LIST command (or MLSD or NLST).
Do not use FtpCommand function anyway.
Use FtpFindFirstFile and InternetFindNextFile instead.
Goal
Have an Excel file with a "Search" button that opens a custom program. This program is used for researches. If the program is already opened when the user clicks on the button, make it popup and focus on that given program.
Current Situation
Here's the code I'm trying to use to make it work:
Search Button
Private Sub btnSearch_Click()
Dim x As Variant
Dim Path As String
If Not IsAppRunning("Word.Application") Then
Path = "C:\Tmp\MyProgram.exe"
x = Shell(Path, vbNormalFocus)
End If
End Sub
IsAppRunning()
Function IsAppRunning(ByVal sAppName) As Boolean
Dim oApp As Object
On Error Resume Next
Set oApp = GetObject(, sAppName)
If Not oApp Is Nothing Then
Set oApp = Nothing
IsAppRunning = True
End If
End Function
This code will work only when I put "Word.Application" as the executable. If I try to put "MyProgram.Application" the function will never see the program is running. How can I find that "MyProgram.exe" is currently opened?
Further more, I'd need to put the focus on it...
You can check this more directly by getting a list of open processes.
This will search based on the process name, returning true/false as appropriate.
Sub exampleIsProcessRunning()
Debug.Print IsProcessRunning("MyProgram.EXE")
Debug.Print IsProcessRunning("NOT RUNNING.EXE")
End Sub
Function IsProcessRunning(process As String)
Dim objList As Object
Set objList = GetObject("winmgmts:") _
.ExecQuery("select * from win32_process where name='" & process & "'")
IsProcessRunning = objList.Count > 0
End Function
Here's how I brought the search window to front:
Private Const SW_RESTORE = 9
Private Declare Function BringWindowToTop Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As Any, ByVal lpWindowName As Any) As Long
Private Declare Function ShowWindow Lib "user32" (ByVal hwnd As Long, ByVal nCmdShow As Long) As Long
Private Sub btnSearch_Click()
Dim x As Variant
Dim Path As String
If IsProcessRunning("MyProgram.exe") = False Then
Path = "C:\Tmp\MyProgram.exe"
x = Shell(Path, vbNormalFocus)
Else
Dim THandle As Long
THandle = FindWindow(vbEmpty, "Window / Form Text")
Dim iret As Long
iret = BringWindowToTop(THandle)
Call ShowWindow(THandle, SW_RESTORE)
End If
End Sub
Now if the window was minimized and the user clicks the search button again, the window will simply pop up.
Just want to point out that the Window Text may change when documents are open in the application instance.
For example, I was trying to bring CorelDRAW to focus and everything would work fine so long as there wasn't a document open in Corel, if there was, I would need to pass the complete name to FindWindow() including the open document.
So, instead of just:
FindWindow("CorelDRAW 2020 (64-Bit)")
It would have to be:
FindWindow("CorelDRAW 2020 (64-Bit) - C:\CompletePath\FileName.cdr")
As that is what would be returned from GetWindowText()
Obviously this is an issue as you don't know what document a user will have open in the application, so for anyone else who may be coming here, years later, who may be experiencing the same issue, here's what I did.
Option Explicit
Private Module
Private Const EXE_NAME As String = "CorelDRW.exe"
Private Const WINDOW_TEXT As String = "CorelDRAW 2020" ' This is common with all opened documents
Private Const GW_HWNDNEXT = 2
Private Const SW_RESTORE = 9
Private Declare PtrSafe Function ShowWindow Lib "user32" (ByVal hWnd As Long, ByVal nCmdShow As Long) As Long
Private Declare PtrSafe Function GetWindow Lib "user32" (ByVal hWnd As Long, ByVal wCmd As Long) As Long
Private Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As Any, ByVal lpWindowName As Any) As Long
Private Declare PtrSafe Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hWnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
Public Sub FocusIfRunning(parAppName as String, parWindowText as String)
Dim oProcs As Object
Dim lWindowHandle As Long
Dim sWindowText As String
Dim sBuffer As String
' Create WMI object and execute a WQL query statement to find if your application
' is a running process. The query will return an SWbemObjectSet.
Set oProcs = GetObject("winmgmts:").ExecQuery("SELECT * FROM win32_process WHERE " & _
"name = '" & parAppName & "'")
' The Count property of the SWbemObjectSet will be > 0 if there were
' matches to your query.
If oProcs.Count > 0 Then
' Go through all the handles checking if the start of the GetWindowText()
' result matches your WindowText pre-file name.
' GetWindowText() needs a buffer, that's what the Space(255) is.
lWindowHandle = FindWindow(vbEmpty, vbEmpty)
Do While lWindowHandle
sBuffer = Space(255)
sWindowText = Left(sBuffer, GetWindowText(lWindowHandle, sBuffer, 255))
If Mid(sWindowText, 1, Len(parWindowText)) Like parWindowText Then Exit Do
' Get the next handle. Will return 0 when there are no more.
lWindowHandle = GetWindow(lWindowHandle, GW_HWNDNEXT)
Loop
Call ShowWindow(lWindowHandle , SW_RESTORE)
End If
End Sub
Private Sub btnFocusWindow_Click()
Call FocusIfRunning(EXE_NAME, WINDOW_TEXT)
End Sub
Hopefully somebody gets use from this and doesn't have to spend the time on it I did.
Just wanted to say thank you for this solution. Only just started playing around with code and wanted to automate my job a bit. This code will paste current selection in excel sheet into an already open application with as single click. Will make my life so much easier!!
Thanks for sharing
Public Const SW_RESTORE = 9
Public Declare Function BringWindowToTop Lib "user32" (ByVal hwnd As Long) As Long
Public Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As Any, ByVal lpWindowName As Any) As Long
Public Declare Function ShowWindow Lib "user32" (ByVal hwnd As Long, ByVal nCmdShow As Long) As Long
Public Sub updatepart()
'
' updatepart Macro
' copies current selection
' finds and focuses on all ready running Notepad application called Test
' pastes value into Notepad document
' Keyboard Shortcut: Ctrl+u
'
Dim data As Range
Set data = Application.Selection
If data.Count <> 1 Then
MsgBox "Selection is too large"
Exit Sub
End If
Selection.Copy
If IsProcessRunning("Notepad.EXE") = False Then
MsgBox "Notepad is down"
Else
Dim THandle As Long
THandle = FindWindow(vbEmpty, "Test - Notepad")
Dim iret As Long
iret = BringWindowToTop(THandle)
Call ShowWindow(THandle, SW_RESTORE)
End If
waittime (500)
'Call SendKeys("{F7}")
Call SendKeys("^v", True) '{F12}
Call SendKeys("{ENTER}")
End Sub
Function waittime(ByVal milliseconds As Double)
Application.Wait (Now() + milliseconds / 24 / 60 / 60 / 1000)
End Function
Function IsProcessRunning(process As String)
Dim objList As Object
Set objList = GetObject("winmgmts:") _
.ExecQuery("select * from win32_process where name='" & process & "'")
If objList.Count > 0 Then
IsProcessRunning = True
Else
IsProcessRunning = False
End If
End Function
We work with a program that embeds Excel in a larger program (SAP Xcelsius/Dashboard Designer). Is there a way, using VBA, to detect if the current instance of Excel is an Embedded instance or not?
The embedding occurs as a result of the command line invokation:
"C:\Program Files\Microsoft Office\Office12\EXCEL.EXE" -Embedding
Try this in VBA:
Option Base 0
Option Explicit
Private Declare Function GetCommandLine Lib "kernel32" Alias "GetCommandLineW" () As Long
Private Declare Function lstrlenW Lib "kernel32" (ByVal lpString As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (MyDest As Any, MySource As Any, ByVal MySize As Long)
Function CmdToStr(Cmd As Long) As String
Dim Buffer() As Byte
Dim StrLen As Long
If Cmd Then
StrLen = lstrlenW(Cmd) * 2
If StrLen Then
ReDim Buffer(0 To (StrLen - 1)) As Byte
CopyMemory Buffer(0), ByVal Cmd, StrLen
CmdToStr = Buffer
End If
End If
End Function
Private Sub Workbook_Open()
Dim CmdRaw As Long
Dim CmdLine As String
Dim CmdArgs As Variant
Dim ValidationType As String
Dim SourcePath As String
Dim TargetPath As String
CmdRaw = GetCommandLine
CmdLine = CmdToStr(CmdRaw)
If Strings.InStr(1, CmdLine, "-Embedding", vbTextCompare) > 0 Then
Call MsgBox("IsEmbedded")
End If
End Sub
VBA-Base-Sourcecode taken from: https://thebestworkers.wordpress.com/2012/04/10/passing-command-line-arguments-to-a-macro-enabled-office-object/
Try this in C# (VSTO):
var isEmbedded = new List<string>(Environment.GetCommandLineArgs()).Contains("-Embedding");
MessageBox.Show(string.Format("IsEmbedded={0}", isEmbedded));