How to enumerate all Bluetooth services? - c#

I want to get the list of available Bluetooth services for any Bluetooth device.
I found BluetoothEnumerateInstalledServices from Windows API, but it enumerates only Installed services. This way I get a list of 3 services instead of 4.
How do I get a list of all services on a Bluetooth device?

I found an one way, but it does not provide full necessary information:
#pragma comment(lib, "ws2_32.lib")
#include <winsock2.h>
#include <Ws2bth.h>
#pragma comment(lib, "Bthprops.lib")
#include <BluetoothAPIs.h>
#include <stdio.h>
#include <iostream>
int main(int argc, char** argv)
{
WSADATA data;
if (WSAStartup(0x0202, &data) != 0)
{
// Выход по ошибке
printf("WSACleanup() failed with error code %ld\n", WSAGetLastError());
return 1;
}
#define BUF_SIZE 10240
WSAQUERYSET* pQuerySet = (WSAQUERYSET*) new BYTE[BUF_SIZE];
ZeroMemory(pQuerySet, BUF_SIZE);
pQuerySet->dwSize = sizeof(WSAQUERYSET);
pQuerySet->dwNameSpace = NS_BTH;
// Запускаем поиск устройств
HANDLE lookupHandle = 0;
int lookupResult = WSALookupServiceBegin(pQuerySet,
LUP_RETURN_NAME | LUP_CONTAINERS | LUP_RETURN_ADDR | LUP_FLUSHCACHE |
LUP_RETURN_TYPE | LUP_RETURN_BLOB | LUP_RES_SERVICE,
&lookupHandle);
if (lookupResult != 0)
{
// Ошибка при инициализации поиска
printf("WSALookupServiceBegin() failed with error code %ld\n", WSAGetLastError());
}
else
{
printf("WSALookupServiceBegin() is OK\n");
}
while (lookupResult == 0)
{
DWORD bufferLen = BUF_SIZE;
lookupResult = WSALookupServiceNext(lookupHandle,
LUP_RETURN_NAME | LUP_RETURN_ADDR,
&bufferLen,
pQuerySet);
if (lookupResult != 0)
break;
DWORD addressLength = 128;
char* addressString = new char[addressLength];
int result = WSAAddressToString(pQuerySet->lpcsaBuffer->RemoteAddr.lpSockaddr,
pQuerySet->lpcsaBuffer->RemoteAddr.iSockaddrLength,
NULL,
(LPWSTR)addressString,
&addressLength);
if (result != 0)
{
printf("\n WSAAddressToString() for remote address failed with error code %ld\n", WSAGetLastError());
}
else {
printf("MAC: ");
printf("%S ", addressString);
printf("Name: ");
wprintf(pQuerySet->lpszServiceInstanceName);
printf("\n");
WSAQUERYSET* pQuerySetServices = (WSAQUERYSET*) new BYTE[BUF_SIZE];
ZeroMemory(pQuerySetServices, BUF_SIZE);
pQuerySetServices->dwSize = sizeof(WSAQUERYSET);
pQuerySetServices->dwNameSpace = NS_BTH;
pQuerySetServices->dwNumberOfCsAddrs = 0;
pQuerySetServices->lpszContext = (LPWSTR)addressString;
pQuerySetServices->lpServiceClassId = (GUID*)&L2CAP_PROTOCOL_UUID;
HANDLE lookupServicesHandle = 0;
int lookupServicesResult = WSALookupServiceBegin(pQuerySetServices, LUP_RETURN_NAME | LUP_RETURN_TYPE | LUP_RES_SERVICE | LUP_RETURN_ADDR | LUP_RETURN_BLOB | LUP_RETURN_COMMENT, &lookupServicesHandle);
if (lookupServicesResult != 0)
{
printf("WSALookupServiceBegin() failed with error code %ld\n", WSAGetLastError());
}
else
{
while (lookupServicesResult == 0)
{
DWORD bufferLen = BUF_SIZE;
lookupServicesResult = WSALookupServiceNext(lookupServicesHandle,
LUP_RETURN_ALL,
&bufferLen,
pQuerySetServices);
if (lookupServicesResult != 0)
break;
GUID guid = *pQuerySetServices->lpServiceClassId;
OLECHAR* guidString;
StringFromCLSID(guid, &guidString);
printf(" ");
wprintf(guidString);
printf(" ");
wprintf(pQuerySetServices->lpszServiceInstanceName);
printf("\n");
}
WSALookupServiceEnd(lookupServicesHandle);
}
}
}
WSALookupServiceEnd(lookupHandle);
WSACleanup();
}
Output:
MAC: (00:1E:B5:8C:64:49) Name: Moga Pro HID
{00000000-0000-0000-0000-000000000000}
{00000000-0000-0000-0000-000000000000} Android Controller Gen-2(ACC)
MAC: (30:39:26:FE:C8:62) Name: SBH20
{00000000-0000-0000-0000-000000000000} Hands-Free unit
{00000000-0000-0000-0000-000000000000} Headset
{00000000-0000-0000-0000-000000000000}
{00000000-0000-0000-0000-000000000000}
{00000000-0000-0000-0000-000000000000}
This method can get a right count of services, but the GUIDs always empty and some services does not have readable name.

Related

SIGABRT when calling mono_runtime_object_init

