the application tries to access the registry key values using advapi.dll regqueryvalueex method which works fine in xp (32-bit) but return 2 on windows 7(64-bit). however regopenkeyex opens the registry keys successfully in both the machines.
tried these below steps already but still couldn't read the registry key values
1. tried running vb 6 ide as admin
2. moved the registry keys to wow64node in regedit
For some reason, you are targeting the advapi.dll library, which was created for 16-bit Windows. I don't know how you are even getting it to work even in Windows XP, since this is a 16-bit only DLL, which will not load into a Win32 process, unless there is some kind of thunking layer.
As for the return value of "2" for RegOpenKeyEx(), the documentation tells you:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms724911%28v=vs.85%29.aspx
Return value
If the function succeeds, the return value is ERROR_SUCCESS.
If the function fails, the return value is a system error code.
If the lpData buffer is too small to receive the data, the function
returns ERROR_MORE_DATA.
If the lpValueName registry value does not exist, the function returns
ERROR_FILE_NOT_FOUND.
Googling "System error code" gives you: http://msdn.microsoft.com/en-gb/library/windows/desktop/ms681382%28v=vs.85%29.aspx
The bit you need is:
ERROR_FILE_NOT_FOUND
2 (0x2)
The system cannot find the file specified.
It is very likely that if you were trying to use advapi.dll in your declare statement you would get this error when trying to run the API call. Basically, check your declare statements.
Of course, if you could supply your code, we would know for sure, rather than trying to do psychic debugging.
Related
I've been playing around with CryptoAPI and everything was fine.
I've imported .PFX to the certificate store, got context, got CSP handle. Every function I've been using I've checked for the mistakes with GetLastError function. But when I'd called CryptGetUserKey with three arguments which are hCryptProv, dwKeySpec and pointer to UserKey, I got an error, but GetLastError call didn't show me anything but a random value like 2148073485 that means nothing I suppose.
How can I find out what is wrong?
OS - Windows 7 32b HP;
Programming language - C++;
IDE - MSVS2013 Ultimate.
GetLastError call didn't show me anything but a random value like 2148073485 that means nothing I suppose.
You fail WINAPI forever. It took me like five seconds to launch Calc.exe and convert it to hex: 8009000D, which looks like a perfectly valid error HRESULT.
Let's take some time to analyze it a bit more:
8 is ERROR.
9 is not 7, meaning it's not a regular Win32 error. A search in Visual C++ headers tells me 9 is FACILITY_SSPI.
If I search 8009000D in Visual C++ headers, I get this line:
#define NTE_NO_KEY _HRESULT_TYPEDEF_(0x8009000DL) There, you have it, it's your error: NTE_NO_KEY.
MSDN is rather unhelpful, but Google shows some other questions about the NTE_NO_KEY error, such as this.
I'm trying to use RegNotifyChangeKeyValue to monitor changes of a 64-bit registry key.
To open this key from a 32-bit application, we must add the access flag KEY_WOW64_64KEY.
Unfortunately I can't seem to be able to monitor changes to this key, only it's 32-bit counterpart.
I'm including a demo project along with the unit I'm using to implement registry monitoring. Download it here: RegMonitor
Steps to reproduce the problem:
Compile the program. Run it as administrator. Click the Start button.
Open regedit and navigate to
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
Add a new value there. RegMonitor will not detect any change.
Navigate to
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Run
Add a new value there. RegMonitor will detect this change.
I've added the KEY_WOW64_64KEY access flag when opening the registry, but it still does not notify of any changes to correct key, only the Wow6432Node redirect.
Any idea if it's possible to use RegNotifyChangeKeyValue to monitor such key?
The following minimal example detects changes in the 64 bit view of the registry, from a 32 bit process. I don't know what's different about your program, but this code proves that a 32 bit program can indeed detect changes in both views.
I know this doesn't solve you problem, but I hope it helps steer you in the right direction.
program RegMonitor;
{$APPTYPE CONSOLE}
uses
SysUtils, Windows;
procedure Main;
const
dwFilter: DWORD =
REG_NOTIFY_CHANGE_NAME or
REG_NOTIFY_CHANGE_ATTRIBUTES or
REG_NOTIFY_CHANGE_LAST_SET or
REG_NOTIFY_CHANGE_SECURITY;
var
Error: Integer;
key: HKEY;
begin
Error := RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
'Software\Microsoft\Windows\CurrentVersion\RunOnce',
0,
KEY_NOTIFY or KEY_WOW64_64KEY,
key
);
if Error<>ERROR_SUCCESS then
RaiseLastOSError(Error);
try
Error := RegNotifyChangeKeyValue(
key,
True,
dwFilter,
0,
False
);
if Error<>ERROR_SUCCESS then
RaiseLastOSError(Error);
Writeln('Change detected');
Readln;
finally
RegCloseKey(key);
end;
end;
begin
Main;
end.
Now, as for your program, it looks like there are lots of problems with it. But the fundamental problem, the one that means you are not notified of changes, is that your event is created incorrectly. You create it like this:
CreateEvent(Nil, True, False, 'RegistryChangeMonitorEvent')
but you need to create it like this
CreateEvent(nil, True, False, nil)
I've not delved into what the requirements are for this event, the documentation does not offer any clues. All I did was look for differences between your code and the code in the MSDN example.
Make that change to the event creation and you have enough to start receiving notifications. However, when I did that change, your program still did not work and failed with an AV. One of your objects was not created. However, I think those are pretty routine bugs that you can sort out for yourself.
I wonder why you are using KEY_ALL_ACCESS. Why don't you use KEY_NOTIFY when you open the key to be passed to RegNotifyChangeKeyValue? And when you try to build a report of what has changed in a key, why don't you use KEY_READ? Since you are not attempting to write ever, KEY_ALL_ACCESS is not appropriate. If you make these changes then you won't need to run as admin.
I'm trying to register a performance counter and part of this process includes adding some textual descriptions to a specific registry key. For English this key is HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\009 which apparently is also known as HKEY_PERFORMANCE_TEXT. There are a pair of values under there (Counter, Help) that have REG_MULTI_SZ data, and I need to modify them to accomplish my goal.
The official way of doing this is by using a tool called lodctr along with a .h and .ini file. There is also a function for doing this programmatically, but my understanding is that it is just a simple wrapper around calling the lodctr program. I found the prospect of maintaining, distributing, and keeping synchronized 3 separate files a bit cumbersome, so I previously wrote code to do this and it worked fine under Windows XP (and possibly Vista, though I don't remember for sure).
Now I'm trying to use the same code on Windows 7 and it doesn't work. The problem is that whenever I try to set the registry values it fails with ERROR_BADKEY; even regedit fails to modify the values, so it's not a problem with my code. I ran Process Monitor against it and noticed that there was no activity at the driver level, so it seems this access must be getting blocked in user-mode code (e.g. advapi32.dll or wherever). I understand why Microsoft would try to prevent people from doing this as it is very easy to screw up, and doing so will screw up the entire performance counter collection on the machine.
I'm going to debug lodctr and see what the magic is purely out of curiosity, but I'm wondering if anybody has run into this before? Are there any alternatives other than the lodctr utility? Perhaps calling the NT registry API directly? I would really prefer to avoid the hassle of the lodctr method if possible.
A minimal example to reproduce the issue:
HKEY hKey = NULL;
LONG nResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib\\009"), 0, KEY_ALL_ACCESS, &hKey);
if(ERROR_SUCCESS == nResult)
{
LPCTSTR lpData = _T("bar");
DWORD cbData = (_tcsclen(lpData) + 1) * sizeof(TCHAR);
nResult = RegSetValueEx(hKey, _T("foo"), 0, REG_SZ, (const BYTE*)lpData, cbData);
// here nResult == ERROR_BADKEY
RegCloseKey(hKey);
hKey = NULL;
}
EDIT 1:
I spent about an hour or so trying to debug the official APIs and couldn't figure it out so I tried some more Google. After a while I came across this KB article which explains the RegSetValueEx behavior. Since it mentioned modifying system files that got me to thinking that perhaps this particular registry data is backed by a mapped file. Then I came across another KB article that mentions Perfc009.dat and Perfh009.dat in the system32 folder. Opened these up in a hex editor and sure enough it is the raw REG_MULTI_SZ data I am trying to modify. Now that I know that maybe I can take another look and figure it out, though I am bored with it for now.
Never mind, I give up. It's easier to just go with the flow. Instead of trying to modify the registry directly, I will create the .h and .ini files programmatically and invoke the relevant functions.
We have an older massive C++ application and we have been converting it to support Unicode as well as 64-bits. The following strange thing has been happening:
Calls to registry functions and windows creation functions, like the following, have been failing:
hWnd = CreateSysWindowExW( ExStyle, ClassNameW.StringW(), Label2.StringW(), Style,
Posn.X(), Posn.Y(),
Size.X(), Size.Y(),
hParentWnd, (HMENU)Id,
AppInstance(), NULL);
ClassNameW and Label2 are instances of our own Text class which essentially uses malloc to allocate the memory used to store the string.
Anyway, when the functions fail, and I call GetLastError it returns the error code for "invalid memory access" (though I can inspect and see the string arguments fine in the debugger). Yet if I change the code as follows then it works perfectly fine:
BSTR Label2S = SysAllocString(Label2.StringW());
BSTR ClassNameWS = SysAllocString(ClassNameW.StringW());
hWnd = CreateSysWindowExW( ExStyle, ClassNameWS, Label2S, Style,
Posn.X(), Posn.Y(),
Size.X(), Size.Y(),
hParentWnd, (HMENU)Id,
AppInstance(), NULL);
SysFreeString(ClassNameWS); ClassNameWS = 0;
SysFreeString(Label2S); Label2S = 0;
So what gives? Why would the original functions work fine with the arguments in local memory, but when used with Unicode, the registry function require SysAllocString, and when used in 64-bit, the Windows creation functions also require SysAllocString'd string arguments? Our Windows procedure functions have all been converted to be Unicode, always, and yes we use SetWindowLogW call the correct default Unicode DefWindowProcW etc. That all seems to work fine and handles and draws Unicode properly etc.
The documentation at http://msdn.microsoft.com/en-us/library/ms632679%28v=vs.85%29.aspx does not say anything about this. While our application is massive we do use debug heaps and tools like Purify to check for and clean up any memory corruption. Also at the time of this failure, there is still only one main system thread. So it is not a thread issue.
So what is going on? I have read that if string arguments are marshalled anywhere or passed across process boundaries, then you have to use SysAllocString/BSTR, yet we call lots of API functions and there is lots of code out there which calls these functions just using plain local strings?
What am I missing? I have tried Googling this, as someone else must have run into this, but with little luck.
Edit 1: Our StringW function does not create any temporary objects which might go out of scope before the actual API call. The function is as follows:
Class Text {
const wchar_t* StringW () const
{
return TextStartW;
}
wchar_t* TextStartW; // pointer to current start of text in DataArea
I have been running our application with the debug heap and memory checking and other diagnostic tools, and found no source of memory corruption, and looking at the assembly, there is no sign of temporary objects or invalid memory access.
BUT I finally figured it out:
We compile our code /Zp1, which means byte aligned memory allocations. SysAllocString (in 64-bits) always return a pointer that is aligned on a 8 byte boundary. Presumably a 32-bit ANSI C++ application goes through an API layer to the underlying Unicode windows DLLs, which would also align the pointer for you.
But if you use Unicode, you do not get that incidental pointer alignment that the conversion mapping layer gives you, and if you use 64-bits, of course the situation will get even worse.
I added a method to our Text class which shifts the string pointer so that it is aligned on an eight byte boundary, and viola, everything runs fine!!!
Of course the Microsoft people say it must be memory corruption and I am jumping the wrong conclusion, but there is evidence it is not the case.
Also, if you use /Zp1 and include windows.h in a 64-bit application, the debugger will tell you sizeof(BITMAP)==28, but calling GetObject on a bitmap will fail and tell you it needs a 32-byte structure. So I suspect that some of Microsoft's API is inherently dependent on aligned pointers, and I also know that some optimized assembly (I have seen some from Fortran compilers) takes advantage of that and crashes badly if you ever give it unaligned pointers.
So the moral of all of this is, dont use "funky" compiler arguments like /Zp1. In our case we have to for historical reasons, but the number of times this has bitten us...
Someone please give me a "this is useful" tick on my answer please?
Using a bit of psychic debugging, I'm going to guess that the strings in your application are pooled in a read-only section.
It's possible that the CreateSysWindowsEx is attempting to write to the memory passed in for the window class or title. That would explain why the calls work when allocated on the heap (SysAllocString) but not when used as constants.
The easiest way to investigate this is to use a low level debugger like windbg - it should break into the debugger at the point where the access violation occurs which should help figure out the problem. Don't use Visual Studio, it has a nasty habit of being helpful and hiding first chance exceptions.
Another thing to try is to enable appverifier on your application - it's possible that it may show something.
Calling a Windows API function does not cross the process boundary, since the various Windows DLLs are loaded into your process.
It sounds like whatever pointer that StringW() is returning isn't valid when Windows is trying to access it. I would look there - is it possible that the pointer returned it out of scope and deleted shortly after it is called?
If you share some more details about your string class, that could help diagnose the problem here.
I'm dealing with a problem in a kernel module that get data from userspace using a /proc entry.
I set open/write/release entries for my own defined /proc entry, and manage well to use it to get data from userspace.
I handle errors in open/write functions well, and they are visible to user as open/fopen or write/fwrite/fprintf errors.
But some of the errors can only be checked at close (because it's the time all the data is available). In these cases I return something different than 0, which I supposed to be in some way the value 'close' or 'fclose' will return to user.
But whatever the value I return my close behave like if all is fine.
To be sure I replaced all the release() code by a simple 'return(-1);' and wrote a program that open/write/close the /proc entry, and prints the close return value (and the errno). It always return '0' whatever the value I give.
Behavior is the same with 'fclose', or by using shell mechanism (echo "..." >/proc/my/entry).
Any clue about this strange behavior that is not the one claimed in many tutorials I found?
BTW I'm using RHEL5 kernel (2.6.18, redhat modified), on a 64bit system.
Thanks.
Regards,
Yannick
The release() isn't allowed to cause the close() to fail.
You could require your userspace programs to call fsync() on the file descriptor before close(), if they want to find out about all possible errors; then implement your final error checking in the fsync() handler.