Get friendly name of a device from WM_DEVICECHANGE LParam - c#

So i'm building an app for a school PC that tracks all inserted devices.
I managed to use RegisterDeviceNotification() to get a notification in the main thread whenever i plug in or remove a device.
All i can get though, is the LParam, a pointer that is device unique.
I can't find anything about how to get the friendly name of the device using that LParam.
The only resource i can find is this CodeProject from 2006 (in C++).
I can't find anything on pinvoke.net and the only thing i found (i don't remember exactly where) is using a ManagementObjectSearcher to get this data, but it finds null data. (here's the code)
ManagementObjectSearcher searcher = new ManagementObjectSearcher("Select Name from Win32_PnpEntity");
foreach (ManagementObject devices in searcher.Get())
{
foreach (var v in devices.Properties)
{
Console.WriteLine(v.Value);
}
}
searcher.Dispose();
Can anyone please help me figure out how to get the friendly name of the device?

you need register device notifications with
RegisterDeviceNotificationW
static DEV_BROADCAST_DEVICEINTERFACE dbd = { sizeof(dbd), DBT_DEVTYP_DEVICEINTERFACE };
_hDevNot = RegisterDeviceNotificationW(hwnd, &dbd,
DEVICE_NOTIFY_WINDOW_HANDLE|DEVICE_NOTIFY_ALL_INTERFACE_CLASSES);
as result you will receive WM_DEVICECHANGE message
here you need check wParam for for DBT_DEVICEARRIVAL and
DBT_DEVICEREMOVECOMPLETE events
check that dbcc_devicetype == DBT_DEVTYP_DEVICEINTERFACE
inside DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_name you got
device interface name
you can use this name inside CM_Get_Device_Interface_PropertyW
function with DEVPKEY_Device_InstanceId on
DBT_DEVICEARRIVAL event
you got Device Instance ID
use it in call CM_Locate_DevNodeW
use result in call CM_Get_DevNode_PropertyW with
DEVPKEY_NAME or DEVPKEY_DeviceInterface_FriendlyName
on DBT_DEVICEREMOVECOMPLETE - you can only look in self
database (if you create it on arrival) for such name and friendly
name.
demo code:
struct DeviceName : public LIST_ENTRY
{
ULONG InterfaceHash;
WCHAR Name[];
void* operator new(size_t cb, size_t len)
{
return LocalAlloc(0, cb + len);
}
void operator delete(void* pv)
{
LocalFree(pv);
}
};
volatile const UCHAR guz = 0;
CONFIGRET GetFriendlyNameByDevNode(DeviceName** pp, DEVINST dnDevInst)
{
CONFIGRET status;
ULONG cb = 32;
DEVPROPTYPE PropertyType;
do
{
if (DeviceName* p = new(cb) DeviceName)
{
status = CM_Get_DevNode_PropertyW(
dnDevInst, &DEVPKEY_DeviceInterface_FriendlyName, &PropertyType, (PBYTE)p->Name, &cb, 0);
if (status == CR_SUCCESS)
{
if (PropertyType == DEVPROP_TYPE_STRING)
{
*pp = p;
return CR_SUCCESS;
}
else
{
status = CR_WRONG_TYPE;
}
}
delete p;
}
else
{
status = CR_OUT_OF_MEMORY;
}
} while (CR_BUFFER_SMALL == status);
return status;
}
CONFIGRET GetFriendlyNameByInterface(DeviceName** pp, PCWSTR pszDeviceInterface)
{
// RTCu must be disabled !
ULONG cb = 0, rcb = 64;
PVOID stack = alloca(guz);
DEVPROPTYPE PropertyType;
CONFIGRET status;
union {
PVOID pv;
PWSTR DeviceID;
PBYTE pb;
};
do
{
if (cb < rcb)
{
rcb = cb = RtlPointerToOffset(pv = alloca(rcb - cb), stack);
}
} while (CR_BUFFER_SMALL == (status = CM_Get_Device_Interface_PropertyW(
pszDeviceInterface, &DEVPKEY_Device_InstanceId, &PropertyType, pb, &rcb, 0)));
if (status == CR_SUCCESS)
{
if (PropertyType == DEVPROP_TYPE_STRING)
{
DEVINST dnDevInst;
status = CM_Locate_DevNodeW(&dnDevInst, DeviceID, CM_LOCATE_DEVNODE_NORMAL);
return status == CR_SUCCESS ? GetFriendlyNameByDevNode(pp, dnDevInst) : status;
}
else
{
status = CR_WRONG_TYPE;
}
}
return status;
}
case WM_DESTROY:
if (_hDevNot)
{
UnregisterDeviceNotification(_hDevNot);
PLIST_ENTRY head = &_DevListHead, entry = head->Flink;
while (entry != head)
{
DeviceName* p = static_cast<DeviceName*>(entry);
entry = entry->Flink;
delete p;
}
}
break;
case WM_DEVICECHANGE:
switch (wParam)
{
case DBT_DEVICEREMOVECOMPLETE:
case DBT_DEVICEARRIVAL:
if (reinterpret_cast<PDEV_BROADCAST_DEVICEINTERFACE>(lParam)->dbcc_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
{
DeviceName* p;
ULONG InterfaceHash;
UNICODE_STRING dbcc_name;
RtlInitUnicodeString(&dbcc_name, reinterpret_cast<PDEV_BROADCAST_DEVICEINTERFACE>(lParam)->dbcc_name);
RtlHashUnicodeString(&dbcc_name, FALSE, HASH_STRING_ALGORITHM_DEFAULT, &InterfaceHash);
if (wParam == DBT_DEVICEARRIVAL)
{
if (CR_SUCCESS == GetFriendlyNameByInterface(&p, dbcc_name.Buffer))
{
p->InterfaceHash = InterfaceHash;
InsertHeadList(&_DevListHead, p);
DbgPrint("inserted %S ( %wZ )\n", p->Name, &dbcc_name);
}
}
else
{
PLIST_ENTRY head = &_DevListHead, entry = head;
while ((entry = entry->Flink) != head)
{
if (static_cast<DeviceName*>(entry)->InterfaceHash == InterfaceHash)
{
DbgPrint("removed %S ( %wZ )\n",
static_cast<DeviceName*>(entry)->Name, &dbcc_name);
RemoveEntryList(entry);
delete static_cast<DeviceName*>(entry);
break;
}
}
}
}
break;
}
return 0;
case WM_CREATE:
InitializeListHead(&_DevListHead);
static DEV_BROADCAST_DEVICEINTERFACE dbd = { sizeof(dbd), DBT_DEVTYP_DEVICEINTERFACE };
_hDevNot = RegisterDeviceNotificationW(hwnd, &dbd, DEVICE_NOTIFY_WINDOW_HANDLE|DEVICE_NOTIFY_ALL_INTERFACE_CLASSES);
break;

Related

ECDSA signing in c# verify in c

I'm trying to sign data in C#, using ECDSA algorithm (this part looks OK) and to verify signature in C using Windows crypto API.
Signature part:
CngKeyCreationParameters keyCreationParameters = new CngKeyCreationParameters();
keyCreationParameters.ExportPolicy = CngExportPolicies.AllowPlaintextExport;
keyCreationParameters.KeyUsage = CngKeyUsages.Signing;
CngKey key = CngKey.Create(CngAlgorithm.ECDsaP256, null, keyCreationParameters);
ECDsaCng dsa = new ECDsaCng(key); //dsa = Digital Signature Algorithm
byte[] privateKey = dsa.Key.Export(CngKeyBlobFormat.EccPrivateBlob);
File.WriteAllText("privatekey.txt", String.Join(",", privateKey));
byte[] publicKey = dsa.Key.Export(CngKeyBlobFormat.EccPublicBlob);
File.WriteAllText("publicKey.txt", String.Join(",", publicKey));
CngKey importedKey = CngKey.Import(File.ReadAllText("privatekey.txt").Split(',').Select(m => byte.Parse(m)).ToArray(), CngKeyBlobFormat.EccPrivateBlob);
ECDsaCng importedDSA = new ECDsaCng(importedKey); //dsa = Digital Signature Algorithm
byte[] signed = dsa.SignData(new byte[] { 1, 2, 3, 4, 5 });
File.WriteAllText("signed.txt", String.Join(",", signed));
At this point I'm able to create a signature key and export it to a byte buffer in a file.
Problems come when I'm trying to import this public key in C using windows crypto API.
BYTE KeyBlob[] = { // public key exported by above c# code
69,67,83,49,32,0,0,0,227,146,138,255,218,235,122,141,44,110,211,95,59,227,226,163,81,188,242,115,60,171,46,141,221,117,169,139,42,143,67,85,144,242,232,188,22,158,230,15,110,6,214,252,252,242,224,241,110,186,1,244,176,65,88,184,94,19,98,174,158,7,154,152
};
int _tmain()
{
HCRYPTPROV hProv = NULL;
HCRYPTKEY hKey = NULL;
DWORD dwBlobLen;
BYTE* pbKeyBlob;
if (!CryptAcquireContext(
&hProv,
NULL,
MS_ENHANCED_PROV,
PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT))
{
printf(" Error in AcquireContext 0x%08x \n", GetLastError());
return 1;
}
if (!CryptImportKey(
hProv,
KeyBlob,
sizeof(DesKeyBlob),
0,
CRYPT_EXPORTABLE,
&hKey))
{
printf("Error 0x%08x in importing the key \n",
GetLastError());
}
which returns
Error 0x80090007 in importing the key
which is (believing winerror.h) :
//
// MessageId: NTE_BAD_VER
//
// MessageText:
//
// Bad Version of provider.
//
#define NTE_BAD_VER _HRESULT_TYPEDEF_(0x80090007L)
What do I do wrong?
Thanks to this wonderful website I just found : referencesouce.microsoft.com, I've been able to disassemble what the C# API does when verifying a signature and importing a key.
Apparently I need ncrypt/bcrypt, and signature is verified against a hash, and not the data itself:
public bool VerifyData(Stream data, byte[] signature) {
if (data == null) {
throw new ArgumentNullException("data");
}
if (signature == null) {
throw new ArgumentNullException("signature");
}
using (BCryptHashAlgorithm hashAlgorithm = new BCryptHashAlgorithm(HashAlgorithm, BCryptNative.ProviderName.MicrosoftPrimitiveProvider)) {
hashAlgorithm.HashStream(data);
byte[] hashValue = hashAlgorithm.HashFinal();
return VerifyHash(hashValue, signature);
}
}
[SecuritySafeCritical]
public override bool VerifyHash(byte[] hash, byte[] signature) {
if (hash == null) {
throw new ArgumentNullException("hash");
}
if (signature == null) {
throw new ArgumentNullException("signature");
}
// We need to get the raw key handle to verify the signature. Asserting here is safe since verifiation
// is not a protected operation, and we do not expose the handle to the user code.
new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Assert();
// This looks odd, but Key.Handle is really a duplicate so we need to dispose it
using (SafeNCryptKeyHandle keyHandle = Key.Handle) {
CodeAccessPermission.RevertAssert();
return NCryptNative.VerifySignature(keyHandle, hash, signature);
}
}
Here is a native solution, for whoever needs that:
#include <windows.h>
#include <wincrypt.h>
#include <stdio.h>
char key[72] = { 69,67,83,49,32,0,0,0,227,146,138,255,218,235,122,141,44,110,211,95,59,227,226,163,81,188,242,115,60,171,46,141,221,117,169,139,42,143,67,85,144,242,232,188,22,158,230,15,110,6,214,252,252,242,224,241,110,186,1,244,176,65,88,184,94,19,98,174,158,7,154,152 };
char sign[64] = { 165,50,54,149,14,175,128,54,21,30,129,165,137,203,45,123,180,121,118,20,15,61,253,186,65,129,21,26,54,84,40,205,103,254,108,34,126,205,116,183,44,189,5,180,28,119,228,70,127,116,227,248,232,144,53,226,185,251,217,179,148,88,208,152 };
char message[] = { 1, 2, 3, 4, 5 };
BOOL crypt_init(char* key, unsigned long key_len)
{
HCRYPTPROV hProv = NULL;
BCRYPT_ALG_HANDLE hHashAlg = NULL, hSignAlg = NULL;
BCRYPT_HASH_HANDLE hHash = NULL;
PBYTE pbHash = NULL;
PBYTE pbHashObject = NULL;
DWORD cbHashObject = 0,
cbHash = 0,
cbData = 0;
NTSTATUS status;
if (ERROR_SUCCESS != NCryptOpenStorageProvider(&hProv, NULL, 0)) {
printf("CryptAcquireContext failed - err=0x%x.\n", GetLastError());
return FALSE;
}
NCRYPT_KEY_HANDLE keyHandle;
if (ERROR_SUCCESS != NCryptImportKey(hProv, NULL, BCRYPT_ECCPUBLIC_BLOB, NULL, &keyHandle, (PBYTE)key, 72, 0)) {
printf("CryptAcquireContext failed - err=0x%x.\n", GetLastError());
return FALSE;
}
if (!BCRYPT_SUCCESS(status = BCryptOpenAlgorithmProvider(
&hHashAlg,
BCRYPT_SHA256_ALGORITHM,
NULL,
0)))
{
printf("BCryptOpenAlgorithmProvider failed - err=0x%x.\n", status);
return false;
}
if(!BCRYPT_SUCCESS(status = BCryptGetProperty(hHashAlg, BCRYPT_OBJECT_LENGTH, (PBYTE)&cbHashObject, sizeof(DWORD), &cbData, 0))) {
printf("BCryptGetProperty failed - err=0x%x.\n", status);
return FALSE;
}
pbHashObject = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbHashObject);
if (NULL == pbHashObject) {
printf("memory allocation failed\n");
return FALSE;
}
if (!BCRYPT_SUCCESS(status = BCryptGetProperty(hHashAlg, BCRYPT_HASH_LENGTH, (PBYTE)&cbHash, sizeof(DWORD), &cbData, 0))) {
printf("BCryptGetProperty failed - err=0x%x.\n", status);
return FALSE;
}
pbHash = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbHash);
if (NULL == pbHash)
{
printf("memory allocation failed\n");
return FALSE;
}
if (!BCRYPT_SUCCESS(status = BCryptCreateHash(hHashAlg, &hHash, pbHashObject, cbHashObject, NULL, 0, 0)))
{
printf("BCryptCreateHash failed - err=0x%x.\n", status);
return FALSE;
}
if (!BCRYPT_SUCCESS(status = BCryptHashData(hHash, (PBYTE)message, sizeof(message), 0)))
{
printf("BCryptHashData failed - err=0x%x.\n", status);
return FALSE;
}
if (!BCRYPT_SUCCESS(status = BCryptFinishHash(hHash, pbHash, cbHash, 0)))
{
printf("BCryptFinishHash failed - err=0x%x.\n", status);
return FALSE;
}
if(ERROR_SUCCESS != NCryptVerifySignature(keyHandle, NULL, pbHash, cbHash, (PBYTE) sign, sizeof(sign), 0)) {
printf("BCryptVerifySignature failed - err=0x%x.\n", status);
return FALSE;
}
return TRUE;
}
int main() {
crypt_init(key, 72);
}

How to find VLC Attribute Library (C# Unity)

I have this Delegates thats been wrote like this
public static T GetInteropDelegate<T>(IntPtr handler)
{
string functionName = null;
var procAddress = IntPtr.Zero;
var supportedPlatform = UMPSettings.SupportedPlatform;
try
{
var attrs = typeof(T).GetCustomAttributes(typeof(InteropFunctionAttribute), false);
if (attrs.Length == 0)
throw new Exception("Could not find the LibVLCAttribute.");
var attr = (InteropFunctionAttribute)attrs[0];
functionName = attr.FunctionName;
if (_interopDelegates.ContainsKey(functionName))
return (T)Convert.ChangeType(_interopDelegates[attr.FunctionName], typeof(T), null);
if (supportedPlatform == UMPSettings.Platforms.Win)
procAddress = WindowsInterops.GetProcAddress(handler, attr.FunctionName);
if (supportedPlatform == UMPSettings.Platforms.Mac)
procAddress = MacInterops.dlsym(handler, attr.FunctionName);
if (supportedPlatform == UMPSettings.Platforms.Linux)
procAddress = LinuxInterops.dlsym(handler, attr.FunctionName);
if (procAddress == IntPtr.Zero)
throw new Win32Exception("Can't get process address from " + handler + " library: " + Marshal.GetLastWin32Error());
var delegateForFunctionPointer = Marshal.GetDelegateForFunctionPointer(procAddress, typeof(T));
_interopDelegates[attr.FunctionName] = delegateForFunctionPointer;
return (T)Convert.ChangeType(delegateForFunctionPointer, typeof(T), null);
}
catch (Exception e)
{
Debug.LogError("GetMethod error: " + functionName);
throw new MissingMethodException(string.Format("The address of the function '{0}' does not exist in " + handler + " library.", functionName), e);
}
}
Now the problem with this is that . It always throw the error
Exception: Could not find the LibVLCAttribute.
UMP.InteropLibraryLoader.GetInteropDelegate[libvlc_media_get_stats] (IntPtr handler) (at Assets/UniversalMediaPlayer/Scripts/Sources/InteropLibraryLoader.cs:149)
Rethrow as MissingMethodException: The address of the function '' does not exist in 235143168 library.
UMP.InteropLibraryLoader.GetInteropDelegate[libvlc_media_get_stats] (IntPtr handler) (at Assets/UniversalMediaPlayer/Scripts/Sources/InteropLibraryLoader.cs:173)
UMP.VlcMethods.LoadMethodsFromVLCLibrary (IntPtr handler) (at Assets/UniversalMediaPlayer/StreamingWork/VlcMethods.cs:59)
Now there's a script that holds my method of vlc
VlcMethod.cs
using System;
using System.Runtime.InteropServices;
using UMP.Wrappers;
namespace UMP
{
public class VlcMethods
{
private static VlcMethods instance = null;
public static VlcMethods Instance
{
get
{
if (instance == null)
{
instance = new VlcMethods();
}
return instance;
}
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int libvlc_media_get_stats(IntPtr p_md, out libvlc_media_stats_t p_stats);
public libvlc_media_get_stats Libvlc_media_get_stats;
public VlcMethods()
{
var libraryExtension = string.Empty;
var settings = UMPSettings.Instance;
IntPtr handler = InteropLibraryLoader.Load(Wrapper.LibraryVLCName, settings.UseExternalLibs, settings.AdditionalLibsPath, libraryExtension);
if (handler != IntPtr.Zero)
{
LoadMethodsFromVLCLibrary(handler);
}
}
~VlcMethods()
{
instance = null;
}
private void LoadMethodsFromVLCLibrary(IntPtr handler)
{
if (handler == IntPtr.Zero)
return;
try
{
//Libvlc_media_get_stats = (libvlc_media_get_stats)InteropLibraryLoader.GetInteropDelegate<libvlc_media_get_stats>(handler);
//[Pk Recode 29/12 2017]
Libvlc_media_get_stats = InteropLibraryLoader.GetInteropDelegate<libvlc_media_get_stats>(handler);
}
catch (Exception exception)
{
InteropLibraryLoader.Unload(handler);
throw new ArgumentException(
String.Format("No suitable " + Wrapper.LIBRARY_VLC_NAME + " could be found in the provided path: {0}", exception.Message),
Wrapper.LIBRARY_VLC_NAME + "Directory", exception);
}
}
}
}
Now i'm using also my vlc method for checking the network condition which is like this
libvlc_media_stats_t preStat;
VlcMethods.Instance.Libvlc_media_get_stats(mediaObj, out preStat);
while (true)
{
yield return new WaitForSeconds(1f);
libvlc_media_stats_t t;
VlcMethods.Instance.Libvlc_media_get_stats(mediaObj, out t);
int playedBuff = t.i_demux_read_bytes - preStat.i_demux_read_bytes;
int downBuff = t.i_read_bytes - preStat.i_read_bytes;
int storageBuff = t.i_read_bytes - t.i_demux_read_bytes;
sumStorageBuffer -= storagebuffQueue.Dequeue();
storagebuffQueue.Enqueue(storageBuff);
sumStorageBuffer += storageBuff;
sumDownBuff -= downBuffQueue.Dequeue();
downBuffQueue.Enqueue(downBuff);
sumDownBuff += downBuff;
averageStorageBuffer = (sumStorageBuffer / (float)storagebuffQueue.Count) / playedBuff;
averageDownloadBuffer = (sumDownBuff / (float)downBuffQueue.Count) / playedBuff;
preStat = t;
And now i don't know really why it is throwing that error. -_-. Anyone can site ? Thank you in advance. This is driving me nuts.
I came up with the idea that i need to delete my vlcmethod.cs and on my livecam.cs
private IEnumerator CheckNetworkCondition()
{
averageStorageBuffer = 0;
averageDownloadBuffer = 0;
Queue<float> storagebuffQueue = new Queue<float>();
float sumStorageBuffer = 0;
Queue<float> downBuffQueue = new Queue<float>();
float sumDownBuff = 0;
for (int i = 0; i < averageCount; i++)
{
storagebuffQueue.Enqueue(0);
downBuffQueue.Enqueue(0);
}
MediaStats? preStat = null;
while (true)
{
yield return new WaitForSeconds(1f);
var mediaStats = new MediaStats();
if (ump.PlatformPlayer is MediaPlayerStandalone)
mediaStats = (ump.PlatformPlayer as MediaPlayerStandalone).MediaStats;
if (ump.PlatformPlayer is MediaPlayerAndroid)
mediaStats = (ump.PlatformPlayer as MediaPlayerAndroid).MediaStats;
if (preStat == null)
preStat = mediaStats;
int playedBuff = mediaStats.DemuxReadBytes - preStat.Value.DemuxReadBytes;
int downBuff = mediaStats.InputReadBytes - preStat.Value.InputReadBytes;
int storageBuff = mediaStats.InputReadBytes - mediaStats.DemuxReadBytes;
sumStorageBuffer -= storagebuffQueue.Dequeue();
storagebuffQueue.Enqueue(storageBuff);
sumStorageBuffer += storageBuff;
sumDownBuff -= downBuffQueue.Dequeue();
downBuffQueue.Enqueue(downBuff);
sumDownBuff += downBuff;
averageStorageBuffer = (sumStorageBuffer / (float)storagebuffQueue.Count) / playedBuff;
averageDownloadBuffer = (sumDownBuff / (float)downBuffQueue.Count) / playedBuff;
preStat = mediaStats;
UpdatekNetworkCondition();
}
}

USBDeviceInfo/ManagementObjectSearcher gives Arguments that where´nt asked for

I have some code i wrote for finding the COM-Port of a certain Motor-Controller, based off of this Article:
Getting Serial Port Information
Since this Code doesn´t explicitely look for ComPorts, but for Device Names and Infos, I played around a bit and found out that when you look for a certain device in the resulting list, referenced by name, and write that to a *.txt file, the COMPort shows up in (brackets) after the name, like so: Devicename (COM5).
This I used to write that information to a string using Array.Find, and from then on it´s just selecting the number to connect to.
My Problem is that i don´t want to loop through ALL devices, but just until the one I´m looking for is found, and then break the loop.
This, however, results in a string[1] Array without the COMPort attached to entries, opposed to a string[2] Array with ComPort attached if I don´t break the loop.
I want to know why the COMPort gets attached in the first place (my guess is collection.Dispose), and why breaking the loop kills that "function/bug/whatever".
{
public static void ComPortSelectionMain(/*string[] args*/)
{
string ComDummy; // ComPort, ComPortString;
int ComNumber = 0;
var usbDevices = GetUSBDevices();
var ComList = new List<string>();
foreach (var usbDevice in usbDevices)
{
if (usbDevice.Description == "PI C-863")
{
//Console.WriteLine("Device ID: {0}, PNP Device ID: {1}, Description: {2}", usbDevice.DeviceID, usbDevice.PnpDeviceID, usbDevice.Description);
ComList.Add(usbDevice.Name); //Add USB Device
}
}
var ComArray = ComList.ToArray();
var target = "PI C-863 (COM";
// var target2 = ")";
int arrayindex = 0;
int start = 0, stop = 0;
string targetname = "PI C-863";
string test = (Array.Find(ComArray, element => element.Contains(targetname)));
//Console.WriteLine("Test: " + test);
if (test == targetname) //look if comarray contains target
{
//int index = Array.FindIndex(ComArray, item => item == "("); // row.Contains(targetname));
int indexsigned = Array.IndexOf(ComArray, target);
int index = Math.Abs(indexsigned);
start = ComArray[index].IndexOf('(') + 1;
arrayindex = index;
stop = ComArray[index].IndexOf(')');
}
int COMlength = 0, portlength = 0, pos = 0;
COMlength = stop - start;
portlength = stop - start - 3;
pos = start + 3;
//Console.WriteLine("COM: {0}", ComArray[arrayindex]);
ComDummy = ComArray[arrayindex].Substring(start, COMlength);
//Console.WriteLine("ComDummy: {0}", ComDummy);
ComNumber = Convert.ToInt32(ComArray[arrayindex].Substring(pos, portlength));
Console.WriteLine("ComPort Number: {0}", ComNumber);
Console.Read();
}
static List<USBDeviceInfo> GetUSBDevices()
{
List<USBDeviceInfo> devices = new List<USBDeviceInfo>();
ManagementObjectCollection collection;
using (var searcher = new ManagementObjectSearcher(#"Select * From Win32_PnPEntity"))
collection = searcher.Get();
bool kappa = true;
foreach (var device in collection)
{
devices.Add(new USBDeviceInfo(
(string)device.GetPropertyValue("DeviceID"),
(string)device.GetPropertyValue("PNPDeviceID"),
(string)device.GetPropertyValue("Description"),
(string)device.GetPropertyValue("Name"),
(string)device.GetPropertyValue("Service")
));
***//if ((devices.Exists(element => element.Description == "PI C-863")) && kappa)
//{
// Console.WriteLine("Found PI C-863!");
// kappa = false;
// //break;
//}*** <<< THIS IF() BREAKS MY CODE
}
collection.Dispose();
return devices;
}
}
class USBDeviceInfo
{
public USBDeviceInfo(string deviceID, string pnpDeviceID, string description, string name, string var)
{
this.DeviceID = deviceID;
this.PnpDeviceID = pnpDeviceID;
this.Description = description;
this.Name = name;
this.Var = var;
}
public string DeviceID { get; private set; }
public string PnpDeviceID { get; private set; }
public string Description { get; private set; }
public string Name { get; private set; }
public string Var { get; private set; }
}
The if(devices.Exist) question breaks my code if I use it and let if break the loop, can somebody explain why, and what i could do?
(Code works fine so far, but not being able to break the loop slows it down quite a bit)
Thanks in advance :)
Regards, Cinnabar
You should try :
static List<USBDeviceInfo> GetUSBDevices()
{
ManagementObjectCollection collection;
using (var searcher = new ManagementObjectSearcher(#"Select * From Win32_PnPEntity"))
collection = searcher.Get();
foreach (var device in collection)
{
if(device.GetPropertyValue("Description").Equals("PI C-863"))
{
Console.WriteLine("Found PI C-863!");
break;
}
}
collection.Dispose();
return devices;
}
I did not test it, but i think iterating over a List while adding into it could be the issue.
SerialPort.GetPortNames() reads the comports on computer. Use following code to read the comports and fill combo box (dropdown).
private void refreshPortChoices()
{
int selectedPortIndex = this.cbbPortName.SelectedIndex;
this.cbbPortName.Items.Clear();
this.cbbPortName.Items.AddRange(SerialPort.GetPortNames());
if (selectedPortIndex < this.cbbPortName.Items.Count)
{
this.cbbPortName.SelectedIndex = selectedPortIndex;
}
if (this.cbbPortName.Items.Count == 0)
{
this.cbbPortName.Items.Add("none");
this.btnConnection.Enabled = false;
}
else
{
this.btnConnection.Enabled = true;
}
}

Extract Embedded Image Object in RTF

I have rtf documents that include an embedded object (an image). I need to extract this as an Image object (or any other usable format). I have checked out this CodeProject article but the default apps don't render it correctly (They render the 'default image' image, not the image itself), so I moved on.
Here is a sample of the RTF Code (I had to shorten it because of size):
{\rtf1\ansi\deff0{\fonttbl{\f0\fnil\fcharset0 MS Sans Serif;}}
\viewkind4\uc1\pard\lang1033\f0\fs18{\object\objemb{\*\objclass Package}\objw855\objh810{\*\objdata
01050000
02000000
08000000
5061636b61676500
00000000
00000000
1f900000
02007369675f5f2e6a706700433a5c55736572735c726563657074696f6e5c4465736b746f705c
5369676e6174757265735c7369675f5f2e6a7067000000030034000000433a5c55736572735c52
45434550547e315c417070446174615c4c6f63616c5c54656d705c7369675f5f20283132292e6a
706700c18e0000ffd8ffe000104a46494600010101004800470000ffdb00430001010101010101
010101010101010101010101010101010101010101010101010101010101010101010101010101
010101010101010101010101010101010101ffdb00430101010101010101010101010101010101
010101010101010101010101010101010101010101010101010101010101010101010101010101
010101010101010101ffc0001108012c03e803012200021101031101ffc4001f00010002030002
0301000000000000000000090a07080b050602030401ffc4003f10000006030001040201030301
04070900000203040506010708090a11121314152116172223314118192532591a24576598d6d8
2933384651788497b7ffc4001a010101000301010000000000000000000000030204050106ffc4
002b11010003010100020103030402030000000002030401051112130614211522230731415124
32536162ffda000c03010002110311003f00bfc000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000
...
005c0072006500630065007000740069006f006e005c004400650073006b0074006f0070005c00
5300690067006e006100740075007200650073005c007300690067005f005f002e006a00700067
00
01050000
00000000
}{\result{\pict\wmetafile8\picw2010\pich1905\picwgoal855\pichgoal810
0100090000033b0700000200210600000000050000000b0200000000050000000c02350038001c
000000fb02f4ff000000000000900100000001000000005365676f65205549000e0a52104c2308
00dd1900d894ef758001f3758d0e664a040000002d010000050000000902000000000500000001
02ffffff00a5000000410bc600880020002000000000002000200000000c002800000020000000
400000000100010000000000000100000000000000000000000000000000000000000000ffffff
...
0021001c001c000000fb021000070000000000bc02000000000102022253797374656d00008d0e
664a00000a0022008a0100000000ffffffff8cdd1900040000002d010100030000000000
}}}\par
}
Here is a piece of code that can extract all objects ('Package' class objects) from an RTF stream:
public static void ExtractPackageObjects(string filePath)
{
using (StreamReader sr = new StreamReader(filePath))
{
RtfReader reader = new RtfReader(sr);
IEnumerator<RtfObject> enumerator = reader.Read().GetEnumerator();
while(enumerator.MoveNext())
{
if (enumerator.Current.Text == "object")
{
if (RtfReader.MoveToNextControlWord(enumerator, "objclass"))
{
string className = RtfReader.GetNextText(enumerator);
if (className == "Package")
{
if (RtfReader.MoveToNextControlWord(enumerator, "objdata"))
{
byte[] data = RtfReader.GetNextTextAsByteArray(enumerator);
using (MemoryStream packageData = new MemoryStream())
{
RtfReader.ExtractObjectData(new MemoryStream(data), packageData);
packageData.Position = 0;
PackagedObject po = PackagedObject.Extract(packageData);
File.WriteAllBytes(po.DisplayName, po.Data);
}
}
}
}
}
}
}
}
And here are the utility classes that this code uses. There is a simple stream-based RTF parser that allows to get to the interesting control words.
There is also a utility to extract data from a serialized Object Packager instance. Object Packager is an almost 20-years ago OLE1.0 thing and the serialized binary format is not documented (to my knowledge), but it's understandable.
This works fine on your provided sample, but you may have to adapt things around.
public class RtfReader
{
public RtfReader(TextReader reader)
{
if (reader == null)
throw new ArgumentNullException("reader");
Reader = reader;
}
public TextReader Reader { get; private set; }
public IEnumerable<RtfObject> Read()
{
StringBuilder controlWord = new StringBuilder();
StringBuilder text = new StringBuilder();
Stack<RtfParseState> stack = new Stack<RtfParseState>();
RtfParseState state = RtfParseState.Group;
do
{
int i = Reader.Read();
if (i < 0)
{
if (!string.IsNullOrWhiteSpace(controlWord.ToString()))
yield return new RtfControlWord(controlWord.ToString());
if (!string.IsNullOrWhiteSpace(text.ToString()))
yield return new RtfText(text.ToString());
yield break;
}
char c = (char)i;
// noise chars
if ((c == '\r') ||
(c == '\n'))
continue;
switch (state)
{
case RtfParseState.Group:
if (c == '{')
{
stack.Push(state);
break;
}
if (c == '\\')
{
state = RtfParseState.ControlWord;
break;
}
break;
case RtfParseState.ControlWord:
if (c == '\\')
{
// another controlWord
if (!string.IsNullOrWhiteSpace(controlWord.ToString()))
{
yield return new RtfControlWord(controlWord.ToString());
controlWord.Clear();
}
break;
}
if (c == '{')
{
// a new group
state = RtfParseState.Group;
if (!string.IsNullOrWhiteSpace(controlWord.ToString()))
{
yield return new RtfControlWord(controlWord.ToString());
controlWord.Clear();
}
break;
}
if (c == '}')
{
// close group
state = stack.Count > 0 ? stack.Pop() : RtfParseState.Group;
if (!string.IsNullOrWhiteSpace(controlWord.ToString()))
{
yield return new RtfControlWord(controlWord.ToString());
controlWord.Clear();
}
break;
}
if (!Char.IsLetterOrDigit(c))
{
state = RtfParseState.Text;
text.Append(c);
if (!string.IsNullOrWhiteSpace(controlWord.ToString()))
{
yield return new RtfControlWord(controlWord.ToString());
controlWord.Clear();
}
break;
}
controlWord.Append(c);
break;
case RtfParseState.Text:
if (c == '\\')
{
state = RtfParseState.EscapedText;
break;
}
if (c == '{')
{
if (!string.IsNullOrWhiteSpace(text.ToString()))
{
yield return new RtfText(text.ToString());
text.Clear();
}
// a new group
state = RtfParseState.Group;
break;
}
if (c == '}')
{
if (!string.IsNullOrWhiteSpace(text.ToString()))
{
yield return new RtfText(text.ToString());
text.Clear();
}
// close group
state = stack.Count > 0 ? stack.Pop() : RtfParseState.Group;
break;
}
text.Append(c);
break;
case RtfParseState.EscapedText:
if ((c == '\\') || (c == '}') || (c == '{'))
{
state = RtfParseState.Text;
text.Append(c);
break;
}
// ansi character escape
if (c == '\'')
{
text.Append(FromHexa((char)Reader.Read(), (char)Reader.Read()));
break;
}
if (!string.IsNullOrWhiteSpace(text.ToString()))
{
yield return new RtfText(text.ToString());
text.Clear();
}
// in fact, it's a normal controlWord
controlWord.Append(c);
state = RtfParseState.ControlWord;
break;
}
}
while (true);
}
public static bool MoveToNextControlWord(IEnumerator<RtfObject> enumerator, string word)
{
if (enumerator == null)
throw new ArgumentNullException("enumerator");
while (enumerator.MoveNext())
{
if (enumerator.Current.Text == word)
return true;
}
return false;
}
public static string GetNextText(IEnumerator<RtfObject> enumerator)
{
if (enumerator == null)
throw new ArgumentNullException("enumerator");
while (enumerator.MoveNext())
{
RtfText text = enumerator.Current as RtfText;
if (text != null)
return text.Text;
}
return null;
}
public static byte[] GetNextTextAsByteArray(IEnumerator<RtfObject> enumerator)
{
if (enumerator == null)
throw new ArgumentNullException("enumerator");
while (enumerator.MoveNext())
{
RtfText text = enumerator.Current as RtfText;
if (text != null)
{
List<byte> bytes = new List<byte>();
for (int i = 0; i < text.Text.Length; i += 2)
{
bytes.Add((byte)FromHexa(text.Text[i], text.Text[i + 1]));
}
return bytes.ToArray();
}
}
return null;
}
// Extracts an EmbeddedObject/ObjectHeader from a stream
// see [MS -OLEDS]: Object Linking and Embedding (OLE) Data Structures for more information
// chapter 2.2: OLE1.0 Format Structures
public static void ExtractObjectData(Stream inputStream, Stream outputStream)
{
if (inputStream == null)
throw new ArgumentNullException("inputStream");
if (outputStream == null)
throw new ArgumentNullException("outputStream");
BinaryReader reader = new BinaryReader(inputStream);
reader.ReadInt32(); // OLEVersion
int formatId = reader.ReadInt32(); // FormatID
if (formatId != 2) // see 2.2.4 Object Header. 2 means EmbeddedObject
throw new NotSupportedException();
ReadLengthPrefixedAnsiString(reader); // className
ReadLengthPrefixedAnsiString(reader); // topicName
ReadLengthPrefixedAnsiString(reader); // itemName
int nativeDataSize = reader.ReadInt32();
byte[] bytes = reader.ReadBytes(nativeDataSize);
outputStream.Write(bytes, 0, bytes.Length);
}
// see chapter 2.1.4 LengthPrefixedAnsiString
private static string ReadLengthPrefixedAnsiString(BinaryReader reader)
{
int length = reader.ReadInt32();
if (length == 0)
return string.Empty;
byte[] bytes = reader.ReadBytes(length);
return Encoding.Default.GetString(bytes, 0, length - 1);
}
private enum RtfParseState
{
ControlWord,
Text,
EscapedText,
Group
}
private static char FromHexa(char hi, char lo)
{
return (char)byte.Parse(hi.ToString() + lo, NumberStyles.HexNumber);
}
}
// Utility class to parse an OLE1.0 OLEOBJECT
public class PackagedObject
{
private PackagedObject()
{
}
public string DisplayName { get; private set; }
public string IconFilePath { get; private set; }
public int IconIndex { get; private set; }
public string FilePath { get; private set; }
public byte[] Data { get; private set; }
private static string ReadAnsiString(BinaryReader reader)
{
StringBuilder sb = new StringBuilder();
do
{
byte b = reader.ReadByte();
if (b == 0)
return sb.ToString();
sb.Append((char)b);
}
while (true);
}
public static PackagedObject Extract(Stream inputStream)
{
if (inputStream == null)
throw new ArgumentNullException("inputStream");
BinaryReader reader = new BinaryReader(inputStream);
reader.ReadUInt16(); // sig
PackagedObject po = new PackagedObject();
po.DisplayName = ReadAnsiString(reader);
po.IconFilePath = ReadAnsiString(reader);
po.IconIndex = reader.ReadUInt16();
int type = reader.ReadUInt16();
if (type != 3) // 3 is file, 1 is link
throw new NotSupportedException();
reader.ReadInt32(); // nextsize
po.FilePath = ReadAnsiString(reader);
int dataSize = reader.ReadInt32();
po.Data = reader.ReadBytes(dataSize);
// note after that, there may be unicode + long path info
return po;
}
}
public class RtfObject
{
public RtfObject(string text)
{
if (text == null)
throw new ArgumentNullException("text");
Text = text.Trim();
}
public string Text { get; private set; }
}
public class RtfText : RtfObject
{
public RtfText(string text)
: base(text)
{
}
}
public class RtfControlWord : RtfObject
{
public RtfControlWord(string name)
: base(name)
{
}
}
OK, this should work for you. To demonstrate my solution, I created a WinForms project with a PictureBox whose paint event handler was mapped to the following function:
private void rtfImage_Paint(object sender, PaintEventArgs e)
{
string rtfStr = System.IO.File.ReadAllText("MySampleFile.rtf");
string imageDataHex = ExtractImgHex(rtfStr);
byte[] imageBuffer = ToBinary(imageDataHex);
Image image;
using (MemoryStream stream = new MemoryStream(imageBuffer))
{
image = Image.FromStream(stream);
}
Rectangle rect = new Rectangle(0, 0, 100, 100);
e.Graphics.DrawImage(image, rect);
}
This code relies the on the System.Drawing.Image.FromStream() method, along with two "helper" functions:
A string extractor:
string ExtractImgHex(string s)
{
// I'm sure you could use regex here, but this works.
// This assumes one picture per file; loops required otherwise
int pictTagIdx = s.IndexOf("{\\pict\\");
int startIndex = s.IndexOf(" ", pictTagIdx)+1;
int endIndex = s.IndexOf("}", startIndex);
return s.Substring(startIndex, endIndex - startIndex);
}
... and a binary converter:
public static byte[] ToBinary(string imageDataHex)
{
//this function taken entirely from:
// http://www.codeproject.com/Articles/27431/Writing-Your-Own-RTF-Converter
if (imageDataHex == null)
{
throw new ArgumentNullException("imageDataHex");
}
int hexDigits = imageDataHex.Length;
int dataSize = hexDigits / 2;
byte[] imageDataBinary = new byte[dataSize];
StringBuilder hex = new StringBuilder(2);
int dataPos = 0;
for (int i = 0; i < hexDigits; i++)
{
char c = imageDataHex[i];
if (char.IsWhiteSpace(c))
{
continue;
}
hex.Append(imageDataHex[i]);
if (hex.Length == 2)
{
imageDataBinary[dataPos] = byte.Parse(hex.ToString(), System.Globalization.NumberStyles.HexNumber);
dataPos++;
hex.Remove(0, 2);
}
}
return imageDataBinary;
}
Below code can extract all type of embedded objects. including image/docs/mails etc with original file name. And save them in a local path.
string MyDir = #"E:\temp\";
Document doc = new Document(MyDir + "Requirement#4.rtf");
NodeCollection nodeColl = doc.GetChildNodes(NodeType.Shape, true);
foreach (var node in nodeColl)
{
Shape shape1 = (Shape)node;
if (shape1.OleFormat != null)
{
shape1.OleFormat.Save(MyDir + shape1.OleFormat.SuggestedFileName + shape1.OleFormat.SuggestedExtension);
}
}

Setting focus to already opened Tab of Internet Explorer from C# program using .net 2.0

I have two questions.
How can I set focus to already opened Tab of Internet Explorer from C# program using .net 2.0.
How can I open a new URL in a new Tab of running Internet Explorer instance (not in new window.) from C# program.
I can only use .net up to 2.0.
Your help will be appreciated.
Here is the code how to activate tab based on URL address of the tab. I tested and it works fine. You can add your functionality how to activate tab based on Text/Description, etc. If you need have it running under .net 2.0 then change var to specific type.
Here is an actual code itself. I wrapped it in separate class.
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Accessibility;
namespace IETabsInteraction
{
internal class TabActivator
{
#region Nested type: OBJID
private enum OBJID : uint
{
OBJID_WINDOW = 0x00000000,
}
#endregion
#region Declarations
private const int CHILDID_SELF = 0;
private readonly IntPtr _hWnd;
private IAccessible _accessible;
[DllImport("oleacc.dll")]
private static extern int AccessibleObjectFromWindow(IntPtr hwnd, uint id, ref Guid iid,
[In, Out, MarshalAs(UnmanagedType.IUnknown)] ref object
ppvObject);
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass,
string lpszWindow);
[DllImport("oleacc.dll")]
private static extern int AccessibleChildren(IAccessible paccContainer, int iChildStart, int cChildren,
[In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] object[] rgvarChildren, out int pcObtained);
#endregion
#region Constructors
internal TabActivator(IntPtr ieHandle)
{
_hWnd = ieHandle;
AccessibleObjectFromWindow(GetDirectUIHWND(ieHandle), OBJID.OBJID_WINDOW, ref _accessible);
CheckForAccessible();
}
private TabActivator(IAccessible acc)
{
if (acc == null)
throw new Exception("Could not get accessible");
_accessible = acc;
}
#endregion
private TabActivator[] Children
{
get
{
var num = 0;
var res = GetAccessibleChildren(_accessible, out num);
if (res == null)
return new TabActivator[0];
var list = new List<TabActivator>(res.Length);
foreach (object obj in res)
{
var acc = obj as IAccessible;
if (acc != null)
list.Add(new TabActivator(acc));
}
return list.ToArray();
}
}
private int ChildCount
{
get { return _accessible.accChildCount; }
}
/// <summary>
/// Gets LocationUrl of the tab
/// </summary>
private string LocationUrl
{
get
{
var url = _accessible.accDescription[CHILDID_SELF];
if (url.Contains(Environment.NewLine))
url = url.Split('\n')[1];
return url;
}
}
private void CheckForAccessible()
{
if (_accessible == null)
throw new Exception("Could not get accessible. Accessible can't be null");
}
internal void ActivateByTabsUrl(string tabsUrl)
{
var tabIndexToActivate = GetTabIndexToActivate(tabsUrl);
AccessibleObjectFromWindow(GetDirectUIHWND(_hWnd), OBJID.OBJID_WINDOW, ref _accessible);
CheckForAccessible();
var index = 0;
var ieDirectUIHWND = new TabActivator(_hWnd);
foreach (var accessor in ieDirectUIHWND.Children)
{
foreach (var child in accessor.Children)
{
foreach (var tab in child.Children)
{
if (tabIndexToActivate >= child.ChildCount - 1)
return;
if (index == tabIndexToActivate)
{
tab.ActivateTab();
return;
}
index++;
}
}
}
}
private void ActivateTab()
{
_accessible.accDoDefaultAction(CHILDID_SELF);
}
private int GetTabIndexToActivate(string tabsUrl)
{
AccessibleObjectFromWindow(GetDirectUIHWND(_hWnd), OBJID.OBJID_WINDOW, ref _accessible);
CheckForAccessible();
var index = 0;
var ieDirectUIHWND = new TabActivator(_hWnd);
foreach (var accessor in ieDirectUIHWND.Children)
{
foreach (var child in accessor.Children)
{
foreach (var tab in child.Children)
{
var tabUrl = tab.LocationUrl;
if (!string.IsNullOrEmpty(tabUrl))
{
if (tab.LocationUrl.Contains(tabsUrl))
return index;
}
index++;
}
}
}
return -1;
}
private IntPtr GetDirectUIHWND(IntPtr ieFrame)
{
// For IE 8:
var directUI = FindWindowEx(ieFrame, IntPtr.Zero, "CommandBarClass", null);
directUI = FindWindowEx(directUI, IntPtr.Zero, "ReBarWindow32", null);
directUI = FindWindowEx(directUI, IntPtr.Zero, "TabBandClass", null);
directUI = FindWindowEx(directUI, IntPtr.Zero, "DirectUIHWND", null);
if (directUI == IntPtr.Zero)
{
// For IE 9:
//directUI = FindWindowEx(ieFrame, IntPtr.Zero, "WorkerW", "Navigation Bar");
directUI = FindWindowEx(ieFrame, IntPtr.Zero, "WorkerW", null);
directUI = FindWindowEx(directUI, IntPtr.Zero, "ReBarWindow32", null);
directUI = FindWindowEx(directUI, IntPtr.Zero, "TabBandClass", null);
directUI = FindWindowEx(directUI, IntPtr.Zero, "DirectUIHWND", null);
}
return directUI;
}
private static int AccessibleObjectFromWindow(IntPtr hwnd, OBJID idObject, ref IAccessible acc)
{
var guid = new Guid("{618736e0-3c3d-11cf-810c-00aa00389b71}"); // IAccessibleobject obj = null;
object obj = null;
var num = AccessibleObjectFromWindow(hwnd, (uint) idObject, ref guid, ref obj);
acc = (IAccessible) obj;
return num;
}
private static object[] GetAccessibleChildren(IAccessible ao, out int childs)
{
childs = 0;
object[] ret = null;
var count = ao.accChildCount;
if (count > 0)
{
ret = new object[count];
AccessibleChildren(ao, 0, count, ret, out childs);
}
return ret;
}
}
}
To execute this code use:
var hWnd = (IntPtr)ie.HWND;
new TabActivator(hWnd).ActivateByTabsUrl("www.stackoverflow.com");
To answer your second question. You will need to find ie that you have already running:
private static void OpenTabInExistingIE()
{
var shellWindows = new ShellWindows();
// check if IE is open
if (shellWindows.Count > 0)
((InternetExplorer)shellWindows.Item(0)).Navigate2("www.stackoverflow.com", 2048);
}
For all these code you will have to add reference to SHDocVw.dll and
#using SHDocVw;
Here are flags for Navigate2 method
Enum BrowserNavConstants
navOpenInNewWindow = 1
navNoHistory = 2
navNoReadFromCache = 4
navNoWriteToCache = 8
navAllowAutosearch = 16
navBrowserBar = 32
navHyperlink = 64
navEnforceRestricted = 128
navNewWindowsManaged = 256
navUntrustedForDownload = 512
navTrustedForActiveX = 1024
navOpenInNewTab = 2048
navOpenInBackgroundTab = 4096
navKeepWordWheelText = 8192
navVirtualTab = 16384
navBlockRedirectsXDomain = 32768
navOpenNewForegroundTab = 65536
End Enum

Categories