How can I set a password for Visio files? - passwords

I want to put a password on the files so no one can open without their permission

It appears the short answer is not unless you have password protection for zip files.
You can however test some vba code and play with visibility. It won't guarantee security of your document because Visio doesn't have flexibility to save as a Macro-Enabled drawing... limiting your ability to really secure it with VBA.
You could however pique the confusion of the undesired user reading/viewing by having all of your pages hidden... Security by obscurity if you will.... Unless they enable macros, they can still ideally do anything they want with the document which Is why you should use encrypted zip software and password protect the document that way.
Anyway... if you're still game for this crazy experiment I tried...
Enabled developer view. Then go into View Code. So here's how this works... First you need to generate your password hash. Then once your password hash is created... Delete the entire
Copy all the main sub, the temporary sub, and the core subs and functions below to your "ThisDocument" object in the developer > View Code page
Set your password by entering your password in place of "Mypassword" in the GenMyPwd sub. You can execute it by leaving your curser in the text of that sub and clicking the "run" button at the top of the Microsoft Visual Basic for Applications menu.
Once you see the pop-up, press Ctrl+V and paste the content to notepad. You'll get something to this effect.
---------------------------
Your Password Hash
---------------------------
78F56C460A6CA4B15554E5FE5469AA036FB21EFA7151E991D6F9A9FDA4548F79
---------------------------
OK
---------------------------
Once you have your hash, set the variable in the private for your own unique hash value.
mypassword = "78F56C460A6CA4B15554E5FE5469AA036FB21EFA7151E991D6F9A9FDA4548F79"
One caveat though, you'll have to create a button for your HidePages Script... or create a key-capture event for a hotkey combination and use it add some additional vba code to Save, HidePages, and then close visio.
Main Sub to capture open document event. - Will look like this before you set your variable
Private Sub Document_DocumentOpened(ByVal doc As IVDocument)
Unauthenticated = True
myPassword = ""
Do While Unauthenticated
'Add number of tries
tries = tries + 1
'Prompt Password
TryPassword = InputBox("Enter the password", "Password Required!")
'Hash Password attempt and compare to Current Hash
If Sha256Hash(TryPassword) = myPassword Then
'Escape the loop
Unauthenticated = False
Call ShowPages
Else
If ((tries > 2) And (Unauthenticated = True)) Then KillVisio
End If
Loop
End Sub
Main Sub After you set your variable
Private Sub Document_DocumentOpened(ByVal doc As IVDocument)
Unauthenticated = True
myPassword = "6DA6F219DAC977DA75F2F2894F33ABAD5052AF2A60AE9219AF0E302EDDD5BBC4"
Do While Unauthenticated
'Add number of tries
tries = tries + 1
'Prompt Password
TryPassword = InputBox("Enter the password", "Password Required!")
'Hash Password attempt and compare to Current Hash
If Sha256Hash(TryPassword) = myPassword Then
'Escape the loop
Unauthenticated = False
Call ShowPages
Else
If ((tries > 2) And (Unauthenticated = True)) Then KillVisio
End If
Loop
End Sub
Additional Required Subs and functions
Sub KillVisio()
Set WShshell = CreateObject("WScript.Shell")
strcommand = "C:\windows\system32\taskkill /im visio.exe -f"
WShshell.Run ("cmd /c " & strcommand)
End Sub
Sub GenMyPwd()
MsgBox Sha256Hash("P#ssw0rd"), vbExclamation, "Your Password Hash"
End Sub
Sub ShowPages()
Set vPages = ThisDocument.Pages
For i = 1 To vPages.Count
Set Visibility = vPages(i).PageSheet.CellsU("UIVisibility")
If Visibility = 1 Then
Visibility.FormulaU = 0
End If
Next
End Sub
Sub HidePages()
Set vPages = ThisDocument.Pages
For i = 1 To vPages.Count
Set Visibility = vPages(i).PageSheet.CellsU("UIVisibility")
If Visibility = 0 Then
Visibility.FormulaU = 1
End If
Next
End Sub
Function Sha256Hash(str)
Dim b() As Byte
b = str
Sha256Hash = BytesToHex(Sha256HashBytes(b))
End Function
Function MD5HashBytes(aBytes)
Set objsha256 = CreateObject("System.Security.Cryptography.MD5CryptoServiceProvider")
s = objsha256.Initialize()
MD5HashBytes = objsha256.ComputeHash_2((aBytes))
End Function
Function Sha256HashBytes(aBytes)
'Set objsha256 = CreateObject("System.Security.Cryptography.MD5CryptoServiceProvider")
Set objsha256 = CreateObject("System.Security.Cryptography.SHA256Managed")
With objsha256
s = .Initialize()
Sha256HashBytes = .ComputeHash_2((aBytes))
End With
End Function
Function StringtoUTFBytes(aString)
Set UTF8 = CreateObject("System.Text.UTF8Encoding")
StringtoUTFBytes = UTF8.GetBytes_4(aString)
End Function
Function BytesToHex(aBytes)
For x = 1 To LenB(aBytes)
hexStr = Hex(AscB(MidB((aBytes), x, 1)))
If Len(hexStr) = 1 Then hexStr = "0" & hexStr
BytesToHex = BytesToHex & hexStr
Next
End Function

