Under Windows, performance counters have different names, depending on the operating system language. For example, on an English Windows version, there is the performance counter \Processor(_Total)\% Processor Time. The same counter is called \Prozessor(_Total)\Prozessorzeit (%) on a German Windows version.
Is there any way to retrieve the performance counter value in a language-independent way (using C++ or C#)? Or is there an alternative to get the processor load of the whole computer without performance counters?
Each PerfMon counter is given a unique (per machine) integer ID to identify the PerfMon counter (however in the case of the standard counters this id is guaranteed to stay the same).
The information linking PerfMon counters id's to both their US English name and their Localized name is stored in the registry in the following key:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib
Once you have used the registry to obtain the PerfMon counter name (which you can embed in your app as a constant for standard counters) you can use the PdhLookupPerfNameByIndex function to look up the localized name for the given counter ID.
See Using PDH APIs correctly in a localized language (Microsoft KB) for more details.
You might also find Finding perfmon counter id via winreg (StackOverflow) somewhat relevant.
Add this
using System.Runtime.InteropServices;
using Microsoft.Win32;
In your class import the DLL(my classed is named Program)
[DllImport("pdh.dll", SetLastError = true, CharSet = CharSet.Unicode)]
static extern UInt32 PdhLookupPerfIndexByName(string szMachineName, string szNameBuffer, ref uint pdwIndex);
Send the name of the counter you want in your OS language and it return the english NAME
public string GetEnglishName(string name)
{
string buffer2 = name;
UInt32 iRet2 = new UInt32();
iRet3 = PdhLookupPerfIndexByName(null, buffer2, ref iRet2);
//Console.WriteLine(iRet2.ToString());
RegistryKey pRegKey = Registry.LocalMachine;
pRegKey = pRegKey.OpenSubKey(#"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\009");
string[] after;
after = (string[])pRegKey.GetValue("Counter");
string value = iRet2.ToString();
int pos = Array.IndexOf(after, value);
return after[pos + 1];
}
Here is how to use it
Program m = new Program();
string result = m.GetEnglishName("Mémoire");
Console.WriteLine(result);
There are the WinAPI functions, QueryHighPerformanceCounter and QueryHighPerformanceFrequency.
Have you tried using the Pdh helper functions and the PdhAddEnglishCounter function?
My version of Full Path localization using PdhGetCounterInfoW.
std::wstring GetLocalizedCounterFullPath(const std::wstring& englishCounterName)
{
std::wstring localizedCounterName;
PDH_HQUERY queryHandle = nullptr;
try
{
std::ostringstream errorText;
auto status = PdhOpenQueryW(nullptr, 0, &queryHandle);
if (status != ERROR_SUCCESS)
{
errorText << "PdhOpenQueryW failed with " << std::hex << status;
throw std::runtime_error(errorText.str());
}
PDH_HCOUNTER counterHandle;
status = PdhAddEnglishCounterW(queryHandle, englishCounterName.data(), 0, &counterHandle);
if (status != ERROR_SUCCESS)
{
errorText << "PdhAddEnglishCounterW failed with " << std::hex << status;
throw std::runtime_error(errorText.str());
}
DWORD bufferSize = 0;
std::vector<unsigned char> counterInfo;
do
{
if (bufferSize != 0)
{
counterInfo.resize(bufferSize);
}
status = PdhGetCounterInfoW(counterHandle,
TRUE,
&bufferSize,
reinterpret_cast<PPDH_COUNTER_INFO_W>(counterInfo.data()));
}
while(static_cast<unsigned>(status) == PDH_MORE_DATA);
if (status != ERROR_SUCCESS)
{
errorText << "PdhGetCounterInfoW failed with " << std::hex << status;
throw std::runtime_error(errorText.str());
}
localizedCounterName = reinterpret_cast<PPDH_COUNTER_INFO_W>(counterInfo.data())->szFullPath;
status = PdhCloseQuery(queryHandle);
if (status != ERROR_SUCCESS)
{
errorText << "PdhCloseQuery failed with " << std::hex << status;
throw std::runtime_error(errorText.str());
}
}
catch (const std::exception& e)
{
std::wcout << e.what() << "\n";
PdhCloseQuery(queryHandle);
}
return localizedCounterName;
}
Related
If I run this:
Console.WriteLine("Foo".GetHashCode());
Console.WriteLine("Foo".GetHashCode());
it will print the same number twice but if I run the program again it will print a different number.
According to Microsoft and other places on the internet we cannot rely on GetHashCode function to return the same value. But if I plan on using it on strings only how can I make use of it and expect to always return the same value for the same string? I love how fast it is. It will be great if I could get the source code of it and use it on my application.
Reason why I need it (you may skip this part)
I have a lot of complex objects that I need to serialize and send them between inter process communication. As you know BinaryFormatter is now obsolete so I then tried System.Text.Json to serialize my objects. That was very fast but because I have a lot of complex objects deserialization did not work well because I am making heavy use of polymorphism. Then I tried Newtonsoft (json.net) and that work great with this example: https://stackoverflow.com/a/71398251/637142. But it was very slow. I then decided I will use the best option and that is ProtoBuffers. So I was using protobuf-net and that worked great but the problem is that I have some objects that are very complex and it was a pain to place thousands of attributes. For example I have a base class that was being used by 70 other classes I had to place an attribute of inheritance for every single one it was not practical. So lastly I decided to implement my own algorithm it was not that complicated. I just have to traverse the properties of each object and if one property was not a value type then traverse them again recursively. But in order for this custom serialization that I build to be fast I needed to store all reflection objects in memory. So I have a dictionary with the types and propertyInfos. So the first time I serialize it will be slow but then it is even faster than ProtoBuf! So yes this approach is fast but every process must have the same exact object otherwise it will not work. Another tradeoff is that it's size is larger than protobuf because every time I serialize a property I include the full name of that property before. As a result I want to hash the full name of the property into an integer (4 bytes) and the GetHashCode() function does exactly that!
A lot of people may suggest that I should use MD5 or a different alternative but take a look at the performance difference:
// generate 1 million random GUIDS
List<string> randomGuids = new List<string>();
for (int i = 0; i < 1_000_000; i++)
randomGuids.Add(Guid.NewGuid().ToString());
// needed to measure time
var sw = new Stopwatch();
sw.Start();
// using md5 (takes aprox 260 ms)
using (var md5 = MD5.Create())
{
sw.Restart();
foreach (var guid in randomGuids)
{
byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(guid);
byte[] hashBytes = md5.ComputeHash(inputBytes);
// make use of hashBytes to make sure code is compiled
if (hashBytes.Length == 44)
throw new Exception();
}
var elapsed = sw.Elapsed.TotalMilliseconds;
Console.WriteLine($"md5: {elapsed}");
}
// using .net framework 4.7 source code (takes aprox 65 ms)
{
[System.Security.SecuritySafeCritical] // auto-generated
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
static int GetHashCodeDotNetFramework4_7(string str)
{
#if FEATURE_RANDOMIZED_STRING_HASHING
if(HashHelpers.s_UseRandomizedStringHashing)
{
return InternalMarvin32HashString(this, this.Length, 0);
}
#endif // FEATURE_RANDOMIZED_STRING_HASHING
unsafe
{
fixed (char* src = str)
{
#if WIN32
int hash1 = (5381<<16) + 5381;
#else
int hash1 = 5381;
#endif
int hash2 = hash1;
#if WIN32
// 32 bit machines.
int* pint = (int *)src;
int len = this.Length;
while (len > 2)
{
hash1 = ((hash1 << 5) + hash1 + (hash1 >> 27)) ^ pint[0];
hash2 = ((hash2 << 5) + hash2 + (hash2 >> 27)) ^ pint[1];
pint += 2;
len -= 4;
}
if (len > 0)
{
hash1 = ((hash1 << 5) + hash1 + (hash1 >> 27)) ^ pint[0];
}
#else
int c;
char* s = src;
while ((c = s[0]) != 0)
{
hash1 = ((hash1 << 5) + hash1) ^ c;
c = s[1];
if (c == 0)
break;
hash2 = ((hash2 << 5) + hash2) ^ c;
s += 2;
}
#endif
#if DEBUG
// We want to ensure we can change our hash function daily.
// This is perfectly fine as long as you don't persist the
// value from GetHashCode to disk or count on String A
// hashing before string B. Those are bugs in your code.
hash1 ^= -484733382;
#endif
return hash1 + (hash2 * 1566083941);
}
}
}
sw.Restart();
foreach (var guid in randomGuids)
if (GetHashCodeDotNetFramework4_7(guid) == 1234567)
throw new Exception("this will probably never happen");
var elapsed = sw.Elapsed.TotalMilliseconds;
Console.WriteLine($".NetFramework4.7SourceCode: {elapsed}");
}
// using .net 6 built in GetHashCode function (takes aprox: 22 ms)
{
sw.Restart();
foreach (var guid in randomGuids)
if (guid.GetHashCode() == 1234567)
throw new Exception("this will probably never happen");
var elapsed = sw.Elapsed.TotalMilliseconds;
Console.WriteLine($".net6: {elapsed}");
}
Running this in release mode these where my results:
md5: 254.7139
.NetFramework4.7SourceCode: 74.2588
.net6: 23.274
I got the source code from .NET Framework 4.8 from this link: https://referencesource.microsoft.com/#mscorlib/system/string.cs,8281103e6f23cb5c
Anyways searching on the internet I have found this helpful article:
https://andrewlock.net/why-is-string-gethashcode-different-each-time-i-run-my-program-in-net-core/
and I have done exactly what it tells you to do and I have added:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<runtime>
<UseRandomizedStringHashAlgorithm enabled="1" />
</runtime>
</configuration>
to my app.config file and still I get different values for "foo".GetHashCode() every time I run my application.
How can I make the GetHashcode() method return always the same value for the string "foo" in .net 6?
Edit
I will just use the solution of .net framework 4.8 source code that took 73ms to execute and move on. I was just curios to understand why was the build in hashcode so much faster.
At least I understand now why the hash is different every time. By looking at the source code of .net 6 the reason why it has a different hash every time is because of this:
namespace System
{
internal static partial class Marvin
{
... .net source code
....
public static ulong DefaultSeed { get; } = GenerateSeed();
private static unsafe ulong GenerateSeed()
{
ulong seed;
Interop.GetRandomBytes((byte*)&seed, sizeof(ulong));
return seed;
}
}
}
As a result I have tried this just for fun and still did not work:
var ass = typeof(string).Assembly;
var marvin = ass.GetType("System.Marvin");
var defaultSeed = marvin.GetProperty("DefaultSeed");
var value = defaultSeed.GetValue(null); // returns 3644491462759144438
var field = marvin.GetField("<DefaultSeed>k__BackingField", BindingFlags.NonPublic | BindingFlags.Static);
ulong v = 3644491462759144438;
field.SetValue(null, v);
but on the last line I get the exception: System.FieldAccessException: 'Cannot set initonly static field '<DefaultSeed>k__BackingField' after type 'System.Marvin' is initialized.'
But still even if this worked it would be very unsfafe. I rader have something execute 3 times slower and move on.
Why not to use the implementation suggested on the article you shared?
I'm copying it for reference:
static int GetDeterministicHashCode(this string str)
{
unchecked
{
int hash1 = (5381 << 16) + 5381;
int hash2 = hash1;
for (int i = 0; i < str.Length; i += 2)
{
hash1 = ((hash1 << 5) + hash1) ^ str[i];
if (i == str.Length - 1)
break;
hash2 = ((hash2 << 5) + hash2) ^ str[i + 1];
}
return hash1 + (hash2 * 1566083941);
}
}
I'm working on a project which required a dll file for another program written in c# to use (I'm not very familiar with the usage of C++/C#). After finishing the development(?) of the dll file, I started its testing process(run the function call from dll in C# for many times to ensure it works fine). I've asked the way to pass data from C++ to C# here, and the problem is, the program will stop without any error message(I've put try catch in my program) after calling it over 2 times.
I've seen a saying that if there's a memory corruption, the program will stop at a very normal line(e.g. std::cout << ...). I think my situation is similar to that saying...
And here's my code structure...
//dll.hpp
extern "C" LIB_API void inference(unsigned char* img_pointer, long data_len, cv::Mat*& res, int& img_count, int& mat_type_size, double params[2]);
extern "C" LIB_API void clear_mem(cv::Mat* res);
//dll.cpp
LIB_API void inference(unsigned char* img_pointer, long data_len, cv::Mat*& res, int& img_count, int& mat_type_size, double params[2])
{
try
{
img_count = 8;
mat_type_size = sizeof(cv::Mat);
res = new cv::Mat[img_count];
cv::Mat& img1 = res[0];
cv::Mat& img2 = res[1];
cv::Mat& img3 = res[2];
cv::Mat& img4 = res[3];
cv::Mat& img5 = res[4];
cv::Mat& img6 = res[5];
cv::Mat& img7 = res[6];
cv::Mat& img8 = res[7];
//some process to update img1~img8
std::cout << "res->" << res << std::endl;
std::cout << "===== finish inference process ===== >> " << (std::clock() - t_inf1) / (double)CLOCKS_PER_SEC << " s" << std::endl;
}
catch (const std::runtime_error& re)
{
std::cerr << "*** Runtime error: " << re.what() << std::endl;
return;
}
catch (const std::exception& ex)
{
std::cerr << "*** Error occurred: " << ex.what() << std::endl;
return;
}
catch (...)
{
std::cerr << "*** Unknown failure occurred... Possible memory corruption" << std::endl;
return;
}
}
LIB_API void clear_mem(cv::Mat* res)
{
try
{
std::cout << ">> In 'clear_mem'...." << std::endl;
std::cout << "res in clear_mem->" << res << std::endl;
delete[] res;
std::cout << ">> finish deleting res...." << std::endl;
}
catch (const std::runtime_error& re)
{
std::cerr << "*** Runtime error: " << re.what() << std::endl;
return;
}
catch (const std::exception& ex)
{
std::cerr << "*** Error occurred: " << ex.what() << std::endl;
return;
}
catch (...)
{
std::cerr << "*** Unknown failure occurred... Possible memory corruption" << std::endl;
return;
}
}
//test.cs
namespace Test_Unet_Console
{
class Program
{
[DllImport(#"D:\Coco\Code\C_plus_plus\unet_cpp_dll\x64\Release\unet_cpp_dll.dll")]
private static extern void inference(byte[] img, long data_len, out IntPtr images, ref int img_count, out int mat_type_size,
[In, MarshalAs(UnmanagedType.LPArray, SizeConst = 3)]double[] param);
[DllImport(#"D:\Coco\Code\C_plus_plus\unet_cpp_dll\x64\Release\unet_cpp_dll.dll")]
private static extern void init_inference();
[DllImport(#"D:\Coco\Code\C_plus_plus\unet_cpp_dll\x64\Release\unet_cpp_dll.dll")]
private static extern void clear_mem(IntPtr images);
static void Cppdll_inf(Bitmap image, out List<Mat> output_pic, double[] param, out IntPtr imgPtrs)
{
Console.WriteLine("before fmt");
ImageFormat fmt = new ImageFormat(image.RawFormat.Guid);
Console.WriteLine("before imageCodecInfo");
var imageCodecInfo = ImageCodecInfo.GetImageEncoders().FirstOrDefault(codec => codec.FormatID == image.RawFormat.Guid);
//this is for situations, where the image is not read from disk, and is stored in the memory(e.g. image comes from a camera or snapshot)
if (imageCodecInfo == null)
{
fmt = ImageFormat.Jpeg;
Console.WriteLine("C# - imageCodecInfo is null");
}
Console.WriteLine("before MemoryStream");
using (MemoryStream ms = new MemoryStream())
{
try
{
Console.WriteLine("C# - before image.Save");
image.Save(ms, fmt);
Console.WriteLine("C# - finish image.Save");
byte[] image_byte_array = ms.ToArray();
Console.WriteLine("C# - finish reading pic");
int imgCount = 0;
inference(image_byte_array, ms.Length, out var imgPtrs, ref imgCount, out var matTypeSize, param);
output_pic = new List<Mat>();
for (int i = 0; i < imgCount; i++)
{
output_pic.Add(new Mat(IntPtr.Add(imgPtrs, i * matTypeSize)));
}
Console.WriteLine("finish getting value from imgPtrs.....");
}
catch (Exception ex)
{
throw ex;
}
}
}
// I've tried to add this in my code, but it will cause some error(I didn't record it...)
static void clear()
{
Console.WriteLine("start gc collect");
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine("finish gc collect in clear");
}
static void show_result(List<Mat> pic_list)
{
for (int i = 0; i < pic_list.Count; i++)
{
Console.WriteLine(i);
Cv2.ImShow("test", pic_list[i]);
Cv2.WaitKey(500);
}
Cv2.DestroyAllWindows();
Console.WriteLine("finish showing pic");
}
static void Main()
{
Bitmap image1 = new Bitmap("C:\\Users\\Coco\\Desktop\\(3).png");
double[] param = { 0.7, 20 }; //{ VI_threshold, area_threshold }
Console.WriteLine(">>> Initializing from C# =======");
init_inference(); // >> initialization of models
Console.WriteLine(">>> Finish initializing from C# ======");
for (int i = 0; i < 3; i++)
{
Console.WriteLine(i);
List<Mat> result;
IntPtr imgPtrs;
Cppdll_inf(image1, out result, param, out imgPtrs); // inference of picture
Console.WriteLine(">>> Finish image1 C# ======");
show_result(result); // showing pic to check if result is correct
clear_mem(imgPtrs); // clean the memory send from dll(?
result.Clear();
Console.WriteLine(">>> Finish result.Clear() ======");
Console.WriteLine("================================");
}
}
}
}
I've tried not to return the result from dll to C#, it can run about 100 times(the maximum I've tested). So I think the problem might be the process when passing data from dll to C#...
By the way, here's my memory usage when running the program...
I've searched many info on the internet, but I still have no idea how to fix this problem, so any advise or help is really appreciated!
(Thanks in advance for finish reading my messy question description! )
It's been quite long not recording the answer of this question...
There are two ways to handle this(in my experience):
Adding a function with doing delete[] cv::Mat* in your cpp, call this function every time after you received a Mat* from dll
Using IDisposable Class in C#'s calling with DLL function
(Imagine like it kills itself after every run with this syntax)
(This is Chinese material, but I think it's pretty clear with its
example code)
I researched a lot about my problem and found many questions relative to [how to pass string from c# to c dll] :
Passing strings from C# to C++ DLL and back -- minimal example
https://www.codeproject.com/Articles/1189085/%2FArticles%2F1189085%2FPassing-strings-between-managed-and-unmanaged-code
But none of them couldn't help me. Any way I prefer to ask my question :
Briefly explanation :
My c function working properly in c# just when I interchange the GetProcessIntegrityLevel parameters (both in c dll and also in c# import-dll) from :
BOOL GetProcessIntegrityLevel(DWORD dwPID, LPSTR szIntegrityLevel);
To this one :
BOOL GetProcessIntegrityLevel(LPSTR szIntegrityLevel, DWORD dwPID);
In 1st state my program working properly and changes the LPSTR szIntegrityLevel But in 2nd, It doesn't work and LPSTR szIntegrityLevel is always empty with any pid.
I created a c dll library in which I declared the following c function that get Integrity Level of a process through a pid :
#define MAX_INTEGRITY_LEVEL_LENGTH 30
extern "C"
{
__declspec(dllexport) BOOL GetProcessIntegrityLevel(DWORD dwPID, LPSTR szIntegrityLevel);
}
C function implementation :
BOOL GetProcessIntegrityLevel(DWORD dwPID, LPSTR szIntegrityLevel)
{
BOOL bFlag = FALSE; // Return flag
HANDLE hToken = INVALID_HANDLE_VALUE; // Token handle
HANDLE hProcess = NULL; // Process handle
BOOL bProcToken = FALSE; // OpenProcessToken() result
BOOL bTokenInfo = FALSE; // GetTokenInformation() result
DWORD dwLengthNeeded = 0; // Token information length
DWORD dwError = ERROR_SUCCESS; // GetTokenInformation() last error
DWORD dwIntegrityLevel = 0; // Integrity level
PTOKEN_MANDATORY_LABEL pTIL = NULL; // Use as token information
// Open the process
hProcess = OpenProcess(MAXIMUM_ALLOWED | PROCESS_QUERY_LIMITED_INFORMATION,
FALSE, dwPID);
if (hProcess != NULL)
{
// Open process token
bProcToken = OpenProcessToken(hProcess, TOKEN_QUERY, &hToken);
if (bProcToken == TRUE)
{
// Get token information
bTokenInfo = GetTokenInformation(hToken, TokenIntegrityLevel,
NULL, 0, &dwLengthNeeded);
if (bTokenInfo == FALSE)
{
dwError = GetLastError();
if (dwError == ERROR_INSUFFICIENT_BUFFER)
{
pTIL = (PTOKEN_MANDATORY_LABEL)LocalAlloc(0, dwLengthNeeded);
if (pTIL != NULL)
{
// Get token information
bTokenInfo = GetTokenInformation(hToken, TokenIntegrityLevel,
pTIL, dwLengthNeeded, &dwLengthNeeded);
if (bTokenInfo == TRUE)
{
// Get integrity level
dwIntegrityLevel = *GetSidSubAuthority(pTIL->Label.Sid,
(DWORD)(UCHAR)(*GetSidSubAuthorityCount(pTIL->Label.Sid) - 1));
if (dwIntegrityLevel <= SECURITY_MANDATORY_LOW_RID)
{
// Low Integrity
StrCpyA(szIntegrityLevel, "Low");
}
else if ((dwIntegrityLevel >= SECURITY_MANDATORY_MEDIUM_RID) &&
(dwIntegrityLevel < SECURITY_MANDATORY_HIGH_RID))
{
// Medium Integrity
StrCpyA(szIntegrityLevel, "Medium");
}
else if ((dwIntegrityLevel >= SECURITY_MANDATORY_HIGH_RID) &&
(dwIntegrityLevel < SECURITY_MANDATORY_SYSTEM_RID))
{
// High Integrity
StrCpyA(szIntegrityLevel, "High");
}
else if (dwIntegrityLevel >= SECURITY_MANDATORY_SYSTEM_RID)
{
// System Integrity
StrCpyA(szIntegrityLevel, "System");
}
else if (dwIntegrityLevel == SECURITY_MANDATORY_UNTRUSTED_RID)
{
// Untrusted integrity
StrCpyA(szIntegrityLevel, "Untrusted");
}
else
{
StrCpyA(szIntegrityLevel, "UnKnown");
}
bFlag = TRUE;
}
LocalFree(pTIL);
}
}
}
// Close token handle
CloseHandle(hToken);
}
// Close the process handle
CloseHandle(hProcess);
}
return bFlag;
}
So, I import GetProcessIntegrityLevel() from my c dll in c# as following :
// Define function pointers for using of c dll functions
[DllImport("ProcessesPropDll.dll",CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.Bool)]
// Get integrity level
static extern bool GetProcessIntegrityLevel(ulong dwPID, StringBuilder szIntegrityLevel);
And call the function in c# like this :
// Integrity level
StringBuilder integrityLevel = new StringBuilder(200);
if(GetProcessIntegrityLevel(11684, integrityLevel) == true)
{
MessageBox.Show(integrityLevel.ToString());
}
In this state when i run the program, the GetProcessIntegrityLevel() returns true but integrityLevel is always empty in messagebox for any pid!!!!
Surprisingly, when I interchange the parameters in my c function and also in c#, It does work :
__declspec(dllexport) BOOL GetProcessIntegrityLevel(LPSTR szIntegrityLevel, DWORD dwPID);
This is very strange for me. Also I tried with MarshalAs(UnmanagedType.LPStr)] but give me the same result.
In C# ulong is a 64 bit type. The PID parameter is DWORD which is a 32 bit parameter.
Change your C# parameter declaration from ulong to uint to fix the problem.
I am writing wrappers using C++/CLR. The managed C# class has a function signature as below
//C#
int WriteToInstrument(string command, ref string response, int stage);
I have to write a C++ wrapper to this function in something like the following signature
//C++
int WriteToInstrumentWrap(const char * command, char * response, int stage);
My question is: how can I handle the conversion from "ref string" in C# to char* in C++? Or how can I handle the situation that requires to take a ref string from C# that can be used in C/C++? Many thanks in advance.
I'll add some examples of code I've written this morning. In general, when speaking of returning objects (in the broad meaning where even a char* string is an object), the big questions in C/C++ are:
Who allocates the memory
How many elements are needed
How is the memory allocated (which allocator is used)
And as a corollary, how the memory must be freed
One last optional question is if the memory must be really freed: a method could return a pointer to an internal object that has a lifetime equal to the lifetime of the program and that mustn't be freed. For example:
const char* Message()
{
return "OK";
}
You mustn't free the memory returned by Message()!
This questions get even more complex when you are writing a library (a dll) that will be used by other programs: the malloc and the new that are used in a dll can be different/distinct from the malloc and the new used by the main program (or by another dll), so that you shouldn't free with your (main program) free the memory that is malloc(ed) by a dll.
There are three possible solutions to this particular problem:
Use a shared allocator, for example one given by the OS. Windows gives LocalAlloc and CoTaskMemAlloc. They are even accessible from .NET (Marshal.AllocHGlobal and Marshal.AllocCoTaskMem). In this way the main application can free the memory allocated by the dll
The API of your dll has a Free() method that must be used to free the memory allocated by the dll
The API of your dll has some methods like SetAllocator(void *(*allocator)(size_t)) and SetFree(void (*free)(void*)), so methods that store a function pointer, that the main application can use to set the allocator and free to be used by the dll, so that they are shared between the main application and the dll. The dll will use those allocators. Note that SetAllocator(malloc); SetFree(free) if done by the main application is perfectly legal: now the dll will use the main application's malloc, and not the dll's malloc!
Shortcut used in some example I'll give: the method has as a parameter the allocator (a function pointer) that will then be used
As an important sidenote: we are in 2018. It is at least 15 years that you should have forgotten of char* for strings in C for Windows. Use wchar_t. Always.
And finally some code :-)
Now... given (C# code):
int WriteToInstrument(string command, ref string response, int stage)
{
response = "The quick brown fox jumps over the lazy dog";
return 0;
}
Simple method that calls WriteToInstrument and then copies the response result to an ansi string (char*). The buffer is allocated by the caller, and is of size length. After the method is executed, length contains the number of characters used (including the terminating \0). The response is always \0 terminated. The problem here is that the response could get truncated and/or the caller could allocate a buffer too much big (that won't really protect it from the truncation problem, if it is unlucky :-) ). I'll repeat myself here: using char* for strings in 2018 is ancient technology.
// Utility method to copy a unicode string to a fixed size buffer
size_t Utf16ToAnsi(const wchar_t *wstr, char *str, size_t length)
{
if (length == 0)
{
return 0;
}
// This whole piece of code can be moved to a method
size_t length2 = WideCharToMultiByte(CP_ACP, 0, wstr, -1, str, (int)length, nullptr, nullptr);
// WideCharToMultiByte will try to write up to *length characters, but
// if the buffer is too much small, it will return 0,
// **and the tring won't be 0-terminated**
if (length2 != 0)
{
return length2;
}
// Buffer too much small
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
// We add a terminating 0
str[length - 1] = 0;
return length;
}
// Big bad error, shouldn't happen. Return 0 but terminate the string
str[0] = 0;
return 0;
}
Example of use:
char response[16];
size_t length = sizeof(response) / sizeof(char); // useless / sizeof(char) == / 1 by definition
WriteToInstrumentWrap1("cmd1", response, &length, 1);
std::cout << "fixed buffer char[]: " << response << ", used length: " << length << std::endl;
or (using std::vector<>/std::array<>)
//Alternative: std::array<char, 16> response;
std::vector<char> response(16);
size_t length = response.size();
WriteToInstrumentWrap1("cmd1", response.data(), &length, 1);
std::cout << "fixed buffer vector<char>: " << response.data() << ", used length: " << length << std::endl;
Simple method that calls WriteToInstrument and then copies the response result to an unicode string (wchar_t*). The buffer is allocated by the caller, and is of size length. After the method is executed, length contains the number of characters used (including the terminating \0). The response is always \0 terminated.
// in input length is the size of response, in output the number of characters (not bytes!) written to response
// (INCLUDING THE \0!). The string is always correctly terminated.
int WriteToInstrumentWrap2(const wchar_t *command, wchar_t *response, size_t *length, int stage)
{
auto str1 = gcnew String(command);
String ^str2 = nullptr;
int res = WriteToInstrument(str1, str2, 5);
pin_ptr<const Char> ppchar = PtrToStringChars(str2);
const wchar_t *pch = const_cast<wchar_t*>(ppchar);
*length = (size_t)str2->Length < *length ? str2->Length : *length - 1;
memcpy(response, pch, *length * sizeof(wchar_t));
response[*length] = '\0';
*length++;
return res;
}
Example of use:
wchar_t response[16];
size_t length = sizeof(response) / sizeof(wchar_t);
WriteToInstrumentWrap2(L"cmd1", response, &length, 1);
std::wcout << L"fixed buffer wchar_t[]: " << response << L", used length: " << length << std::endl;
or (using std::vector<>/std::array<char, 16>)
//Alternative: std::array<wchar_t, 16> response;
std::vector<wchar_t> response(16);
size_t length = response.size();
WriteToInstrumentWrap2(L"cmd1", response.data(), &length, 1);
std::wcout << L"fixed buffer vector<wchar_t>: " << response.data() << ", used length: " << length << std::endl;
All the next examples will use char instead of wchar_t. It is quite easy to convert them. I'll repeat myself here: using char* for strings in 2018 is ancient technology. It is like using ArrayList instead of List<>
Simple method that calls WriteToInstrument, allocates the response buffer using CoTaskMemAlloc and copies the result to an ansi string (char*). The caller must CoTaskMemFree the allocated memory. The response is always \0 terminated.
// Memory allocated with CoTaskMemAlloc. Remember to CoTaskMemFree!
int WriteToInstrumentWrap3(const char *command, char **response, int stage)
{
auto str1 = gcnew String(command);
String ^str2 = nullptr;
int res = WriteToInstrument(str1, str2, 5);
pin_ptr<const Char> ppchar = PtrToStringChars(str2);
const wchar_t *pch = const_cast<wchar_t*>(ppchar);
// length includes the terminating \0
size_t length = WideCharToMultiByte(CP_ACP, 0, pch, -1, nullptr, 0, nullptr, nullptr);
*response = (char*)CoTaskMemAlloc(length * sizeof(char));
WideCharToMultiByte(CP_ACP, 0, pch, -1, *response, length, nullptr, nullptr);
return res;
}
Example of use:
char *response;
WriteToInstrumentWrap3("cmd1", &response, 1);
std::cout << "CoTaskMemFree char: " << response << ", used length: " << strlen(response) + 1 << std::endl;
// Must free with CoTaskMemFree!
CoTaskMemFree(response);
Simple method that calls WriteToInstrument, allocates the response buffer using a "private" "library" allocator and copies the result to an ansi string (char*). The caller must use the library deallocator MyLibraryFree to free the allocated memory. The response is always \0 terminated.
// Free method used by users of the library
void MyLibraryFree(void *p)
{
free(p);
}
// The memory is allocated through a proprietary allocator of the library. Use MyLibraryFree() to free it.
int WriteToInstrumentWrap4(const char *command, char **response, int stage)
{
auto str1 = gcnew String(command);
String ^str2 = nullptr;
int res = WriteToInstrument(str1, str2, 5);
pin_ptr<const Char> ppchar = PtrToStringChars(str2);
const wchar_t *pch = const_cast<wchar_t*>(ppchar);
// length includes the terminating \0
size_t length = WideCharToMultiByte(CP_ACP, 0, pch, -1, nullptr, 0, nullptr, nullptr);
*response = (char*)malloc(length);
WideCharToMultiByte(CP_ACP, 0, pch, -1, *response, length, nullptr, nullptr);
return res;
}
Example of use:
char *response;
WriteToInstrumentWrap4("cmd1", &response, 1);
std::cout << "Simple MyLibraryFree char: " << response << ", used length: " << strlen(response) + 1 << std::endl;
// Must free with the MyLibraryFree() method
MyLibraryFree(response);
Simple method that calls WriteToInstrument, allocates the response buffer using a settable (through the SetLibraryAllocator/SetLibraryFree methods) allocator (there is a default that is used if no special allocator is selected) and copies the result to an ansi string (char*). The caller must use the library deallocator LibraryFree (that uses the allocator selected by SetLibraryFree) to free the allocated memory or if it has setted a different allocator, it can directly use that deallocator. The response is always \0 terminated.
void *(*libraryAllocator)(size_t length) = malloc;
void (*libraryFree)(void *p) = free;
// Free method used by library
void SetLibraryAllocator(void *(*allocator)(size_t length))
{
libraryAllocator = allocator;
}
// Free method used by library
void SetLibraryFree(void (*free)(void *p))
{
libraryFree = free;
}
// Free method used by library
void LibraryFree(void *p)
{
libraryFree(p);
}
// The memory is allocated through the allocator specified by SetLibraryAllocator (default the malloc of the dll)
// You can use LibraryFree to free it, or change the SetLibraryAllocator and the SetLibraryFree with an allocator
// of your choosing and then use your free.
int WriteToInstrumentWrap5(const char *command, char **response, int stage)
{
auto str1 = gcnew String(command);
String ^str2 = nullptr;
int res = WriteToInstrument(str1, str2, 5);
pin_ptr<const Char> ppchar = PtrToStringChars(str2);
const wchar_t *pch = const_cast<wchar_t*>(ppchar);
// length includes the terminating \0
size_t length = WideCharToMultiByte(CP_ACP, 0, pch, -1, nullptr, 0, nullptr, nullptr);
*response = (char*)libraryAllocator(length);
WideCharToMultiByte(CP_ACP, 0, pch, -1, *response, length, nullptr, nullptr);
return res;
}
Example of use:
void* MyLocalAlloc(size_t size)
{
return LocalAlloc(0, size);
}
void MyLocalFree(void *p)
{
LocalFree(p);
}
and then:
// Using the main program malloc/free
SetLibraryAllocator(malloc);
SetLibraryFree(free);
char *response;
WriteToInstrumentWrap5("cmd1", &response, 1);
std::cout << "SetLibraryAllocator(malloc) char: " << response << ", used length: " << strlen(response) + 1 << std::endl;
// Here I'm using the main program free, because the allocator has been set to malloc
free(response);
or
// Using the Windows LocalAlloc/LocalFree. Note that we need to use an intermediate method to call them because
// they have a different signature (stdcall instead of cdecl and an additional parameter for LocalAlloc)
SetLibraryAllocator(MyLocalAlloc);
SetLibraryFree(MyLocalFree);
char *response;
WriteToInstrumentWrap5("cmd1", &response, 1);
std::cout << "SetLibraryAllocator(LocalAlloc) char: " << response << ", used length: " << strlen(response) + 1 << std::endl;
// Here I'm using diretly the Windows API LocalFree
LocalFree(response);
More complex method that calls WriteToInstrument but has as a parameter an allocator that will be used to allocate the response buffer. There is an addition parameter par that will be passed to the allocator. The method then will copy the result as an ansi string (char*). The caller must free the memory using a specific deallocator based on the allocator used. The response is always \0 terminated.
// allocator is a function that will be used for allocating the memory. par will be passed as a parameter to allocator(length, par)
// the length of allocator is in number of elements, *not in bytes!*
int WriteToInstrumentWrap6(const char *command, char **response, char *(*allocator)(size_t length, void *par), void *par, int stage)
{
auto str1 = gcnew String(command);
String ^str2 = nullptr;
int res = WriteToInstrument(str1, str2, 5);
pin_ptr<const Char> ppchar = PtrToStringChars(str2);
const wchar_t *pch = const_cast<wchar_t*>(ppchar);
// length includes the terminating \0
size_t length = WideCharToMultiByte(CP_ACP, 0, pch, -1, nullptr, 0, nullptr, nullptr);
*response = allocator(length, par);
WideCharToMultiByte(CP_ACP, 0, pch, -1, *response, length, nullptr, nullptr);
return res;
}
Examples of use (multiple allocator showed: vector<>, malloc, new[], unique_ptr<>):
Note the use of the par parameter.
template<typename T>
T* vector_allocator(size_t length, void *par)
{
std::vector<T> *pvector = static_cast<std::vector<T>*>(par);
pvector->resize(length);
return pvector->data();
}
template<typename T>
T* malloc_allocator(size_t length, void *par)
{
return (T*)malloc(length * sizeof(T));
}
template<typename T>
T* new_allocator(size_t length, void *par)
{
return new T[length];
}
template<typename T>
T* uniqueptr_allocator(size_t length, void *par)
{
std::unique_ptr<T[]> *pp = static_cast<std::unique_ptr<T[]>*>(par);
pp->reset(new T[length]);
return pp->get();
}
and then (note the fact that sometimes one of the parameter passed to WriteToInstrumentWrap6 is useless because we already have a pointer to the buffer):
{
std::vector<char> response;
char *useless;
WriteToInstrumentWrap6("cmd1", &useless, vector_allocator<char>, &response, 1);
std::cout << "vector char: " << response.data() << ", used length: " << response.size() << std::endl;
// The memory is automatically freed by std::vector<>
}
{
char *response;
WriteToInstrumentWrap6("cmd1", &response, malloc_allocator<char>, nullptr, 1);
std::cout << "malloc char: " << response << ", used length: " << strlen(response) + 1 << std::endl;
// Must free with free
free(response);
}
{
char *response;
WriteToInstrumentWrap6("cmd1", &response, new_allocator<char>, nullptr, 1);
std::cout << "new[] char: " << response << ", used length: " << strlen(response) + 1 << std::endl;
// Must free with delete[]
delete[] response;
}
{
std::unique_ptr<char[]> response;
char *useless;
WriteToInstrumentWrap6("cmd1", &useless, uniqueptr_allocator<char>, &response, 1);
std::cout << "unique_ptr<> char: " << response.get() << ", used length: " << strlen(response.get()) + 1 << std::endl;
// The memory is automatically freed by std::unique_ptr<>
}
In a high level overflow, you need C++/CLI (C++ that is using managed .NET code)
OK, you take a handle of type System::String (.NET) and get it's length property. Use that value to allocate a new buffer of size + 2 chars using malloc and memset to zero it out. lock the string, copy its contents and unlock it again.
There is a conversion operator to go from System::String ^ to MFC's CString, if that helps. It will make the code a single liner
Yes. But again,
CString unmanaged = CString(System::String ^) does all that for you.
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.