|
Looks fine at first glance, except for the final few lines of course; one really should see the byte array as binary data (output best in hex), not as a string which it isn't.
|
|
|
|
|
Yes, I could not recall how to convert the byte array, but I don't think it matters since the data OP is reading is pure binary. I also revisited this and did get it to work with StringBuilder - my bad. Thanks for the hints, I am beginning to understand P/Invoke a bit more.
Unrequited desire is character building. OriginalGriff
I'm sitting here giving you a standing ovation - Len Goodman
|
|
|
|
|
you really should not use (nor suggest the use of) text-related data types or methods for non-textual data. If it isn't text, use the appropriate value types, byte[] being a prime candidate.
Abusing strings may or may not work, and the outcome may well depend on the data itself: text oriented data and code is an open invitation for the system to step in and do all kinds of fancy things with byte sequences that look like a NewLine, a NULL, an accent+letter combination; even ASCII/Unicode conversions and Unicode normalization are possible. None of these can happen when you stay away from textual types for binary data.
string s="";
foreach(byte b in bytes) s+=" "+b.ToString("X2");
Console.WriteLine(s);
|
|
|
|
|
This was my suggestion to OP; did you mean to post this to me?
Unrequited desire is character building. OriginalGriff
I'm sitting here giving you a standing ovation - Len Goodman
|
|
|
|
|
Yes,
You did offer a reply that correctly used byte[] however
Richard MacCutchan wrote: and did get it to work with StringBuilder
from your earlier post made me tell you off StringBuilder.
|
|
|
|
|
Unrequited desire is character building. OriginalGriff
I'm sitting here giving you a standing ovation - Len Goodman
|
|
|
|
|
Hi Richard,
I tried your code but it errors "does not contain a static Main method". I changed it to "private static int ReadRegKey(UIntPtr HKEY_LOCAL_MACHINE, string lpSubKey, string valueName)" which gave me the error "Cannot covert 'string' to 'int' on "return keyValue".
I explicity declared "string keyValue = keyBuffer.ToString();" and got the "Embedded statement cannot be a declaration or labeled statement" so I removed 'string' from "string keyValue = keyBuffer.ToString();", bracketed the snippet & changed "private static int" back to "private static string" and am now back where I started "ReadKey...: not all code paths return a value" Aaargh!!!
On another note, and trying a different approach, I found that 'Default' key Names can be referred to as "" (open quotes,close quotes with no spaces). So using Luc's IntPtr suggestion I am trying
public static readonly UIntPtr HKEY_LOCAL_MACHINE = new UIntPtr(0x80000002u);
public const string lpSubKey = "SECURITY\\Policy\\PolEdtEv";
public const int KEY_READ = 0x20019;
public const uint REG_NONE = 0x00000001;
public const string valueName = "";
[DllImport("advapi32.dll", EntryPoint = "RegOpenKeyEx")]
public static extern int RegOpenKeyEx(UIntPtr hKey, string lpSubKey, int ulOptions, int samDesired, out UIntPtr phkResult);
[DllImport("advapi32.dll", EntryPoint = "RegQueryValueEx")]
public static extern int RegQueryValueEx(UIntPtr hKey, string pSubKey, int reserved, out uint lpType, IntPtr lpData, ref int lpcbData);
private static int ReadRegKey(UIntPtr HKEY_LOCAL_MACHINE, string lpSubKey, string valueName)
{
UIntPtr hKey;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, lpSubKey, 0, KEY_READ, out hKey) == 0)
{
int size = 1024;
uint type = 0;
IntPtr [] keyBuffer = new IntPtr [1024];
if (RegQueryValueEx(hKey, valueName, 0, out type, keyBuffer, ref size) == 0)
{
int keyValue = keyBuffer;
Console.WriteLine(keyBuffer);
return keyValue;
}
}
}
but I am getting "cannot convert from 'System.IntPtr[]' to 'System.IntPtr'" on the line "if (RegQueryValueEx(hKey, valueName, 0, out type, keyBuffer, ref size) == 0)" and "Cannot implicitly convert type 'System.IntPtr[]' to 'int'" on the line "int keyValue = keyBuffer;"
I have tried replacing the 'IntPtrs' with 'ints' and with 'bytes []' but it makes no difference.
|
|
|
|
|
You seem to be getting yourself totally tied in knots by confusing the different types that represent values and objects; I don't understand why you changed my definition of byte[] to IntPtr [] , and then tried to convert the array into a simple int , which is, of course, impossible.
The code I gave you will work with the following slight changes. The ReadRegKey() method should be changed to return a byte array and the keyValue variable should be changed to a byte[] thus:
private static byte[] ReadRegKey(UIntPtr HKEY_LOCAL_MACHINE, string lpSubKey, string valueName)
{
UIntPtr hKey;
byte[] keyValue = null;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, lpSubKey, 0, KEY_READ, out hKey) == 0)
{
Console.WriteLine(valueName);
int size = 1024;
uint type = 0;
byte[] keyBuffer = new byte[1024];
if (RegQueryValueEx(hKey, valueName, 0, out type, keyBuffer, ref size) == 0)
keyValue = keyBuffer;
}
return keyValue;
}
Remember that you may only return the type that you define for your method signature; anything else will be rejected by the compiler. Also, as I stated before, and Luc reminded me, the data you are reading is binsry values, not a string and so cannot be displayed by a simple Console.WriteLine() statement.
Unrequited desire is character building. OriginalGriff
I'm sitting here giving you a standing ovation - Len Goodman
|
|
|
|
|
Firstly, thank you for patience with a newbie who feels very much like a noob at the moment
Secondly, I don't really need to writeline the result, all I need to do is check if the value is not "01 fa 07 00 03 00 00 00 03 00 00 00 03 00 00 00 03 00 00 00 03 00 00 00 03 00 00 00 03 00 00 00 03 00 00 00 03 00 00 00 09 00 00 00" and set it to that if it isn't
Thirdly, and most frustratingly, building the code you kindly offered results in "does not contain a static 'Main' method suitable for an entry point", which is why I started down the path mentioned earlier.
|
|
|
|
|
OK add the following just before the first DllImport statement:
static void Main(string[] args)
{
byte[] regkey = ReadRegKey(HKEY_LOCAL_MACHINE, lpSubKey, "");
}
In order to change the key value(s) you will need to modify the relevant bytes and use a call to RegSetValueEx() [^] to store the updated value, in a similar way to what you have done here.
I am not sure how you came to be working on such a complex application given your level of knowledge, but I would urge you to spend some good study time learning C# and general Windows application programming. A good start for C# and .NET would be .Net Book Zero[^] by Charles Petzold. There are also some good quick tutorials here[^] on MSDN, which is another resource that you should get familiar with.
Unrequited desire is character building. OriginalGriff
I'm sitting here giving you a standing ovation - Len Goodman
|
|
|
|
|
Richard, thank you.
I knew that Main had to go somewhere, I just wasn't sure where.
I know (having spent hours on pinvoke.net) that I need to use RegSetValueEx, but thanks.
I came to this following a desire to have an EventLog monitor which exports Security Events to a SQL db.
The Application & System logs work perfectly but the only reason that the Security log wasn't working was because Local Policies\Audit Policy wasn't configured for Success\Failure audits. Thus I needed a way to programmatically enable auditing. So here I am.
I have a 3-week holiday coming up soon. I'll spend it reading.
The problem I (and a whole bunch of other forum-posters by the looks of things) have is that the tuts are fine for the day-to-day stuff but when you need to go from Beginner to Novice or Novice to Intermediate the only real recourse is experience or the experience of others (read: forums).
There are, for example, dozens of sites with very detailed and informative instructions on using PInvoke for REG_SZ, DWORD & other types. I have yet to see one on getting "Default" i.e. "unknown" types and REG_NONE values (where the example actually works and some attention seeker isn't just posting garbage)
Anyhoo, rant complete, thanks muchly to you and Luc.
|
|
|
|
|
CCodeNewbie wrote: I knew that Main had to go somewhere
Anywhere inside the class is fine.
CCodeNewbie wrote: to go from Beginner to Novice ...
True, it's not easy, and we all had to start somewhere. I just felt that this problem was just a bit too far beyond your skill level, and maybe you should put it aside and focus more on studying the language basics.
CCodeNewbie wrote: I have yet to see one on getting "Default" i.e. "unknown" types and REG_NONE values (where the example actually works and some attention seeker isn't just posting garbage)
Well that's what I have given you, so with a bit more work you could turn it into an article for others to benefit from.
CCodeNewbie wrote: thanks muchly to you and Luc.
Happy to help and hope it moves you on to further successes.
Unrequited desire is character building. OriginalGriff
I'm sitting here giving you a standing ovation - Len Goodman
|
|
|
|
|
I have often used registry, but never with REG_NONE.
The data you have shown isn't text, so strings and StringBuilders are not going to cut it. You seem to need a byte array; create a sufficiently large byte array, then pass that as lpData; use an adapted prototype (get rid of StringBuilder), you can have several prototypes for the one native function, just like managed method overloading.
I tend to always pass arrays by using GCHandle and an IntPtr, see the relevant section in this P/Invoke article[^].
[DllImport("advapi32.dll",EntryPoint = "RegQueryValueEx")]
public static extern int RegQueryValueEx(UIntPtr hKey,stringlpValueName,int lpReserved,out uint lpType, IntPtr lpData,ref int lpcbData);
|
|
|
|
|
Hi there,
Two things:
a) I cannot find the registry value you mentioned in my Win7. Are you sure the value exist somewhere? Is it in Windows server?
b) You are not familiar with how function gets parameter from outside and how to pass parameter back to the outside world.
For the function ReadRegKey that you write, please note it is supposed to return an integer. So make sure you return some integer!
1) Put a return statement outside the if block. That is to return a default value.
2) According to http://msdn.microsoft.com/en-us/library/windows/desktop/ms724897(v=vs.85).aspx[^], I would do the following:
private static int ReadRegKey(UIntPtr HKEY_LOCAL_MACHINE, string lpSubKey, string valueName)
{
LONG regReturnType = RegOpenKeyEx(HKEY_LOCAL_MACHINE, lpSubKey, 0, KEY_READ, out valueName );
if (regReturnType == ERROR_SUCCESS)
{
Console.WriteLine(valueName);
int size = 1024;
uint type;
string keyValue = String.Empty;
StringBuilder keyBuffer = new StringBuilder();
regReturnType = RegQueryValueEx(HKEY_LOCAL_MACHINE, valueName, 0, out type, keyBuffer, ref size)
if (regReturnType == ERROR_SUCCESS)
{
keyValue = keyBuffer.ToString();
Console.WriteLine(keyValue);
}
return regReturnType;
}
return regReturnType;
}
|
|
|
|
|
Quote: a) I cannot find the registry value you mentioned in my Win7. Are you sure the value exist somewhere? Is it in Windows server? - Only exists on W2K, XP, Server2003 (I think), Vista & 7 use a different method
Quote: b) You are not familiar with how function gets parameter from outside and how to pass parameter back to the outside world. - yeah, and then some. Got to start somewhere though. I wasn't really expecting to have to use PInvoke ...
Quote: please note it is supposed to return an integer - that was part of the problem. I have discovered that the actual registry entry is a binary value represented hexadecimally in a REG_NONE (i.e. "unknown") type with a no-name field. Talk about making life difficult!
Thanks for your input but Richard MacCutchan has supplied a very good and working answer, fortunately changing the value is a lot easier. Now if only VC# had a REG_NONE RegistryValueKind....
|
|
|
|
|
hi, Whenever I start a instance of a form with frm.Show() from a backgroundworkder or a thread other than the mainform's thread like the sample below, the new form is unstable. but it's okay with frm.ShowDialog(). I want to use frm.show() because the code don't stop and wait for the user action. Any idea about it?
private void bgworker_DoWork(object sender, DoWorkEventArgs e)
{
NewWindow frm=new NewWindow();
frm.Show();
}
private void bgworker_DoWork(object sender, DoWorkEventArgs e)
{
NewWindow frm=new NewWindow();
frm.ShowDialog();
}
|
|
|
|
|
I think your problem may be because using Form.Show() you have two threads running UI displays, and they are probably interfering with each other. Whereas ShowDialog() stops all activity until the dialog is dismissed by user interaction. You should put all your UI code (showing and manipulating forms) in your main thread and use the background thread(s) to do other work.
Unrequited desire is character building. OriginalGriff
I'm sitting here giving you a standing ovation - Len Goodman
|
|
|
|
|
thank you very much. At least, I got to know that all UI actions must be executed within the same thread.
|
|
|
|
|
You should create and access all GUI parts from the main thread; the ProgressChanged and RunWorkerCompleted handlers of a BGW do run on the main thread (provided the main thread was used to create the BGW!). So maybe you could create the one Form in the ProgressChanged handler.
If not, look here[^] for a recommended way to get GUI things done from another thread.
|
|
|
|
|
On a technical level, you need to marshal this into the UI thread, as the others said. (The reason it's hanging is because there is no message loop in that thread.) But if you find yourself doing that there's a good chance that your design is in need of revision; you shouldn't generally be doing direct updates of the UI from a worker thread anyway, even if it did work correctly. Almost by definition, a background thread is business logic, and you should always keep that separate from UI.
A better solution is to have your background worker signal events (either the built in progress event or new events that you define), and have the UI hook onto them and update itself. Note that these events are dispatched in the context of the background thread so you need to use Invoke or BeginInvoke in the handlers to update the UI.
|
|
|
|
|
Alright, I have two questions but this is the first on my list. Currently I am developing a custom control which I plan to create in a manner similar to Microsoft Office Word's documents. I have a custom control (derived from the Panel control) which contains a RichTextBox control. The text box is larger in size (8.5" x 11" sheet, actually) and so it cannot display entirely on the screen at once. The Panel has AutoScroll set to true, which works as expected.
However, I would like to capture mouse wheel events inside the RichTextBox control on the panel and scroll the Panel accordingly. I have hooked the "MouseWheel" event from my Panel class. This works fine as well. I used Debug.WriteLine inside the event handler to ensure that the event was being caught, in which case it was. However, I could not get the panel to scroll. I tried changing the Panel's AutoScrollPosition as well as a few other properties, calling some methods, etc., but to no avail.
I looked online, via Google Search, and I had no luck there. How can I scroll the panel programmatically?
djj55: Nice but may have a permission problem
Pete O'Hanlon: He has my permission to run it.
|
|
|
|
|
Are you calling the Panel's 'Focus()' method in the Panel MouseWheel Event ? This is a frequently reported requirement in discussions of this issue I've seen before.
But, perhaps that's not useful here since you may not wish to lose Focus from the RTF document ?
Possibly this may be helpful:[^]
Unfortunately, my mouse-wheel has never worked, so I can't have a go at this interesting challenge.
best, Bill
"I have always wished for my computer to be as easy to use as my telephone; my wish has come true because I can no longer figure out how to use my telephone." Bjarne Stroustrop circa 1990
|
|
|
|
|
Thank you but that did not do the trick. I even tried to give the Panel focus regardless of whether it would take away from the document. Still no luck. The only solution I have come up with is detecting the mouse wheel and moving each "page" up/down using "page.Top += e.Delta". It works fairly well. The only downfall is that the panel's (auto)scrollbar gets smaller as I scroll DOWN the document. And it will scroll practically infinitely past the beginning/end of the document. But until I resolve this, that will suffice. I have another question but I will be placing it in another thread.
djj55: Nice but may have a permission problem
Pete O'Hanlon: He has my permission to run it.
|
|
|
|
|
The chances are that you won't get Panel.MouseWheel events - instead, you will get RichTextBox.MouseWheel events, particularly if the RTB has the focus or is docked to fill the panel.
Also note that the RTB will have it's own scroll bars - so scrolling the panel is likely to just scroll the RTB off the screen...
In my case, the mouse wheel scrolls the RTB automatically, with no code required at all.
Ideological Purity is no substitute for being able to stick your thumb down a pipe to stop the water
|
|
|
|
|
I am aware of the RTB receiving the MouseWheel event. That is the event that I hooked. I DO want the entire panel to scroll. The RTB is a fixed size and does not fit the entire screen at once. I do not want the RTB to scroll. I am trying to somewhat mimic Microsoft Word, with multiple "pages" and you scroll through them. I have already removed the scroll bars from the RTB.
djj55: Nice but may have a permission problem
Pete O'Hanlon: He has my permission to run it.
|
|
|
|
|