Visio 2016 includes Rights Management support. This feature basically allows you to protect the document and specify who can do what with that document.
Maybe that is what you are after?

Related

Access 2010 - VBA - Editing underlying table data using text boxes on a form

I'm using too many boolean indicators and I'm sure its very inefficient/stupid...
Currently in the Access database I have numerous forms which are used to edit underlying records. Text boxes on these forms are not bound to the underlying table. I do not wish to bind the form or any of its controls directly to the underlying tables, if the data is editable by the user (less human error from users). Instead I've a Boolean for every control which contains editable information.
Users enter 'edit mode', change information (Boolean now equals true), click 'save changes', review the changes and accept and then the relevant queries are run to reflect these changes. I like this order of events however, I'm creating increasingly complex forms with 40 or so editable controls and hence 40 Boolean variables.
Anyone think of an nicer alternative? Is there a property of the controls (mainly text boxes) I can use?
CODE:
Private Sub CommentsText_AfterUpdate()
If Nz(Me.CommentsText) = "" Then
CommentsEdit = False
Else
CommentsEdit = True
End If
End Sub
'Within the 'save changes' method
If CommentsEdit Then
CommentsEdit = False
sql = "Update [General-CN] Set [Comments] = '" & Left(Me.CommentsText, 250) & "' Where [ID ( G )] = " & Me.[GeneralPK] & ";"
DoCmd.RunSQL (sql)
End If
normally data validation during data entry is one the things that normally, in my experience, before or later put the developer on his knees.
From your question, I can feel that the core is to preserve database integrity. Unfortunately there is no way to ABSOLUTELY preserve your database. If you give access to it to users you can only use some tips:
1 - If possible use combo-box with defined entries instead of using textboxes in which user is free to digit anything (e.g. think an expert system that collect data about the same problem written in many different ways!!!)
2 - Check data integrity and coherence (e.g. type) before writing it to database
3 - When the data is just a boolean (flag) you can use switches, radio button or checkboxes.
These tips help in developing a user interface more friendly and faster from the point of view of data entry.
After this I can give you another way to validate your data.
If you want to show data to user before saving you can create the mask in which you enter your data with unbounded textboxes.
Then, when he clicks the Save Button, you can show a 2nd form, opened in append mode, in which you show data with textboxes bounded to your db.
If he accepts the data, you can save otherwise you can cancel the data entry preserving your database. I post you here some lines of code with an example taken from an application of mine. It's the part in which I manage contacts
The form allows to input contact data
'------------------------------------------------------
' Temp variables to store entries before saving /cancelling
'------------------------------------------------------
Dim bolValidationErr As Boolean
Dim m_vntLastName As Variant
Dim m_vntFirstName As Variant
Dim m_vntFC As Variant
Dim m_vntVATNum As Variant
Dim m_vntAddress As Variant
Dim m_vntCity As Variant
Dim m_vntZIP As Variant
Dim m_vntCountry As Variant
Dim m_vntPhone As Variant
Dim m_vntFAX As Variant
Dim m_vntEMail As Variant
Dim m_vntNote As Variant
Dim m_vntContactType As Variant
'------------------------------------------------------
' Suppress error "Impossible to save the record...
'------------------------------------------------------
Private Sub Form_Error(DataErr As Integer, Response As Integer)
If DataErr = 2169 Then
Response = True
End If
End Sub
'------------------------------------------------------
' W/o customer last name, cancel saving
'------------------------------------------------------
Private Sub Form_Beforeupdate(Cancel As Integer)
On Error GoTo Err_Form_BeforeUpdate
Dim strType As String
Dim bolNewContact As Boolean
Dim intErrFC As Integer
Dim intErrVATNum As Integer
Dim intErrFullName As Integer
Dim strErrMsg As String
Dim intAnswer As Integer
bolValidationErr = False
'------------------------------------------------------
' If LastName is missing, cancel data saving
' Cancel = True cause the raise of the error
' "You can't save record at this time..."
' SetWarnings doesn't work. It's needed to intercept with Form_Error event
'------------------------------------------------------
If HasNoValue(Me.txtLastName) Then
strErrMsg = "Put here your error msg"
intAnswer = MsgBox(strErrMsg, vbOKOnly + vbExclamation, "Entry Error")
Cancel = True ' Cancel db update
Call BackupCurrentData ' Store data input until now
bolValidationErr = True ' Unvalid data
Exit Sub
End If
Exit_Form_BeforeUpdate:
Exit Sub
Err_Form_BeforeUpdate:
GoTo Exit_Form_BeforeUpdate
End Sub
'------------------------------------------------------
' Store the content of textboxes for restoring them in case
' of cancelling
'------------------------------------------------------
' If the record is new, if the BeforeUpdate event is cancelled,
' NULL values are restored (in fact there were no data!!!)
'------------------------------------------------------
Private Sub BackupCurrentData()
m_vntLastName = Me.txtLastName
m_vntFirstName = Me.txtFirstName
m_vntFC = Me.txtFC
m_vntVATNum = Me.txtVATNum
m_vntAddress = Me.txtAddress
m_vntCity = Me.txtCity
m_vntZIP = Me.txtZIP
m_vntCountry = Me.txtCountry
m_vntPhone = Me.txtTelNum
m_vntFAX = Me.txtFax
m_vntEMail = Me.txtEmail
m_vntNote = Me.txtNotes
m_vntContactType = Me.cmbContactType
End Sub
'------------------------------------------------------
' Restore contents of textboxes before cancelling operation
'------------------------------------------------------
Private Sub RestoreCurrentData()
Me.txtLastName = m_vntLastName
Me.txtFirstName = m_vntFirstName
Me.txtFC = m_vntFC
Me.txtVATNum = m_vntVATNum
Me.txtAddress = m_vntAddress
Me.txtCity = m_vntCity
Me.txtZIP = m_vntZIP
Me.txtCountry = m_vntCountry
Me.txtTelNum = m_vntPhone
Me.txtFax = m_vntFAX
Me.txtEmail = m_vntEMail
Me.txtNotes = m_vntNote
Me.cmbContactType = m_vntContactType
End Sub
I think that this code can be adapted to your needs.
The variable names are enough self-describing
Anyway feel free to contact me if you need further help.
Bye,
Wiz:-)

