Error code 87


I've a program that needs to run on both WinXP and Win2k systems. However, it seems not to run on a Win2k system, as it generates a System Error Code 87 (ERROR_INVALID_PARAMETER). As i only have Delphi installed on a WinXP system, i cannot debug the program on the Win2k system.

The program doesn't directly use many lowlevel WinAPI procedures. It uses the RunningProcessesList from JCL and it reads and writes some values from the registry.

I really have no clue why it won't run on Win2k. My experience was that most API calls where supported by both WinXP and Win2k. Do you have some list with API calls that aren't supported by Win2k? Maybe i'll then find the causer of my problems.

Also a list with procedures that might trigger such a very undescriptive error message would be welcome...

Thanks in advance for any help!
Who is Participating?
Wim ten BrinkConnect With a Mentor Self-employed developerCommented:
Okay, a wild guess... Are you using the registry to access some information? Especially writing to a key in the local machine area? Then the problem could be that those users don't have enough access rights. Check if your application runs for administrators but not for regular users... ;-)

Your error message is a bit too generic to solve just like this. You should try to see if you can determine the exact location of where the bug occuts, e.g. by including an unique tag at every place where you show/write a log message.
Wim ten BrinkSelf-employed developerCommented:
It might be easier to just use WMI to get an overview of all running processes. But okay...

For a list of procedures and the platform requirements, visit for the MSDN library. Here's there are complete overviews of the Windows API, the valid parameters and on which platforms it runs. But the MSDN site is huge...

Now, about retrieving a list of all running processes, you could just use WMI. Do do so, you first need to import the C:\WINNT\system32\wbem\wbemdisp.tlb type library which will handle the process retrieval. Basically, all you'd need then is this code:

  WbemScripting_TLB in 'WbemScripting_TLB.pas'; // This one was created by the import.

function ADsEnumerateNext( pEnumVariant: IEnumVARIANT; cElements: ULONG; var pvar: OleVARIANT; var pcElementsFetched: ULONG ): HRESULT; safecall; external 'activeds.dll'; // Delphi doesn't know this function.

procedure DumpProcesses( const List: TStrings ); // Fills list with executable names.
  Enum: IEnumVARIANT;
  varArr: OleVariant;
  lNumElements: ULong;
  Process: SWBemObject;
  Enum := CoSWbemLocator.Create.ConnectServer( '', 'root\cimv2', '', '', '', '', 0, nil ).ExecQuery( 'Select * from Win32_Process', 'WQL', wbemFlagBidirectional, nil )._NewEnum as IEnumVariant;
  while ( Succeeded( ADsEnumerateNext( Enum, 1, varArr, lNumElements ) ) ) and ( lNumElements > 0 ) do begin
    Process := IUnknown( varArr ) as SWBemObject;
    List.Add( VarToStr( Process.Properties_.Item( 'ExecutablePath', 0 ).Get_Value ) );
  Process := nil;
  Enum := nil;

Or do something else with the process information in the Process object above. There's lots of useful information inside it.

About the Windows API, my experience is that you really have to be very careful since even the smallest service pack might disable your nice procedures. Fortunately, those things won't happen very often.
EvarestAuthor Commented:
Dear WorkShop_Alex,

as in the other post about WMI, i'd rather not use it (memoryleaks and slow). My app now does exactly what it should do, and oddly, it seems not to be the RunningProcessesList procedure which is causing all this trouble. My users are telling me that whatever they do, they get this code 87 error...

As i'm not calling WinAPI directly from anywhere in my code except the RunningProcessesList, I cannot say what's the problem.

As you pointed out, MSDN is not exactly the best place to go searching for an answer. And it's quite impossible for me to send my users an app with on every line of code a messagebox so i know where my app finally goes wrong :-)

I thought that maybe an expert had had a similar problem (code 87 but quite difficult to point the source). However, as it seems, it's not going to be the case...

Thanks anyway,
Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

you don't have to show a message box in every spot you want to find out what's going on... what you do is use a .log file instead, the user keeps going and finds the errors, and you send all the information, every exception, every error to the log file, if you're good enough with exceptions and error trapping, your .log file should tell exactly where the problem is
EvarestAuthor Commented:
"if you're good enough with exceptions and error trapping, your .log file should tell exactly where the problem is"

That's true: the only problem is that it only returns the very descriptive error message:

System Error.  Code: 87.Falscher Parameter.

And this is not really something that can help me any further...
EvarestAuthor Commented:
Quite a nice note: this error message occured after a program uptime of 220 milliseconds :-)

It seems that the problem is located somewhere in the beginning of my code. Also, it seems that not all systems running Win2k have these problems...

It's getting worse and worse...

EvarestAuthor Commented:
I've sent a debug version of the program to my users. I hope they will run it and send the debug file to me.

I'm using the registry LOCAL_MACHINE, but i've encapsuled that into a try...except block. That should be OK then...
EvarestAuthor Commented:

