|
Bill Dean wrote:
I keep getting an error message saying that the key is bad when WSE 2.0 attempts the encryption.
Please be specific: what is the exception type and message? What are you doing in code when the exception is thrown?
Without this information, I can only guess that you're having one of three problems:- The X.509 certificate is not signed with the necessary OIDs that identify the certificate for client and/or server authentication.
- Since you made this certificate yourself, you most likely used a self-signing certificate authority (CA). You must add the CA to the trusted certificate store for the machine.
- The ceritifcate is not accessible because you've stored the private key into another user's ceritifcate store (like your local user's or the administrative store), or because the ASPNET user accountcannot access private keys by default and you're not impersonating another user (or running ASP.NET under a different user context).
I'm going to assume that since you have WSE 2.0 installed you have the Help 2 topics installed as well, so please read ms-help://MS.WSE20.1033/wse/html/34caf185-5484-42b3-98ea-3f17f3fc1f16.htm[^] and follow the links for more information.
If you post the specific exception type and message - as well as any other relevent data or code - we may be able to provide a better answer.
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
Thanks Heath,
I should know better than to post such a detail-bare question. My bad.
My client application is a .net web application, running on the same machine that the web service runs on: a win2kpro development machine. I am trying to: 1) sign the request from the client with an x509 cert. 2) sign the response with an x509 cert, and 3) encrypt the response with an x509 cert.
1) and 2) are no problem. But when I add the code for 3) I get this exception:
System.Web.Services.Protocols.SoapHeaderException: Server unavailable, please try later ---> System.ComponentModel.Win32Exception: Bad Key at Microsoft.Web.Services2.Security.Cryptography.RSACryptoServiceProvider.Encrypt(Byte[] plaintext, Boolean useOAEP) at Microsoft.Web.Services2.Security.Cryptography.RSA15KeyExchangeFormatter.EncryptKey(Byte[] plainKey) at Microsoft.Web.Services2.Security.EncryptedKey.Encrypt() at Microsoft.Web.Services2.Security.EncryptedKey.GetXml(XmlDocument document) at Microsoft.Web.Services2.Security.Security.SerializeXml(SoapEnvelope document) at Microsoft.Web.Services2.Security.SecurityOutputFilter.ProcessHeader(Security security, SoapEnvelope envelope) at Microsoft.Web.Services2.Security.SecurityOutputFilter.ProcessMessage(SoapEnvelope envelope) at Microsoft.Web.Services2.Pipeline.ProcessOutputMessage(SoapEnvelope envelope) at Microsoft.Web.Services2.WebServicesExtension.AfterSerializeServer(SoapServerMessage message) --- End of inner exception stack trace ---
This exception is reported by the client and occurs sometime after the return in the web method is called.
The stack trace is:
SoapHeaderException: System.Web.Services.Protocols.SoapHeaderException: Server unavailable, please try later ---> System.ComponentModel.Win32Exception: Bad Key
at Microsoft.Web.Services2.Security.Cryptography.RSACryptoServiceProvider.Encrypt(Byte[] plaintext, Boolean useOAEP)
at Microsoft.Web.Services2.Security.Cryptography.RSA15KeyExchangeFormatter.EncryptKey(Byte[] plainKey)
at Microsoft.Web.Services2.Security.EncryptedKey.Encrypt()
at Microsoft.Web.Services2.Security.EncryptedKey.GetXml(XmlDocument document)
at Microsoft.Web.Services2.Security.Security.SerializeXml(SoapEnvelope document)
at Microsoft.Web.Services2.Security.SecurityOutputFilter.ProcessHeader(Security security, SoapEnvelope envelope)
at Microsoft.Web.Services2.Security.SecurityOutputFilter.ProcessMessage(SoapEnvelope envelope)
at Microsoft.Web.Services2.Pipeline.ProcessOutputMessage(SoapEnvelope envelope)
at Microsoft.Web.Services2.WebServicesExtension.AfterSerializeServer(SoapServerMessage message)
--- End of inner exception stack trace ---]
System.Web.Services.Protocols.SoapHttpClientProtocol.ReadResponse(SoapClientMessage message, WebResponse response, Stream responseStream, Boolean asyncCall)
System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(String methodName, Object[] parameters)
SecureServiceLib.RestekSecureServiceClient2.Invoke(String methodName, Object[] parameters) in c:\projects\securewebservice\secureservicesolution\secureservicelib\clsresteksecureserviceclient2.cs:26
WSE2Client.localhost.Service2.HelloWorld() in c:\inetpub\wwwroot\WSE2Client\Web References\localhost\Reference.cs:45
WSE2Client.WebForm1.Page_Load(Object sender, EventArgs e) in c:\inetpub\wwwroot\wse2client\webform1.aspx.cs:24
System.Web.UI.Control.OnLoad(EventArgs e)
System.Web.UI.Control.LoadRecursive()
System.Web.UI.Page.ProcessRequestMain()
The code that adds the encryption is:
protected virtual void AddSignAndEncryptInformation()
{
_addResponseEncryption();
_addResponseSignature();
}
private void _addResponseEncryption()
{
SoapContext responseContext = ResponseSoapContext.Current;
X509SecurityToken e =this.GetResponseEncryptingSecurtyToken ();
responseContext.Security.Tokens.Add (e);
responseContext.Security.Elements.Add (new EncryptedData (e));
}
protected virtual X509SecurityToken GetResponseEncryptingSecurtyToken()
{
X509SecurityToken securityToken = null;
X509CertificateStore store = X509CertificateStore.LocalMachineStore(X509CertificateStore.MyStore);
bool open = store.OpenRead();
try
{
byte[] certHash=this.GetHash ("RestekClient");
X509CertificateCollection certs =store.FindCertificateByHash (certHash);
X509Certificate cert =
((X509Certificate) certs[0]);
if (cert != null)
{
securityToken = new X509SecurityToken(cert);
}
}
finally
{
if (store != null)
store.Close();
}
bool b= securityToken.Certificate.SupportsDataEncryption ;
if (b)
return securityToken;
throw new Exception ("Cert does not support data encryption");
}
private byte[] GetHash(string KeyName)
{
byte[] b=null;
if (KeyName=="RestekClient")
b=new byte[] {0xee, 0x2b, 0xba, 0xb4, 0xeb, 0x6d, 0xff, 0x1e, 0xf2, 0xc4, 0x70, 0xf9, 0x10, 0xa5, 0xfd, 0xf4, 0x03, 0xd8, 0xfb, 0xaf};
if (KeyName=="RestekServer")
b=new byte[] {0xab, 0xaf, 0xe2, 0x9d, 0xa2, 0x0a, 0xda, 0xd1, 0x02, 0x0d, 0xee, 0x50, 0xf1, 0xf1, 0xb5, 0xc1, 0x22, 0x4c, 0x1d, 0xe3};
if (KeyName=="WSEQuickStartServer")
b=new byte[] {0x87, 0xd9, 0x2c, 0xca, 0xb7, 0x14, 0xc3, 0x0d, 0xb0, 0xe0, 0xba, 0xe6, 0xb9, 0xb0, 0xb6, 0x5b, 0x5d, 0x6d, 0xf7, 0xcf};
return(b);
}
and the trivial webmethod I am using to test all this stuff is:
[WebMethod]
public string HelloWorld()
{
this.AssureCredentialsValid ();
this.AddSignAndEncryptInformation ();
return ("Hello World");
}
According to the WSE2 Cert tool, the ASPNET user has full control over the private key file for the RestekClient cert. Yes, the cert is self-signed. Any further guidance anyone can provide will be greatly appreciated.
Thanks again
Bill
|
|
|
|
|
For starters, make sure the CA that signed your X.509 certificate is installed into the trusted CA store of your machine.
If that fails I can look into it more. The certificate must be trusted, however, which is one likely cause of "Bad key" (it could also be that you didn't enable the right attributes for the key to sign and encrypt data, so be sure to check that as well).
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
Thanks for the follow-up Heath.
The cert is self-signed, so I am assuming that I need to add the certificate itself to my trusted CA store...right? Assuming this is correct, I exported the cert from Local Computer \ Personal and then imported it into Local Machine \ Trusted Root Authority...but the problem remains.
How can I tell for sure if it is trusted?
How can I tell if I have enable[ed] the right attributes for the key to sign and encrypt data?
Thank for entertaining my questions...I've been through the WSE2.0 docs 1/2 a dozen times and cannot find the answer, so I am a little at whit's end. Any other good sources of documentation?
Bill
|
|
|
|
|
Actually, you must add the CA (the CA was self-signed, and then used to sign your certificate - at least that's what you were supposed to do) to the trusted CA store. If you don't, then the security implementation won't trust your certificate you use to sign and encrypt data because it doesn't trust what signed it.
Read a very old tutorial of mine about certificates and using OpenSSL at http://www.devhood.com/Tutorials/tutorial_details.aspx?tutorial_id=209[^]. It may provide some limited insight.
You should not be using your self-signed CA for signing and encrypting data. You use that to sign certificates for certain purposes, and the CA must be set up to be able to sign with those privileges. My tutorial covers that, and there's a lot of information on the web about X.509, which is beyond the scope of this article.
You can look at the certificate in Windows to see what it is signed to do. Just double-click the file assuming it's in a format that Windows understands (like an X.509 DER file - a binary DER-encoded file). There usually have .pfx extensions (but of course the extension is meaningless if the file format isn't correct).
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
|
I'm not a new programmer, but this one's got me stymied; hopefully it's a fairly trivial problem.
I'm using a socket connection to receive communication from a server. Normally, the entire message is received before the program moves on with its next instructions. However, at times when the processor is particularly busy the program seems to progress with its instructions without having received the entire communication. In other words, it seems to clean out the buffer, which due to the computer's business is holding only the first packet at this point, then move on without waiting for the buffer to fill with the next packet.
Is there a way to stop the program until it has been told that the entire communication has been received? Or a way to iteratively receive the packets until the program is told the communication is finished?
Here's my code:
<br />
IPHostEntry IPAdd = Dns.Resolve("servername.com");<br />
IPEndPoint IPEP = new IPEndPoint(IPAdd.AddressList[0], 2628);<br />
Socket s = new Socket(IPEP.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);<br />
string str = "Message"<br />
Byte[] Receiver = new Byte[50000];<br />
s.Connect(IPEP);<br />
Int32 bytes = s.Receive(Receiver, Receiver.Length, 0);<br />
Byte[] Sender = System.Text.Encoding.ASCII.GetBytes(str);<br />
s.Send(Sender, Sender.Length, 0);<br />
bytes = s.Receive(Receiver, Receiver.Length, 0);<br />
strResponse = System.Text.Encoding.ASCII.GetString(Receiver, 0, bytes);<br />
...Furthur code
Thanks for your help!
|
|
|
|
|
Take a look at some of the options from the SocketOptionName enumeration. This is used in conjunection with the SocketOptionLevel to set socket options using the Socket.SetSocketOption method. Not allowing your packets to be fragmented might be one option.
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
Interesting. I'll take a look.
Thanks.
|
|
|
|
|
I am working on a project the involves transferring data from a bar code scanner. The scanner runs PC-DOS and has a command line transfer utility that uses Xmodem. I have written an application that shells out and uses the same CLI utility to receive the file. This works, but I would like to impliment my own Xmodem protocol into my application to have more control over what is happening (and just to learn).
So far I haven't found any *free* examples of an Xmodem implimentation using C#. I have found several products that I can purchase, but this isn't what I had in mind.
I have found the specification for the Xmodem protocol and it's reads as being fairly straight forward. I'm curious to if anyone else has written the own implimentation, or if I'm overlooking why this shouldn't be too difficult.
|
|
|
|
|
therealmccoy wrote:
So far I haven't found any *free* examples of an Xmodem implimentation using C#. I have found several products that I can purchase, but this isn't what I had in mind.
If you can't find anything free using google or some other web search and you can't find anything by clicking "Search comments" in this forum (since it isn't indexed by google and the other major search engines...yet), then anything free doesn't exist.
You'll either have to implement your own xmodem APIs or purchase one of the libraries you've found. I'm sure the developers have spent a lot of time and planning and deserve what they get. You would like to get paid for your projects, wouldn't you?
Besides, with a paid product you can expect support. With free ones you're at the author's whim.
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
Heath Stewart wrote:
You'll either have to implement your own xmodem APIs or purchase one of the libraries you've found. I'm sure the developers have spent a lot of time and planning and deserve what they get. You would like to get paid for your projects, wouldn't you?
In order to get paid for any of my projects I will need to learn a lot more. With that in mind I guess I will be implimenting my own interface (ohhh.. what a challenge). During the course of this project I'm sure I'll have more questions, but when I'm done this API it will be released into the public domain, much like the original Xmodem specification was.
For others searching this forum and looking for information on an Xmodem implimentation (as well as the total lack of any type of serial support in .NET) check the following site:
http://ourworld.compuserve.com/homepages/richard_grier/xmcomm.htm[^]
|
|
|
|
|
There should be in .NET 2.0, codename "Whidbey". See http://msdn2.microsoft.com/library/System.IO.Ports[^] for details.
Because "Whidbey" is currently in beta, there is no gaurantee that what you read now will be there in the release, but do have comfort in the knowledge that serial support in the BCL is something that has been requested by the community for a long time.
If you need to or want to implement your Xmodem implementation for .NET 1.0 and 1.1, I recommend downloading[^] the .NET Framework 2.0 runtime and SDK and using ildasm.exe - the IL Disassembler - from the SDK's Bin directory to examine how the System.IO.Ports namespace classes work with the Win32 APIs. You can also use .NET Reflector[^] to decompile (and disassembler) the assemblies to get tips for your own implementation.
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
Hi,
I am trying to return a string(char*) from a c++ dll and the string i return comes out blank. can anyone help me on this.
Vinayak D. Labade
|
|
|
|
|
Maybe, but since you didn't provide any required information - like the C# method and C++ function signatures - it's impossible to help you.
One thing I can tell you, however, is that keep in mind a string (System.String ) is already a reference type, so unless you see char** don't use ref or out with the parameter, despite any [in] or [out] comments you may see in the API documentation.
If you paste your C++ signature, I can tell you what the C# signature should be. Be explicit.
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
Thnaks ...
here is the code snippet taht I am using.
C# code
-------------------------------------------------
public class newtestdll
{
[DllImport("C:\\DLLDEV\\qw\\debug\\qw.DLL", EntryPoint="ReportVersion", SetLastError=true,
CharSet=CharSet.Unicode, ExactSpelling=true,
CallingConvention=CallingConvention.StdCall)]
public static extern string ReportVersion(string str);
}
-------------------------------------------------
str = newtestdll.ReportVersion(string);//function call
--------------------------------------------------
**************************************************
--------------------------------------------------
C++ definition
---------------------------------------------------
__declspec(dllexport) char* CQwApp::ReportVersion(char* a)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
a = "return String";
return a;
}
---------------------------------------------------
I even tried using StringBuilder but am not able to modify the StringBuilder properly.
Vinayak D. Labade
|
|
|
|
|
I see many problems with that.
First, never hard-code the path to your DLL from which you want to import a function. Just set the DLL name and make sure the directory is in your PATH environment variable or in the local directory of your application that runs this code (not necessarily where the DLL assembly that may contain this code is). This is how Windows (and actually other OS's like linux and UNIX) finds DLLs. Read the documentation for the native CreateProcess API for more information.
Seconds, you're setting CharSet to CharSet.Unicode . char* is an ANSI string. Be sure to read the documentation for the CharSet enumeration for details.
Third, you don't need much of the fields you're setting in the DllImportAttribute . You only need exact spelling if, for example, you're importing SomeFunctionA or SomeFunctionW , where you don't want an "A" or "W" appended depending on the CharSet . It won't hurt, though. And only set SetLastError to true if your function actually sets the last error. I see nothing in your code that would.
The simple signature for your native function follows:
[DllImport("qw.dll")]
static extern string ReportVersion(string a); However, there are a few reasons why this won't work and a few things you should be aware of.
A char* is, obviously, a pointer to a char . If you're setting this to another string the pointer is is modified to point to another string such that when your function returns what you passed as the parameter is the new string. You don't need to return it as well. Besides, you should never return a string because it's not possible to return an error code if the function fails. You're only choice is to return NULL, which doesn't tell you what actually failed. You could use SetLastError in your native code, but it's far better to return an error value.
Also, you're importing a method - not a function. Methods use the CallingConvention.ThisCall - at least instance methods. Now you have a problem.
You can't call your instance method without a context to whatever this would be in your native code (an instance of CQwApp )
This means you have to set the DllImportAttibute.CallingConvention field to CallingConvention.ThisCall and create a pair of proxy functions (not methods) to create and destroy (or just a single proxy method to get) an instance of CQwApp . See a previous reply regarding this issue at http://www.codeproject.com/script/comments/forums.asp?msg=771919&forumid=1649#xx771919xx[^].
Finally, you should consider that - if your method really is so basic and doesn't require instance data - either define it as static and use the __cdecl calling convention (which means you don't declare any DllImportAttribute.CallingConvention , though you may need to set the EntryPoint explicitly since the name will be C++ mangled) or declare it as a function instead of any sort of method. That will make it easier to P/Invoke.
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
Thanks for the reply. I was able to call the function and return a string as required. The dll function i am calling has some output which i need.
i am facing another problem though.
I get error for this code in the dll
---------------------------------------------
FILE *stream;
GetCurrentDirectory( 256, buffer );
strcat( buffer, "\somefile.txt" );
stream = fopen( buffer, "r" );
fseek( stream, 0L, SEEK_SET );
fscanf( stream, "%d\n", &ct_ );
----------------------------------------------
what do you think might be the issue here
if i call the same code from a MFC exe it works fine but not when i call from C# code
Thnaks & Regards,
Vinayak D. Labade
|
|
|
|
|
What's the error? I can't really help you if you don't tell me what's wrong.
I can guess, however, that you can't open the somefile.txt from the current directory and you're only opening it for read access, and it won't be created.
The CLR works differently than a typical Win32 EXE (MFC is just a wrapper for Win32 APIs) and what you expect to be the current directory may not be.
Also keep in mind that even with native applications, the current working directory (retrieved by GetCurrentDirectory ) is not necessary the directory in which the application is running. If from a console window you execute an application from another directory, the directory which was the current directory is used. For applications launched through shortcuts, if any working directory is specified for the shortcut that is used. There's other cases that will cause the current working directory to be different than the application directory.
To get the application directory, call GetModuleFileName(NULL, szBuffer, MAX_PATH) , where szBuffer is a TCHAR szBuffer[MAX_PATH] .
Finally, regarding your native code there's a lot of things you should consider changing. Don't use "magic numbers" like 256. What's that mean? Use constants that are more descriptive like MAX_PATH (which is actually 260, and is what Windows defines as the maximum characters in a path). Also don't use unsafe string manipulation functions like strcat that don't ensure NULL termination (which is one major cause of buffer overruns, the most common cause of security vulnerabilies and other types of bugs). MSDN recommends using StrSafe[^], which are safe implementations of string manipulation functions.
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
I am looking to implement a web site that can conform to the strict standards of US govt secure internet web site protocols for password and username use. Things like expiring passwords, keeping track of whether a password has been used before, or a password closely used before. Password complexity and secure storage of passwords and on and on. Basically I am looking to see if there has been a COTS product that has been developed to perform all your password needs for a secure web site or will I have to code all this my self? Any help or direction is much appreciated. Thanks.
Big Friendly Letters : DON'T PANIC
|
|
|
|
|
I have some documents stored on a server, I want to use these as a template and populate them with some infromation from a database.
At first I thought of automating Word, this worked nicely on my local machine when I tried it out as a normal winform. But then when I tried it on the webpage I got a "The message filter indicated that the application is busy" when I tried using it. I've looked around alot and found no solution for this, so I'm more or less ready to drop all the work I've done so far regarding this.(Iterated through bookmarks and replaced the text)
Now I've been thinking that Word 2003 is saved as XML, so perhaps I could replace text in that instead. In the Word file I have certain keywords I want to replace, for example User = @usr then I would like to replace @usr with something from the database.
Problem I have is that XML is a very big subject and I have problem figuring out if this is possible or not. I dont want to spend more days(wasted alot of days on learning how to automate word)if it is not possible(In a easy way).
So, anyone have any tips how I can do or tips on what I should read up on.
Or is it possible to use any other way of searching the text and replacing instances like that in a easier way?(We are talking about Word 2003 documents only, or if it is easy 2000 documents too)
|
|
|
|
|
Hello,
I'm new to this site, as an active member, and i've been reading it for a while now to.
But today for the first time i couldn't find an answer to my problem, even google couldn't help me out.
So what is the problem?
I bought this fancy new laptop (acer travelmate 8008) and I'm playing with it, but I realy don't like the "on screen" displays the basic software gives mee. So I want to write it myselve using C#.
Now the first problem is, the special keys I'm talking about don't have a ascii code or are ingnored by the keydown, keypress and keyup functions.
So how do i detect these events?
I tried searching for an API call but couldn't find one, or i didn't understand what the writer talked about. (new to API call's)
Maby i could use a DLL of the program that handles the "special keys"?
anny help will be greatly apriciated...
and thanx in advance
ps: hope this is the right forum
pss: maby an idea for an article?
|
|
|
|
|
The OEM keys (original equipment manufacturer) are supported through the KeyEventArgs.KeyData property when you override OnKeyDown (best when extending classes in which the keys are handled) or handle the KeyDown event. See the property documentation in the .NET Framework SDK for more details.
Compile the following example:
using System;
using System.Drawing;
using System.Windows.Forms;
class Test : Form
{
static void Main()
{
Application.Run(new Test());
}
TextBox tb;
Test()
{
tb = new TextBox();
Controls.Add(tb);
tb.Multiline = true;
tb.Dock = DockStyle.Fill;
Text = "Press any key";
KeyPreview = true;
}
protected override void OnKeyDown(KeyEventArgs e)
{
AddLine(e.KeyData);
base.OnKeyDown(e);
}
void AddLine(Keys keys)
{
tb.AppendText(keys.ToString() + Environment.NewLine);
}
} With keys there really isn't much reason to require P/Invoke, though P/Invoking the native GetKeyState or GetAsyncKeyState APIs can be helpful for toggle keys that wouldn't be in KeyEventArgs.Modifiers .
For more information on P/Invoke (Platform Invoke), read Consuming Unmanaged DLL Functions[^] and Marshaling Data with Platform Invoke[^] in the .NET Framework SDK.
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
this is truly great info and solves most of my key problems.
Only a few keys (like the powermanagement key and programmable keys return LButton, OemClear (value 255).
These buttons are not supported by the .NET framework (i think).
So I'll have to find a workaround for these.
And special thanx to you Heath Stewart for your quil and helpfull reply!
|
|
|
|
|
Actually, they would be supported but you need to take that data into consideration with other properties of KeyEventArgs . You're only limited to 256 bits for keys, but there's modifiers. I recommend reading the documentation for the GetKeyState API at http://msdn.microsoft.com/library[^] to learn about keyboard buffers and keys.
Your OEM's special keys are still keys and/or modifier keys. All you need to do is figure out what their values are and in what properties the .NET BCL puts them into the KeyEventArgs class. Worse case scenario is that you have to P/Invoke GetKeyState or GetAsyncKeyState , but that's fairly simple if you read those P/Invoke topics I linked earlier. You should also check out http://pinvoke.net[^] for common API signatures in managed code.
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|