Using a swear word filter with InStr in Visual Basic 2012

I want to compare the IF argument to a string array. The user will try to put in a teamname into a textbox, if the user uses a swear word anywhere within that textbox, it will display an error message and clear the textbox. If the user has not sworn, it will register the teamname and carry on with the program (As can be seen in the 2nd IF statement). I have tried to get this code to work for a week now and cannot get it to work.
Private Sub SelectionButtonEnter_Click(sender As Object, e As EventArgs) Handles SelectionButtonEnter.Click
Dim HasSworn As Boolean = False
Dim swears() As String = {"Fuck", "fuck", "Shit", "shit", "Shite", "shite", "Dick", "dick", "Pussy", "pussy", "Piss", "piss", "Vagina", "vagina", "Faggot", "faggot"} 'Declare potential swear words the kids can use
For Each swear As String In swears
If InStr(SelectionTextBoxTeamName.Text, swear) > 0 Then
SelectionTextBoxTeamName.Clear() 'Clear the textbox
MessageBox.Show("Remember ... You can be disqualified, raise your hand and Blair will set up the program for you again") 'Let the user know they have entered a swear word and ask them to select another team name
End If
If Not InStr(SelectionTextBoxTeamName.Text, swear) > 0 Then
Timer1.Enabled = True 'Enable timer 1 for the learn box
Timer3ForSelection.Enabled = True 'Enable this timer to show the learn button
TeamName = SelectionTextBoxTeamName.Text() 'Once this button has been pressed, store the content of that textbox in a the TeamName string
SelectionLabelTeamName.Text = "Welcome " & SelectionTextBoxTeamName.Text & " Please click 'Learn' in the box below to begin" 'Display the contents of the string along with other text here
SelectionLabelTeamNameTL.Text() = "Team Name: " & TeamName 'Display the contents of the string along with other text here
SelectionTextBoxTeamName.BackColor = Color.Green 'Have the back color of the box set to green
SelectionTextBoxTeamName.Enabled = False 'Do not allow the user/users enter another team name
End If
Next 'A next must be declared in a for each statement
End Sub
Thanks in advance.
I don't think I'd approach it that way; if the user types f**kyou, your code wouldn't catch it. How about this instead:
In your code:
If ContainsBannedWord(SelectionTextBoxTeamName.Text) Then
Msgbox "Hold out your hand, bad person. SlapSlapSlap"
Else
Msgbox "Good boy!"
End if
Function ContainsBannedWord(sInput As String) As Boolean
Dim aBannedWords(1 To 5) As String
Dim x As Long
' Make all the banned words capitalized
aBannedWords(1) = "BANNED1"
aBannedWords(2) = "BANNED2"
aBannedWords(3) = "BANNED3"
aBannedWords(4) = "BANNED4"
aBannedWords(5) = "BANNED5"
For x = LBound(aBannedWords) To UBound(aBannedWords)
If InStr(UCase(sInput), aBannedWords(x)) > 0 Then
ContainsBannedWord = True
Exit Function
End If
Next
ContainsBannedWord = False
End Function

