Sending POST request with IWebBrowser2 in plain C - c

I need to compile a POST request routine using IWebBrowser2 in plain C, the problem is that "the post data specified by PostData is passed as a SAFEARRAY Data Type structure. The VARIANT should be of type VT_ARRAY|VT_UI1 and point to a SAFEARRAY Data Type. The SAFEARRAY Data Type should be of element type VT_UI1, dimension one, and have an element count equal to the number of bytes of post data." as it says in https://learn.microsoft.com/en-us/previous-versions/aa752133(v=vs.85)
When i send the request to my local server it just dont receive the $_POST['name'] nor $_POST['sub'] variables, like i didnt send nothing
INT32
WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT32 nShowCmd)
{
HRESULT HResult = 0;
CLSID CLSID_IE;
IWebBrowser2 *pWebBrowser;
VARIANT vEmpty;
VARIANT_BOOL vBusy;
VariantInit(&vEmpty);
CoInitializeEx(0, COINIT_MULTITHREADED);
CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);
CoCreateInstance(&CLSID_InternetExplorer, 0, CLSCTX_ALL, &IID_IWebBrowser2, &pWebBrowser);
IWebBrowser2_put_Visible(pWebBrowser, VARIANT_FALSE);
/* process the formulary data */
LPSTR pPostData = NULL;
CHAR strFormulary[] = "sub=gt&name=sdfs";
LPSAFEARRAY FormularyArray = SafeArrayCreateVector(VT_UI1, 0, sizeof(strFormulary));
VARIANT PostData = FormularyArray;
SafeArrayAccessData(FormularyArray, (LPVOID*)&pPostData);
memcpy(pPostData, &strFormulary, sizeof(strFormulary));
SafeArrayUnaccessData(FormularyArray);
/* Set the headers data */
VARIANT Headers;
V_VT(&Headers) = VT_BSTR;
V_BSTR(&Headers) = SysAllocString(L"Content-Type: application/x-www-form-urlencodedrn");
/* Set POST request */
BSTR bstrURL = SysAllocString(L"http://192.168.100.44/user.php");
IWebBrowser2_Navigate(pWebBrowser, bstrURL, &vEmpty, &vEmpty, &PostData, &Headers);
// Wait for page to load
do {
LARGE_INTEGER TimeOut;
UINT32 Milliseconds = 2000;
TimeOut.QuadPart = UInt32x32To64( Milliseconds, 1000 );
TimeOut.QuadPart *= -1;
NtDelayExecution(FALSE, &TimeOut);
IWebBrowser2_get_Busy(pWebBrowser, &vBusy);
} while(vBusy);
// Get IDispatch interface
IDispatch* pDispatch;
IWebBrowser2_get_Document(pWebBrowser, &pDispatch);
IHTMLDocument2* pDocument;
IDispatch_QueryInterface(pDispatch, &IID_IHTMLDocument2 , &pDocument);
IHTMLElement* lpBodyElm;
IHTMLDocument2_get_body(pDocument, &lpBodyElm);
IHTMLElement* lpParentElm;
IHTMLElement_get_parentElement(lpBodyElm, &lpParentElm);
// Get Inner HTML content content of the request
BSTR bstrBody;
lpParentElm->lpVtbl->get_innerHTML(lpParentElm, &bstrBody);
wprintf(L"%ls\n\n", bstrBody);
cleanup:
SysFreeString(bstrURL);
IWebBrowser2_Quit(pWebBrowser);
IWebBrowser2_Release(pWebBrowser);
IDispatch_Release(pDispatch);
IHTMLDocument2_Release(pDocument);
IHTMLElement_Release(lpBodyElm);
lpParentElm->lpVtbl->Release(lpParentElm);
CoUninitialize();
RtlExitUserProcess(STATUS_SUCCESS);
}