I am relatively new to C++, and have copied some code from a live stream to get started with embedding C# mono into my game engine.
I have created a C# script:
using System;
namespace Neutron {
public class Main {
public float FloatVar { get; set; }
public Main() {
Console.WriteLine("Main constructor");
}
public void PrintMessage() {
Console.WriteLine("Hello World from C#!");
}
public void PrintCustomMessage(string message) {
Console.WriteLine($"C# says: {message}");
}
}
}
and built it to
../Sandbox/Sandbox/bin/Debug/Sandbox.dll (which i have verified within the c++ program that I am embedding it into)
when i call mono_runtime_object_init passing the MonoObject* created from calling mono_object_new (I have verified that it doesnt return a nullptr)
The following error occurs:
* Assertion at object.c:116, condition `is_ok (error)' not met, function:mono_runtime_object_init, (null) assembly:/usr/lib/mono/4.5/mscorlib.dll type:TypeInitializationException member:(null)
Followed by a long stack trace.
Here are my relavent files:
ScriptingEngine.cpp (See the InitMono function towards the bottom)
//
// Created by aw1lt on 05/12/22.
//
#include "ScriptingEngine.h"
#include "Logger.h"
#include <mono/jit/jit.h>
#include <mono/metadata/assembly.h>
#include <fstream>
namespace Neutron {
struct ScriptEngineData {
MonoDomain* RootDomain = nullptr;
MonoDomain* AppDomain = nullptr;
MonoAssembly* CoreAssembly = nullptr;
};
char* ReadBytes(const std::string& filepath, uint32_t* outSize) {
std::ifstream stream(filepath, std::ios::binary | std::ios::ate);
if (!stream) {
// Failed to open the file
return nullptr;
}
std::streampos end = stream.tellg();
stream.seekg(0, std::ios::beg);
uint32_t size = end - stream.tellg();
if (size == 0) {
// File is empty
return nullptr;
}
char* buffer = new char[size];
stream.read((char*)buffer, size);
stream.close();
*outSize = size;
return buffer;
}
MonoAssembly* LoadCSharpAssembly(const std::string& assemblyPath) {
uint32_t fileSize = 0;
char* fileData = ReadBytes(assemblyPath, &fileSize);
// NOTE: We can't use this image for anything other than loading the assembly because this image doesn't have a reference to the assembly
MonoImageOpenStatus status;
MonoImage* image = mono_image_open_from_data_full(fileData, fileSize, 1, &status, 0);
if (status != MONO_IMAGE_OK) {
const char* errorMessage = mono_image_strerror(status);
Logger::Crit(errorMessage);
return nullptr;
}
MonoAssembly* assembly = mono_assembly_load_from_full(image, assemblyPath.c_str(), &status, 0);
mono_image_close(image);
// Don't forget to free the file data
delete[] fileData;
return assembly;
}
void PrintAssemblyTypes(MonoAssembly* assembly) {
MonoImage* image = mono_assembly_get_image(assembly);
const MonoTableInfo* typeDefinitionsTable = mono_image_get_table_info(image, MONO_TABLE_TYPEDEF);
int32_t numTypes = mono_table_info_get_rows(typeDefinitionsTable);
for (int32_t i = 0; i < numTypes; i++) {
uint32_t cols[MONO_TYPEDEF_SIZE];
mono_metadata_decode_row(typeDefinitionsTable, i, cols, MONO_TYPEDEF_SIZE);
const char* nameSpace = mono_metadata_string_heap(image, cols[MONO_TYPEDEF_NAMESPACE]);
const char* name = mono_metadata_string_heap(image, cols[MONO_TYPEDEF_NAME]);
Logger::Log(std::string(nameSpace) + "." + name);
}
}
static ScriptEngineData* s_Data;
void ScriptingEngine::Init() {
s_Data = new ScriptEngineData();
InitMono();
}
void ScriptingEngine::Shutdown() {
delete s_Data;
}
void ScriptingEngine::InitMono(std::string path) {
MonoDomain* rootDomain = mono_jit_init("NeutronJITRuntime");
Logger::Assert(rootDomain != nullptr);
//system(("cat " + path).c_str());
// Store the root domain pointer
s_Data->RootDomain = rootDomain;
// Create an App Domain
s_Data->AppDomain = mono_domain_create_appdomain("NeutronScriptRuntime", nullptr);
mono_domain_set(s_Data->AppDomain, true);
s_Data->CoreAssembly = LoadCSharpAssembly(path);
Logger::Assert(s_Data->CoreAssembly != nullptr);
MonoImage* assemblyImage = mono_assembly_get_image(s_Data->CoreAssembly);
MonoClass* monoClass = mono_class_from_name(assemblyImage, "Neutron", "Main");
Logger::Assert(monoClass != nullptr);
PrintAssemblyTypes(s_Data->CoreAssembly);
MonoObject* instance = mono_object_new(s_Data->AppDomain, monoClass);
Logger::Assert(instance != nullptr);
mono_runtime_object_init(instance); // << ERROR HAPPENS HERE
}
void ScriptingEngine::ShutdownMono() {
}
} // Neutron
my header file, ScriptingEngine.h
//
// Created by aw1lt on 05/12/22.
//
#ifndef NEUTRONENGINE_SCRIPTINGENGINE_H
#define NEUTRONENGINE_SCRIPTINGENGINE_H
#include <string>
namespace Neutron {
class ScriptingEngine {
public:
static void Init();
static void Shutdown();
private:
static void InitMono(std::string path = "../Sandbox/Sandbox/bin/Debug/Sandbox.dll");
static void ShutdownMono();
};
} // Neutron
#endif //NEUTRONENGINE_SCRIPTINGENGINE_H
I also tried the answers on this page.
Thank you, and sorry if this answer is a mess.

c++ com how to inherit IUIAutomationPropertyChangedEventHandler interface

c# code:
var nativeAutomation = new UIAutomationClient.CUIAutomation8();
nativeAutomation.AddPropertyChangedEventHandler(ele, UIA.TreeScope.TreeScope_Element, null, new handler(), pidarray);
the handler used in AddPropertyChangedEventHandler
class handler : UIAutomationClient.IUIAutomationPropertyChangedEventHandler
{
public void HandlePropertyChangedEvent(UIA.IUIAutomationElement src, int propertyId, object newValue)
{
UIA.IUIAutomationElement sourceElement = src as UIA.IUIAutomationElement;
Console.WriteLine(propertyId + ":" + newValue);
}
}
it works very well
but when i using c++:
#include "stdafx.h"
#include <Windows.h>
#include "test.h"
#include "cbt.h"
#include <UIAutomationClient.h>
#include <iostream>
#include <string>
#pragma comment(lib,"testDll.lib")
class A :public IUIAutomationPropertyChangedEventHandler {
ULONG m_ref;
public:
A() :m_ref(0)
{}
virtual HRESULT STDMETHODCALLTYPE QueryInterface(const IID &id, void** p) override {
// return IUnknown::QueryInterface(id,p);
REFIID d = { 0x0000001b,0x0000,0x0000, {0xC0,00,00,00,00,00,00,0x46} };// IdentityUnmarshal.
if (id == d) {
return E_NOINTERFACE;
}
*p = this;
return S_OK;
//return E_NOINTERFACE;
}
virtual ULONG STDMETHODCALLTYPE AddRef() override {
++m_ref;
//return IUnknown::AddRef();
return m_ref;
}
virtual ULONG STDMETHODCALLTYPE Release() override {
// return IUnknown::Release();
--m_ref;
if (!m_ref)
delete this;
return m_ref;
}
virtual HRESULT STDMETHODCALLTYPE HandlePropertyChangedEvent(
/* [in] */ __RPC__in_opt IUIAutomationElement *sender,
/* [in] */ PROPERTYID propertyId,
/* [in] */ VARIANT newValue) {
printf("dsdsdsdsddsd\n");
return S_OK;
};
};
int main()
{
// cbt::Instance();
CoInitializeEx(NULL, COINIT_MULTITHREADED);
IUIAutomation* am = NULL;
HRESULT hr = CoCreateInstance(__uuidof(CUIAutomation8), NULL, CLSCTX_INPROC_SERVER,
__uuidof(IUIAutomation), (void**)&am);
if (S_OK != hr)
hr = CoCreateInstance(__uuidof(CUIAutomation), NULL, CLSCTX_INPROC_SERVER,
__uuidof(IUIAutomation), (void**)&am);
A* a = new A;
std::string hx;
std::getline(std::cin, hx);
char* s = NULL;
HWND h = (HWND)strtol(hx.c_str(), &s, 16);
IUIAutomationElement* ele = NULL;
am->ElementFromHandle(h, &ele);
/*SAFEARRAY* sa = SafeArrayCreateVector(VT_I4, 0, 4);
LONG i = 0;
long pid = UIA_AutomationIdPropertyId;
SafeArrayPutElement(sa, &i, &pid);
i = 1;
pid = UIA_BoundingRectanglePropertyId;
SafeArrayPutElement(sa, &i, &pid);
i = 2;
pid = UIA_ClassNamePropertyId;
SafeArrayPutElement(sa, &i, &pid);
i = 3;
pid = UIA_NamePropertyId;
SafeArrayPutElement(sa, &i, &pid);
am->AddPropertyChangedEventHandler(ele, TreeScope_Element, NULL, p,sa );
SafeArrayDestroy(sa);*/
PROPERTYID *pids = new PROPERTYID[4];
pids[0] = UIA_AutomationIdPropertyId;
pids[1] = UIA_BoundingRectanglePropertyId;
pids[2] = UIA_ClassNamePropertyId;
pids[3] = UIA_NamePropertyId;
am->AddPropertyChangedEventHandlerNativeArray(ele, TreeScope_Element, NULL, a, pids, 4);
getchar();
CoUninitialize();
return 0;
}
so,it is very easy in c#.
but,with c++,i need to override Addref(), Release(), QueryInterface().
error occurs when call
am->AddPropertyChangedEventHandlerNativeArray(ele, TreeScope_Element, NULL, a, pids, 4);
looks like i should return a IMarshal object in the QueryInterface().
i think it needs a otherThread to loop events.
guys , how to code this IMarshal object?
ok,i got the answer at https://learn.microsoft.com/en-us/windows/win32/winauto/uiauto-howto-implement-event-handlers
my internet unstable these days.didn't see the page

Communication between C Server and C# Server just sending "p" character

I'm working on Client-Server application on Windows. Everything perfect running but when I want to send text (ex: Hello Dude) from C# client to C server then it send just "p" character. I dont know why? Thank you.
C# - Client Codes
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Net;
using System.Net.Sockets;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
string ip, nick;
int port;
Console.Write("Nick Giriniz : ");
nick = Console.ReadLine();
Socket soc = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
System.Net.IPAddress ipAdd = System.Net.IPAddress.Parse("192.168.1.37");
System.Net.IPEndPoint remoteEP = new IPEndPoint(ipAdd, 5150);
soc.Connect(remoteEP);
NetworkStream ag = new NetworkStream(soc);
BinaryReader okuyucu = new BinaryReader(ag);
baslangic:
byte[] byData = System.Text.Encoding.ASCII.GetBytes("Hi Dude");
soc.Send(byData);
Console.Write("Wait for answer");
string reply = okuyucu.ReadString();
Console.Write(reply );
goto baslangic;
}
}
}
C - Server
#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <string.h>
#define DEFAULT_PORT 5150
#define AZAMIUZUNLUK 1024
int g_port = DEFAULT_PORT; // Gelen Istekleri Dinleyecek Port
char g_szAddress[128]; // Gelen Istekleri Dinleyecek Arayuz
DWORD WINAPI ClientThread(LPVOID lpParam) //Dword = 32 bit isaretsiz tamsayi.
{
SOCKET sock =(SOCKET)lpParam;
int ret;
char gelenverix[512];
char str[AZAMIUZUNLUK];
for (;;) {
ret = recv(sock, gelenverix, 512, 0); //recv(socket,xxxxx, uzunluk, bayrak);
if (ret == 0)
break;
if (ret == SOCKET_ERROR) {
fprintf(stderr, "Mesajlasma Sona Erdi\n", WSAGetLastError());
break;
}
if (gelenverix == '\x1b')
break;
putchar(gelenverix);
}
return 0;
}
int main(void)
{
WSADATA wsd;
SOCKET sListen,sClient;
int addrSize;
HANDLE hThread;
DWORD dwThreadId;
struct sockaddr_in local, client;
if (WSAStartup(MAKEWORD(2,2), &wsd) != 0) {
fprintf(stderr, "WSAStartup yuklemesi basarisiz!\n");
return 1;
} else {
fprintf(stderr, "WSAStartup Yuklendi!\n");
}
sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
if (sListen == SOCKET_ERROR) {
fprintf(stderr, "Socket Baglantisi Basarisiz!\n", WSAGetLastError());
return 1;
} else {
fprintf(stderr, "Socket Baglantisi Basarili!\n", WSAGetLastError());
}
local.sin_addr.s_addr = htonl(INADDR_ANY); // ip adresimi kullan
local.sin_family = AF_INET; // adres ailesi Arpa Internet protokolu
local.sin_port = htons(g_port); // default port numarasi
if (bind(sListen, (struct sockaddr *)&local, sizeof(local)) == SOCKET_ERROR) {
fprintf(stderr, "bind() failed: %d\n", WSAGetLastError());
return 1;
}
listen(sListen, 8); //8 - cagri kurugunda izin verilen baglanti sayisi
for (;;) {
addrSize = sizeof(client);
sClient = accept(sListen, (struct sockaddr *) &client, &addrSize);
if (sClient == INVALID_SOCKET) {
fprintf(stderr, "accept() failed: %d\n", WSAGetLastError());
break;
}
fprintf(stderr, "Accepted client: %s:%d\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port));
hThread = CreateThread(NULL, 0, ClientThread, (LPVOID)sClient, 0, &dwThreadId);
if (hThread == NULL) {
fprintf(stderr, "CreateThread() failed: %d\n", GetLastError());
break;
}
CloseHandle(hThread);
}
closesocket(sListen);
WSACleanup();
return 0;
}
putchar(gelenverix) should make your compiler yell in pain, as it expects a char and the code passes it a char*.
Use puts() instead. Also make sure gelenverix is 0-terminated beforehand.
ret = recv(sock, gelenverix, 512 - 1, 0); /* One less as you need space to 0-terminate the buffer. */
if (ret == 0)
break;
if (ret == SOCKET_ERROR) {
...
break;
}
gelenverix[ret] = '\0'.
puts(gelenverix);
Or just do
for (size_t i = 0; i < ret; ++i)
{
putchar(gelenverix[i]);
}

C# Firewall, delete specific entry

I am currently programming a windows-firewallmanager for a company.
Problem is, that I can only delete an entry by name and not by an INetFwRule object or something.
There are entries, that have the same name two times where one is for TCP and the other one for UDP and we might want to delete only one of them.
I could delete both and create one of them afterwards again, but I would not like to use that workaround.
Does anyone have an easy solution to this?
You can only delete rules by name using the INetFwRules interface which seems to be a badly designed API because different rules can have the same name. A workaround is to filter the rules not only by name by also by the other properties that specifies the rule you want to delete. When you have found the rule to delete you can then rename the rule to a unique name using the INetFwRule interface.
You can then delete the rule using this unique temporary name.
Based on #"Martin Liversage" suggesting, here is a working C++ example tested with C# interop.
"AddAppFirewallRule" will only add the firewall rule if it doesn't exist.
"RemoveAppFirewallRule" will remove all firewall rules that match the exe path.
C/C++
#include "pch.h"
#include <windows.h>
#include <stdio.h>
#include <netfw.h>
#include <atlcomcli.h>
#include "Exports.h"
HRESULT WFCOMInitialize(INetFwPolicy2** ppNetFwPolicy2)
{
return CoCreateInstance(__uuidof(NetFwPolicy2), nullptr, CLSCTX_INPROC_SERVER, __uuidof(INetFwPolicy2), (void**)ppNetFwPolicy2);
}
extern "C"
{
MyFrameworkOSNative_EXPORT int MyFrameworkOSNative_AddAppFirewallRule(int privateNetworks, int publicNetworks, int domainNetworks, wchar_t* exePath, wchar_t* name, wchar_t* groupName, wchar_t* desc, wchar_t* ports, int tcp, int udp)
{
// declare locals
int result = 0;
HRESULT addRuleResult;
BSTR ruleName = SysAllocString(name);
BSTR ruleGroup = SysAllocString(groupName);
BSTR ruleDesc = SysAllocString(desc);
BSTR ruleExe = SysAllocString(exePath);
BSTR rulePorts = nullptr;
if (ports != nullptr) rulePorts = SysAllocString(ports);
INetFwPolicy2* policy = nullptr;
INetFwRules* rules = nullptr;
INetFwRule* rule = nullptr;
long profilesBitMask = 0;
HRESULT iterateResult = 0;
IUnknown* rulesCollection = nullptr;
IEnumVARIANT* variant = nullptr;
CComVariant var = {};
ULONG fetched = 0;
bool found = false;
// init
if (FAILED(WFCOMInitialize(&policy))) goto Cleanup;
if (FAILED(policy->get_Rules(&rules))) goto Cleanup;
//if (FAILED(policy->get_CurrentProfileTypes(&profilesBitMask))) goto Cleanup;
if (privateNetworks) profilesBitMask |= NET_FW_PROFILE2_PRIVATE;
if (publicNetworks) profilesBitMask |= NET_FW_PROFILE2_PUBLIC;
if (domainNetworks) profilesBitMask |= NET_FW_PROFILE2_DOMAIN;
if (FAILED(CoCreateInstance(__uuidof(NetFwRule), nullptr, CLSCTX_INPROC_SERVER, __uuidof(INetFwRule), (void**)&rule))) goto Cleanup;
// setup rule
rule->put_Name(ruleName);
rule->put_Description(ruleDesc);
rule->put_ApplicationName(ruleExe);
if (tcp && udp) rule->put_Protocol(NET_FW_IP_PROTOCOL_ANY);
else if (tcp) rule->put_Protocol(NET_FW_IP_PROTOCOL_TCP);
else if (udp) rule->put_Protocol(NET_FW_IP_PROTOCOL_UDP);
if (rulePorts != nullptr) rule->put_LocalPorts(rulePorts);
rule->put_Direction(NET_FW_RULE_DIR_MAX);
rule->put_Grouping(ruleGroup);
rule->put_Profiles(profilesBitMask);
rule->put_Action(NET_FW_ACTION_ALLOW);
rule->put_Enabled(VARIANT_TRUE);
// get rules enumerator
if (FAILED(rules->get__NewEnum(&rulesCollection))) goto Cleanup;
if (FAILED(rulesCollection->QueryInterface(__uuidof(IEnumVARIANT), (void**)&variant))) goto Cleanup;
// enumerate rules to check if it already exists
var.Clear();
iterateResult = variant->Next(1, &var, &fetched);
while (SUCCEEDED(iterateResult) && iterateResult != S_FALSE)
{
BSTR ruleEXEPath = nullptr;
INetFwRule* existingRule = nullptr;
long exitingRuleProfileBitMask = 0;
if (FAILED((V_DISPATCH(&var))->QueryInterface(__uuidof(INetFwRule), reinterpret_cast<void**>(&existingRule)))) goto Cleanup;
if (FAILED(existingRule->get_ApplicationName(&ruleEXEPath))) goto Cleanup;
if (FAILED(existingRule->get_Profiles(&exitingRuleProfileBitMask))) goto Cleanup;
if (ruleEXEPath != nullptr && wcscmp(ruleEXEPath, exePath) == 0 && exitingRuleProfileBitMask == profilesBitMask)// check if exe paths match
{
BSTR existingRuleName = nullptr;
if (SUCCEEDED(existingRule->get_Name(&existingRuleName)))
{
if (existingRuleName != nullptr)
{
if (wcscmp(ruleName, existingRuleName) == 0) found = true;
SysFreeString(existingRuleName);
}
}
}
// cleanup iteration
if (existingRule != nullptr)
{
existingRule->Release();
existingRule = nullptr;
}
if (ruleEXEPath != nullptr) SysFreeString(ruleEXEPath);
// exit loop if found
if (found) break;
// get next item in collection
var.Clear();
iterateResult = variant->Next(1, &var, &fetched);
}
// add rule if it doesn't already exist
if (!found)
{
addRuleResult = rules->Add(rule);
if (FAILED(addRuleResult)) goto Cleanup;
}
result = 1;// success
// cleanup resources
Cleanup:;
if (variant != nullptr) variant->Release();
if (rulesCollection != nullptr) rulesCollection->Release();
if (ruleName != nullptr) SysFreeString(ruleName);
if (ruleGroup != nullptr) SysFreeString(ruleGroup);
if (ruleDesc != nullptr) SysFreeString(ruleDesc);
if (ruleExe != nullptr) SysFreeString(ruleExe);
if (rulePorts != nullptr) SysFreeString(rulePorts);
if (rule != nullptr) rule->Release();
if (rules != nullptr) rules->Release();
if (policy != nullptr) policy->Release();
return result;
}
MyFrameworkOSNative_EXPORT int MyFrameworkOSNative_RemoveAppFirewallRule(wchar_t* exePath)
{
// declare locals
int result = 0;
INetFwPolicy2* policy = nullptr;
INetFwRules* rules = nullptr;
INetFwRule* rule = nullptr;
long profilesBitMask = 0;
HRESULT iterateResult = 0;
IUnknown* rulesCollection = nullptr;
IEnumVARIANT* variant = nullptr;
CComVariant var = {};
ULONG fetched = 0;
bool found = false;
// init
if (FAILED(WFCOMInitialize(&policy))) goto Cleanup;
if (FAILED(policy->get_Rules(&rules))) goto Cleanup;
// get rules enumerator
if (FAILED(rules->get__NewEnum(&rulesCollection))) goto Cleanup;
if (FAILED(rulesCollection->QueryInterface(__uuidof(IEnumVARIANT), (void**)&variant))) goto Cleanup;
// enumerate rules
var.Clear();
iterateResult = variant->Next(1, &var, &fetched);
while (SUCCEEDED(iterateResult) && iterateResult != S_FALSE)
{
BSTR ruleEXEPath = nullptr;
if (FAILED((V_DISPATCH(&var))->QueryInterface(__uuidof(INetFwRule), reinterpret_cast<void**>(&rule)))) goto Cleanup;
if (FAILED(rule->get_ApplicationName(&ruleEXEPath))) goto Cleanup;
if (ruleEXEPath != nullptr && wcscmp(ruleEXEPath, exePath) == 0)// check if exe paths match
{
found = true;
SysFreeString(ruleEXEPath);
BSTR ruleName = nullptr;
if (FAILED(rule->get_Name(&ruleName)))
{
if (ruleName != nullptr) SysFreeString(ruleName);
goto Cleanup;
}
if (FAILED(rules->Remove(ruleName)))
{
if (ruleName != nullptr) SysFreeString(ruleName);
goto Cleanup;
}
if (ruleName != nullptr) SysFreeString(ruleName);
// get next item in collection
var.Clear();
iterateResult = variant->Next(1, &var, &fetched);
continue;// continue to scan for more rules with same criteria
}
// cleanup iteration
if (rule != nullptr)
{
rule->Release();
rule = nullptr;
}
if (ruleEXEPath != nullptr) SysFreeString(ruleEXEPath);
// get next item in collection
var.Clear();
iterateResult = variant->Next(1, &var, &fetched);
}
if (!found) goto Cleanup;
result = 1;// success
// cleanup resources
Cleanup:;
if (variant != nullptr) variant->Release();
if (rulesCollection != nullptr) rulesCollection->Release();
if (rule != nullptr) rule->Release();
if (rules != nullptr) rules->Release();
if (policy != nullptr) policy->Release();
return result;
}
}
C#
[DllImport("MyFramework.OS.Native.dll")]
private static unsafe extern int VMyFrameworkOSNative_AddAppFirewallRule(int privateNetworks, int publicNetworks, int domainNetworks, char* exePath, char* name, char* groupName, char* desc, char* ports, int tcp, int udp);
[DllImport("MyFramework.OS.Native.dll")]
private static unsafe extern int MyFrameworkOSNative_RemoveAppFirewallRule(char* exePath);
public static unsafe bool AddAppFirewallRule(bool privateNetworks, bool publicNetworks, bool domainNetworks, string exePath, string ruleName, string ruleDesc, int port = -1, bool tcp = true, bool udp = true)
{
// ensure COM is init
Ole32.CoInitialize(IntPtr.Zero);
// invoke native method
string portValue = port.ToString();
fixed (char* exePathPtr = exePath)
fixed (char* ruleNamePtr = ruleName)
fixed (char* ruleDescPtr = ruleDesc)
fixed (char* portValuePtr = portValue)
{
return MyFrameworkOSNative_AddAppFirewallRule
(
privateNetworks ? 1 : 0,
publicNetworks ? 1 : 0,
domainNetworks ? 1 : 0,
exePathPtr,
ruleNamePtr, ruleNamePtr,
ruleDescPtr,
port > 0 ? portValuePtr : null,
tcp ? 1 : 0, udp ? 1 : 0
) != 0;
}
}
public static unsafe bool RemoveAppFirewallRule(string exePath)
{
// ensure COM is init
Ole32.CoInitialize(IntPtr.Zero);
// invoke native method
fixed (char* exePathPtr = exePath)
{
return VMyFrameworkOSNative_RemoveAppFirewallRule(exePathPtr) != 0;
}
}
UnitTests
[Fact]
public void AddAppFirewallRule()
{
using (var lib = new LibHandle("MyFramework.OS.Native.dll"))
{
Assert.True(NetworkUtils.AddAppFirewallRule(true, true, false, #"<Path-To-Exe>", "TestRule", "Test Rule Desc"));
}
}
[Fact]
public void RemoveAppFirewallRule()
{
using (var lib = new LibHandle("MyFramework.OS.Native.dll"))
{
Assert.True(NetworkUtils.RemoveAppFirewallRule(#"<Path-To-Exe>"));
}
}
public static void RemoveFirewallRules(string RuleName = "BreakermindCom")
{
try
{
Type tNetFwPolicy2 = Type.GetTypeFromProgID("HNetCfg.FwPolicy2");
INetFwPolicy2 fwPolicy2 = (INetFwPolicy2)Activator.CreateInstance(tNetFwPolicy2);
var currentProfiles = fwPolicy2.CurrentProfileTypes;
// Lista rules
// List<INetFwRule> RuleList = new List<INetFwRule>();
foreach (INetFwRule rule in fwPolicy2.Rules)
{
// Add rule to list
// RuleList.Add(rule);
// Console.WriteLine(rule.Name);
if (rule.Name.IndexOf(RuleName) != -1)
{
// Now add the rule
INetFwPolicy2 firewallPolicy = (INetFwPolicy2)Activator.CreateInstance(Type.GetTypeFromProgID("HNetCfg.FwPolicy2"));
firewallPolicy.Rules.Remove(rule.Name);
Console.WriteLine(rule.Name + " has been deleted from Firewall Policy");
}
}
}
catch (Exception r)
{
Console.WriteLine("Error delete rule from firewall");
}}
Look at this

How to reproduce quser.exe using API calls?

Quser.exe allows a client to see user sessions on a remote RDP server. For example,
C:\>quser /server:MyRDPserver
USERNAME SESSIONNAME ID STATE IDLE TIME LOGON TIME
userA 3 Disc 1+20:03 08/07/2014 12:36
userB 4 Disc 1+22:28 08/07/2014 10:38
I would like to build this functionality into a C++ or C# program. Yes, I could just spawn quser.exe and parse the output, but is there an Win32 API or .Net framework class that can give me the same information? Specifically:
User Name
Connection State
Logon time
I've found that using WMI (Win32_LoggedOnUser) to find the same information is unreliable, as it often lists stale connections. I've also tried the psloggedon approach of enumerating subkeys of HKEY_USERS and looking for the Volatile Environment key, but this also suffers from the same problem.
I'm going to answer my own question.
First of all, you need to make sure that permissions are set correctly on the target machine. This entails setting HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server\AllowRemoteRPC to 1. A powershell script to do this is:
# Get the service account credential
$cred = Get-Credential my_admin_account
$Target_Computers = #("Computer_1","Computer_2")
# open the remote registry
[long]$HIVE_HKLM = 2147483650
foreach($c in $Target_Computers)
{
$StdRegProv = Get-WmiObject -List -Namespace root\default -ComputerName $c -Credential $cred | where { $_.Name -eq "StdRegProv" }
$StdRegProv.SetDWORDValue($HIVE_HKLM, "SYSTEM\CurrentControlSet\Control\Terminal Server", "AllowRemoteRPC", 1)
}
As Xearinox said, for C++ you can use the WTSxxx functions in the Win32 API. Assuming your computers are not XP, here is some C++ code:
#include <string>
#include <iostream>
#include <iomanip>
#include <windows.h>
#include <WtsApi32.h>
using namespace std;
const unsigned num_connection_states = 10;
const wchar_t* connection_state_list[num_connection_states] = {
L"Active",
L"Connected",
L"ConnectQuery",
L"Shadow",
L"Disc",
L"Idle",
L"Listen",
L"Reset",
L"Down",
L"Init" };
int print_error(DWORD err)
{
// format the message
LPTSTR* ppBuffer = nullptr;
DWORD retval = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER, nullptr, err, 0, reinterpret_cast<LPTSTR>(ppBuffer), 0, nullptr);
// print out
wcerr << "Error: *ppBuffer" << endl;
return 1;
}
wstring format_time(const LARGE_INTEGER& time)
{
// convert to a local Win32 file time
FILETIME ft = { time.LowPart, time.HighPart };
FileTimeToLocalFileTime( &ft, &ft );
// convert to a system time
SYSTEMTIME st;
FileTimeToSystemTime( &ft, &st );
wchar_t local_date[255], local_time[255];
GetDateFormat( LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, local_date, sizeof(local_date)/sizeof(wchar_t) );
GetTimeFormat( LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, local_time, sizeof(local_time)/sizeof(wchar_t) );
wstring result = local_date;
result.append(L" ");
result.append(local_time);
return result;
}
const _int64 SECOND = 10000000;
const _int64 MINUTE = 60*SECOND;
const _int64 HOUR = 60*MINUTE;
const _int64 DAY = 24*HOUR;
wstring format_timespan(const LARGE_INTEGER& timespan)
{
// convert to a local Win32 file time
FILETIME ft = { timespan.LowPart, timespan.HighPart };
FileTimeToLocalFileTime( &ft, &ft );
// convert to a system time
SYSTEMTIME st;
FileTimeToSystemTime( &ft, &st );
wchar_t local_time[255];
int daydiff = floor(
GetTimeFormat( LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, local_time, sizeof(local_time)/sizeof(wchar_t) );
wstring result = local_date;
result.append(L" ");
result.append(local_time);
return result;
}
int wmain(int argc, wchar_t* argv[])
{
// check args
if(argc > 2)
{
wcout << "Usage: " << argv[0] << " [server_name]\n";
return 1;
}
// server name
bool current_server = true;
wstring server_name = L".";
if(argc == 2)
{
server_name = argv[1];
current_server = false;
}
// open the server
HANDLE hServer;
if(current_server)
hServer = WTS_CURRENT_SERVER_HANDLE;
else
hServer = WTSOpenServer(const_cast<LPWSTR>(server_name.c_str()));
// enumerate through the sessions
DWORD Count = 0;
WTS_SESSION_INFO* pSessionInfo = nullptr;
BOOL success = WTSEnumerateSessions(hServer, 0, 1, &pSessionInfo, &Count);
if(success == 0)
return false;
// write the headers
wcout << " " << left << setw(24) << "USERNAME";
wcout << setw(19) << "SESSIONNAME";
wcout << "ID ";
wcout << setw(9) << "STATE";
wcout << "IDLE TIME LOGON TIME";
// loop through each session
for(unsigned long s=0; s<Count; s++)
{
LPTSTR pBuffer = nullptr;
DWORD BytesReturned = 0;
wcout << "\n " << left;
// try getting all info at once
WTSINFO* info = nullptr;
success = WTSQuerySessionInformation(hServer, pSessionInfo[s].SessionId, WTSSessionInfo, reinterpret_cast<LPTSTR*>(&info), &BytesReturned);
bool have_wtsinfo = true;
if(!success)
{
// see why failed
DWORD err = GetLastError();
if(err == ERROR_NOT_SUPPORTED)
have_wtsinfo = false;
else
return print_error(err);
}
// print user name
wstring user_name;
if(have_wtsinfo)
user_name = info->UserName;
else
{
success = WTSQuerySessionInformation(hServer, pSessionInfo[s].SessionId, WTSUserName, &pBuffer, &BytesReturned);
if(!success)
continue;
user_name = pBuffer;
WTSFreeMemory(pBuffer);
}
wcout << setw(24) << user_name;
// print session name
wstring session_name;
if(have_wtsinfo)
session_name = info->WinStationName;
else
{
success = WTSQuerySessionInformation(hServer, pSessionInfo[s].SessionId, WTSWinStationName, &pBuffer, &BytesReturned);
if(!success)
continue;
session_name = pBuffer;
WTSFreeMemory(pBuffer);
}
wcout << setw(19) << session_name;
// print session ID
wcout << right << setw(2) << pSessionInfo[s].SessionId;
// print connection state
WTS_CONNECTSTATE_CLASS connect_state;
if(have_wtsinfo)
connect_state = info->State;
else
{
success = WTSQuerySessionInformation(hServer, pSessionInfo[s].SessionId, WTSConnectState, &pBuffer, &BytesReturned);
if(!success)
continue;
connect_state = *reinterpret_cast<WTS_CONNECTSTATE_CLASS*>(pBuffer);
WTSFreeMemory(pBuffer);
}
if(connect_state>=num_connection_states)
continue;
wcout << " " << left << setw(8) << connection_state_list[connect_state];
// get idle time
LARGE_INTEGER idle = info->CurrentTime;
idle.QuadPart -= info->LogonTime.QuadPart;
// print logon time - not supported
if(info->LogonTime.QuadPart!=0)
{
wcout << format_time(info->LogonTime);
}
// clean up
WTSFreeMemory(info);
}
// clean up
WTSFreeMemory(pSessionInfo);
if(!current_server)
WTSCloseServer(hServer);
}
For C#, the easiest way is to use the Cassia library, which is basically a C# wrapper around the same API functions.
You can call a Win32 API to create a process and pass the "quser /server:MyRDPserver" as parameters,I usually do like this:
PROCESS_INFORMATION process_info;
STARTUPINFOA startup_info;
string cmdline2;
char error_msg[1024];
memset(&process_info, 0, sizeof(process_info));
memset(&startup_info, 0, sizeof(startup_info));
startup_info.cb = sizeof(startup_info);
argc = argarray.size();
for(int i = 0; i < argc; i++) {
cmdline2 += argarray.at(i);
if(i != (argc - 1)) cmdline2 += " ";
}
string command = suCmdLineRemoveQuotations(argarray.at(0));
retval = CreateProcessA(command.c_str(), (LPSTR)cmdline2.c_str(), NULL, NULL, TRUE,
0, NULL, NULL, &startup_info, &process_info);
if (!retval) {
windows_error_string(error_msg, sizeof(error_msg));
error = error_msg;
return false;
}
WaitForSingleObject(process_info.hProcess, msecs);
if(GetExitCodeProcess(process_info.hProcess, &status)) {
// status maybe is STILL_ACTIVE, in that case, the process is killed
if(status == STILL_ACTIVE) {
TerminateProcess(process_info.hProcess, 1);
}
ecode = status;
}
return true;
when the process startup, you can redirect the output.If you use Qt,the problem become simple,you can use QProcess to implement.

Categories

Resources