have record loaded when access gets focus

I have access 2007 as my DB engine for a PLC system. I use RSLinx as my DDE. Access is always loaded, Batch_Setup form as Popup and access minimized.
What I am trying to do is have the form Batch_Setup display the current batch information everytime access is maximized. I do a DDE request to get the current Formula_Number but I can not figure out how to make the form goto the Formula_Number.
Here is the VBA code:
Private Sub Form_Activate()
Dim BATCH_NAME As String, STRX As String, LOOPX As Integer
Dim TEMP_X As Integer
abddeinitiate = DDEInitiate("RSLinx", "GCT")
BATCH_NAME = DDERequest(abddeinitiate, "BATCH_NAME")
STRX = 1
LOOPX = 1
While Not (STRX = "-")
STRX = Mid(BATCH_NAME, LOOPX, 1)
LOOPX = LOOPX + 1
Wend
LOOPX = LOOPX - 2
STRX = Left(BATCH_NAME, LOOPX)
TEMP_X = MsgBox(STRX, vbOKCancel)
With Me.Recordset
.FindFirst "FORMULA_NUMBER = " & CInt(STRX)
End With
End Sub
I have tried Activate, GotFocus, Load, .... but I can not get it to goto the current batch setup. I can Find it thru the Find but I want it to goto it when Access is restored with the Batch_Setup form always loaded as Popup.

Toggle Buttons in Powerpoint