i solved it this way:
INT32
WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT32 nShowCmd)
{
HRESULT HResult = 0;
CLSID CLSID_IE;
IWebBrowser2 *pWebBrowser;
VARIANT vEmpty;
VARIANT_BOOL vBusy;
VariantInit(&vEmpty);
CoInitializeEx(0, COINIT_MULTITHREADED);
CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);
CoCreateInstance(&CLSID_InternetExplorer, 0, CLSCTX_ALL, &IID_IWebBrowser2, &pWebBrowser);
IWebBrowser2_put_Visible(pWebBrowser, VARIANT_FALSE);
/* Set the POST data */
VARIANT PostData;
PostData.vt = VT_NULL;
CHAR PostDataContent[] = "sub=gt&name=sdfs";
UINT32 PostDatalenght = sizeof(PostDataContent);
// Create safe array
SAFEARRAY* psa = SafeArrayCreateVector(VT_UI1, 0, PostDatalenght);
if (psa != NULL)
{
// Store elements into the SafeArray
BYTE HUGEP* pByte = (PBYTE)&PostDataContent;
HRESULT hr = S_OK;
for (long i=0; i<PostDatalenght; i++){
hr = SafeArrayPutElement(psa, &i, pByte);
pByte++;
}
// Get a pointer to the elements of the array.
SafeArrayAccessData(psa, (void HUGEP**)&pByte);
PostData.vt = VT_ARRAY|VT_UI1;
PostData.parray = psa;
}
/* Set the headers data */
VARIANT Headers;
V_VT(&Headers) = VT_BSTR;
V_BSTR(&Headers) = SysAllocString(L"Content-Type: application/x-www-form-urlencoded");
/* Set POST request */
BSTR bstrURL = SysAllocString(L"http://192.168.100.44/user.php");
IWebBrowser2_Navigate(pWebBrowser, bstrURL, &vEmpty, &vEmpty, &PostData, &Headers);
// Wait for page to load
do {
LARGE_INTEGER TimeOut;
UINT32 Milliseconds = 2000;
TimeOut.QuadPart = UInt32x32To64( Milliseconds, 1000 );
TimeOut.QuadPart *= -1;
NtDelayExecution(FALSE, &TimeOut);
IWebBrowser2_get_Busy(pWebBrowser, &vBusy);
} while(vBusy);
// Get IDispatch interface
IDispatch* pDispatch;
IWebBrowser2_get_Document(pWebBrowser, &pDispatch);
IHTMLDocument2* pDocument;
IDispatch_QueryInterface(pDispatch, &IID_IHTMLDocument2 , &pDocument);
IHTMLElement* lpBodyElm;
IHTMLDocument2_get_body(pDocument, &lpBodyElm);
IHTMLElement* lpParentElm;
IHTMLElement_get_parentElement(lpBodyElm, &lpParentElm);
// Get Inner HTML content content of the request
BSTR bstrBody;
lpParentElm->lpVtbl->get_innerHTML(lpParentElm, &bstrBody);
wprintf(L"%ls\n\n", bstrBody);
cleanup:
SysFreeString(bstrURL);
IWebBrowser2_Quit(pWebBrowser);
IWebBrowser2_Release(pWebBrowser);
IDispatch_Release(pDispatch);
IHTMLDocument2_Release(pDocument);
IHTMLElement_Release(lpBodyElm);
lpParentElm->lpVtbl->Release(lpParentElm);
CoUninitialize();
RtlExitUserProcess(STATUS_SUCCESS);
}

Related

why not found device obj?

I write driver .
Creates an Device Object (name = ICOCTL_1) when the service starts but getlastError function return not_foun_file(code 2)
enter image description here
void CUserAppDlg::OnBnClickedbtncreate(){
deviceHandle = CreateFile(L"\\\\.\\IOCTL_1", GENERIC_ALL, 0, 0, OPEN_EXISTING,
FILE_ATTRIBUTE_SYSTEM, 0);
DWORD data = GetLastError();
TCHAR s[100];
_stprintf_s(s, _T("%X"), data);
MessageBox(s);}

VLC coding and display

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.

Detect USB drive insertion in C (Windows)

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.

GetGUIThreadInfo() returns TRUE but GUITHREADINFO contains only zeroes

