How does HidD_GetAttributes retrieve the attributes from a Device Object? - c

I'm working on creating a virtual HID device in Windows 10. To prepare myself for writing the drivers, I've been analyzing the sample provided here: https://github.com/Microsoft/Windows-driver-samples/tree/master/hid/vhidmini2.
In the file app/testvhid.c, HidD_GetAttributes is used to retrieve the attributes of the HID device. It appears that the attributes are initialized in driver/vhidmini.c (hidAttributes in the EvtDeviceAdd function). However, hidAttributes is stored inside of a DEVICE_CONTEXT structure, which (from my understanding) is defined by the driver.
If hidAttributes is a user defined attribute, then how does HidD_GetAttributes know to retrieve it from the device?
I've tried to replicate this for myself by creating a KMDF driver which is based mostly on the sample given. The relevant driver code is as follows (The majority of this was taken from the sample, with the exception of the call to WdfDeviceCreateDeviceInterface):
NTSTATUS
kmdfTest2CreateDevice(
_Inout_ PWDFDEVICE_INIT DeviceInit
)
{
WDF_OBJECT_ATTRIBUTES deviceAttributes;
PDEVICE_CONTEXT deviceContext;
WDFDEVICE device;
NTSTATUS status;
PHID_DEVICE_ATTRIBUTES hidAttributes;
WdfFdoInitSetFilter(DeviceInit);
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, DEVICE_CONTEXT);
status = WdfDeviceCreate(&DeviceInit, &deviceAttributes, &device);
if (NT_SUCCESS(status)) {
deviceContext = DeviceGetContext(device);
deviceContext->Device = device;
deviceContext->DeviceData = 0;
hidAttributes = &deviceContext->HidDeviceAttributes;
RtlZeroMemory(hidAttributes, sizeof(HID_DEVICE_ATTRIBUTES));
hidAttributes->Size = sizeof(HID_DEVICE_ATTRIBUTES);
hidAttributes->VendorID = HIDMINI_VID;
hidAttributes->ProductID = HIDMINI_PID;
hidAttributes->VersionNumber = HIDMINI_VERSION;
if (NT_SUCCESS(status)) {
status = kmdfTest2QueueInitialize(device);
}
deviceContext->HidDescriptor = G_DefaultHidDescriptor;
deviceContext->ReportDescriptor = G_DefaultReportDescriptor;
status = WdfDeviceCreateDeviceInterface(
device,
&GUID_DEVINTERFACE_HID,
NULL // ReferenceString
);
}
return status;
}
The relevant section of code in the user mode test application is as follows (this code is virtually entirely from the given sample):
BOOLEAN
CheckIfOurDevice(
HANDLE file)
{
PHIDP_PREPARSED_DATA Ppd; // The opaque parser info describing this device
HIDP_CAPS Caps; // The Capabilities of this hid device.
HIDD_ATTRIBUTES attr; // Device attributes
if (!HidD_GetAttributes(file, &attr))
{
printf("Error: HidD_GetAttributes failed \n");
return FALSE;
}
printf("Device Attributes - PID: 0x%x, VID: 0x%x \n", attr.ProductID, attr.VendorID);
if ((attr.VendorID != HIDMINI_VID) || (attr.ProductID != HIDMINI_PID))
{
printf("Device attributes doesn't match the sample \n");
return FALSE;
}
if (!HidD_GetPreparsedData(file, &Ppd))
{
printf("Error: HidD_GetPreparsedData failed \n");
return FALSE;
}
if (!HidP_GetCaps(Ppd, &Caps))
{
printf("Error: HidP_GetCaps failed \n");
HidD_FreePreparsedData(Ppd);
return FALSE;
}
if ((Caps.UsagePage == g_MyUsagePage) && (Caps.Usage == g_MyUsage)) {
printf("Success: Found my device.. \n");
return TRUE;
}
else {
printf("failed: UsagePage: %d, Usage: %d \n", Caps.UsagePage, Caps.Usage);
}
return FALSE;
}
BOOLEAN
GetHidInterface(_Out_ HANDLE* Handle) {
CONFIGRET cr = CR_SUCCESS;
*Handle = INVALID_HANDLE_VALUE;
ULONG deviceInterfaceListLength = 0;
GUID InterfaceGuid;
PSTR deviceInterfaceList = NULL;
HANDLE devHandle = INVALID_HANDLE_VALUE;
if (NULL == Handle) {
printf("Error: Invalid device handle parameter\n");
return FALSE;
}
HidD_GetHidGuid(&InterfaceGuid);
cr = CM_Get_Device_Interface_List_Size(
&deviceInterfaceListLength,
&InterfaceGuid,
NULL,
CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
if (cr != CR_SUCCESS) {
printf("Error 0x%x retrieving device interface list size.\n", cr);
return FALSE;
}
if (deviceInterfaceListLength <= 1) {
printf("Error: No active device interfaces found.\n"
" Is the sample driver loaded?");
return FALSE;
}
deviceInterfaceList = (PSTR)malloc(deviceInterfaceListLength * sizeof(WCHAR));
if (deviceInterfaceList == NULL) {
printf("Error allocating memory for device interface list.\n");
return FALSE;
}
ZeroMemory(deviceInterfaceList, deviceInterfaceListLength * sizeof(WCHAR));
cr = CM_Get_Device_Interface_List(
&InterfaceGuid,
NULL,
deviceInterfaceList,
deviceInterfaceListLength,
CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
if (cr != CR_SUCCESS) {
printf("Error 0x%x retrieving device interface list.\n", cr);
return FALSE;
}
printf("\n....looking for our HID device (with UP=0x%04X "
"and Usage=0x%02X)\n", g_MyUsagePage, g_MyUsage);
PSTR currentInterface;
for (currentInterface = deviceInterfaceList;
*currentInterface;
currentInterface += strlen(currentInterface) + 1) {
devHandle = CreateFile(currentInterface,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, // no SECURITY_ATTRIBUTES structure
OPEN_EXISTING, // No special create flags
0, // No special attributes
NULL); // No template file
if (INVALID_HANDLE_VALUE == devHandle) {
printf("Warning: CreateFile failed: %d\n", GetLastError());
continue;
}
if (CheckIfOurDevice(devHandle)) {
*Handle = devHandle;
return TRUE;
}
else {
CloseHandle(devHandle);
}
}
return FALSE;
}
The HidD_GetAttributes function passes, but the CheckIfOurDevice function fails when checking the device attributes ("Device attributes doesn't match the sample"). I've checked some of the attribute values that are being set by HidD_GetAttributes, but they don't match up with the ones set by the driver. Is the sample making some other call that I'm missing?

Related

How to receive message from kernel in user-mode in c?

Basically I want to get filepath of every file created in windows using File system minifilter driver on Post Operation and send the filepath to user-mode, I have achieved this using below code:
BOOLEAN
GetFullPath(
IN PFLT_FILE_NAME_INFORMATION nameInfo,
IN PFLT_CALLBACK_DATA FltCallBackData,
IN PCFLT_RELATED_OBJECTS FltObjects,
IN OUT PUNICODE_STRING pFullPathName){
UNREFERENCED_PARAMETER(nameInfo);
BOOLEAN bResult;
NTSTATUS status;
PDEVICE_OBJECT pDiskDeviceObject = NULL;
UNICODE_STRING VolumeName = { 0 };
PFLT_FILE_NAME_INFORMATION TempNameInfo = NULL;
PAGED_CODE();
__try{
VolumeName.Buffer = NULL;
// Get the associated file name
status = FltGetFileNameInformation(FltCallBackData, FLT_FILE_NAME_NORMALIZED
| FLT_FILE_NAME_QUERY_DEFAULT, &TempNameInfo);
if (!NT_SUCCESS(status)){
bResult = FALSE;
__leave;
}
status = FltParseFileNameInformation(TempNameInfo);
if (!NT_SUCCESS(status)){
bResult = FALSE;
__leave;
}
// Try to get the volume device object & convert this to the volume name
status = FltGetDiskDeviceObject(FltObjects->Volume, &pDiskDeviceObject);
if (!NT_SUCCESS(status)){
bResult = FALSE;
__leave;
}
// Get the volume name
status = IoVolumeDeviceToDosName(pDiskDeviceObject, &VolumeName);
if (!NT_SUCCESS(status)){
bResult = FALSE;
__leave;
}
// Store the filename in pFullPathName
RtlInitUnicodeString(pFullPathName, (PWSTR)NULL);
pFullPathName->MaximumLength = (USHORT)(VolumeName.Length +
TempNameInfo->Name.Length + sizeof(UNICODE_NULL));
//pFullPathName->Buffer = (PWSTR)ExAllocatePool2(PagedPool,
// pFullPathName->MaximumLength, AV_SCAN_CTX_TAG);
pFullPathName->Buffer = ExAllocatePool2(POOL_FLAG_PAGED, 100, '3331');
if (pFullPathName->Buffer == NULL){
AV_DBG_PRINTEX((0, AVDBG_TRACE_ZERO, "Failed to allocate memory\n"));
bResult = FALSE;
__leave;
}
status = RtlAppendUnicodeStringToString(pFullPathName, &VolumeName);
if (!NT_SUCCESS(status)){
ExFreePool(pFullPathName->Buffer);
bResult = FALSE;
__leave;
}
pFullPathName->MaximumLength = 100;
status = RtlAppendUnicodeStringToString(pFullPathName,
&TempNameInfo->ParentDir);
if (!NT_SUCCESS(status)){
bResult = FALSE;
__leave;
}
status = RtlAppendUnicodeStringToString(pFullPathName,
&TempNameInfo->FinalComponent);
if (!NT_SUCCESS(status)){
ExFreePool(pFullPathName->Buffer);
bResult = FALSE;
__leave;
}
//DbgPrint(" Full Path Name = %wZ\n", pFullPathName );
AV_DBG_PRINTEX((0, AVDBG_TRACE_ZERO, "<Fullpath> Full Path Name = %wZ, %d\n", pFullPathName, pFullPathName->Length));
LARGE_INTEGER timeout = { 0 };
timeout.QuadPart = 1;
//timeout.QuadPart = -(timeout.QuadPart * _1ms);
status = FltSendMessage(Globals.Filter,
&Globals.ScanClientPort,
pFullPathName,
pFullPathName->Length,
NULL,
NULL,
&timeout);
bResult = TRUE;
}
__finally{
// Free all allocated resources
if (pDiskDeviceObject)
ObDereferenceObject(pDiskDeviceObject);
if (VolumeName.Buffer)
ExFreePool(VolumeName.Buffer);
if (TempNameInfo)
FltReleaseFileNameInformation(TempNameInfo);
}
return bResult;
}
In my kernel debugger, I see the Full file path just as I want it, and then I basically receive that in user-mode as below:
int main() {
ULONG bytesReturned = 0;
AV_CONNECTION_CONTEXT connectionCtx = {0};
COMMAND_MESSAGE commandMessage = { 0 };
char* buffer = (char *)malloc(500);
HRESULT hResult = 0;
printf("Enter your request: ");
scanf_s("%s", buffer, max_buffer_length);
printf("Entered request is: %s:%d\n", buffer, strlen(buffer));
//strncpy_s(buffer,500, "status=sto", 11);
char recvbuffer[500] = { 0 };
if (port == NULL) {
connectionCtx.Type = AvConnectForScan;
hResult = FilterConnectCommunicationPort(L"\\NeehackAVScanPort", 0, &connectionCtx, sizeof(AV_CONNECTION_CONTEXT), NULL, &port);
printf("hresult: 0x%08x\n", hResult);
if (hResult) {
printf("Failed to Connect to Kernel\n");
return -1;
}
}
printf("Connected to kernel, sending: %s:%d\n", buffer, strlen(buffer));
/*
hr = FilterSendMessage( Context->ConnectionPort,
&commandMessage,
sizeof( COMMAND_MESSAGE ),
NULL,
0,
&bytesReturned);
*/
commandMessage.Command = AvCmdCreateSectionForDataScan;
hResult = FilterSendMessage(port, &commandMessage, sizeof(COMMAND_MESSAGE), recvbuffer, 500, &bytesReturned);
printf("sending data hresult: 0x%08x recv:%s\n", hResult, recvbuffer);
FILTER_MESSAGE_HEADER msg;
//connectionCtx.Type = AvConnectForScan;
while (true) {
hResult = FilterGetMessage(port,
&msg,
1024,
NULL);
printf("message is: %s:%wZ\n", msg, &msg);
}
if (FAILED(hResult)) {
printf("Failed to send data 0x%08x\n", hResult);
return -1;
}
printf("kernel said: %s\n", recvbuffer);
return 0;
}
The problem is on printf("message is: %s:%wZ\n", msg, &msg); I get null strings or message is: :(null) every time the message is sent by the kernel.
Can anyone tell me what am I doing wrong?
You need to have both ends of the port agree on the format of the message. Something along the lines of the following just to give an idea:
typedef struct _MY_MESSAGE {
FILTER_MESSAGE_HEADER Header;
WCHAR FullPathName[1024];
} MY_MESSAGE;
FltSendMessage(pFullPathName->Buffer, pFullPathName->Length)
MY_MESSAGE Message;
FilterGetMessage(&Message.Header, sizeof(Message));
printf("FullPathName: %ls\n", Message.FullPathName);

Kaa Data Collection on Request, Not Loop

I'm doing Kaa project.
First, i have used Data Collection demo and then do some modification to my sensor. The data is send to platform every seconds(i can configure it).
And now, i want to create some service which if i send request(using ulfius framework), my device upload 1 data.
My problem is, i have to do more than 10 request to upload data, how can i solve it. Please Help.
Below is some of my code :
int callback_kaa(const struct _u_request * request,struct _u_response * response, void * user_data){
kaa_client_send(kaa_client, &kaa_add_log_record, (void *)kaa_client);
ulfius_set_string_body_response(response, 200, "Hello Kaa!");}
int main(/*int argc, char *argv[]*/){
printf("DHT11 Logging Demo\n");
if (wiringPiSetup() == -1) {
printf("Failed to initialize Pi wiring\n");
exit(1);}
if (ulfius_init_instance(&instance, PORT, NULL, NULL) != U_OK) {
fprintf(stderr, "Error ulfius_init_instance, abort\n");
return(1);}
ulfius_add_endpoint_by_val(&instance, "POST", "/kaaplatform", NULL, 0,&callback_kaa, NULL);
kaa_error_t error_code = kaa_client_create(&kaa_client, NULL);
KAA_RETURN_IF_ERROR(error_code, "Failed create Kaa client");
kaa_log_bucket_constraints_t bucket_sizes = {
.max_bucket_size = MAX_LOG_BUCKET_SIZE,
.max_bucket_log_count = 1,};
error_code = ext_unlimited_log_storage_create(&log_storage_context,
kaa_client_get_context(kaa_client)->logger);
KAA_RETURN_IF_ERROR(error_code, "Failed to create unlimited log storage");
error_code = ext_log_upload_strategy_create(kaa_client_get_context(kaa_client), &log_upload_strategy_context, THRESHOLD_COUNT_FLAG);
KAA_RETURN_IF_ERROR(error_code, "Failed to create log upload strategy");
error_code = ext_log_upload_strategy_set_threshold_count(log_upload_strategy_context, KAA_UPLOAD_COUNT_THRESHOLD);
KAA_RETURN_IF_ERROR(error_code, "Failed to set threshold log record count");
error_code = kaa_logging_init(kaa_client_get_context(kaa_client)>log_collector
, log_storage_context
, log_upload_strategy_context
, &bucket_sizes);
KAA_RETURN_IF_ERROR(error_code, "Failed to init Kaa log collector");
kaa_channel_manager_set_auth_failure_handler(
kaa_client_get_context(kaa_client)->channel_manager,
auth_failure_handler, kaa_client);
const uint8_t *endpoint_key_hash = NULL;
size_t endpoint_key_hash_length = 0;
ext_get_sha1_base64_public(&endpoint_key_hash, &endpoint_key_hash_length);
printf("Endpoint Key Hash: %.*s\n", (int)endpoint_key_hash_length,endpoint_key_hash);
if (ulfius_start_framework(&instance) == U_OK) {
printf("Start framework on port %d\n", instance.port);
getchar();
} else {
fprintf(stderr, "Error starting framework\n");
}
kaa_client_destroy(kaa_client);
printf("Data analytics demo stopped\n");
ulfius_stop_framework(&instance);
ulfius_clean_instance(&instance);
return error_code;
}
and also, i create some function (kaa_client_send) at file kaa_client.h :
void kaa_client_send(kaa_client_t *kaa_client,external_process_fn external_process, void *external_process_context)
{
KAA_RETURN_IF_NIL(kaa_client, KAA_ERR_BADPARAM);
kaa_error_t error_code = kaa_check_readiness(kaa_client->kaa_context);
if (error_code != KAA_ERR_NONE) {
KAA_LOG_ERROR(kaa_client->kaa_context->logger, error_code, "Cannot start Kaa client: Kaa context is not fully initialized");
return error_code;
}
kaa_client->external_process_fn = external_process;
kaa_client->external_process_context = external_process_context;
kaa_client->external_process_max_delay = 5;
kaa_client->external_process_last_call = KAA_TIME();
KAA_LOG_INFO(kaa_client->kaa_context->logger, KAA_ERR_NONE, "Starting Kaa client...");
if (kaa_client->external_process_fn) {
kaa_client->external_process_fn(kaa_client->external_process_context);
kaa_client->external_process_last_call = KAA_TIME();
}
//Check Kaa channel is ready to transmit something
if (kaa_process_failover(kaa_client->kaa_context)) {
kaa_client->boostrap_complete = false;
} else {
if (kaa_client->channel_id > 0) {
if (kaa_client->channel_state == KAA_CLIENT_CHANNEL_STATE_NOT_CONNECTED) {
error_code = kaa_client_process_channel_disconnected(kaa_client);
} else if (kaa_client->channel_state == KAA_CLIENT_CHANNEL_STATE_CONNECTED) {
error_code = kaa_client_process_channel_connected(kaa_client);
if (error_code == KAA_ERR_TIMEOUT)
kaa_client_deinit_channel(kaa_client);
}
} else {
//No initialized channels
if (kaa_client->boostrap_complete) {
KAA_LOG_INFO(kaa_client->kaa_context->logger, KAA_ERR_NONE,
"Channel [0x%08X] Boostrap complete, reinitializing to Operations ...", kaa_client->channel_id);
kaa_client->boostrap_complete = false;
kaa_client_deinit_channel(kaa_client);
error_code = kaa_client_init_channel(kaa_client, KAA_CLIENT_CHANNEL_TYPE_OPERATIONS);
if (error_code == KAA_ERR_BAD_STATE) {
kaa_client_deinit_channel(kaa_client);
kaa_client->boostrap_complete = false;
}
} else {
KAA_LOG_INFO(kaa_client->kaa_context->logger, KAA_ERR_NONE,
"Channel [0x%08X] Operations error, reinitializing to Bootstrap ...", kaa_client->channel_id);
kaa_client->boostrap_complete = true;
kaa_client_deinit_channel(kaa_client);
kaa_client_init_channel(kaa_client, KAA_CLIENT_CHANNEL_TYPE_BOOTSTRAP);
}
}
}
KAA_LOG_INFO(kaa_client->kaa_context->logger, KAA_ERR_NONE, "Kaa client stopped");
return error_code;
}

Unable to get the associated network UNC of a mapped drive C/C++

Have written a DLL that attempts to convert a mapped drive to its equivalent network UNC. But it fails when DLL is called by setup program running as an elevated process. As a potential fix I modified the example source offered by #RbMn from an answer to the following question: How to correctly detect Network drive when running with elevated privileges
The call to GetLogicalDrives worked just like it was stated it would. However when it makes a call to WNetGetConnection with a mapped drive letter the error returned is 1222 (ERROR_NO_NETWORK) thus not giving the associated UNC. I believe the problem stems from how I go about impersonating a logon. Since my knowledge of UAC matters is very limited, I am not certain what I have to alter about impersonating a logon in order to correctly get the information I need.
Any help is greatly appreciated.
Below is the actual code:
BOOL ConvertToMappedFolder(LPSTR pUncPath, LPSTR pMappedDrive)
{
BOOL bRet = 0;
if (1)
{
HANDLE hToken = NULL;
ULONG rcb = 0;
TOKEN_ELEVATION_TYPE tet = 0;
TOKEN_LINKED_TOKEN tlt = { 0 };
ULONG err = BOOL_TO_ERR(OpenProcessToken(GetCurrentProcess() /* NtCurrentProcess() */, TOKEN_QUERY, &hToken));
if (err == NOERROR)
{
err = BOOL_TO_ERR(GetTokenInformation(hToken, TokenElevationType, &tet, sizeof(tet), &rcb));
if (err == NOERROR)
{
if (tet == TokenElevationTypeFull)
{
err = BOOL_TO_ERR(GetTokenInformation(hToken, TokenLinkedToken, &tlt, sizeof(tlt), &rcb));
if (err == NOERROR)
{
if (NOERROR == (err = BOOL_TO_ERR(SetThreadToken(0, tlt.LinkedToken))))
{
bRet = ConvertToMappedFolderEx(pUncPath, pMappedDrive);
SetThreadToken(0, 0);
}
CloseHandle(tlt.LinkedToken);
}
}
}
}
}
BOOL ConvertToMappedFolderEx(LPSTR pUncPath, LPSTR pMappedDrive)
{
int nPos = 0;
UINT nType = 0;
char strDrive[MAX_PATH+1] = "?:\\";
DWORD dwDriveList = GetLogicalDrives();
BOOL bRet = FALSE;
(*pMappedDrive) = 0;
// Check each drive letter determining if it is a mapped drive...
while (dwDriveList)
{
if (dwDriveList & 1)
{
strDrive[0] = 0x41 + nPos;
nType = GetDriveType(strDrive);
// If drive unknown do not attempt to determine if its UNC matches up...
if (DRIVE_UNKNOWN != nType)
{
char szDeviceName[MAX_PATH+1] = "";
char szDriveLetter[4] = " :";
DWORD dwResult = 0;
DWORD cchBuff = MAX_PATH;
szDriveLetter[0] = strDrive[0];
dwResult = WNetGetConnection(szDriveLetter, (LPSTR) szDeviceName, &cchBuff);
if (NO_ERROR == dwResult)
{
LPSTR pPath = _stristr(pUncPath, szDeviceName);
if (NULL != pPath)
{
strcpy(pMappedDrive, szDriveLetter);
strcat(pMappedDrive, (pUncPath + strlen(szDeviceName)));
bRet = TRUE;
break;
}
}
}
}
dwDriveList >>= 1;
nPos++;
}
return (bRet);
}
connection made using Microsoft LAN Manager is per logon session. more exactly it associated with a logon session LUID. this is stored in token and can be read from TOKEN_STATISTICS.AuthenticationId. so result for any network drive functions depend from your current token - thread (if you impersonate) or process. use different tokens - can give different results. the elevated and not elevated processes always run in different logon sessions (have different AuthenticationId in process token).
so no sense speak about network drives in windows. need speak about network drives in logon session. and different logon session have different set of network drives. we can do next - enumerate all currently running processes, for every process open it token and query AuthenticationId - then we can once impersonate and query for every new AuthenticationId or say we can query AuthenticationId for not elevated token, linked to our elevated, and then try found process with exactly this token, impersonate it, and query with this token.
code example:
void CheckDrives()
{
LONG dwDriveList = GetLogicalDrives();
WCHAR Drive[] = L"Z:";
ULONG n = 1 + 'Z' - 'A';
do
{
if (_bittest(&dwDriveList, --n))
{
if (DRIVE_REMOTE == GetDriveTypeW(Drive))
{
PUSE_INFO_0 pui;
if (NET_API_STATUS err = NetUseGetInfo(0, Drive, 0, (BYTE**)&pui))
{
DbgPrint("%S error=%u\n", Drive, err);
}
else
{
DbgPrint("%S -> %S\n", pui->ui0_local, pui->ui0_remote);
NetApiBufferFree(pui);
}
}
}
--*Drive;
} while (n);
}
BOOL ImpersonateNotElevated(LUID AuthenticationId)
{
BOOL fOk = FALSE;
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnapshot != INVALID_HANDLE_VALUE)
{
PROCESSENTRY32W pe = { sizeof(pe) };
ULONG rcb;
BOOL fFound = FALSE;
if (Process32First(hSnapshot, &pe))
{
do
{
if (HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pe.th32ProcessID))
{
HANDLE hToken, hNewToken;
if (OpenProcessToken(hProcess, TOKEN_QUERY|TOKEN_DUPLICATE, &hToken))
{
TOKEN_STATISTICS ts;
if (GetTokenInformation(hToken, TokenStatistics, &ts, sizeof(ts), &rcb))
{
if (ts.AuthenticationId.LowPart == AuthenticationId.LowPart && ts.AuthenticationId.HighPart == AuthenticationId.HighPart)
{
fFound = TRUE;
if (DuplicateToken(hToken, SecurityImpersonation, &hNewToken))
{
fOk = SetThreadToken(0, hNewToken);
CloseHandle(hNewToken);
}
}
}
CloseHandle(hToken);
}
CloseHandle(hProcess);
}
} while (!fFound && Process32Next(hSnapshot, &pe));
}
CloseHandle(hSnapshot);
}
return fOk;
}
void CheckDrivesNotElevated()
{
HANDLE hToken;
if (OpenProcessToken(NtCurrentProcess(), TOKEN_QUERY, &hToken))
{
union {
TOKEN_ELEVATION_TYPE tet;
TOKEN_LINKED_TOKEN tlt;
};
ULONG rcb;
if (GetTokenInformation(hToken, TokenElevationType, &tet, sizeof(tet), &rcb))
{
if (tet == TokenElevationTypeFull)
{
if (GetTokenInformation(hToken, TokenLinkedToken, &tlt, sizeof(tlt), &rcb))
{
TOKEN_STATISTICS ts;
BOOL fOk = GetTokenInformation(tlt.LinkedToken, ::TokenStatistics, &ts, sizeof(ts), &rcb);
CloseHandle(tlt.LinkedToken);
if (fOk)
{
if (ImpersonateNotElevated(ts.AuthenticationId))
{
CheckDrives();
SetThreadToken(0, 0);
}
}
}
}
else
{
CheckDrives();
}
}
CloseHandle(hToken);
}
}

Serial port reading in c, using WinApi functions; WaitCommEvent fails

I tried to write a small event-based application in C for serial port reading (sources below). My program is to use the WinApi functions. The comport.c has the functions written to handle COM-port (open, read, write), the utils.c has some helper functions.
My program produces always the following output:
COM1 is selected to be listened.
GetCommMask result: 0x00000029 (EV_RXCHAR: 0x0001, EV_CTS: 0x0008, EV_RLSD: 0x0020)
Press any key to proceed...
I/O is pending (WaitCommEvent)...
I/O is pending (WaitCommEvent)...
I/O is pending (WaitCommEvent)...
I/O is pending (WaitCommEvent)...
I/O is pending (WaitCommEvent)...
It seems, that the function WaitCommEvent fails, the GetLastError() gives back error 87 (I/O pending).
Please help me to find out what the problem is, which parameter is invalid? See below the code.
The main.c:
#include "stdafx.h"
#include "comport.h"
#include "utils.h"
#include <conio.h>
#define READ_BUFF_MAX_LENGTH 1024
int _tmain(int argc, _TCHAR* argv[])
{
DWORD dwEvtMask;
HANDLE hComPort;
OVERLAPPED oEventHandler;
int portNum;
DWORD readTotal;
BOOL bOverlappedPending = FALSE;
char readBuff[READ_BUFF_MAX_LENGTH];
if(2 > argc)
{
printf("Use the program: ZliFuerZlvbusInterface.exe XXX (where XXX is the number of com port), \r\ne.G. for COM1 -> ZliFuerZlvbusInterface.exe 1\r\n");
return 1;
}
else
{
portNum = atoi(argv[1]);
if(0 == IsValidComNumber(portNum))
{
printf("ERROR: COM port number %d is invalid (parsed from '%s').\r\n", portNum, argv[1]);
return 2;
}
else
{
printf("COM%d is selected to be listened.\r\n", portNum);
}
}
if(0 == CreateSerialConnection(&hComPort, &oEventHandler, portNum, 1200, 8, EVEN, STOP1))
{
return 3;
}
if(FALSE == GetCommMask(hComPort, &dwEvtMask))
{
printf("GetCommMask failed with error:\r\n");
PrintLastErrorText();
return 4;
}
else
{
printf("GetCommMask result: 0x%08X (EV_RXCHAR: 0x0001, EV_CTS: 0x0008, EV_RLSD: 0x0020)\r\n", dwEvtMask);
}
printf("Press any key to proceed...\r\n");
getch();
while(1)
{
if(0 != kbhit())
{
if(27 == getch()) // ESC pressed
{
printf("Key ESC pressed, exiting...\r\n");
break;
}
}
bOverlappedPending = FALSE;
readTotal = 0;
if(TRUE == WaitCommEvent(hComPort, &dwEvtMask, &oEventHandler))
{
if(dwEvtMask & EV_CTS) // Clear-to-send signal present
{
PrintCurrentDateTime();
printf("COM%d: Clear-to-send signal set\r\n", portNum);
}
if(dwEvtMask & EV_RLSD) // Data-carrier-detect signal present
{
PrintCurrentDateTime();
printf("COM%d: Data-carrier-detect signal set\r\n", portNum);
}
if(dwEvtMask & EV_RXCHAR) // Data received
{
ReadSerial(&hComPort, &oEventHandler, portNum, readBuff, READ_BUFF_MAX_LENGTH);
}
}
else
{
if(ERROR_IO_PENDING == GetLastError())
{
printf("I/O is pending (WaitCommEvent)...\r\n");
bOverlappedPending = TRUE;
}
else
{
printf("WaitCommEvent failed with error:\r\n");
PrintLastErrorText();
}
}
if(TRUE == bOverlappedPending)
{
if(FALSE == GetOverlappedResult(hComPort, &oEventHandler, &readTotal, TRUE))
{
printf("GetOverlappedResult failed with error:\r\n");
PrintLastErrorText();
}
}
}
CloseSerialConnection(&hComPort);
return 0;
}
The comport.c:
#include <stdio.h>
#include "comport.h"
#include "utils.h"
int IsValidComNumber(int com)
{
if ((com < 1) ||
(com > 256))
{
return 0;
}
return 1;
}
int IsValidBaud(int baud)
{
switch(baud)
{
case CBR_110:
case CBR_300:
case CBR_600:
case CBR_1200:
case CBR_2400:
case CBR_4800:
case CBR_9600:
case CBR_14400:
case CBR_19200:
case CBR_38400:
case CBR_56000:
case CBR_57600:
case CBR_115200:
case CBR_128000:
case CBR_256000:
{
return 1;
break;
}
default:
{
break;
}
}
return 0;
}
int IsValidBits(int bits)
{
if ((bits < 5) ||
(bits > 8))
{
return 0;
}
else
{
return 1;
}
}
int CreateSerialConnection(HANDLE* handle, OVERLAPPED* overlapped, int portNumber, int baud, int bits, enum ParType parity, enum StopType stopbits)
{
DCB dcb;
COMMTIMEOUTS timeouts;
TCHAR portVirtualFile[32];
// For serial port name this format must be used (as virtual file): "\\\\.\\COMx"
memset(portVirtualFile, 0, 32);
#ifdef _UNICODE
swprintf(portVirtualFile, 32, L"\\\\.\\COM%d", portNumber);
#else
sprintf_s(portVirtualFile, 32, "\\\\.\\COM%d", portNumber);
#endif
if(0 == IsValidBaud(baud))
{
printf("ERROR: Specified baud rate %d is invalid for serial connection to COM%d.\r\n", baud, portNumber);
return 0;
}
if(0 == IsValidBits(bits))
{
printf("ERROR: Specified number of data bits %d is invalid for serial connection to COM%d.\r\n", bits, portNumber);
return 0;
}
*handle = CreateFile(portVirtualFile, // Specify port device
GENERIC_READ | GENERIC_WRITE, // Specify mode that open device.
0, // the devide isn't shared.
NULL, // the object gets a default security.
OPEN_EXISTING, // Specify which action to take on file.
FILE_FLAG_OVERLAPPED, // Use overlapped I/O.
NULL); // default.
if(*handle == INVALID_HANDLE_VALUE)
{
printf("ERROR: Opening serial port COM%d failed\r\n", portNumber);
return 0;
}
if(FALSE == GetCommState(*handle, &dcb))
{
printf("ERROR: Getting current state of COM%d\r\n", portNumber);
PrintLastErrorText();
return 0;
}
memset(&dcb, 0, sizeof(dcb)); //zero initialize the structure
dcb.DCBlength = sizeof(dcb); //fill in length
dcb.BaudRate = baud; // baud rate
dcb.ByteSize = bits; // data size, xmit and rcv
dcb.Parity = parity; // parity bit
dcb.StopBits = stopbits; // stop bits
if(FALSE == SetCommState(*handle, &dcb))
{
printf("ERROR: Setting new state of COM%d failed.\r\n", portNumber);
PrintLastErrorText();
return 0;
}
if(FALSE == SetCommMask(*handle, EV_RXCHAR | EV_CTS | EV_RLSD))
{
printf("ERROR: Setting new COM MASK (events) for COM%d failed.\r\n", portNumber);
PrintLastErrorText();
return 0;
}
timeouts.ReadIntervalTimeout = MAXDWORD;
timeouts.ReadTotalTimeoutMultiplier = 0;
timeouts.ReadTotalTimeoutConstant = 0;
timeouts.WriteTotalTimeoutMultiplier = 0;
timeouts.WriteTotalTimeoutConstant = 0;
if(FALSE == SetCommTimeouts(*handle, &timeouts))
{
printf("ERROR: Setting timeout parameters for COM%d failed.\r\n", portNumber);
PrintLastErrorText();
return 0;
}
(*overlapped).hEvent = CreateEvent(
NULL, // default security attributes
TRUE, // manual-reset event
FALSE, // not signaled
NULL // no name
);
if(NULL == overlapped->hEvent)
{
printf("ERROR: CreateEvent for COM%d failed.\r\n", portNumber);
PrintLastErrorText();
return 0;
}
// Initialize the rest of the OVERLAPPED structure to zero.
overlapped->Internal = 0;
overlapped->InternalHigh = 0;
overlapped->Offset = 0;
overlapped->OffsetHigh = 0;
return 1;
}
int CloseSerialConnection(HANDLE* handle)
{
if(FALSE == CloseHandle(*handle))
{
printf("ERROR: Cannot close handle 0x8.8%X\r\n", *handle);
PrintLastErrorText();
return 0;
}
*handle = NULL;
return 1;
}
int ReadSerial(HANDLE* handle, LPOVERLAPPED ov, int num, char* buffer, int max_len)
{
DWORD readTotal = 0;
if(FALSE == ClearCommError(*handle, NULL, NULL))
{
printf("ClearCommError failed with error:\r\n");
PrintLastErrorText();
return 0;
}
else
{
memset(buffer, 0, max_len);
if(FALSE == ReadFile(*handle, buffer, max_len, &readTotal, ov))
{
printf("ERROR: Reading from port COM%d failed\r\n", num);
if(ERROR_IO_PENDING == GetLastError())
{
printf("I/O is pending (ReadFile)...\r\n");
if(FALSE == GetOverlappedResult(*handle, ov, &readTotal, TRUE))
{
printf("GetOverlappedResult failed with error:\r\n");
PrintLastErrorText();
return 0;
}
}
else
{
PrintLastErrorText();
return 0;
}
}
else
{
PrintCurrentDateTime();
printf("Received %d characters on port COM%d: ", readTotal, num);
PrintBufferContent(buffer, readTotal);
}
}
return 1;
}
The utils.c:
#include <Windows.h>
#include <stdio.h>
#include "utils.h"
void PrintLastErrorText(void)
{
DWORD retSize;
LPTSTR pTemp = NULL;
retSize = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY, NULL, GetLastError(), LANG_NEUTRAL, (LPTSTR)&pTemp, 0, NULL);
if ((retSize > 0) &&
(pTemp != NULL))
{
printf("Last error: %s (0x%08X)\r\n", pTemp, GetLastError());
LocalFree((HLOCAL)pTemp);
}
}
void PrintCurrentDateTime(void)
{
SYSTEMTIME systime;
GetLocalTime(&systime);
printf("%04d.%02d.%02d %02d:%02d:%02d:%03d ", systime.wYear, systime.wMonth, systime.wDay, systime.wHour, systime.wMinute, systime.wSecond, systime.wMilliseconds);
}
void PrintBufferContent(char* buff, int len)
{
int i;
for(i = 0; i<len; i++)
{
printf("%02X ", buff[i]);
}
}
You're using the same OVERLAPPED structure for WaitCommEvent and ReadFile. Try using separate/independent OVERLAPPED for each.
UPDATE: Ignore that previous answer.
If your call to WaitCommEvent returns ERROR_IO_PENDING, you're not waiting for it to complete. Rather than loop around and call WaitCommEvent again, you need to wait for the operation to complete (typically via GetOverlappedResult).
You cannot have multiple pending asynchronous requests share a single OVERLAPPED structure. By looping and calling WaitCommEvent again after ERROR_IO_PENDING, that's exactly what's happening.

