I'm trying to figure out how to set up a printer language monitor without using WIN32 API's AddMonitor() (i.e. by editing the Registry or using an INF file), but I keep running into problems, and I'm not seeing any good examples of INF files for this purpose.
For testing purposes, I edited ntprint.inf to point PJL_LANGUAGE_MONITOR to my DLL instead of pjlmon.dll, and changed the appropriate Registry keys to also do the same. Every time I try to reload the print spooler I can see that it seems to successfully load my language monitor, based on debug output, but when I print I keep getting debug messages that say "UpdateNow not set" with a PID of whatever editor I'm using.
My question is, do you think this "UpdateNow not set" message is related to the problem, or is it just some inconsequential symptom?
Employer moved on to another project, moot point now.
Related
I am new to kernel mode windows driver development and having issues getting debug information out of the WFP callout samples. I am looking for either more options or tips of what I am doing wrong with the options I have been trying.
To start with I downloaded the WFP sampler and followed the instructions in it's description. I am using a Windows 8.1 x64 host and a Windows 7 x64 target connected via a simulated serial cable. They are both VirtualBox VMs.
The primary command I am debugging with is
WFPSampler.Exe -s PROXY -l FWPM_LAYER_ALE_BIND_REDIRECT_V4 -aaid "C:\Program Files (x86)\Internet Explorer\iexplore.exe" -pla 10.0.2.15 -v
Where 10.0.2.15 is the IP address of a diffrent network interface than the routing table is endign traffic to. I also used the following inspect command as recommended by the instructions:
WFPSampler.exe -s BASIC_PACKET_EXAMINATION -l FWPM_LAYER_INBOUND_IPPACKET_V4 -v
"netsh wfp show state" shows the callout and filter associated with the expected layer
However I never got any messages from traceview as per the last steps of those instructions. Tracelog had similar lack of output. This was true with or without WPP tracing enabled on the driver project. I also tried higher verbosity, all to no effect.
Additionally the remote debugger in visual studio either stopped at "Driver Post Install Actions (x64) (possible reboot): Pass" or "Waiting to reconnect..." rebooting the target did not cause more output in the Debugger Immediate Window (the Output window never got any output). Rebooting the target VM did not get any unusual prompts (some things I read implied it should). The reconnect checkbox when setting up the debugger sometimes caused it to get past the "Waiting to reconnect..." prompt, other times it was not needed. I set a number of breakpoints that should have been hit including one at the top of every classify function and none were ever hit.
I tried to debug with WinDbg, but well, frankly I can't find the documentation about how to use this tool. I start it on the target machine and chose kernel debug, local. then I get a prompt that tells me the symbol search path is invalid and no clue what I am supposed to set it to. Any documentation on how to use this tool as opposed to just installing it may be helpful if it lets me debug these callout drivers.
Finally of course I tried just debugging it based on symptoms and I find that the examination callout does nothing as far as I can tell, while the proxy callout just eats all traffic from the targeted application, with one caveat. That caveat is that when I target firefox or chrome with the proxy callout and try to launch that app it fails to launch a UI and the partially started process cannot be killed from task manager.
I assumed that behavior may be the result of the sample failing to check FwpsQueryPacketInjectionState but modifying as best I can figure out that should be used does not seem to change the behavior.
So in short I am stuck and need direction please?
I started experimenting with the WFPSampler and also discovered that tracing didn't work. Oddly enough, there was a lot of additional code to make WPP tracing work on multiple OS's, but the sample doesn’t capture any trace events. So I debugged it and found the call to the nt!WmiTraceMessage always passed 2 as the TRACE_HANDLE. This seemed bad. Safe it to say, this wasn't exactly straight forward to unscramble WPP macros and then finally find the origin in the .vcxprog file. The definition of WPP_COMPID_LEVEL_LOGGER(COMPID,LEVEL)=2 is incorrect. While I was there, I also converted the DbgPrintEx Levels to match Tace_Level by adding 2 so Error/Warning match the model.
Complete the following steps for SysLib/WFPSampler and Sys/WFPSamplerCalloutDriver
Open the Project
Right Click on WFPSamplerCalloutDriver
Unload Project
Right Cick on WFPSamplerCalloutDriver
Edit WFPSamplerCalloutDriver.vcxproj
Type: WppPreprpocessorDefinitions
Change this definition in both places in the file:
To:
<WppTraceFunction>DbgPrintEx(COMPID,LEVEL,MSG,...)</WppTraceFunction
<WppPreprocessorDefinitions>WPP_COMPID_LEVEL_LOGGER(COMPID,lvl)=(WPP_CONTROL(0).Logger),;WPP_COMPID_LEVEL_ENABLED(COMPID,lvl)=(WPP_CONTROL(0).Level >= lvl+2)</WppPreprocessorDefinitions>
Save the File
Right Cick on WFPSamplerCalloutDriver
Click Reload Project
Rebuild
I believe if you adopt this model of using DbgPrintEx as your trace function, you can switch to WPP without editing the entire project. However, I still think it's better to just convert in your program.
Cheers,
John
Not exactly an answer to this question, I never got a debugger working, but an explanation of why the wfpsampler sample didn't work for proxying by ALE layers. The end goal of this project.
In the Proxy callout there were these lines (i think before my refactor they were in the PerformProxySocketRedirection method):
if (ipProtocol == IPPROTO_TCP)
pBindRequest1->portReservationToken = (pRedirectData)->pProxyData->tcpPortReservationToken;
else if (ipProtocol == IPPROTO_UDP)
pBindRequest1->portReservationToken = (pRedirectData)->pProxyData->udpPortReservationToken;
udpPortReservationToken or tcpPortReservationToken should have been initialized by a call to CreatePersistentUdpPortReservation or CreatePersistentTcpPortReservation and this is handled in a helper function named HlprWinSockCreatePortReservation, but said helper function is never called, from anywhere in the entire solution. Those fields are never set, anywhere, ever.
Additionaly, that value only needed set if the local port was being changed, but that block of code executed regardless.
remove these lines, and so long as you don't change the local port, the ale redirect sample works as you would expect including changing the outgoing interface if you change the local IP. If you do need to change the local port, you will have to use HlprWinSockCreatePortReservation to initialize the appropriate port reservation token variable in the PROXY_DATA. This must be done in user mode, so you need to do it in the service when setting up the filter.
Disclaimer: I think that is the only important change, but if you are here for a solution to this problem know that while tracking this down without a working debugger i changed a ridiculously large amount of code so there may have been more to it I forgot over the course of the last few weeks. But I did go back and verify that that block was always called and those fields were never set in the original.
I have a VB6 application that I provide support for. This application works on both Windows XP and Windows 7. Some users were migrated from Windows XP to Windows 7 using the User State Migration tool. These users now receive a generic "Application has crashed" Windows error message when they open certain screens (forms) in the application. My assumption is that there is a missing dll/ocx reference, but I'm having trouble tracking it down.
I've tried many/varied troubleshooting techniques:
Full uninstall and reinstall of my application
Manually re-registering all dll's and ocx's that I know are used
Running Process Monitor on a broken computer and a working computer to compare what dll's and ocx's are accessed. The answer might be here but even after filtering out most of the background noise the amount of data is overwhelming. At a minimum I reviewed all of the calls right before it crashes and all of the calls that were not successful. All of the non-successful calls match between working and non-working.
Installed the Windows Debugger Tools and captured a crash dump. Analyzed the crash dump with DebugDiag. DebugDiag says the exception is in msvbvm60.dll. I tried building a PDB file for my exe and loading it in DebugDiag to get more detail about where the exception is occuring but DebugDiag doesn't want to accept the PDB (might be doing something wrong here, but it just seems to ignore it. This same PDB file works fine when I do remote debugging, however.)
I recompiled my VB6 program without any optimizations in PCode. I've read online that sometimes building in PCode, while bad for performance, will tell you the real exception.
Used the above created PDB file to remote debug the VB6 application. The debugger says that the application crashes after the new window has been created, on a line that sets MousePointer = vbHourGlass... To me it seems unlikely that this is the real cause of the error. There are at least 20 other locations in the program where this same line is called and all work fine.
(Forgot about this one)
Used Dependency Walker and profiled the application on both a working and non-working computer. All errors found by dependency walker were the same between the two computers. There were no additional dependencies found on a working computer, and all missing dependencies on the non-working computer were also missing on the working one.
None of these actions changed my error message or showed me what the error is (unless it really is the mouse cursor issue)... There are no entries in the Windows Event Log related to the app crash.
The non-working and working computers all have the same base Windows 7 image, the only difference is whatever is being changed by USMT, which further convinces me that this is some kind of quirky configuration change or a missing dll/ocx or perhaps an unregistered dll/ocx.
Any ideas or thoughts on how I can track down the root cause of the issue would be greatly appreciated.
Update 1 - Response to questions
#MarkHall I have tried running it as admin, though not with UAC off. The application runs fine on a Windows 7 box as a non-admin with full UAC. Windows XP was 32-bit, Windows 7 is 64-bit, but again it works just fine on a like for like box where the user was not migrated from Windows XP.
#Beaner It's possible that it stores settings somewhere that have been corrupted, but the remote debugging leads me to think that it's more likely something else since it seems to die on a step related to the UI, which then makes me think it's probably a missing dll/ocx reference.
#Bob77 The application is installed into Program Files (x86). While many of the libraries do reside in the same folder, they are all registered.
Peter, often I've noticed that the debugger will indicate a line of code that is actually incorrect, depending on WHERE in the actual assembly language the fault occurs. You should look REAL close around your statement that sets the cursor to vbHourGlass. Your exception is PROBABLY happening BEFORE that line of code, but that line is what the debugger thinks is the actual faulted line of code.
Since you said it happens when a window OPENS, I'd look real close at any ocx's you may have referenced on the form, but perhaps NOT actually being used, or called. You might have one there that you don't intend to be there, that could be causing security issues, or something on Win7? Edit the .frm file by hand if you have to, and look at all the GUIDs the form references.
It is possible that one machine is using PER-USER registration, and the other is using PER-SYSTEM registration?? I don't know...
I would take a much closer look at the form that you are trying to open, and be VERY cautious of everything you are doing in the form load events, and so on. This sounds like it could be something as stupid as Windows Aero being enabled on one system, and not another, or some other sort of "Theme" setting that is throwing the VB Form Rendering routine into a hissyfit... Perhaps even something as stupid as a transparent color index in the icon you selected for that from?
If you are still developing this app, (or at least maintaining it), create an entirely NEW form, and re-create all the controls, etc, on the form (resist the temptation to copy/paste them from the old one...), and then see if THAT does the trick. Then, copy all the event code to the new form one event at a time, with at LEAST enough event code to make the form function, even if it's just a "dead form", that loads no data, or whatever the form is supposed to do. Check and debug after each change, and you WILL find it eventually. Of course, make sure you isolate one of the defunct systems to have a platform that you can duplicate the issue on, or then it's just guessing. I find that using something like Acronis w/ Universal Restore is a great option to then take the image file into a good HV, like VirtualBox, and then restore that image as a VM, so you can debug without interfering with your actual users. This sounds like a lot of work, but then again, so is re-writing an application that already exists, right? :)
Failing THAT... /* and */ are your friends!! (Well, we're dealing with VB, so ' would be your best friend! heh... But I'd start commenting out all the code on the form until that sucker opens. Then once it opens, start putting one line back at a time, and re-running it... That's called "VooDoo Debugging", but sometimes, you gotta do what you gotta do...
THANKS A LOT PETER! :) Now you got ME so involved in this, I feel like I'M the one debugging this sucker! Like if it was MY code I was trying to fix! :)
Let me know if any of this helps... I am actually quite interested in what you discover.
I have a completely random error popping up on a particular piece of software out in the field. The application is a game written in VB6 and is running on Windows 7 64-bit. Every once in a while, the app crashes, with a generic "program.exe has stopped responding" message box. This game can run fine for days on end until this message appears, or within a matter of hours. No exception is being thrown.
We run this app in Windows 2000 compatibility mode (this was its original OS), with visual themes disabled, and as an administrator. The app itself is purposely simple in terms of using external components and API calls.
References:
Visual Basic for Applications
Visual Basic runtime objects and procedures
Visual Basic objects and procedures
OLE Automation
Microsoft DAO 3.51 Object Library
Microsoft Data Formatting Object Library
Components:
Microsoft Comm Control 6.0
Microsoft Windows Common Controls 6.0 (SP6)
Resizer XT
As you can see, these are pretty straightforward, Microsoft-standard tools, for the most part. The database components exist to interact with an Access database used for bookkeeping, and the Resizer XT was inserted to move this game more easily from its original 800x600 resolution to 1920x1080.
There is no networking enabled on the kiosks; no network drivers, and hence no connections to remote databases. Everything is encapsulated in a single box.
In the Windows Application event log, when this happens, there is an Event ID 1000 faulting a seemingly random module -- so far, either ntdll.dll or lpk.dll. In terms of API calls, I don't see any from ntdll.dll. We are using kernel32, user32, and winmm, for various file system and sound functions. I can't reproduce as it is completely random, so I don't even know where to start troubleshooting. Any ideas?
EDIT: A little more info. I've tried several different versions of Dependency Walker, at the suggestion of some other developers, and the latest version shows that I am missing IESHIMS.dll and GRPSVC.dll (these two seems to be well-known bugs in Depends.exe), and that I have missing symbols in COMCTRL32.dll and IEFRAME.dll. Any clues there?
The message from the application event log isn't that useful - what you need is a post mortem process dump from your process - so you can see where in your code things started going wrong.
Every time I've seen one of these problems it generally comes down to a bad API parameter rather than something more exotic, this may be caused by bad data coming in, but usually it's a good ol fashioned bug that causes the problem.
As you've probably figured already this isn't going to be easy to debug; ideally you'd have a repeatable failure case to debug, instead of relying on capturing dump files from a remote machine, but until you can make it repeatable remote dumps are the only way forwards.
Dr Watson used to do this, but is no longer shipped, so the alternatives are:
How to use the Userdump.exe tool to create a dump file
Sysinternals ProcDump
Collecting User-Mode dumps
What you need to get is a minidump, these contain the important parts of the process space, excluding standard modules (e.g. Kernel32.dll) - and replacing the dump with a version number.
There are instructions for Automatically Capturing a Dump When a Process Crashes - which uses cdb.exe shipped with the debugging tools, however the crucial item is the registry key \\HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\AeDebug
You can change your code to add better error handling - especially useful if you can narrow down the cause to a few procedures and use the techniques described in Using symbolic debug information to locate a program crash. to directly process the map files.
Once you've got a minidump and the symbol files WinDbg is the tool of choice for digging into these dumps - however it can be a bit of a voyage to discover what the cause is.
The only other thing I'd consider, and this depends on your application structure, is to attempt to capture all input events for replay.
Another option is to find a copy of VMWare 7.1 which has replay debugging and use that as the first step in capturing a reproducible set of steps.
Right click your executable object and let it be WINXP compatible pending
when you discover source of the problem to finally solve it
I'm running a test script from batch file.
Because it is test, the programs are expected to fail once in a while. It is file as long as error code is returned so I can continue and mark specific test as failed.
However there is very annoying behavior of executable files under Microsoft Windows - if something fails it pop-ups window like:
This application has failed to start because foo.dll was not found, Re-installing the application may fix the problem
<OK>
Or even better:
The instruction at "..." referenced to memory at "..." ..
Click on OK to terminate the program
Click on CANCEL to debug the program
The result is known - the script execution blocks till somebody presses "Ok" button. And when we talk about automatic scripts that may run automatically at night in some headless virtual machine, it may be very problematic.
Is there a simple way to prevent such behavior and just make an application to exit with failure code - without changing the code of the program itself?
Is this possible at all?
The answer is following: You need to disable WER.
Simplest description for this I found at http://www.noktec.be/archives/259
Simply (ON XP): Right Click on My Computer > Advanced > Error Reporting > Disable
Voila - programs crash silently!
This does not solves problem when DLL is missing, but this is much rare case and this is good enough for me.
You can suppress AV's and such from showing a dialog box by running your application, or the script (the script engine, like cscript.exe), under a debugger.
Use Gflags.exe, or modify the registry directly, and set Image File Execution Options for the image in question. See this article for details on how to use the appropriate registry keys. You can set it up using a debugger commandline like "C:\Debuggers\ntsd.exe -g -G -c'command'", where you can pass commands to ignore certain types of exceptions in the -c"commmand" argument. This will effectively give you a tool to suppress interactive dialogs as a result of exceptions like AV, and will let the process continue (presumably to immediate end after the exception has occured).
This article explains the commands you can use to control exceptions and events from withing the debugger.
The -g and -G flags make sure that the process won't break into the debugger automatically during process start and end respectively. You'll have to play with the various exception suppression options to make sure that you 'eat' all possible first and second chance exceptiosn that might cause the process to break into the debugger.
Also, if you can tolerate a process being broken into the debugger (as against being stuck showing a dialog box), perhaps that would be a better option overall. You can evaluate each debug break in batch mode at a later time and decide which bugs you care to fix.
It is possible. We used to use IBM's Rational Robot product which could monitor the screen for specific items and, if found, send keystrokes to windows and other sorts of things.
We actually used it for fully automated unit and system testing, much like you're trying to do.
Now I thought that Robot has been through quite a few name changes so it may be hard to find but there it is, right on IBM's web page and with a free downloadable trial for you. It's not cheap, clocking in at a smidgeon under USD5,000 but it was worth it for us.
There's also TestComplete where you could get a licence for just unedr USD1,000 - it touts "Black-box testing - Functional testing of any Windows application" as one of its features and also has a downloadable demo to see if it's suitable before purchase.
However, you may be able to find another product to do the same sort of thing.
I initially thought of Expect but the ActiveState one seems to concentrate on console applications which leads me to believe it may not do graphics well.
The only other option I can suggest is to write your own program in VBScript. I've done this before to automate the starting of many processes (log on to work VPN, start mail, log in and so on) so I could be fully set up with one mouseclick instead of having to start everything manually.
You can use AppActivate to bring a window to the foreground and SendKeys to send arbitrary keypresses to it after that. It's possible you may be able to cobble together something from that if you want a cheaper solution.
The problem:
We use a program written by our biggest customer to receive orders, book tranports and do other order-related stuff. We have no other chance but to use the program and the customer is very unsupportive when it comes to problems with their program. We just have to live with the program.
Now this program is most of the time extremely slow when using it with two or more user so I tried to look behind the curtain and find the source of the problem.
Some points about the program I found out so far:
It's written in VB 6.0
It uses a password-protected Access-DB (Access 2000 MDB) that is located a folder on one user's machine.
That folder is shared over the network and used by all other users.
It uses the msjet40.dll version 4.00.9704 to communicate with access. I guess it's ADO?
I also used Process Monitor to monitor file access and found out why the program is so slow: it is doing thousands of read operations on the mdb-file, even when the program is idle. Over the network this is of course tremendously slow:
Process Monitor Trace http://img217.imageshack.us/img217/1456/screenshothw5.png
The real question:
Is there any way to monitor the queries that are responsible for the read activity? Is there a trace flag I can set? Hooking the JET DLL's? I guess the program is doing some expensive queries that are causing JET to read lots of data in the process.
PS: I already tried to put the mdb on our company's file server with the success that accessing it was even slower than over the local share. I also tried changing the locking mechanisms (opportunistic locking) on the client with no success.
I want to know what's going on and need some hard facts and suggestions for our customer's developer to help him/her make the programm faster.
To get your grubby hands on exactly what Access is doing query-wise behind the scenes there's an undocumented feature called JETSHOWPLAN - when switched on in the registry it creates a showplan.out text file. The details are in
this TechRepublic article alternate, summarized here:
The ShowPlan option was added to Jet 3.0, and produces a text file
that contains the query's plan. (ShowPlan doesn't support subqueries.)
You must enable it by adding a Debug key to the registry like so:
\\HKEY_LOCAL_MACHINE\SOFTWARE\MICROSOFT\JET\4.0\Engines\Debug
Under the new Debug key, add a string data type named JETSHOWPLAN
(you must use all uppercase letters). Then, add the key value ON to
enable the feature. If Access has been running in the background, you
must close it and relaunch it for the function to work.
When ShowPlan is enabled, Jet creates a text file named SHOWPLAN.OUT
(which might end up in your My Documents folder or the current
default folder, depending on the version of Jet you're using) every
time Jet compiles a query. You can then view this text file for clues
to how Jet is running your queries.
We recommend that you disable this feature by changing the key's value
to OFF unless you're specifically using it. Jet appends the plan to
an existing file and eventually, the process actually slows things
down. Turn on the feature only when you need to review a specific
query plan. Open the database, run the query, and then disable the
feature.
For tracking down nightmare problems it's unbeatable - it's the sort of thing you get on your big expensive industrial databases - this feature is cool - it's lovely and fluffy - it's my friend… ;-)
Could you not throw a packet sniffer (like Wireshark) on the network and watch the traffic between one user and the host machine?
If it uses an ODBC connection you can enable logging for that.
Start ODBC Data Source Administrator.
Select the Tracing tab
Select the Start Tracing Now button.
Select Apply or OK.
Run the app for awhile.
Return to ODBC Administrator.
Select the Tracing tab.
Select the Stop Tracing Now button.
The trace can be viewed in the location that you initially specified in the Log file Path box.
First question: Do you have a copy of MS Access 2000 or better?
If so:
When you say the MDB is "password protected", do you mean that when you try to open it using MS Access you get a prompt for a password only, or does it prompt you for a user name and password? (Or give you an error message that says, "You do not have the necessary permissions to use the foo.mdb object."?)
If it's the latter, (user-level security), look for a corresponding .MDW file that goes along with the MDB. If you find it, this is the "workgroup information file" that is used as a "key" for opening the MDB. Try making a desktop shortcut with a target like:
"Path to MSACCESS.EXE" "Path To foo.mdb" /wrkgrp "Path to foo.mdw"
MS Access should then prompt you for your user name and password which is (hopefully) the same as what the VB6 app asks you for. This would at least allow you to open the MDB file and look at the table structure to see if there are any obvious design flaws.
Beyond that, as far as I know, Eduardo is correct that you pretty much need to be able to run a debugger on the developer's source code to find out exactly what the real-time queries are doing...
It is not possible without the help of the developers. Sorry.