I am trying to insert toggle buttons into several pages on a powerpoint. I've got the buttons to behave the way I want, but now I can't see to do two things:
A. Run the program!!! I've deleted everything and started from scratch, except for my first code (see below) and have nothing else written. What do I need to fix it. When I click on the shape that is connected to YourName() nothing happens.
B. I'd like to set the buttons' values to 0 at the start. Once this runs, do you think my code will do that?
Thanks
Sub YourName()
Dim userName As String
Dim ToggleButton1 As ToggleButton
Dim ToggleButton2 As ToggleButton
Dim ToggleButton3 As ToggleButton
Dim ToggleButton4 As ToggleButton
Dim done As Boolean
done = False
While Not done
userName = InputBox(Prompt:="My name is", Title:="Input Name")
If userName = "" Then
done = False
Else
done = True
End If
Wend
FeedbackAnswered = False
ActivePresentation.Slides(2).ToggleButton("ToggleButton1").Value = 0
ActivePresentation.Slides(2).ToggleButton("ToggleButton2").Value = 0
ActivePresentation.Slides(2).ToggleButton("ToggleButton3").Value = 0
ActivePresentation.Slides(2).ToggleButton("ToggleButton4").Value = 0
ActivePresentation.SlideShowWindow.View.Next
End Sub
Your code won't compile (open the IDE, open the module the code's in, choose Debug | Compile). When you try to run broken code within a slide show (as it seems you're doing) PPT doesn't issue any error messages, it just won't attempt to run the code at all.
This at least compiles; I didn't have time to create a presentation with the correct shapes but hey, had to leave SOME of the fun for you:
Option Explicit
Sub YourName()
Dim userName As String
' Dim these as Object; there's no such thing as ToggleButton
Dim ToggleButton1 As Object
Dim ToggleButton2 As Object
Dim ToggleButton3 As Object
Dim ToggleButton4 As Object
Dim done As Boolean
' You forgot one:
Dim FeedbackAnswered As Boolean
done = False
While Not done
userName = InputBox(Prompt:="My name is", Title:="Input Name")
If userName = "" Then
done = False
' you might want to add an Exit Sub here, otherwise the poor
' user has no way out
Else
done = True
End If
Wend
FeedbackAnswered = False
' Fixed these too:
ActivePresentation.Slides(2).Shapes("ToggleButton1").OLEFormat.Object.Value = 0
ActivePresentation.Slides(2).Shapes("ToggleButton2").OLEFormat.Object.Value = 0
ActivePresentation.Slides(2).Shapes("ToggleButton3").OLEFormat.Object.Value = 0
ActivePresentation.Slides(2).Shapes("ToggleButton4").OLEFormat.Object.Value = 0
ActivePresentation.SlideShowWindow.View.Next
End Sub

Access Sign in Module

I'm trying to create a finance database that requires users to sign in and log out. I have that part working correctly. On the homepage of the database, I'm trying to get their last 25 (or X number) of transactions to display using a query. For some reason, I cannot get the code to pass as it shows a "Data type mismatch." Here is the various code - I'll explain each as I go:
Global Variables (My Global Module)
Option Compare Database
'global variables
Global C As Long
Global C2 As Long
Global HoldString As String
Global Flag As Boolean
Global Reply As String
Global mbReply As VbMsgBoxResult
Global User As String
Global GUser As Long
Global db As Database
The following are the Subs() to Log In (First Sub() is for Exit button, second sub() is for sign in button):
Option Compare Database
Private Sub B_Exit_Click()
mbReply = MsgBox(title:="Exit", _
prompt:="Are you sure you wish to exit the system?", _
Buttons:=vbYesNo)
If mbReply = vbNo Then
Exit Sub
Else
DoCmd.Quit acQuitSaveNone
End If
End Sub
Private Sub B_SignIn_Click()
'variables
Set db = CurrentDb()
Dim Employees As DAO.Recordset
Set Employees = db.OpenRecordset("Employees", dbOpenDynaset)
Dim isEmployeed As Boolean
Dim PassMatch As Boolean
Dim isTerm As Boolean
'check to see if the user is in the system
isEmployeed = False
PassMatch = False
isTerm = False
Do While Not Employees.EOF
If Employees![UserName] = T_Username.Value Then
isEmployeed = True
'make sure the employee is not terminated
If Employees![Terminated] = "Yes" Then
isTerm = True
End If
If isTerm = True Then
MsgBox ("This user has been terminated.")
Exit Sub
End If
'make sure password is correct
If Employees![Password] = T_Password.Value Then
PassMatch = True
End If
If PassMatch = False Then
MsgBox ("Incorrect Password.")
Exit Sub
End If
'mark signed in
Employees.Edit
Employees![SignedIn] = 1
Employees.Update
User = Employees![FirstName] & " " & Employees![LastName]
GUser = Employees![ID] 'Sets GUswer to equal record ID.
End If
Employees.MoveNext
Loop
If isEmployeed = False Then
MsgBox ("This username is not in the system.")
Exit Sub
End If
'close this form and open the main menu
Employees.Close
DoCmd.OpenForm FormName:="HomePage"
DoCmd.Close acForm, Me.Name, acSaveNo
End Sub
The next is my SQL code for the query:
SELECT TOP 25 Spend.ID, Spend.Vendor, Spend.MaterialGroup, Spend.GLCode, Spend.CostCenter, Spend.Department, Spend.InvoiceNumber, Spend.InvoiceDate, Spend.Amount, Spend.Tax, Spend.Total, Spend.DateEntered, Spend.DocNumber, Spend.Description, Spend.[Paid?], Spend.EnteredBy, Spend.EnteredBy
FROM Spend
WHERE (((Spend.[EnteredBy])="GUser"));
Spend.[EnteredBy] has a relationship with the Employees table. So EnteredBy is actually a number field because of this relationship.
If I hardcode the "WHERE" statement to be something like (((Spend.[EnteredBy])=2)); then the query will work fine.
Ultimately, what I want to happen is for the query to show the last 25 data entries that the logged on user completed.
Hope this makes sense. If there are questions, please let me know. I feel like I'm missing something small but I cannot figure it out.
Thanks,
Clark
Your query should read:
SELECT TOP 25 Spend.ID, Spend.Vendor, Spend.MaterialGroup, Spend.GLCode, Spend.CostCenter,
Spend.Department, Spend.InvoiceNumber, Spend.InvoiceDate, Spend.Amount, Spend.Tax, Spend.Total,
Spend.DateEntered, Spend.DocNumber, Spend.Description, Spend.[Paid?], Spend.EnteredBy, Spend.EnteredBy
FROM Spend WHERE (((Spend.[EnteredBy])=" & GUser & "));
Note the Ampersands ( & ) I placed before and after your GUser variable. This tells Access to evalute that expression and return the VALUE of it.
I'd also caution you against use the name "User" as a variable name. It's a Reserved Word in Access:
http://office.microsoft.com/en-us/access-help/access-2007-reserved-words-and-symbols-HA010030643.aspx