STM32F103 - PC communication via USB

I am trying to use the found-bits project to communicate with my STM32F103 via USB from a Windows application with no success.
The program keeps returning an error code 31 at the WinUsb_ControlTransfer function call.
I made some changes that solved the problem for receiving the data from the default end point but the issue remains when trying to send data to it.
How can I get my windows application to send and receive data from the STM32?
P.S.: I created .inf and .cat files for my device and installed the driver
BOOL SendDatatoDefaultEndpoint(WINUSB_INTERFACE_HANDLE hDeviceHandle, BYTE byWinUSBCommControl, BYTE *pbyData = NULL, WORD wNumBytesCount = 0)
{
if (hDeviceHandle==INVALID_HANDLE_VALUE)
{
return FALSE;
}
BOOL bResult = TRUE;
WINUSB_SETUP_PACKET SetupPacket;
ZeroMemory(&SetupPacket, sizeof(WINUSB_SETUP_PACKET));
ULONG cbSent = 0;
//Create the setup packet
SetupPacket.RequestType = (BMREQUEST_HOST_TO_DEVICE << 7)/* | (BMREQUEST_VENDOR << 5) | BMREQUEST_TO_INTERFACE*/;
//SetupPacket.Request = byWinUSBCommControl;
//SetupPacket.Value = 0;
SetupPacket.Index = 0; // specify WinUSBComm interface
//SetupPacket.Length = wNumBytesCount;
SetupPacket.Request = USB_REQUEST_GET_DESCRIPTOR;
SetupPacket.Value = USB_DEVICE_DESCRIPTOR_TYPE << 8;
SetupPacket.Length = sizeof(USB_DEVICE_DESCRIPTOR);
bResult = WinUsb_ControlTransfer(hDeviceHandle, SetupPacket, pbyData, wNumBytesCount, &cbSent, 0);
if(!bResult)
{
printf("Error WinUsb_ControlTransfer: %d.\n", GetLastError());
goto done;
}
PTRACE("Data sent: %d \nActual data transferred: %d.\n", wNumBytesCount, cbSent);
done:
return bResult;
}
BOOL GetDataFromDefaultEndpoint(WINUSB_INTERFACE_HANDLE hDeviceHandle, BYTE byWinUSBCommControl, BYTE *pbyData, WORD wNumBytesCount)
{
if ( 0 == wNumBytesCount )
{
return TRUE;
}
if ( NULL == pbyData )
{
return FALSE;
}
if (hDeviceHandle==INVALID_HANDLE_VALUE)
{
return FALSE;
}
BOOL bResult = TRUE;
WINUSB_SETUP_PACKET SetupPacket;
ZeroMemory(&SetupPacket, sizeof(WINUSB_SETUP_PACKET));
ULONG cbSent = 0;
//Create the setup packet
SetupPacket.RequestType = (BMREQUEST_DEVICE_TO_HOST << 7)/* | (BMREQUEST_VENDOR << 5) | BMREQUEST_TO_DEVICE*/;
//SetupPacket.Request = byWinUSBCommControl;
//SetupPacket.Value = 0;
SetupPacket.Index = 0; // specify WinUSBComm interface
//SetupPacket.Length = wNumBytesCount;
SetupPacket.Request = USB_REQUEST_GET_DESCRIPTOR;
SetupPacket.Value = USB_DEVICE_DESCRIPTOR_TYPE << 8;
SetupPacket.Length = sizeof(USB_DEVICE_DESCRIPTOR);
bResult = WinUsb_ControlTransfer(hDeviceHandle, SetupPacket, pbyData, wNumBytesCount, &cbSent, 0);
if(!bResult)
{
printf("Error WinUsb_ControlTransfer: %d.\n", GetLastError());
goto done;
}
PTRACE("Data get : %d \nActual data transferred: %d.\n", wNumBytesCount, cbSent);
done:
return bResult;
}

Resources