vinaysamant
asked on
Disabling "Print" menu of any specific application
Hi,
Xperts, please pay your kind attentions to my requirements as follows -
1. I want to disable "Print" related menus in any application currently running like Word, Xcel or Opera or IE... It can be any WINDOWS based app.
2. I dont want support for DOS apps.
3. I should be able to select specific app[from installation list or what ever you suggest] and disable "Print" related functions of that.
4. Other apps should work normally in this case.
5. I should be able to reenable it as and when i want.
6. If you think a app should be kep running in background, then i want it to be running as service & no one should be able to stop or end that app using task manager.
To give details, I m producing a demo of app to a commercial organisation. So if that succeeds & if i get work, I will like to pay a part of what so ever amount I get from that project, where i might have some related queries, to be solved by successful xpert. Looking for real long term relationship. Feel free to contact me on my email also... its vinay@mimansa.net
If you want points, let me know ur requirement, I will purchase it and give u that... I dont want to be stingy if i m getting my purpose sorted out! But as i have only 80 points left i m assigning all that.... Regards
Sincerely.
Vinay Samant.
Xperts, please pay your kind attentions to my requirements as follows -
1. I want to disable "Print" related menus in any application currently running like Word, Xcel or Opera or IE... It can be any WINDOWS based app.
2. I dont want support for DOS apps.
3. I should be able to select specific app[from installation list or what ever you suggest] and disable "Print" related functions of that.
4. Other apps should work normally in this case.
5. I should be able to reenable it as and when i want.
6. If you think a app should be kep running in background, then i want it to be running as service & no one should be able to stop or end that app using task manager.
To give details, I m producing a demo of app to a commercial organisation. So if that succeeds & if i get work, I will like to pay a part of what so ever amount I get from that project, where i might have some related queries, to be solved by successful xpert. Looking for real long term relationship. Feel free to contact me on my email also... its vinay@mimansa.net
If you want points, let me know ur requirement, I will purchase it and give u that... I dont want to be stingy if i m getting my purpose sorted out! But as i have only 80 points left i m assigning all that.... Regards
Sincerely.
Vinay Samant.
Hi
IMHO, there are 2 ways to disable menu item
1. Monitoring windows creation (see my sample at http://www.freevbcode.com/ShowCode.Asp?ID=1308 ) and delete menu (API DeleteMenu) or disable menu (API EnableMenuItem). In this case your app should run at start up and main form should have Cancel = True in Form_Unload event.
2. Under Windows NT you can modify application resource to remove special menu item.
IMHO, there are 2 ways to disable menu item
1. Monitoring windows creation (see my sample at http://www.freevbcode.com/ShowCode.Asp?ID=1308 ) and delete menu (API DeleteMenu) or disable menu (API EnableMenuItem). In this case your app should run at start up and main form should have Cancel = True in Form_Unload event.
2. Under Windows NT you can modify application resource to remove special menu item.
ASKER
Hi Ark,
you have helped me out twice. Please share ur email so that we can keep in touch. If i get this or any similar project, i will certainly like to share rewards with u. Let me try ur solution!
by the way IMHO means what?
Vinay Samant.
you have helped me out twice. Please share ur email so that we can keep in touch. If i get this or any similar project, i will certainly like to share rewards with u. Let me try ur solution!
by the way IMHO means what?
Vinay Samant.
IMHO = In My Humble Opinion (http://info.astrian.net/jargon/terms/i/IMHO.html)
ASKER
lol
ASKER
Ark Ark Ark,
i am trying your app.... but 1 small doubt... very small for you. As you given way to disable any menu item, and no one will be able to click that, but what if some one is using Ctrl+P or any other direct printing hotkey or any other mean! Means, as we can monitor window creation, can we monitor printer job send to printer by any application, and show a popup asking "do you want to block this" & block that popup for ever. Last part i will do but how to monitor job send to printer & kill it? Please guide. I think we can get that project because this was the last question asked!
With best wishes & regards,
Vinay Samant.
i am trying your app.... but 1 small doubt... very small for you. As you given way to disable any menu item, and no one will be able to click that, but what if some one is using Ctrl+P or any other direct printing hotkey or any other mean! Means, as we can monitor window creation, can we monitor printer job send to printer by any application, and show a popup asking "do you want to block this" & block that popup for ever. Last part i will do but how to monitor job send to printer & kill it? Please guide. I think we can get that project because this was the last question asked!
With best wishes & regards,
Vinay Samant.
ASKER
Hi Ark,
I m increasing your points... 2 the max i have! If you want more then let me know. I will purchase them for you!
Vinay Samant.
I m increasing your points... 2 the max i have! If you want more then let me know. I will purchase them for you!
Vinay Samant.
ASKER
Ark,
Why are you not replying? I tried you app and can trace all windows. But when it comes to retriving menus, menus from ms word, excel cant be retrieved. Can u tell me the reason?
Vinay Samant.
Why are you not replying? I tried you app and can trace all windows. But when it comes to retriving menus, menus from ms word, excel cant be retrieved. Can u tell me the reason?
Vinay Samant.
Hello Vinay!
Sorry for silence - I was absent all weekend. Yes, I encountered same problem when trying to make sample with IE, though samples with some other apps works fine. The reason of this prb is following - IE, new Office, 2000/XP explorer and some other applications use new Toolbar instead of menu. I'll try resolve this problem as well as monitoring printing job (BTW, IMHO thisis a good idea).
Here is my attempts:
'================Bas module================
Private Type MenuItem
hMenu As Long
wID As Long
wIDType As Long
End Type
Private Const MF_BYCOMMAND = &H0&
Private Const MF_BYPOSITION = &H400&
Private Const MF_ENABLED = &H0&
Private Const MF_GRAYED = &H1&
Private Const MF_DISABLED = &H2&
Private Declare Function GetMenu Lib "user32" (ByVal hWnd As Long) As Long
Private Declare Function GetMenuString Lib "user32" Alias "GetMenuStringA" (ByVal hMenu As Long, ByVal wIDItem As Long, ByVal lpString As String, ByVal nMaxCount As Long, ByVal wFlag As Long) As Long
Private Declare Function GetSubMenu Lib "user32" (ByVal hMenu As Long, ByVal nPos As Long) As Long
Private Declare Function GetMenuItemID Lib "user32" (ByVal hMenu As Long, ByVal nPos As Long) As Long
Private Declare Function GetMenuItemCount Lib "user32" (ByVal hMenu As Long) As Long
Private Declare Function EnableMenuItem Lib "user32" (ByVal hMenu As Long, ByVal wIDEnableItem As Long, ByVal wEnable As Long) As Long
Private Declare Function GetClassLong Lib "user32" Alias "GetClassLongA" (ByVal hWnd As Long, ByVal nIndex As Long) As Long
Private Declare Function GetModuleFileName Lib "Kernel32" Alias "GetModuleFileNameA" (ByVal hModule As Long, ByVal lpFileName As String, ByVal nSize As Long) As Long
Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hWnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
Private Declare Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hWnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
Private Declare Function EnumWindows& Lib "user32" (ByVal lpEnumFunc As Long, ByVal lParam As Long)
Private Declare Function IsWindowVisible& Lib "user32" (ByVal hWnd As Long)
Private Declare Function GetParent& Lib "user32" (ByVal hWnd As Long)
Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long) As Long
Private Declare Function GetWindowWord Lib "user32" (ByVal hWnd As Long, ByVal nIndex As Long) As Integer
Private Const GCL_HMODULE = (-16)
Private Const GWL_HINSTANCE = (-6)
Public sCaption As String
Public sClassName As String
Public sPrintMenuName As String
Public sAccelerator As String
Public Function TogglePrintMenu(ByVal hWnd As Long, ByVal bEnable As Boolean)
Dim hMenu As Long, wID As Long
Dim mask As Long, key As Long
Dim sAcc
Dim n As Long, i As Long, f As Long
Dim mi As MenuItem
hMenu = GetMenu(hWnd)
mi.hMenu = hMenu
' If hMenu = 0 Then Exit Function
If sPrintMenuName <> "" Then
Call FindMenuIDByName(hMenu, sPrintMenuName, mi)
End If
If mi.wID = 0 And sAccelerator <> "" Then
sAcc = Split(sAccelerator, "+")
n = UBound(sAcc)
For i = 0 To n - 1
Select Case UCase(sAcc(i))
Case "SHIFT": mask = mask + vbShiftMask
Case "ALT": mask = mask + vbAltMask
Case "CTRL": mask = mask + vbCtrlMask
End Select
Next i
key = Asc(sAcc(n))
mi.wID = GetMenuByShortcut(hWnd, mask, key)
mi.wIDType = MF_BYCOMMAND
End If
If mi.wID = 0 Then Exit Function
If bEnable Then f = MF_ENABLED Else f = MF_GRAYED 'Or MF_DISABLED
EnableMenuItem mi.hMenu, mi.wID, f Or mi.wIDType
End Function
Public Function FindMenuIDByName(ByVal hMenu As Long, ByVal sName As String, mi As MenuItem)
Dim num As Long, i As Long
Dim sub_menu As Long, length As Long
Dim mnu_name As String
Dim cmdID As Long
If hMenu = 0 Then Exit Function
sName = Replace(sName, "&", "")
num = GetMenuItemCount(hMenu)
For i = 0 To num - 1
sub_menu = GetSubMenu(hMenu, i)
mnu_name = Space$(256)
length = GetMenuString(hMenu, i, mnu_name, Len(mnu_name), MF_BYPOSITION)
mnu_name = Left$(mnu_name, length)
mnu_name = Replace(mnu_name, "&", "")
If UCase(mnu_name) = UCase(sName) Then
cmdID = GetMenuItemID(hMenu, i)
If cmdID = -1 Then 'Item ID
mi.hMenu = hMenu
mi.wID = i
mi.wIDType = MF_BYPOSITION
Else 'Command ID
mi.wID = cmdID
mi.wIDType = MF_BYCOMMAND
End If
Exit For
End If
FindMenuIDByName sub_menu, sName, mi
Next i
End Function
'Don't work as expected
Public Function GetMenuByShortcut(ByVal hWnd As Long, ByVal mask As ShiftConstants, ByVal key As KeyCodeConstants) As Long
Dim hMod As Long
Dim sName As String
sName = GetModulePathName(hWnd)
Debug.Print sName
End Function
'Don't work as expected
Public Function GetModulePathName(ByVal hWnd As Long) As String
Dim sName As String
Dim ret As Long
Dim hMod As Long
sName = Space(260)
hMod = GetClassLong(hWnd, GCL_HMODULE)
ret = GetModuleFileName(hMod, sName, Len(sName))
If ret > 0 Then GetModulePathName = Left$(sName, ret)
End Function
Public Function GetWndText(ByVal hWnd As Long) As String
Dim k As Long, sName As String
sName = Space$(128)
k = GetWindowText(hWnd, sName, 128)
If k > 0 Then sName = Left$(sName, k) Else sName = "No caption"
GetWndText = sName
End Function
Public Function GetWndClass(ByVal hWnd As Long) As String
Dim k As Long, sName As String
sName = Space$(128)
k = GetClassName(hWnd, sName, 128)
If k > 0 Then sName = Left$(sName, k) Else sName = "No class"
GetWndClass = sName
End Function
Function EnumWinProc(ByVal hWnd As Long, ByVal lParam As Long) As Long
Dim sClass As String, sName As String
Dim bFind As Boolean
If IsWindowVisible(hWnd) And GetParent(hWnd) = 0 Then
If sCaption <> "" Then
sName = GetWndText(hWnd)
If InStr(1, UCase(sName), UCase(sCaption)) Then
bFind = True
End If
End If
If sClassName <> "" Then
sClass = GetWndClass(hWnd)
If UCase(sClass) = UCase(sClassName) Then bFind = True Else bFind = False
End If
If bFind Then
TogglePrintMenu hWnd, CBool(lParam)
End If
End If
EnumWinProc = 1
End Function
Public Sub ToggleExisting(ByVal bEnable As Boolean)
EnumWindows AddressOf EnumWinProc, bEnable
End Sub
'=============Form code===========
Dim WithEvents SH As cShellHook
Dim bEnable As Boolean
Private Sub Command1_Click()
bEnable = Not bEnable
ToggleExisting bEnable
End Sub
Private Sub Form_Load()
' Label1 = "Press button to disable/enable print menus in all IE windows"
' sCaption = "Microsoft Internet Explorer"
sCaption = "Total Commander"
' sClassName = "IEFrame"
' sAccelerator = "Ctrl+P"
sPrintMenuName = "Ïå÷àòü" ' Print Menu Locale caption
Command1.Caption = "Disable menu"
bEnable = True
Set SH = New cShellHook
SH.SetShellHook Me.hWnd, RSH_REGISTER_TASKMAN
End Sub
Private Sub Form_Unload(Cancel As Integer)
ret = MsgBox("Do you realy want close me?", vbExclamation + vbYesNo)
If ret = vbNo Then
Cancel = True
Else
SH.RemoveShellHook
Set SH = Nothing
End If
End Sub
Private Sub SH_WindowCreated(ByVal hWnd As Long)
TogglePrinMenu hwnd, bEnable
End Sub
PS. Don't worry about points, I already have enough :)
Sorry for silence - I was absent all weekend. Yes, I encountered same problem when trying to make sample with IE, though samples with some other apps works fine. The reason of this prb is following - IE, new Office, 2000/XP explorer and some other applications use new Toolbar instead of menu. I'll try resolve this problem as well as monitoring printing job (BTW, IMHO thisis a good idea).
Here is my attempts:
'================Bas module================
Private Type MenuItem
hMenu As Long
wID As Long
wIDType As Long
End Type
Private Const MF_BYCOMMAND = &H0&
Private Const MF_BYPOSITION = &H400&
Private Const MF_ENABLED = &H0&
Private Const MF_GRAYED = &H1&
Private Const MF_DISABLED = &H2&
Private Declare Function GetMenu Lib "user32" (ByVal hWnd As Long) As Long
Private Declare Function GetMenuString Lib "user32" Alias "GetMenuStringA" (ByVal hMenu As Long, ByVal wIDItem As Long, ByVal lpString As String, ByVal nMaxCount As Long, ByVal wFlag As Long) As Long
Private Declare Function GetSubMenu Lib "user32" (ByVal hMenu As Long, ByVal nPos As Long) As Long
Private Declare Function GetMenuItemID Lib "user32" (ByVal hMenu As Long, ByVal nPos As Long) As Long
Private Declare Function GetMenuItemCount Lib "user32" (ByVal hMenu As Long) As Long
Private Declare Function EnableMenuItem Lib "user32" (ByVal hMenu As Long, ByVal wIDEnableItem As Long, ByVal wEnable As Long) As Long
Private Declare Function GetClassLong Lib "user32" Alias "GetClassLongA" (ByVal hWnd As Long, ByVal nIndex As Long) As Long
Private Declare Function GetModuleFileName Lib "Kernel32" Alias "GetModuleFileNameA" (ByVal hModule As Long, ByVal lpFileName As String, ByVal nSize As Long) As Long
Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hWnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
Private Declare Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hWnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
Private Declare Function EnumWindows& Lib "user32" (ByVal lpEnumFunc As Long, ByVal lParam As Long)
Private Declare Function IsWindowVisible& Lib "user32" (ByVal hWnd As Long)
Private Declare Function GetParent& Lib "user32" (ByVal hWnd As Long)
Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long) As Long
Private Declare Function GetWindowWord Lib "user32" (ByVal hWnd As Long, ByVal nIndex As Long) As Integer
Private Const GCL_HMODULE = (-16)
Private Const GWL_HINSTANCE = (-6)
Public sCaption As String
Public sClassName As String
Public sPrintMenuName As String
Public sAccelerator As String
Public Function TogglePrintMenu(ByVal hWnd As Long, ByVal bEnable As Boolean)
Dim hMenu As Long, wID As Long
Dim mask As Long, key As Long
Dim sAcc
Dim n As Long, i As Long, f As Long
Dim mi As MenuItem
hMenu = GetMenu(hWnd)
mi.hMenu = hMenu
' If hMenu = 0 Then Exit Function
If sPrintMenuName <> "" Then
Call FindMenuIDByName(hMenu, sPrintMenuName, mi)
End If
If mi.wID = 0 And sAccelerator <> "" Then
sAcc = Split(sAccelerator, "+")
n = UBound(sAcc)
For i = 0 To n - 1
Select Case UCase(sAcc(i))
Case "SHIFT": mask = mask + vbShiftMask
Case "ALT": mask = mask + vbAltMask
Case "CTRL": mask = mask + vbCtrlMask
End Select
Next i
key = Asc(sAcc(n))
mi.wID = GetMenuByShortcut(hWnd, mask, key)
mi.wIDType = MF_BYCOMMAND
End If
If mi.wID = 0 Then Exit Function
If bEnable Then f = MF_ENABLED Else f = MF_GRAYED 'Or MF_DISABLED
EnableMenuItem mi.hMenu, mi.wID, f Or mi.wIDType
End Function
Public Function FindMenuIDByName(ByVal hMenu As Long, ByVal sName As String, mi As MenuItem)
Dim num As Long, i As Long
Dim sub_menu As Long, length As Long
Dim mnu_name As String
Dim cmdID As Long
If hMenu = 0 Then Exit Function
sName = Replace(sName, "&", "")
num = GetMenuItemCount(hMenu)
For i = 0 To num - 1
sub_menu = GetSubMenu(hMenu, i)
mnu_name = Space$(256)
length = GetMenuString(hMenu, i, mnu_name, Len(mnu_name), MF_BYPOSITION)
mnu_name = Left$(mnu_name, length)
mnu_name = Replace(mnu_name, "&", "")
If UCase(mnu_name) = UCase(sName) Then
cmdID = GetMenuItemID(hMenu, i)
If cmdID = -1 Then 'Item ID
mi.hMenu = hMenu
mi.wID = i
mi.wIDType = MF_BYPOSITION
Else 'Command ID
mi.wID = cmdID
mi.wIDType = MF_BYCOMMAND
End If
Exit For
End If
FindMenuIDByName sub_menu, sName, mi
Next i
End Function
'Don't work as expected
Public Function GetMenuByShortcut(ByVal hWnd As Long, ByVal mask As ShiftConstants, ByVal key As KeyCodeConstants) As Long
Dim hMod As Long
Dim sName As String
sName = GetModulePathName(hWnd)
Debug.Print sName
End Function
'Don't work as expected
Public Function GetModulePathName(ByVal hWnd As Long) As String
Dim sName As String
Dim ret As Long
Dim hMod As Long
sName = Space(260)
hMod = GetClassLong(hWnd, GCL_HMODULE)
ret = GetModuleFileName(hMod, sName, Len(sName))
If ret > 0 Then GetModulePathName = Left$(sName, ret)
End Function
Public Function GetWndText(ByVal hWnd As Long) As String
Dim k As Long, sName As String
sName = Space$(128)
k = GetWindowText(hWnd, sName, 128)
If k > 0 Then sName = Left$(sName, k) Else sName = "No caption"
GetWndText = sName
End Function
Public Function GetWndClass(ByVal hWnd As Long) As String
Dim k As Long, sName As String
sName = Space$(128)
k = GetClassName(hWnd, sName, 128)
If k > 0 Then sName = Left$(sName, k) Else sName = "No class"
GetWndClass = sName
End Function
Function EnumWinProc(ByVal hWnd As Long, ByVal lParam As Long) As Long
Dim sClass As String, sName As String
Dim bFind As Boolean
If IsWindowVisible(hWnd) And GetParent(hWnd) = 0 Then
If sCaption <> "" Then
sName = GetWndText(hWnd)
If InStr(1, UCase(sName), UCase(sCaption)) Then
bFind = True
End If
End If
If sClassName <> "" Then
sClass = GetWndClass(hWnd)
If UCase(sClass) = UCase(sClassName) Then bFind = True Else bFind = False
End If
If bFind Then
TogglePrintMenu hWnd, CBool(lParam)
End If
End If
EnumWinProc = 1
End Function
Public Sub ToggleExisting(ByVal bEnable As Boolean)
EnumWindows AddressOf EnumWinProc, bEnable
End Sub
'=============Form code===========
Dim WithEvents SH As cShellHook
Dim bEnable As Boolean
Private Sub Command1_Click()
bEnable = Not bEnable
ToggleExisting bEnable
End Sub
Private Sub Form_Load()
' Label1 = "Press button to disable/enable print menus in all IE windows"
' sCaption = "Microsoft Internet Explorer"
sCaption = "Total Commander"
' sClassName = "IEFrame"
' sAccelerator = "Ctrl+P"
sPrintMenuName = "Ïå÷àòü" ' Print Menu Locale caption
Command1.Caption = "Disable menu"
bEnable = True
Set SH = New cShellHook
SH.SetShellHook Me.hWnd, RSH_REGISTER_TASKMAN
End Sub
Private Sub Form_Unload(Cancel As Integer)
ret = MsgBox("Do you realy want close me?", vbExclamation + vbYesNo)
If ret = vbNo Then
Cancel = True
Else
SH.RemoveShellHook
Set SH = Nothing
End If
End Sub
Private Sub SH_WindowCreated(ByVal hWnd As Long)
TogglePrinMenu hwnd, bEnable
End Sub
PS. Don't worry about points, I already have enough :)
PS
As for monitoring print queue, take a look here https://www.experts-exchange.com/questions/20875270/Monitor-Printing-Queue.html
As for monitoring print queue, take a look here https://www.experts-exchange.com/questions/20875270/Monitor-Printing-Queue.html
ASKER
Hi,
Ark listen to a very easy concept. Forget disabling menu as we have to keep struggling between many possibilities. aim was <b>Disabling PRINT from any specified application</b> The steps are very simple now. Lets move as follows -
1. Trapping opening of any application. Getting its handle, caption & listing its occurance.<b>Completed</b>
2. Trapping printing jobs. See the code which traps all printing jobs using EnumJobs -
Now here we just want to find out, which job has been posted by which application. Means either handle or caption of posting application! IF we can get this then our job is to just kill this printing job <b>Not Completed</b>
3. One more simple way to achieve all this is trapping mouse clicks. See it is possible to have global mouse hook the way u have global windows hook. If we can get the Text or Caption of the placed where mouse is recently clicked with caption of parent application, and if it matches with our restricted application then just disabling further print activity or removing latest print job! <b>Not completed</b>
If we can achieve any one of 2 or 3 then we are done. I think 2 is easier. I am also trying the same!
Vinay Samant.
Ark listen to a very easy concept. Forget disabling menu as we have to keep struggling between many possibilities. aim was <b>Disabling PRINT from any specified application</b> The steps are very simple now. Lets move as follows -
1. Trapping opening of any application. Getting its handle, caption & listing its occurance.<b>Completed</b>
2. Trapping printing jobs. See the code which traps all printing jobs using EnumJobs -
Now here we just want to find out, which job has been posted by which application. Means either handle or caption of posting application! IF we can get this then our job is to just kill this printing job <b>Not Completed</b>
3. One more simple way to achieve all this is trapping mouse clicks. See it is possible to have global mouse hook the way u have global windows hook. If we can get the Text or Caption of the placed where mouse is recently clicked with caption of parent application, and if it matches with our restricted application then just disabling further print activity or removing latest print job! <b>Not completed</b>
If we can achieve any one of 2 or 3 then we are done. I think 2 is easier. I am also trying the same!
Vinay Samant.
ASKER
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Hi Ark,
I m using the same link and downloaded the code & used it. It monitor the jobs well but is there any way to find out which application has posted this job??? if this can be done then only its of any use. Because every application is giving different styles name to app. So no link between appname & printjobname exist. We need to get the handle of application which posted this job for printing.... Can u please guide me on that?
Vinay Samant.
I m using the same link and downloaded the code & used it. It monitor the jobs well but is there any way to find out which application has posted this job??? if this can be done then only its of any use. Because every application is giving different styles name to app. So no link between appname & printjobname exist. We need to get the handle of application which posted this job for printing.... Can u please guide me on that?
Vinay Samant.
Sorry, it's too late today, continue tomorrow.
Take a look on GetJob API, in particular at JOB_INFO_1.pDocument
Take a look on GetJob API, in particular at JOB_INFO_1.pDocument
ASKER
hi Ark,
I seen that API visiting microsoft site also. It just returns the name of document its printing. In case of IE, it returns the name of URL stupidly & in case of word & xcel it returns the name of document. In case of opera it returns heading of page. So it used many nonstandard practicees to return the document name. Is there any way where we will be able to find the exact caption of the application which send this job for printing?
Or can we do something like this -
1. LEts declare a global mouse hook. It will trap all cliks of mouse.
2. It will trap the caption where ever mouse is clicked. If it is Print then it will stop activity initiated by that click. Or it will kill the latest printjob at that time. IS this possible?
Cant we really think of disable every thing in certain app which has caption like Print.
Or can we disable the way applications print to printer?
Let me know please.
Please find time to finish this. My demo cant be presented without that!
Vinay Samant.
I seen that API visiting microsoft site also. It just returns the name of document its printing. In case of IE, it returns the name of URL stupidly & in case of word & xcel it returns the name of document. In case of opera it returns heading of page. So it used many nonstandard practicees to return the document name. Is there any way where we will be able to find the exact caption of the application which send this job for printing?
Or can we do something like this -
1. LEts declare a global mouse hook. It will trap all cliks of mouse.
2. It will trap the caption where ever mouse is clicked. If it is Print then it will stop activity initiated by that click. Or it will kill the latest printjob at that time. IS this possible?
Cant we really think of disable every thing in certain app which has caption like Print.
Or can we disable the way applications print to printer?
Let me know please.
Please find time to finish this. My demo cant be presented without that!
Vinay Samant.
Unfortunatelly, user can use hot key (like Ctrl+P) for printing without the mouse. IMHO to get 100 proff result we need experiment with document names for particular application (probably compare pDocument with EnumWindows/GetWindowText) .
ASKER
Hi Ark,
I tried using getwindow text & comparing it with printjobs but it seems to be hopeless. See in case of word the job name will be Microsoft Word - Document1.doc. In case of xcel it will be just book1.xls. In case of opera just caption of window. But in case of IE its name of url!!! Now in this fasion if every app will give different name to printjob then how will we find the posting application?
I have 2nd thought - Can we block printer port itself so that every time any application whoever want to print has to send us message insted of sending message to printer Q. Is it possible? In you yesterday's link there is a page which shows how to get notified as soon as printer gets a job[i dint understood hell of that ;)] In that case, as soon as we get notified that some one trying to print, can we use enumwindows to see who is printing? The link si below -
http://www.merrioncomputing.com/Programming/WatchPrinter.htm
Plese help me out my friend. If you know, you are the only one all over web who has atleast this much of knowledge. Otherwise i am not able to find any more resource online for this problem!
Thanks a lot to you!
Vinay SAmant
I tried using getwindow text & comparing it with printjobs but it seems to be hopeless. See in case of word the job name will be Microsoft Word - Document1.doc. In case of xcel it will be just book1.xls. In case of opera just caption of window. But in case of IE its name of url!!! Now in this fasion if every app will give different name to printjob then how will we find the posting application?
I have 2nd thought - Can we block printer port itself so that every time any application whoever want to print has to send us message insted of sending message to printer Q. Is it possible? In you yesterday's link there is a page which shows how to get notified as soon as printer gets a job[i dint understood hell of that ;)] In that case, as soon as we get notified that some one trying to print, can we use enumwindows to see who is printing? The link si below -
http://www.merrioncomputing.com/Programming/WatchPrinter.htm
Plese help me out my friend. If you know, you are the only one all over web who has atleast this much of knowledge. Otherwise i am not able to find any more resource online for this problem!
Thanks a lot to you!
Vinay SAmant
Hi
I'm afraid, if JOB_INFO haven't appropriate field, we can not retrive this information in plain way. As you can see from merrion sample, all thouse function are from winspool.drv. This is how windows printing works: applications send request to spooler to set document into queue -> spooler inform all other applications (with WM_SPOOLERSTATUS or FindFirst/Next...) about spooler satus so applications can respond on these notifications (delay own print job, cancel one/all jobs etc.). But spooler sends only PREDEFINED info and there is no way to force it send more info. I supposed there is some undocumented way (probably with the most powerfull as well as least undocumented NtQueryInformation API), but I'm not sure it's possible from VB since this (and same) functions use pointers heavelly and VB is not propr language to deal with pointers. You can also try WMI:
Private Sub Command1_Click()
On Error Resume Next
strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set colItems = objWMIService.ExecQuery("S elect * from Win32_PrintJob", , 48)
For Each objItem In colItems
Debug.Print "Caption: " & objItem.Caption
Debug.Print "DataType: " & objItem.DataType
Debug.Print "Description: " & objItem.Description
Debug.Print "Document: " & objItem.Document
Debug.Print "DriverName: " & objItem.DriverName
Debug.Print "ElapsedTime: " & objItem.ElapsedTime
Debug.Print "HostPrintQueue: " & objItem.HostPrintQueue
Debug.Print "InstallDate: " & objItem.InstallDate
Debug.Print "JobId: " & objItem.JobId
Debug.Print "JobStatus: " & objItem.JobStatus
Debug.Print "Name: " & objItem.Name
Debug.Print "Notify: " & objItem.Notify
Debug.Print "Owner: " & objItem.Owner
Debug.Print "PagesPrinted: " & objItem.PagesPrinted
Debug.Print "Parameters: " & objItem.Parameters
Debug.Print "PrintProcessor: " & objItem.PrintProcessor
Debug.Print "Priority: " & objItem.Priority
Debug.Print "Size: " & objItem.Size
Debug.Print "StartTime: " & objItem.StartTime
Debug.Print "Status: " & objItem.Status
Debug.Print "StatusMask: " & objItem.StatusMask
Debug.Print "TimeSubmitted: " & objItem.TimeSubmitted
Debug.Print "TotalPages: " & objItem.TotalPages
Debug.Print "UntilTime: " & objItem.UntilTime
Next
End Sub
Regards
Ark
PS. Just got an idea - another approach can be use - we can trap WindowActivated event from my system shell hook, then get this window caption - if caption match restricted list - set some public boolean variable to True and False otherwise. In monitoring function (either with WM_SPOOLERSTATUS or FindFirst/NextPrinterNotif ication) allow or cancel any job according to this flag.
I'm afraid, if JOB_INFO haven't appropriate field, we can not retrive this information in plain way. As you can see from merrion sample, all thouse function are from winspool.drv. This is how windows printing works: applications send request to spooler to set document into queue -> spooler inform all other applications (with WM_SPOOLERSTATUS or FindFirst/Next...) about spooler satus so applications can respond on these notifications (delay own print job, cancel one/all jobs etc.). But spooler sends only PREDEFINED info and there is no way to force it send more info. I supposed there is some undocumented way (probably with the most powerfull as well as least undocumented NtQueryInformation API), but I'm not sure it's possible from VB since this (and same) functions use pointers heavelly and VB is not propr language to deal with pointers. You can also try WMI:
Private Sub Command1_Click()
On Error Resume Next
strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set colItems = objWMIService.ExecQuery("S
For Each objItem In colItems
Debug.Print "Caption: " & objItem.Caption
Debug.Print "DataType: " & objItem.DataType
Debug.Print "Description: " & objItem.Description
Debug.Print "Document: " & objItem.Document
Debug.Print "DriverName: " & objItem.DriverName
Debug.Print "ElapsedTime: " & objItem.ElapsedTime
Debug.Print "HostPrintQueue: " & objItem.HostPrintQueue
Debug.Print "InstallDate: " & objItem.InstallDate
Debug.Print "JobId: " & objItem.JobId
Debug.Print "JobStatus: " & objItem.JobStatus
Debug.Print "Name: " & objItem.Name
Debug.Print "Notify: " & objItem.Notify
Debug.Print "Owner: " & objItem.Owner
Debug.Print "PagesPrinted: " & objItem.PagesPrinted
Debug.Print "Parameters: " & objItem.Parameters
Debug.Print "PrintProcessor: " & objItem.PrintProcessor
Debug.Print "Priority: " & objItem.Priority
Debug.Print "Size: " & objItem.Size
Debug.Print "StartTime: " & objItem.StartTime
Debug.Print "Status: " & objItem.Status
Debug.Print "StatusMask: " & objItem.StatusMask
Debug.Print "TimeSubmitted: " & objItem.TimeSubmitted
Debug.Print "TotalPages: " & objItem.TotalPages
Debug.Print "UntilTime: " & objItem.UntilTime
Next
End Sub
Regards
Ark
PS. Just got an idea - another approach can be use - we can trap WindowActivated event from my system shell hook, then get this window caption - if caption match restricted list - set some public boolean variable to True and False otherwise. In monitoring function (either with WM_SPOOLERSTATUS or FindFirst/NextPrinterNotif
ASKER
yah but how u know which job is submitted by which window? There is no corelation or hardly any standard relation between windows captions & the names of documents submitted by them. For eg. in case of IE, the window caption is title of html page while name of document submitted to print is url in addressbar! In case of word it attached Microsoft Word with every document name! And in this way every document has different formats to submit names of document for printing!
Vinay Samant.
Vinay Samant.
Check oput my las idea:
1. You can start printing from active window only (either from menu or shortcut)!
My ShellHook ( http://www.freevbcode.com/ShowCode.Asp?ID=1308 ) allow trap activation event and return windows handle. Knowing windows handle, you can get any information you want (caption, class name, process/thread id, executable owned this window etc.). Now you can compare currently active window (by caption, class name, executable) with restricted list and set bCancel flag to True, if this window is in restricted list.
2. Now, using http://www.vbcity.com/download/PrintSpool.zip, you get spooler notification: new job appear - and you know - it's from active window, so just use SetJob API with this JobID to cancel printing.
Alternatevely, you can use GetForegroundWindow API at the moment you receive notification to determine which window is active now and send this job.
Here is a code to get executable path from windows handle (note: works on all platforms except of NT4 - NT4 use psapi.dll for this - if you need code for psapi.dll, let me know)
'===========bas module code=============
Public Const TH32CS_SNAPPROCESS As Long = 2&
Public Const MAX_PATH As Long = 260
Public Type PROCESSENTRY32
dwSize As Long
cntUsage As Long
th32ProcessID As Long
th32DefaultHeapID As Long
th32ModuleID As Long
cntThreads As Long
th32ParentProcessID As Long
pcPriClassBase As Long
dwflags As Long
szexeFile As String * MAX_PATH
End Type
Public Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hWnd As Long,
lpdwProcessId As Long) As Long
Public Declare Function CreateToolhelpSnapshot Lib "Kernel32" Alias
"CreateToolhelp32Snapshot" (ByVal lFlgas As Long, ByVal lProcessID As Long) As Long
Public Declare Function ProcessFirst Lib "Kernel32" Alias "Process32First" (ByVal
hSnapshot As Long, uProcess As PROCESSENTRY32) As Long
Public Declare Function ProcessNext Lib "Kernel32" Alias "Process32Next" (ByVal
hSnapshot As Long, uProcess As PROCESSENTRY32) As Long
Public Declare Sub CloseHandle Lib "Kernel32" (ByVal hPass As Long)
Public Function GetExeFromHandle(hWnd As Long) As String
Dim threadID As Long, processID As Long, hSnapshot As Long
Dim uProcess As PROCESSENTRY32, rProcessFound As Long
Dim i As Integer, szExename As String
' Get ID for window thread
threadID = GetWindowThreadProcessId(h Wnd, processID)
' Check if valid
If threadID = 0 Or processID = 0 Then Exit Function
' Create snapshot of current processes
hSnapshot = CreateToolhelpSnapshot(TH3 2CS_SNAPPR OCESS, 0&)
' Check if snapshot is valid
If hSnapshot = -1 Then Exit Function
'Initialize uProcess with correct size
uProcess.dwSize = Len(uProcess)
'Start looping through processes
rProcessFound = ProcessFirst(hSnapshot, uProcess)
Do While rProcessFound
If uProcess.th32ProcessID = processID Then
'Found it, now get name of exefile
i = InStr(1, uProcess.szexeFile, Chr(0))
If i > 0 Then szExename = Left$(uProcess.szexeFile, i - 1)
Exit Do
Else
'Wrong ID, so continue looping
rProcessFound = ProcessNext(hSnapshot, uProcess)
End If
Loop
Call CloseHandle(hSnapshot)
GetExeFromHandle = szExename
End Function
'========Using========
'Just call
Debug.print GetExeFromHandle(Me.hWnd)
1. You can start printing from active window only (either from menu or shortcut)!
My ShellHook ( http://www.freevbcode.com/ShowCode.Asp?ID=1308 ) allow trap activation event and return windows handle. Knowing windows handle, you can get any information you want (caption, class name, process/thread id, executable owned this window etc.). Now you can compare currently active window (by caption, class name, executable) with restricted list and set bCancel flag to True, if this window is in restricted list.
2. Now, using http://www.vbcity.com/download/PrintSpool.zip, you get spooler notification: new job appear - and you know - it's from active window, so just use SetJob API with this JobID to cancel printing.
Alternatevely, you can use GetForegroundWindow API at the moment you receive notification to determine which window is active now and send this job.
Here is a code to get executable path from windows handle (note: works on all platforms except of NT4 - NT4 use psapi.dll for this - if you need code for psapi.dll, let me know)
'===========bas module code=============
Public Const TH32CS_SNAPPROCESS As Long = 2&
Public Const MAX_PATH As Long = 260
Public Type PROCESSENTRY32
dwSize As Long
cntUsage As Long
th32ProcessID As Long
th32DefaultHeapID As Long
th32ModuleID As Long
cntThreads As Long
th32ParentProcessID As Long
pcPriClassBase As Long
dwflags As Long
szexeFile As String * MAX_PATH
End Type
Public Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hWnd As Long,
lpdwProcessId As Long) As Long
Public Declare Function CreateToolhelpSnapshot Lib "Kernel32" Alias
"CreateToolhelp32Snapshot"
Public Declare Function ProcessFirst Lib "Kernel32" Alias "Process32First" (ByVal
hSnapshot As Long, uProcess As PROCESSENTRY32) As Long
Public Declare Function ProcessNext Lib "Kernel32" Alias "Process32Next" (ByVal
hSnapshot As Long, uProcess As PROCESSENTRY32) As Long
Public Declare Sub CloseHandle Lib "Kernel32" (ByVal hPass As Long)
Public Function GetExeFromHandle(hWnd As Long) As String
Dim threadID As Long, processID As Long, hSnapshot As Long
Dim uProcess As PROCESSENTRY32, rProcessFound As Long
Dim i As Integer, szExename As String
' Get ID for window thread
threadID = GetWindowThreadProcessId(h
' Check if valid
If threadID = 0 Or processID = 0 Then Exit Function
' Create snapshot of current processes
hSnapshot = CreateToolhelpSnapshot(TH3
' Check if snapshot is valid
If hSnapshot = -1 Then Exit Function
'Initialize uProcess with correct size
uProcess.dwSize = Len(uProcess)
'Start looping through processes
rProcessFound = ProcessFirst(hSnapshot, uProcess)
Do While rProcessFound
If uProcess.th32ProcessID = processID Then
'Found it, now get name of exefile
i = InStr(1, uProcess.szexeFile, Chr(0))
If i > 0 Then szExename = Left$(uProcess.szexeFile, i - 1)
Exit Do
Else
'Wrong ID, so continue looping
rProcessFound = ProcessNext(hSnapshot, uProcess)
End If
Loop
Call CloseHandle(hSnapshot)
GetExeFromHandle = szExename
End Function
'========Using========
'Just call
Debug.print GetExeFromHandle(Me.hWnd)
ASKER
Hi,
This idea is cool! But what if a print job appears through lan... and at same moment the activ window is restricted one? Our app will kill the network printing job. I think we can check the machine name in this case isnt it?
Can you please do me a favor? I dint understand a single line of the code written for printer notification on
http://www.merrioncomputing.com/Programming/WatchPrinter.htm
Can u please provide me with code which monitors just submitted printing jobs, list them with their properties like document name, machinename & time of submission & kills them if some one press kill button! I t will be great favor of you! I already developed code which allows tracing windows with changing captions & finding out latest active window! That is working totally fine.... I just need above monitoring code.... I like that idea of getting notified whenever printer q activates insted of using timer & enumjobs to get jobs. It will also conserve resources isnt it?
Vinay Samant
This idea is cool! But what if a print job appears through lan... and at same moment the activ window is restricted one? Our app will kill the network printing job. I think we can check the machine name in this case isnt it?
Can you please do me a favor? I dint understand a single line of the code written for printer notification on
http://www.merrioncomputing.com/Programming/WatchPrinter.htm
Can u please provide me with code which monitors just submitted printing jobs, list them with their properties like document name, machinename & time of submission & kills them if some one press kill button! I t will be great favor of you! I already developed code which allows tracing windows with changing captions & finding out latest active window! That is working totally fine.... I just need above monitoring code.... I like that idea of getting notified whenever printer q activates insted of using timer & enumjobs to get jobs. It will also conserve resources isnt it?
Vinay Samant
Hi
I suggest you to use WM_SPOOLERSTATUS message notification instead of FindFirstPrinterChangeNoti fication. If you read article carefully, you noticed that FindFirst wait notification asyncroneously, ie your app freeze until event occure:
'Cut from merrion article:
========================8< ========== ==========
This will wait forever, unless a printer event occurs. Note that because Visual Basic is a single threaded application no user interface updates can take place while the wait is active.
========================8< ========== ==========
Multithreading and/or 2 apps communications are not simple task in VB.
In this case subclassing main window like printspool.zip does is much better. But unfortunatelly, I can not download this file to make sample for you. Can you send this zip file via e-mail (ark@msun.ru).
PS. I have to finish today. Continue tomorrow.
I suggest you to use WM_SPOOLERSTATUS message notification instead of FindFirstPrinterChangeNoti
'Cut from merrion article:
========================8<
This will wait forever, unless a printer event occurs. Note that because Visual Basic is a single threaded application no user interface updates can take place while the wait is active.
========================8<
Multithreading and/or 2 apps communications are not simple task in VB.
In this case subclassing main window like printspool.zip does is much better. But unfortunatelly, I can not download this file to make sample for you. Can you send this zip file via e-mail (ark@msun.ru).
PS. I have to finish today. Continue tomorrow.
FindFirstPrinterChangeNoti fication does not lock the application - it is WaitForSingleObject and then only because no timeout is specified. It is possible to call WaitForSingleOption with a relatively small timeout and thus have the application run even though no printer events occur. Suggest a look at the MSDN information on WaitForSingleObject API call.
ASKER
Hi Merian & Ark,
Most of my objectives are solved. I just need 1 small help. A piece of code [actual code steps] which uses FindFirstPrinterChangeNoti fication & WaitForSingleObject. This code should just say msgbox "Job Submitted" with document name machine name, author name & timestamp of job submission whenever a job gets submitted for printing! thats all i want.... Rest of the things i will take care of.
My application is about to finish & waiting for this piece of code only! I will be greatful to you if you provide me with that. I m really dumb at API calls!
Vinay Samant
Most of my objectives are solved. I just need 1 small help. A piece of code [actual code steps] which uses FindFirstPrinterChangeNoti
My application is about to finish & waiting for this piece of code only! I will be greatful to you if you provide me with that. I m really dumb at API calls!
Vinay Samant
Hi Merrion
If we set timeout other then infinite, we have to make a loop, wich lead to eating of machine resources. IMHO subclassing is better.
PS. The correct approach should be 2 threads, one watching spooler, one for main app, but multithreading in VB ..... (insert your opinion).
If we set timeout other then infinite, we have to make a loop, wich lead to eating of machine resources. IMHO subclassing is better.
PS. The correct approach should be 2 threads, one watching spooler, one for main app, but multithreading in VB ..... (insert your opinion).
ASKER
Hello,
will you people please pay a little attention to me? Actually my entire app is ready which monitors all apps[courtsey of Ark] Then whenever someone restricts some type of app [Say microsoftword where the class is Opus] then it restricts all windows with that class & enters handles of all those windows into registry...... This is working perfectly fine. Y dont you people please help me out in developing a seperate application which will
1. wait for printer event to happen exactly like merian.
2. Verifies that job is from local machine![very imp to avoid LAN printing jobs]
2. then take handle of foreground window [getforegroundwindow] & see if its within restricted windows in registry[I will write this step as i know where i have stored my data & in which way!]
3. If so kills the job!
4. waits for next printer event to happen!
5. Do you se any problem in this functionality
What else you need?
6. I also want to make this application invisible in TASk Manager [not in taskbar]... How to do it? Is there any way to make this invisible from Task Manager?
Please you people find time to give me this code as all my requirements are going to get solved out of this! I \wont need any more help after this & i wont bug you people any more! But please help me out... Afterall demo has to be submitted within time isnt it? Other what's the use? I will loose the project otherwise.
Vinay Samant.
will you people please pay a little attention to me? Actually my entire app is ready which monitors all apps[courtsey of Ark] Then whenever someone restricts some type of app [Say microsoftword where the class is Opus] then it restricts all windows with that class & enters handles of all those windows into registry...... This is working perfectly fine. Y dont you people please help me out in developing a seperate application which will
1. wait for printer event to happen exactly like merian.
2. Verifies that job is from local machine![very imp to avoid LAN printing jobs]
2. then take handle of foreground window [getforegroundwindow] & see if its within restricted windows in registry[I will write this step as i know where i have stored my data & in which way!]
3. If so kills the job!
4. waits for next printer event to happen!
5. Do you se any problem in this functionality
What else you need?
6. I also want to make this application invisible in TASk Manager [not in taskbar]... How to do it? Is there any way to make this invisible from Task Manager?
Please you people find time to give me this code as all my requirements are going to get solved out of this! I \wont need any more help after this & i wont bug you people any more! But please help me out... Afterall demo has to be submitted within time isnt it? Other what's the use? I will loose the project otherwise.
Vinay Samant.
Go to http://groups.yahoo.com/group/MerrionComputing/files/ (you will need to register) and download PrintWatchServer.zip and PrintWatchClient.zip - this shows the FindFirstPrinterChangeNoti fication stuff plus inter process communication. You should be able to do the rest yourself.
Hi Vinay!
One last important question - your app will be placed at computer connected to printer via lpt/usb directly or it can be place at computer connected to printer via LAN? This is important because in second case your app won't receive WM_SPOOLERSTATUS message and FindFirstPrinterChangeNoti fication is the only way.
One last important question - your app will be placed at computer connected to printer via lpt/usb directly or it can be place at computer connected to printer via LAN? This is important because in second case your app won't receive WM_SPOOLERSTATUS message and FindFirstPrinterChangeNoti
ASKER
Hi Ark,
you will like to know that app is working cooly no probs & i managed to use findfirst.... api ofcourse all due to you! Actually i am posting the code below which kills all jobs in default printer q! Dont think much about foreground window as i will manage it. I am already working on that! Just help me out in few thing if you can -
It uses a function
Call WaitForSingleObject(mEvent Handle, INFINITE)
This waits infinite right! There is function which can wait for many objects at the same time using array of hEventHandle i hope. ITs there on the msdn website. Can we use it so that we can monitor all printers in same application?
Another thing is we are using aWord array to retrieve properties of job.[thats what i understood] I can retrieve jobid and kill it. But can you explain me how to retrieve other information of any job using jobid?
And as i am using your shellhook.dll, the example specifies about getting text & classname for any running window. Can we get exename also of running window? This is very very importent.
Also when my program is running, no one should be able to kill that. I used idea of Cancel = 1. But still taskmanager manages to kill that! Help me out here. This is vital part.
The code is -
'------------------------- ---------- ---------- -----
Option Explicit
Public Declare Function OpenPrinter Lib "winspool.drv" Alias "OpenPrinterA" (ByVal pPrinterName As String, phPrinter As Long, pDefault As Any) As Long
Public Declare Function ClosePrinter Lib "winspool.drv" (ByVal hPrinter As Long) As Long
Public Declare Function EnumJobs Lib "winspool.drv" Alias "EnumJobsA" (ByVal hPrinter As Long, ByVal FirstJob As Long, ByVal NoJobs As Long, ByVal Level As Long, pJob As Any, ByVal cdBuf As Long, pcbNeeded As Long, pcReturned As Long) As Long
Public Declare Sub MoveMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Public Declare Function lstrcpy Lib "kernel32" Alias "lstrcpyA" (lpString1 As Any, lpString2 As Any) As Long
Public Declare Function FindFirstPrinterChangeNoti ficationLo ng Lib "winspool.drv" Alias "FindFirstPrinterChangeNot ification" (ByVal hPrinter As Long, ByVal fdwFlags As Long, ByVal fdwOptions As Long, ByVal lpPrinterNotifyOptions As Long) As Long
Public Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long
Public Declare Function FindNextPrinterChangeNotif icationByL ong Lib "winspool.drv" Alias "FindNextPrinterChangeNoti fication" (ByVal hChange As Long, pdwChange As Long, pPrinterOptions As PRINTER_NOTIFY_OPTIONS, ppPrinterNotifyInfo As Long) As Long
Public Declare Function FreePrinterNotifyInfoByLon g Lib "winspool.drv" Alias "FreePrinterNotifyInfo" (ByVal pInfo As Long) As Long
Public Declare Sub CopyMemoryPRINTER_NOTIFY_I NFO Lib "kernel32" Alias "RtlMoveMemory" (Destination As PRINTER_NOTIFY_INFO, ByVal Source As Long, ByVal Length As Long)
Public Declare Sub CopyMemoryPRINTER_NOTIFY_I NFO_DATA Lib "kernel32" Alias "RtlMoveMemory" (Destination As PRINTER_NOTIFY_INFO_DATA, ByVal Source As Long, ByVal Length As Long)
Public Declare Function SetJob Lib "winspool.drv" Alias "SetJobA" (ByVal hPrinter As Long, ByVal JobId As Long, ByVal Level As Long, pJob As Byte, ByVal Command As Long) As Long
Public Declare Function GetJob Lib "winspool.drv" Alias "GetJobA" (ByVal hPrinter As Long, ByVal JobId As Long, ByVal Level As Long, pJob As Byte, ByVal cdBuf As Long, pcbNeeded As Long) As Long
Public Declare Function IsBadStringPtrByLong Lib "kernel32" Alias "IsBadStringPtrA" (ByVal lpsz As Long, ByVal ucchMax As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Public Declare Function GetComputerName Lib "kernel32" Alias "GetComputerNameA" (ByVal lpBuffer As String, nSize As Long) As Long
Public Declare Function GetForegroundWindow Lib "user32" () As Long
Public Enum PrinterChangeNotifications
PRINTER_CHANGE_ADD_PRINTER = &H1
PRINTER_CHANGE_SET_PRINTER = &H2
PRINTER_CHANGE_DELETE_PRIN TER = &H4
PRINTER_CHANGE_FAILED_CONN ECTION_PRI NTER = &H8
PRINTER_CHANGE_PRINTER = &HFF
PRINTER_CHANGE_ADD_JOB = &H100
PRINTER_CHANGE_SET_JOB = &H200
PRINTER_CHANGE_DELETE_JOB = &H400
PRINTER_CHANGE_WRITE_JOB = &H800
PRINTER_CHANGE_JOB = &HFF00
PRINTER_CHANGE_ADD_FORM = &H10000
PRINTER_CHANGE_SET_FORM = &H20000
PRINTER_CHANGE_DELETE_FORM = &H40000
PRINTER_CHANGE_FORM = &H70000
PRINTER_CHANGE_ADD_PORT = &H100000
PRINTER_CHANGE_CONFIGURE_P ORT = &H200000
PRINTER_CHANGE_DELETE_PORT = &H400000
PRINTER_CHANGE_PORT = &H700000
PRINTER_CHANGE_ADD_PRINT_P ROCESSOR = &H1000000
PRINTER_CHANGE_DELETE_PRIN T_PROCESSO R = &H4000000
PRINTER_CHANGE_PRINT_PROCE SSOR = &H7000000
PRINTER_CHANGE_ADD_PRINTER _DRIVER = &H10000000
PRINTER_CHANGE_SET_PRINTER _DRIVER = &H20000000
PRINTER_CHANGE_DELETE_PRIN TER_DRIVER = &H40000000
PRINTER_CHANGE_PRINTER_DRI VER = &H70000000
PRINTER_CHANGE_TIMEOUT = &H80000000
End Enum
Public Enum JobChangeNotificationField s
JOB_NOTIFY_FIELD_PRINTER_N AME = &H0
JOB_NOTIFY_FIELD_MACHINE_N AME = &H1
JOB_NOTIFY_FIELD_PORT_NAME = &H2
JOB_NOTIFY_FIELD_USER_NAME = &H3
JOB_NOTIFY_FIELD_NOTIFY_NA ME = &H4
JOB_NOTIFY_FIELD_DATATYPE = &H5
JOB_NOTIFY_FIELD_PRINT_PRO CESSOR = &H6
JOB_NOTIFY_FIELD_PARAMETER S = &H7
JOB_NOTIFY_FIELD_DRIVER_NA ME = &H8
JOB_NOTIFY_FIELD_DEVMODE = &H9
JOB_NOTIFY_FIELD_STATUS = &HA
JOB_NOTIFY_FIELD_STATUS_ST RING = &HB
JOB_NOTIFY_FIELD_SECURITY_ DESCRIPTOR = &HC
JOB_NOTIFY_FIELD_DOCUMENT = &HD
JOB_NOTIFY_FIELD_PRIORITY = &HE
JOB_NOTIFY_FIELD_POSITION = &HF
JOB_NOTIFY_FIELD_SUBMITTED = &H10
JOB_NOTIFY_FIELD_START_TIM E = &H11
JOB_NOTIFY_FIELD_UNTIL_TIM E = &H12
JOB_NOTIFY_FIELD_TIME = &H13
JOB_NOTIFY_FIELD_TOTAL_PAG ES = &H14
JOB_NOTIFY_FIELD_PAGES_PRI NTED = &H15
JOB_NOTIFY_FIELD_TOTAL_BYT ES = &H16
JOB_NOTIFY_FIELD_BYTES_PRI NTED = &H17
End Enum
Public Type PRINTER_NOTIFY_OPTIONS
Version As Long
Flags As Long
Count As Long
lpPrintNotifyOptions As Long
End Type
Public Type PRINTER_NOTIFY_OPTIONS_TYP E
Type As Integer
Reserved_0 As Integer
Reserved_1 As Long
Reserved_2 As Long
Count As Long
pFields As Long
End Type
Public Type PRINTER_NOTIFY_INFO_DATA
Type As Integer
Field As Integer
Reserved As Long
id As Long
adwData(0 To 1) As Long
End Type
Public Type PRINTER_NOTIFY_INFO
dwVersion As Long
dwFlags As Long
dwCount As Long
End Type
Const INFINITE = &HFFFF ' Infinite timeout
Const JOB_NOTIFY_TYPE = &H1
Const JOB_CONTROL_DELETE = 5
Public Sub Main()
Dim hPrinter As Long, lngResult As Long, ForeHwnd As Long
Dim mEventHandle As Long
Dim PrintOptions As PRINTER_NOTIFY_OPTIONS
Dim PrinterNotifyOptions(0 To 0) As PRINTER_NOTIFY_OPTIONS_TYP E
lngResult = OpenPrinter(Printer.Device Name, hPrinter, ByVal vbNullString)
If lngResult <> 0 Then
With PrintOptions
.Version = 2 '\\ This must be set to 2
.Count = 1 '\\ There is job notification
With PrinterNotifyOptions(0)
.Type = JOB_NOTIFY_TYPE
ReDim pFieldsJob(0 To 22) As Integer
pFieldsJob(0) = JOB_NOTIFY_FIELD_PRINTER_N AME
pFieldsJob(1) = JOB_NOTIFY_FIELD_MACHINE_N AME
pFieldsJob(2) = JOB_NOTIFY_FIELD_PORT_NAME
pFieldsJob(3) = JOB_NOTIFY_FIELD_USER_NAME
pFieldsJob(4) = JOB_NOTIFY_FIELD_NOTIFY_NA ME
pFieldsJob(5) = JOB_NOTIFY_FIELD_DATATYPE
pFieldsJob(6) = JOB_NOTIFY_FIELD_PRINT_PRO CESSOR
pFieldsJob(7) = JOB_NOTIFY_FIELD_PARAMETER S
pFieldsJob(8) = JOB_NOTIFY_FIELD_DRIVER_NA ME
pFieldsJob(9) = JOB_NOTIFY_FIELD_DEVMODE
pFieldsJob(10) = JOB_NOTIFY_FIELD_STATUS
pFieldsJob(11) = JOB_NOTIFY_FIELD_STATUS_ST RING
pFieldsJob(12) = JOB_NOTIFY_FIELD_DOCUMENT
pFieldsJob(13) = JOB_NOTIFY_FIELD_PRIORITY
pFieldsJob(14) = JOB_NOTIFY_FIELD_POSITION
pFieldsJob(15) = JOB_NOTIFY_FIELD_SUBMITTED
pFieldsJob(16) = JOB_NOTIFY_FIELD_START_TIM E
pFieldsJob(17) = JOB_NOTIFY_FIELD_UNTIL_TIM E
pFieldsJob(18) = JOB_NOTIFY_FIELD_TIME
pFieldsJob(19) = JOB_NOTIFY_FIELD_TOTAL_PAG ES
pFieldsJob(20) = JOB_NOTIFY_FIELD_PAGES_PRI NTED
pFieldsJob(21) = JOB_NOTIFY_FIELD_TOTAL_BYT ES
.Count = (UBound(pFieldsJob) - LBound(pFieldsJob)) + 1 '\\ Add one as the array is zero based
.pFields = VarPtr(pFieldsJob(0))
End With
.lpPrintNotifyOptions = VarPtr(PrinterNotifyOption s(0))
End With
mEventHandle = FindFirstPrinterChangeNoti ficationLo ng(hPrinte r, 0, 0, VarPtr(PrintOptions))
watchstart:
Call WaitForSingleObject(mEvent Handle, INFINITE)
Dim lpPrintInfoBuffer As Long
Dim pdwChange As Long
Dim aData() As PRINTER_NOTIFY_INFO_DATA
Dim mData As PRINTER_NOTIFY_INFO
Call FindNextPrinterChangeNotif icationByL ong(mEvent Handle, pdwChange, PrintOptions, lpPrintInfoBuffer)
mData.dwCount = 0
Call CopyMemoryPRINTER_NOTIFY_I NFO(mData, lpPrintInfoBuffer, Len(mData))
If mData.dwCount > 0 Then
ReDim aData(1 To mData.dwCount) As PRINTER_NOTIFY_INFO_DATA
Call CopyMemoryPRINTER_NOTIFY_I NFO_DATA(a Data(1), lpPrintInfoBuffer + Len(mData), Len(aData(1)) * mData.dwCount)
Dim lchange As Long
Dim sValue As String
sValue = String$(1000, 0)
' GetComputerName ByVal sValue, 1000
' If InStr(1, StringFromPointer(aData(1) .adwData(1 ), aData(1).adwData(0)), sValue, vbTextCompare) > 0 Then
' JOB_NOTIFY_FIELD_STATUS
SetJob hPrinter, aData(1).id, 0, 0, JOB_CONTROL_DELETE
' End If
Erase aData
Call FreePrinterNotifyInfoByLon g(lpPrintI nfoBuffer)
ForeHwnd = GetForegroundWindow
End If
GoTo watchstart
End If
End Sub
Public Function StringFromPointer(lpString As Long, lMaxlength As Long) As String
Dim sRet As String
Dim lRet As Long
If lpString = 0 Then
StringFromPointer = ""
Exit Function
End If
If Not IsBadStringPtrByLong(lpStr ing, lMaxlength) And lMaxlength < 2048 Then
sRet = String$(lMaxlength, 0)
CopyMemory ByVal sRet, ByVal lpString, ByVal Len(sRet)
If InStr(sRet, Chr$(0)) > 0 Then
sRet = Left$(sRet, InStr(sRet, Chr$(0)) - 1)
End If
End If
StringFromPointer = sRet
End Function
'------------------------- ---------- ---------- -----
you will like to know that app is working cooly no probs & i managed to use findfirst.... api ofcourse all due to you! Actually i am posting the code below which kills all jobs in default printer q! Dont think much about foreground window as i will manage it. I am already working on that! Just help me out in few thing if you can -
It uses a function
Call WaitForSingleObject(mEvent
This waits infinite right! There is function which can wait for many objects at the same time using array of hEventHandle i hope. ITs there on the msdn website. Can we use it so that we can monitor all printers in same application?
Another thing is we are using aWord array to retrieve properties of job.[thats what i understood] I can retrieve jobid and kill it. But can you explain me how to retrieve other information of any job using jobid?
And as i am using your shellhook.dll, the example specifies about getting text & classname for any running window. Can we get exename also of running window? This is very very importent.
Also when my program is running, no one should be able to kill that. I used idea of Cancel = 1. But still taskmanager manages to kill that! Help me out here. This is vital part.
The code is -
'-------------------------
Option Explicit
Public Declare Function OpenPrinter Lib "winspool.drv" Alias "OpenPrinterA" (ByVal pPrinterName As String, phPrinter As Long, pDefault As Any) As Long
Public Declare Function ClosePrinter Lib "winspool.drv" (ByVal hPrinter As Long) As Long
Public Declare Function EnumJobs Lib "winspool.drv" Alias "EnumJobsA" (ByVal hPrinter As Long, ByVal FirstJob As Long, ByVal NoJobs As Long, ByVal Level As Long, pJob As Any, ByVal cdBuf As Long, pcbNeeded As Long, pcReturned As Long) As Long
Public Declare Sub MoveMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Public Declare Function lstrcpy Lib "kernel32" Alias "lstrcpyA" (lpString1 As Any, lpString2 As Any) As Long
Public Declare Function FindFirstPrinterChangeNoti
Public Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long
Public Declare Function FindNextPrinterChangeNotif
Public Declare Function FreePrinterNotifyInfoByLon
Public Declare Sub CopyMemoryPRINTER_NOTIFY_I
Public Declare Sub CopyMemoryPRINTER_NOTIFY_I
Public Declare Function SetJob Lib "winspool.drv" Alias "SetJobA" (ByVal hPrinter As Long, ByVal JobId As Long, ByVal Level As Long, pJob As Byte, ByVal Command As Long) As Long
Public Declare Function GetJob Lib "winspool.drv" Alias "GetJobA" (ByVal hPrinter As Long, ByVal JobId As Long, ByVal Level As Long, pJob As Byte, ByVal cdBuf As Long, pcbNeeded As Long) As Long
Public Declare Function IsBadStringPtrByLong Lib "kernel32" Alias "IsBadStringPtrA" (ByVal lpsz As Long, ByVal ucchMax As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Public Declare Function GetComputerName Lib "kernel32" Alias "GetComputerNameA" (ByVal lpBuffer As String, nSize As Long) As Long
Public Declare Function GetForegroundWindow Lib "user32" () As Long
Public Enum PrinterChangeNotifications
PRINTER_CHANGE_ADD_PRINTER
PRINTER_CHANGE_SET_PRINTER
PRINTER_CHANGE_DELETE_PRIN
PRINTER_CHANGE_FAILED_CONN
PRINTER_CHANGE_PRINTER = &HFF
PRINTER_CHANGE_ADD_JOB = &H100
PRINTER_CHANGE_SET_JOB = &H200
PRINTER_CHANGE_DELETE_JOB = &H400
PRINTER_CHANGE_WRITE_JOB = &H800
PRINTER_CHANGE_JOB = &HFF00
PRINTER_CHANGE_ADD_FORM = &H10000
PRINTER_CHANGE_SET_FORM = &H20000
PRINTER_CHANGE_DELETE_FORM
PRINTER_CHANGE_FORM = &H70000
PRINTER_CHANGE_ADD_PORT = &H100000
PRINTER_CHANGE_CONFIGURE_P
PRINTER_CHANGE_DELETE_PORT
PRINTER_CHANGE_PORT = &H700000
PRINTER_CHANGE_ADD_PRINT_P
PRINTER_CHANGE_DELETE_PRIN
PRINTER_CHANGE_PRINT_PROCE
PRINTER_CHANGE_ADD_PRINTER
PRINTER_CHANGE_SET_PRINTER
PRINTER_CHANGE_DELETE_PRIN
PRINTER_CHANGE_PRINTER_DRI
PRINTER_CHANGE_TIMEOUT = &H80000000
End Enum
Public Enum JobChangeNotificationField
JOB_NOTIFY_FIELD_PRINTER_N
JOB_NOTIFY_FIELD_MACHINE_N
JOB_NOTIFY_FIELD_PORT_NAME
JOB_NOTIFY_FIELD_USER_NAME
JOB_NOTIFY_FIELD_NOTIFY_NA
JOB_NOTIFY_FIELD_DATATYPE = &H5
JOB_NOTIFY_FIELD_PRINT_PRO
JOB_NOTIFY_FIELD_PARAMETER
JOB_NOTIFY_FIELD_DRIVER_NA
JOB_NOTIFY_FIELD_DEVMODE = &H9
JOB_NOTIFY_FIELD_STATUS = &HA
JOB_NOTIFY_FIELD_STATUS_ST
JOB_NOTIFY_FIELD_SECURITY_
JOB_NOTIFY_FIELD_DOCUMENT = &HD
JOB_NOTIFY_FIELD_PRIORITY = &HE
JOB_NOTIFY_FIELD_POSITION = &HF
JOB_NOTIFY_FIELD_SUBMITTED
JOB_NOTIFY_FIELD_START_TIM
JOB_NOTIFY_FIELD_UNTIL_TIM
JOB_NOTIFY_FIELD_TIME = &H13
JOB_NOTIFY_FIELD_TOTAL_PAG
JOB_NOTIFY_FIELD_PAGES_PRI
JOB_NOTIFY_FIELD_TOTAL_BYT
JOB_NOTIFY_FIELD_BYTES_PRI
End Enum
Public Type PRINTER_NOTIFY_OPTIONS
Version As Long
Flags As Long
Count As Long
lpPrintNotifyOptions As Long
End Type
Public Type PRINTER_NOTIFY_OPTIONS_TYP
Type As Integer
Reserved_0 As Integer
Reserved_1 As Long
Reserved_2 As Long
Count As Long
pFields As Long
End Type
Public Type PRINTER_NOTIFY_INFO_DATA
Type As Integer
Field As Integer
Reserved As Long
id As Long
adwData(0 To 1) As Long
End Type
Public Type PRINTER_NOTIFY_INFO
dwVersion As Long
dwFlags As Long
dwCount As Long
End Type
Const INFINITE = &HFFFF ' Infinite timeout
Const JOB_NOTIFY_TYPE = &H1
Const JOB_CONTROL_DELETE = 5
Public Sub Main()
Dim hPrinter As Long, lngResult As Long, ForeHwnd As Long
Dim mEventHandle As Long
Dim PrintOptions As PRINTER_NOTIFY_OPTIONS
Dim PrinterNotifyOptions(0 To 0) As PRINTER_NOTIFY_OPTIONS_TYP
lngResult = OpenPrinter(Printer.Device
If lngResult <> 0 Then
With PrintOptions
.Version = 2 '\\ This must be set to 2
.Count = 1 '\\ There is job notification
With PrinterNotifyOptions(0)
.Type = JOB_NOTIFY_TYPE
ReDim pFieldsJob(0 To 22) As Integer
pFieldsJob(0) = JOB_NOTIFY_FIELD_PRINTER_N
pFieldsJob(1) = JOB_NOTIFY_FIELD_MACHINE_N
pFieldsJob(2) = JOB_NOTIFY_FIELD_PORT_NAME
pFieldsJob(3) = JOB_NOTIFY_FIELD_USER_NAME
pFieldsJob(4) = JOB_NOTIFY_FIELD_NOTIFY_NA
pFieldsJob(5) = JOB_NOTIFY_FIELD_DATATYPE
pFieldsJob(6) = JOB_NOTIFY_FIELD_PRINT_PRO
pFieldsJob(7) = JOB_NOTIFY_FIELD_PARAMETER
pFieldsJob(8) = JOB_NOTIFY_FIELD_DRIVER_NA
pFieldsJob(9) = JOB_NOTIFY_FIELD_DEVMODE
pFieldsJob(10) = JOB_NOTIFY_FIELD_STATUS
pFieldsJob(11) = JOB_NOTIFY_FIELD_STATUS_ST
pFieldsJob(12) = JOB_NOTIFY_FIELD_DOCUMENT
pFieldsJob(13) = JOB_NOTIFY_FIELD_PRIORITY
pFieldsJob(14) = JOB_NOTIFY_FIELD_POSITION
pFieldsJob(15) = JOB_NOTIFY_FIELD_SUBMITTED
pFieldsJob(16) = JOB_NOTIFY_FIELD_START_TIM
pFieldsJob(17) = JOB_NOTIFY_FIELD_UNTIL_TIM
pFieldsJob(18) = JOB_NOTIFY_FIELD_TIME
pFieldsJob(19) = JOB_NOTIFY_FIELD_TOTAL_PAG
pFieldsJob(20) = JOB_NOTIFY_FIELD_PAGES_PRI
pFieldsJob(21) = JOB_NOTIFY_FIELD_TOTAL_BYT
.Count = (UBound(pFieldsJob) - LBound(pFieldsJob)) + 1 '\\ Add one as the array is zero based
.pFields = VarPtr(pFieldsJob(0))
End With
.lpPrintNotifyOptions = VarPtr(PrinterNotifyOption
End With
mEventHandle = FindFirstPrinterChangeNoti
watchstart:
Call WaitForSingleObject(mEvent
Dim lpPrintInfoBuffer As Long
Dim pdwChange As Long
Dim aData() As PRINTER_NOTIFY_INFO_DATA
Dim mData As PRINTER_NOTIFY_INFO
Call FindNextPrinterChangeNotif
mData.dwCount = 0
Call CopyMemoryPRINTER_NOTIFY_I
If mData.dwCount > 0 Then
ReDim aData(1 To mData.dwCount) As PRINTER_NOTIFY_INFO_DATA
Call CopyMemoryPRINTER_NOTIFY_I
Dim lchange As Long
Dim sValue As String
sValue = String$(1000, 0)
' GetComputerName ByVal sValue, 1000
' If InStr(1, StringFromPointer(aData(1)
' JOB_NOTIFY_FIELD_STATUS
SetJob hPrinter, aData(1).id, 0, 0, JOB_CONTROL_DELETE
' End If
Erase aData
Call FreePrinterNotifyInfoByLon
ForeHwnd = GetForegroundWindow
End If
GoTo watchstart
End If
End Sub
Public Function StringFromPointer(lpString
Dim sRet As String
Dim lRet As Long
If lpString = 0 Then
StringFromPointer = ""
Exit Function
End If
If Not IsBadStringPtrByLong(lpStr
sRet = String$(lMaxlength, 0)
CopyMemory ByVal sRet, ByVal lpString, ByVal Len(sRet)
If InStr(sRet, Chr$(0)) > 0 Then
sRet = Left$(sRet, InStr(sRet, Chr$(0)) - 1)
End If
End If
StringFromPointer = sRet
End Function
'-------------------------
ASKER
Hi Ark,
No answer since long? Whats the problem? Or r u enjoying week end?
Vinay Samant.
No answer since long? Whats the problem? Or r u enjoying week end?
Vinay Samant.
Hello
Sorry for delay - I was out of here for a few days.
1.>> Call WaitForSingleObject(mEvent Handle, INFINITE)
This waits infinite right! There is function which can wait for many objects at the same time using array of hEventHandle i hope. ITs there on the msdn website. Can we use it so that we can monitor all printers in same application? <<
Yes, you can use smth like this:
For i = 1 to nPrinters
lngResult = OpenPrinter(Printer(i).Dev iceName, hPrinter(i), ByVal vbNullString)
With PrintOptions
'Fill UDT. Note - try to eleminate pFieldsJob() fields with fields you exactly need only, for example, remove JOB_NOTIFY_FIELD_PRINTER_N AME etc - this will save you a lot of machine time.
End With
mEventHandle(i) = FindFirstPrinterChangeNoti ficationLo ng(hPrinte r(i), 0, 0, VarPtr(PrintOptions))
Next i
watchstart:
ret = WaitForSingleObject(i, mEventHandle(i), False, INFINITE)
'Debug.Print "Printer " & ret + 1 & " signaled"
'Other staff
2. As for job info:
Private Declare Function GetJob Lib "winspool.drv" Alias "GetJobA" (ByVal hPrinter As Long, ByVal JobId As Long, ByVal Level As Long, pJob As Byte, ByVal cdBuf As Long, pcbNeeded As Long) As Long
Private Type JOB_INFO_1
JobId As Long
pPrinterName As String
pMachineName As String
pUserName As String
pDocument As String
pDatatype As String
pStatus As String
Status As Long
Priority As Long
Position As Long
TotalPages As Long
PagesPrinted As Long
Submitted As SYSTEMTIME
End Type
'Note - you can use JOB_INFO_2 structure which have more info.
'For samples on retrieving job info see http://www.mvps.org/vb/code/PrnInfo.zip
3. For retrieving exe name from handle see my post fro 04/13
4. As for task manager - try to set Cancel = 1 in Form_QueryUnload event
Sorry for delay - I was out of here for a few days.
1.>> Call WaitForSingleObject(mEvent
This waits infinite right! There is function which can wait for many objects at the same time using array of hEventHandle i hope. ITs there on the msdn website. Can we use it so that we can monitor all printers in same application? <<
Yes, you can use smth like this:
For i = 1 to nPrinters
lngResult = OpenPrinter(Printer(i).Dev
With PrintOptions
'Fill UDT. Note - try to eleminate pFieldsJob() fields with fields you exactly need only, for example, remove JOB_NOTIFY_FIELD_PRINTER_N
End With
mEventHandle(i) = FindFirstPrinterChangeNoti
Next i
watchstart:
ret = WaitForSingleObject(i, mEventHandle(i), False, INFINITE)
'Debug.Print "Printer " & ret + 1 & " signaled"
'Other staff
2. As for job info:
Private Declare Function GetJob Lib "winspool.drv" Alias "GetJobA" (ByVal hPrinter As Long, ByVal JobId As Long, ByVal Level As Long, pJob As Byte, ByVal cdBuf As Long, pcbNeeded As Long) As Long
Private Type JOB_INFO_1
JobId As Long
pPrinterName As String
pMachineName As String
pUserName As String
pDocument As String
pDatatype As String
pStatus As String
Status As Long
Priority As Long
Position As Long
TotalPages As Long
PagesPrinted As Long
Submitted As SYSTEMTIME
End Type
'Note - you can use JOB_INFO_2 structure which have more info.
'For samples on retrieving job info see http://www.mvps.org/vb/code/PrnInfo.zip
3. For retrieving exe name from handle see my post fro 04/13
4. As for task manager - try to set Cancel = 1 in Form_QueryUnload event
ASKER
Hi Ark,
thanks for being in touch. See as soon as you use WaitForSingleObject function with INFINITE option, i will halt there it self & wont move in for loop of printers untill it gets notified. The functions to wait for multiple events is specified on - http://msdn.microsoft.com/library/en-us/dllproc/base/waitformultipleobjects.asp have a look and just let me know, if you can help me out there.
As you specified i should elimintae pFindJob() fields, I just want to get notified as soon as job gets submitted or spooled. Then what 2 options should i specify? Can u please post their names? Rest i will handle.
Getting exe handle is GREAT!
Last thing, Cancel = true works only in case of Alt+F4 or X button on top right corner. If you go through task manager, It closes it any how. No use of Cancel = 1. Basically application remains visible in Task Manager. What am I suppose to do if I want the application to be hidden from Task Manager? Like Nortan Antivirus/yahoo messenger/msn are invisible in Applications of Task Maanger but visible in Processes area. That way i want my application to be running as process. Is it possible? What API should I refer for all this?
Are you from russia? I mailed you last time, but u replied through EE. Dont you like to maintain contacts through mails? Can we be friends? If you dont mind ;)
Vinay Samant.
thanks for being in touch. See as soon as you use WaitForSingleObject function with INFINITE option, i will halt there it self & wont move in for loop of printers untill it gets notified. The functions to wait for multiple events is specified on - http://msdn.microsoft.com/library/en-us/dllproc/base/waitformultipleobjects.asp have a look and just let me know, if you can help me out there.
As you specified i should elimintae pFindJob() fields, I just want to get notified as soon as job gets submitted or spooled. Then what 2 options should i specify? Can u please post their names? Rest i will handle.
Getting exe handle is GREAT!
Last thing, Cancel = true works only in case of Alt+F4 or X button on top right corner. If you go through task manager, It closes it any how. No use of Cancel = 1. Basically application remains visible in Task Manager. What am I suppose to do if I want the application to be hidden from Task Manager? Like Nortan Antivirus/yahoo messenger/msn are invisible in Applications of Task Maanger but visible in Processes area. That way i want my application to be running as process. Is it possible? What API should I refer for all this?
Are you from russia? I mailed you last time, but u replied through EE. Dont you like to maintain contacts through mails? Can we be friends? If you dont mind ;)
Vinay Samant.
Hello
Sorry, I wrote incorrect call to function:
ret = WaitForSingleObject(i, mEventHandle(i), False, INFINITE)
should be
ret = WaitForMultipleObject(i, mEventHandle(i), False, INFINITE)
As for infinite loop - there are 2 ways to make your app work normaly, without freezing:
1. Use finite timeout in a loop:
Do
DoEvents
ret = WaitForSingleObject(mEvent Handle, 100) 'Wait 100 ms.
If ret<>WAIT_TIMEOUT Then
'Process result
End if
Loop
2. Use Client/Server relations like Merrion suggested. In this case Server part with Notification code will sleep until notification event occure and client part (your app) will work normally. Then server signaled to client that notify event occured and send info about event - your app here check info and cancel print if nessesary.
Yes, I'm from Russia and I'll be glad to communicate via email. I post code/ideas here because smbd can have same problems as you and can get solution from this thread now and when it'll be PAQed
Regards
Ark
Sorry, I wrote incorrect call to function:
ret = WaitForSingleObject(i, mEventHandle(i), False, INFINITE)
should be
ret = WaitForMultipleObject(i, mEventHandle(i), False, INFINITE)
As for infinite loop - there are 2 ways to make your app work normaly, without freezing:
1. Use finite timeout in a loop:
Do
DoEvents
ret = WaitForSingleObject(mEvent
If ret<>WAIT_TIMEOUT Then
'Process result
End if
Loop
2. Use Client/Server relations like Merrion suggested. In this case Server part with Notification code will sleep until notification event occure and client part (your app) will work normally. Then server signaled to client that notify event occured and send info about event - your app here check info and cancel print if nessesary.
Yes, I'm from Russia and I'll be glad to communicate via email. I post code/ideas here because smbd can have same problems as you and can get solution from this thread now and when it'll be PAQed
Regards
Ark
ASKER
Hi Ark,
Last thing, Cancel = true works only in case of Alt+F4 or X button on top right corner. If you go through task manager, It closes it any how. No use of Cancel = 1. Basically application remains visible in Task Manager. What am I suppose to do if I want the application to be hidden from Task Manager? Like Nortan Antivirus/yahoo messenger/msn are invisible in Applications of Task Maanger but visible in Processes area. That way i want my application to be running as process. Is it possible? What API should I refer for all this?
You have answered in minutes. MKeans u r online at moment. Do you have any yahoo or msn id at which we can chat? my yahoo id is vinusa500, msn id is vinusa500@hotmail.com
Vinay Samant.
Last thing, Cancel = true works only in case of Alt+F4 or X button on top right corner. If you go through task manager, It closes it any how. No use of Cancel = 1. Basically application remains visible in Task Manager. What am I suppose to do if I want the application to be hidden from Task Manager? Like Nortan Antivirus/yahoo messenger/msn are invisible in Applications of Task Maanger but visible in Processes area. That way i want my application to be running as process. Is it possible? What API should I refer for all this?
You have answered in minutes. MKeans u r online at moment. Do you have any yahoo or msn id at which we can chat? my yahoo id is vinusa500, msn id is vinusa500@hotmail.com
Vinay Samant.
Hi
Try App.TaskVisible = False
Yes, I'm online now, but I haven't yahoo/msn/icq ids.
Try App.TaskVisible = False
Yes, I'm online now, but I haven't yahoo/msn/icq ids.
ASKER
ARK YOU R GINI!!!!!!!!!!!!!!!!!!!!!! !!!!!!!
App.TaskVisible worked!
But task manager still able to kill it! Can we avoid that? This is last problem remaining. If not possible then pls let me know. Otherwise i will close the problem. I m satisfied with the answers!
My new question posted at - https://www.experts-exchange.com/questions/20957522/Trapping-Save-Save-As-all-over-windows.html
Have a look at please!
With regards & thanks,
Vinay Samant.
App.TaskVisible worked!
But task manager still able to kill it! Can we avoid that? This is last problem remaining. If not possible then pls let me know. Otherwise i will close the problem. I m satisfied with the answers!
My new question posted at - https://www.experts-exchange.com/questions/20957522/Trapping-Save-Save-As-all-over-windows.html
Have a look at please!
With regards & thanks,
Vinay Samant.
ASKER
ARK YOU R GINI!!!!!!!!!!!!!!!!!!!!!! !!!!!!!
App.TaskVisible worked!
But task manager still able to kill it! Can we avoid that? This is last problem remaining. If not possible then pls let me know. Otherwise i will close the problem. I m satisfied with the answers!
My new question posted at - https://www.experts-exchange.com/questions/20957522/Trapping-Save-Save-As-all-over-windows.html
Have a look at please!
With regards & thanks,
Vinay Samant.
App.TaskVisible worked!
But task manager still able to kill it! Can we avoid that? This is last problem remaining. If not possible then pls let me know. Otherwise i will close the problem. I m satisfied with the answers!
My new question posted at - https://www.experts-exchange.com/questions/20957522/Trapping-Save-Save-As-all-over-windows.html
Have a look at please!
With regards & thanks,
Vinay Samant.
ASKER
This is special comment for moderator...
I think there are no more Experts in experts exchange. You say that, you are the #1 place for experts, then where are they? And in this case why should i think of Premium services?
Vinay Samant.