i think you struck gold: the problem seems to lay in the access restrictions posed upon limited accounts. Stupid me, but it never crossed my mind that the user with the problems could be working on a company PC, which of course only has limited rights.

I think I've solved most problems with the Registry, but i still have the following problem:

I need to get the complete path of a process by its PID. You can do this by calling


and extracting some info, but this is ONLY possible in administration accounts (thus full rights). PROCESS_QUERY_INFORMATION will give you an error in limited accounts.

Is it possible to get the full path of a process by its PID?

Thanks in advance!
1. Take a look at your Win2K maintenance level.  Some WinXP API calls were retrofitted into Win2K with one of the service packs.

2. Is your program running as a service?

3. Have you done an installation on the Win2K machine or just copied the executable?  There may be some dependent DLLs you are missing.

4. For debugging purposes, you consider Codesite (from Raize Software).
Wim ten BrinkSelf-employed developerCommented:
Evarest, it was a lucky guess but hey, I remembered that I did have similar problems once which were related to the registry being write-protected in some areas.

And yes, limited accounts are as the name implies, limited. To get around such problems you need to create a work-around solution. In one of the projects that I've worked on we solved these issues by creating a system service that would be running under an administrator account, thus having full access. By communicating with this service we could give normal users access to things that normally only administrators could do. Later we changed the model from a service to COM+ applications, that were set to run on a server with administration rights but this was because we changed to a multi-tier solution.

I'm not sure if there's an easy way for a limited user to override the security in some way. It would actually be a breach of security if this was possible because technically this could mean the limited user might also disable or close certain processes. (E.g. the antivirus or firewall software.)

I know you dislike WMI because of the memory leaks but still, it bypasses these security issues if I'm not mistaken. I've chosen for WMI in many situations just because of time limits. If you have a deadline in 5 days, you just can't spend 4 days trying to find some alternative solution, then do the rest in one day... If your project has a time-limit too, considering using WMI for now so your users will have a working version. That should buy you some time to improve things for the next version.
EvarestAuthor Commented:
Dear WorkShop_Alex,

yesterday i managed to create a more stable version of the program by limiting access to the registry and setting the OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, False, PID); between try...excepts.

The OpenProcess will now only give problems in an WinNT4 environment, but that's then a pitty for them... The problem is that there i can only use EnumProcesses to get information about the running processes. With the PIDs I'm able to extract the paths, however, the  PROCESS_QUERY_INFORMATION will fail in a limited account, resulting in no paths for me.

In WinXP, this problem can be prevented by using also the filename (not the entire path), which i get from the ProcessEntry32 of CreateToolhelp32Snapshot. Using this filename, i can scan for files with the same name and returnt their paths.

Actually, there's only a problem with getting PROCESS_QUERY_INFORMATION from files residing in the C:\Windows or C:\Windows\System32 folders... The rest doesn't pose any problems...

Sadly, WMI still isn't an option, as the monitoring program needs to be running indefinately, and i cannot afford any memoryleaks (have had some in the past, and that wasn't the nicest experience to have...)

Wrt Codesite which Aikimark suggested: as i'm only a poor student :-) I can't really afford such a tool...

Wim ten BrinkSelf-employed developerCommented:
It might be a good idea to just write a test application that uses WMI in a tight loop and see how much memory it will waste if you keep it running for a day. If it continuously keeps leaking memory it's not usable. But if it's stops wasting memory after a while, it can be used. Some components are just reserving memory for any further calls, cashing data if need be. WMI is probably doing something similar too.
As an alternative, you might create a small process that just gets the information you wants and writes it in a temporary file. All you have to do then is call the process and read the file afterwards. The lost memory will be reclaimed when this small process ends.

Running indefinitely on Windows systems is a bit rare since there are quite a few parts of Windows that will sooner or later bring down the system. I did write a scheduler application once which was supposed to run indefinitely. This too needed to run indefinitely but it was leaking a bit of memory too. However, the amount of memory loss after a week was still not enough (about 5 MB) to be very troublesome. Thus, as I say, find out how much memory you will be losing and check if this is an acceptable amount.
Or use a little trick and let your application restart itself every N days, thus the process is cleared and with it all lost memory. ;-)

I know, these are just work-arounds. But limited user accounts will never be able to use PID's just because of security reasons. But there's an alternative by creating a system service application. These can be executed by a specific user account, which should be the administrator. All you need then is a way to communicate with the service, telling the service to provide you whatever you need to know. The server will be running under administrator privileges, thus it will be able to read whatever you need to read. And services aren't too hard to code...
EvarestAuthor Commented:
[quote]But there's an alternative by creating a system service application. These can be executed by a specific user account, which should be the administrator. All you need then is a way to communicate with the service, telling the service to provide you whatever you need to know. The server will be running under administrator privileges, thus it will be able to read whatever you need to read. And services aren't too hard to code...[/quote]

For the project i'm working on, this isn't really of use. However it might come in handy lateron, in another project. Thanks for the idea!

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.