I use Windows 7 and Microsoft Visual Studio 2010.
This is my code below (I start notepad.exe and want to find focused sub-window handle:
STARTUPINFO si = { 0 };
PROCESS_INFORMATION pi = { 0 };
memset(&si, 0, sizeof(si));
memset(&pi, 0, sizeof(pi));
si.cb = sizeof(si);
BOOL bResult = CreateProcess("c:\\windows\\syswow64\\notepad.exe", NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
WaitForInputIdle(pi.hProcess, INFINITE);
HWND hWnd = FindWindow("Notepad", NULL);
DWORD dwTID;
dwTID = GetWindowThreadProcessId(hWnd, NULL);
GUITHREADINFO info = { sizeof(info) };
AttachThreadInput(GetCurrentThreadId(), dwTID, TRUE);
GetGUIThreadInfo(dwTID, &info);
AttachThreadInput(GetCurrentThreadId(), dwTID, FALSE);
FindWindow() returns correct hWnd; and GetWindowThreadProcessId() returns correct TID of window thread (have checked it in Spy++). Both AttachThreadInput() and GetGUIThreadInfo() return TRUE. But info contains only zeroes (except cbSize member which contains size of structure). If I use GetFocus() I still receive NULL.
What am I doing wrong?

save file without save dialog

I have 3 global variables:
OPENFILENAME ofn;
TCHAR FileName[1024];
TCHAR Title[1024];
In WM_CREATE, I fill the information for ofn:
static TCHAR filter[] = TEXT("Bitmap Files (*.BMP)\0*.bmp\0") \
TEXT("All Files (*.*)\0*.*\0\0");
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = hwnd;
ofn.hInstance = NULL;
ofn.lpstrFilter = filter;
ofn.lpstrCustomFilter = NULL;
ofn.nMaxCustFilter = 0;
ofn.nFilterIndex = 0;
ofn.lpstrFile = NULL;
ofn.nMaxFile = 1024;
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 1024;
ofn.lpstrInitialDir = NULL;
ofn.lpstrTitle = NULL;
ofn.Flags = 0;
ofn.nFileOffset = 0;
ofn.nFileExtension = 0;
ofn.lpstrDefExt = TEXT("bmp");
ofn.lCustData = 0;
ofn.lpfnHook = NULL;
ofn.lpTemplateName = NULL;
In WM_COMMAND with case ID_FILE_SAVE:, I have
case ID_FILE_SAVE:
if (!SaveAsBmpDialog(hwnd, FileName, Title))
return 0;
SaveAsBmp(FileName);
return 0;
where SaveAsBmpDialog is
static bool SaveAsBmpDialog(HWND hwnd, TCHAR *fileName, TCHAR *title)
{
ofn.hwndOwner = hwnd;
ofn.lpstrFile = fileName;
ofn.lpstrFileTitle = title;
ofn.Flags = NULL;
return GetSaveFileName(&ofn);
}
It works fine to save HDC to a Bitmap file (which can be open).
But in WM_CHAR with wParam == 'p', I have
SaveAsBmp(FileName);
return 0;
I use this function when SaveAsBmpDialog is called at once before, so FileName is a full-path already.
But I get a Bitmap file, which can not be open. (Even if I delete the file first, it creates the file, but still cannot be open). The file size is as before, so I think WriteFile in SaveAsBmp works.
I don't understand why it doesn't work without GetSaveFileName(&ofn) in WM_CHAR.
What I want is to save HDC to a exist file without save dialog.
ps: In SaveAsBmp, I have
HANDLE hFile = CreateFile(FileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
DWORD dwBytesWritten;
//SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
WriteFile(hFile, &fileHeader, sizeof(BITMAPFILEHEADER), &dwBytesWritten, NULL);
WriteFile(hFile, &info.bmiHeader, sizeof(BITMAPINFOHEADER) + info.bmiHeader.biClrUsed * sizeof(RGBQUAD), &dwBytesWritten, NULL);
WriteFile(hFile, pPixels, (int) info.bmiHeader.biSizeImage, &dwBytesWritten, NULL);
CloseHandle(hFile);

Resources