I am new to programming and image processing. Recently i developed a system that detects faces from video feed and recognizes the person. If the person is already available on the database it tags his/her name to the frame, else if the person is new, it asks for their name and takes sufficient photos and stores in the database so that it can identify the person the next time. I am using the fisher-faces algorithm for this task.
Now my question is , i want the system to talk. I want it to tell the name of the person it identified recently.
I can use
static class Once { public: Once(){talk();}} Once_;
to call the function talk once.
but it is not organic and the talk function is not accepting input from the user.
Can anyone please suggest me a solution, or where to start the solution for this problem.
The talk function is
int speech(char* value)
{
ISpVoice * pVoice = NULL;
if (FAILED(::CoInitialize(NULL)))
return FALSE;
HRESULT hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void **)&pVoice);
if( SUCCEEDED( hr ) )
{
hr = pVoice->Speak(L"userINPUT", SPF_IS_XML, NULL);
pVoice->Release();
pVoice = NULL;
}
::CoUninitialize();
return TRUE;
}
so, here's my proposal:
// -- >8 ---------- speech.h --------------------------
#ifndef __speech_onboard__
#define __speech_onboard__
struct ISpVoice; // fwd ref, since mixing opencv and windows headers is a receipt for desaster
namespace Speech
{
class Voice
{
ISpVoice * spVoice;
public:
Voice();
~Voice();
int speak( const char * txt, int flags=0 ) const ;
// Supported values range from -10 to 10
int setRate( int s );
// Supported values range from 0 to 100
int setVolume( int s );
};
};
#endif // __speech_onboard__
// ---- >8 speech.cpp ------------------------------
#include <windows.h>
#include <sapi.h>
#include "speech.h"
#define COM_RELEASE(x) { if ((x)) (x)->Release(); (x) = NULL; }
namespace Speech
{
struct _ComUser
{
_ComUser() {CoInitialize(0);}
~_ComUser() {CoUninitialize();}
} _we_need_a_singleton_per_module;
inline int w2a( WCHAR *in, char *out )
{
out[0]=0;
return WideCharToMultiByte(CP_ACP, 0, in, -1, out, MAX_PATH, 0, 0);
}
inline int a2w( const char *in, WCHAR *out )
{
out[0]=0;
return MultiByteToWideChar(CP_ACP, 0, in, -1, out, MAX_PATH);
}
Voice::Voice()
: spVoice(0)
{
HRESULT hr = CoCreateInstance( CLSID_SpVoice, NULL, CLSCTX_INPROC_SERVER, IID_ISpVoice, (LPVOID *)&(spVoice) );
}
Voice::~Voice()
{
COM_RELEASE( spVoice );
}
//SPF_ASYNC = ( 1L << 0 ) ,
//SPF_PURGEBEFORESPEAK = ( 1L << 1 ) ,
//SPF_IS_FILENAME = ( 1L << 2 ) ,
//SPF_IS_XML = ( 1L << 3 ) ,
//SPF_IS_NOT_XML = ( 1L << 4 ) ,
//SPF_PERSIST_XML = ( 1L << 5 ) ,
//SPF_NLP_SPEAK_PUNC = ( 1L << 6 ) ,
//SPF_PARSE_SAPI = ( 1L << 7 ) ,
//SPF_PARSE_SSML = ( 1L << 8 ) ,
//SPF_PARSE_AUTODETECT = 0,
int Voice::speak( const char * txt, int flags ) const
{
if ( ! spVoice )
return 0;
WCHAR wtxt[800];
a2w(txt,wtxt);
ULONG pulstream = 0;
HRESULT hr = spVoice->Speak( wtxt, flags, &pulstream );
return hr==S_OK;
}
// Supported values range from -10 to 10
int Voice::setRate( int s )
{
if ( ! spVoice )
return 0;
HRESULT hr = spVoice->SetRate( s );
return hr==S_OK;
}
// Supported values range from 0 to 100
int Voice::setVolume( int s )
{
if ( ! spVoice )
return 0;
HRESULT hr = spVoice->SetVolume ( s );
return hr==S_OK;
}
}
// ----- >8 main.cpp --------------------------------------------
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
using namespace cv;
#include "speech.h"
int main(int argc, char** argv)
{
Speech::Voice voice;
voice.speak("hello , oh, hello!", 1); // async
Mat img(300,300,CV_8UC3,Scalar(255,0,0));
namedWindow("Display window",0);
putText(img,"lala la",Point(20,120),0,2.5,Scalar(0,200,0),5);
imshow("Display window", img);
waitKey(0);
voice.speak("bye bye, see you later !"); // sync
return 0;
}
Related
So all I want in life is to have a program where I can say "Hey Computer" and it responds with "Hello". So I set myself upon the task and after some research produced the code below yet whenever I try to compile it through Visual Studio 2017 on Windows 10 I get this error: 'GetVersionExA': was declared deprecated but I don't understand because I don't call that function anywhere in my code.
#include <sphelper.h>
#include <sapi.h>
#include <iostream>
#include <string>
#include <vector>
#include <locale>
const ULONGLONG grammarId = 0;
const wchar_t* ruleName1 = L"ruleName1";
int start_listening(const std::string& word);
ISpRecoGrammar* init_grammar(ISpRecoContext* recoContext, const std::string& command);
void get_text(ISpRecoContext* reco_context);
void check_result(const HRESULT& result);
ISpVoice * pVoice = NULL;
HRESULT hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void **)&pVoice);
inline std::wstring s2w(const std::string &s, const std::locale &loc = std::locale())
{
typedef std::ctype<wchar_t> wchar_facet;
std::wstring return_value;
if (s.empty())
{
return return_value;
}
if (std::has_facet<wchar_facet>(loc))
{
std::vector<wchar_t> to(s.size() + 2, 0);
std::vector<wchar_t>::pointer toPtr = &to[0];
const wchar_facet &facet = std::use_facet<wchar_facet>(loc);
if (0 != facet.widen(s.c_str(), s.c_str() + s.size(), toPtr))
{
return_value = to.data();
}
}
return return_value;
}
int main(int argc, char** argv)
{
HRESULT hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void **)&pVoice);
std::string hello = "hello";
start_listening("Hey computer");
hr = pVoice->Speak(s2w(hello).c_str(), 0, NULL);
return EXIT_SUCCESS;
}
// This function exits when the word passed as parameter is said by the user
int start_listening(const std::string& word)
{
// Initialize COM library
if (FAILED(::CoInitialize(nullptr))) {
return EXIT_FAILURE;
}
std::cout << "You should start Windows Recognition" << std::endl;
std::cout << "Just say \"" << word << "\"" << std::endl;
HRESULT hr;
ISpRecognizer* recognizer;
hr = CoCreateInstance(CLSID_SpSharedRecognizer,
nullptr, CLSCTX_ALL, IID_ISpRecognizer,
reinterpret_cast<void**>(&recognizer));
check_result(hr);
ISpRecoContext* recoContext;
hr = recognizer->CreateRecoContext(&recoContext);
check_result(hr);
// Disable context
hr = recoContext->Pause(0);
check_result(hr);
ISpRecoGrammar* recoGrammar = init_grammar(recoContext, word);
hr = recoContext->SetNotifyWin32Event();
check_result(hr);
HANDLE handleEvent;
handleEvent = recoContext->GetNotifyEventHandle();
if (handleEvent == INVALID_HANDLE_VALUE) {
check_result(E_FAIL);
}
ULONGLONG interest;
interest = SPFEI(SPEI_RECOGNITION);
hr = recoContext->SetInterest(interest, interest);
check_result(hr);
// Activate Grammar
hr = recoGrammar->SetRuleState(ruleName1, 0, SPRS_ACTIVE);
check_result(hr);
// Enable context
hr = recoContext->Resume(0);
check_result(hr);
// Wait for reco
HANDLE handles[1];
handles[0] = handleEvent;
WaitForMultipleObjects(1, handles, FALSE, INFINITE);
get_text(recoContext);
std::cout << "Hello user" << std::endl;
recoGrammar->Release();
::CoUninitialize();
system("PAUSE");
return EXIT_SUCCESS;
}
/**
* Create and initialize the Grammar.
* Create a rule for the grammar.
* Add word to the grammar.
*/
ISpRecoGrammar* init_grammar(ISpRecoContext* recoContext, const std::string& command)
{
HRESULT hr;
SPSTATEHANDLE sate;
ISpRecoGrammar* recoGrammar;
hr = recoContext->CreateGrammar(grammarId, &recoGrammar);
check_result(hr);
WORD langId = MAKELANGID(LANG_FRENCH, SUBLANG_FRENCH);
hr = recoGrammar->ResetGrammar(langId);
check_result(hr);
// TODO: Catch error and use default langId => GetUserDefaultUILanguage()
// Create rules
hr = recoGrammar->GetRule(ruleName1, 0, SPRAF_TopLevel | SPRAF_Active, true, &sate);
check_result(hr);
// Add a word
const std::wstring commandWstr = std::wstring(command.begin(), command.end());
hr = recoGrammar->AddWordTransition(sate, NULL, commandWstr.c_str(), L" ", SPWT_LEXICAL, 1, nullptr);
check_result(hr);
// Commit changes
hr = recoGrammar->Commit(0);
check_result(hr);
return recoGrammar;
}
void get_text(ISpRecoContext* reco_context)
{
const ULONG maxEvents = 10;
SPEVENT events[maxEvents];
ULONG eventCount;
HRESULT hr;
hr = reco_context->GetEvents(maxEvents, events, &eventCount);
// Warning hr equal S_FALSE if everything is OK
// but eventCount < requestedEventCount
if (!(hr == S_OK || hr == S_FALSE)) {
check_result(hr);
}
ISpRecoResult* recoResult;
recoResult = reinterpret_cast<ISpRecoResult*>(events[0].lParam);
wchar_t* text;
hr = recoResult->GetText(SP_GETWHOLEPHRASE, SP_GETWHOLEPHRASE, FALSE, &text, NULL);
check_result(hr);
CoTaskMemFree(text);
}
void check_result(const HRESULT& result)
{
if (result == S_OK) {
return;
}
std::string message;
switch (result) {
case E_INVALIDARG:
message = "One or more arguments are invalids.";
case E_ACCESSDENIED:
message = "Acces Denied.";
case E_NOINTERFACE:
message = "Interface does not exist.";
case E_NOTIMPL:
message = "Not implemented method.";
case E_OUTOFMEMORY:
message = "Out of memory.";
case E_POINTER:
message = "Invalid pointer.";
case E_UNEXPECTED:
message = "Unexpecter error.";
case E_FAIL:
message = "Failure";
default:
message = "Unknown : " + std::to_string(result);
}
throw std::exception(message.c_str());
}
It is suppressable with a pragma:
#pragma warning(disable:4996)
#include <sphelper.h>
#pragma warning(default: 4996)
GetVersionEx is being used by the header sphelper.h which you're including. It's using it to check that the function SpGetDescription() is running on Vista or later. You could probably work around this issue by targeting the 8.1 SDK version instead of 10. However, it's bad that the shipped MS SAPI API in the Windows 10 SDK is using functions which are deprecated in Windows 10.. I'd say this is a MS issue.
Alternately this would work:
#define FKG_FORCED_USAGE 1
#include <sphelper.h>
#undef FKG_FORCED_USAGE
I am trying to create a connection between my local application and my remote application. I used HTTP protocol, when testing in local network, my client-server code had successfully sent file to each other; however, the client couldn't connect to server when i pushed my server code to running on Cloud.
Below is my client-server code in C++. In the code, i tried to send an image from client to server.
client.c
#define EXAMPLE_RX_BUFFER_BYTES (921600)
#define IMAGE_SIZE 921600
static int callback_example( struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len )
{
switch( reason )
{
case LWS_CALLBACK_CLIENT_ESTABLISHED:
lws_callback_on_writable( wsi );
break;
case LWS_CALLBACK_CLIENT_RECEIVE:
break;
case LWS_CALLBACK_CLIENT_WRITEABLE:
{
FILE * check_file;
check_file = fopen("test_buff.jpg", "r");
unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + EXAMPLE_RX_BUFFER_BYTES + LWS_SEND_BUFFER_POST_PADDING];
fread(&buf[LWS_SEND_BUFFER_PRE_PADDING], 1, IMAGE_SIZE, check_file);
printf("%ld\n", sizeof(buf));
printf("hello\n");
printf("%d\n", LWS_SEND_BUFFER_POST_PADDING);
unsigned char *p = &buf[LWS_SEND_BUFFER_PRE_PADDING];
size_t n = IMAGE_SIZE;
lws_write( wsi, p, n, LWS_WRITE_TEXT ); //send
break;
}
case LWS_CALLBACK_CLOSED:
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
web_socket = NULL;
break;
default:
break;
}
return 0;
}
enum protocols
{
PROTOCOL_EXAMPLE = 0,
PROTOCOL_COUNT
};
static struct lws_protocols protocols[] =
{
{
"example-protocol",
callback_example,
0,
EXAMPLE_RX_BUFFER_BYTES,
},
{ NULL, NULL, 0, 0 } /* terminator */
};
int main( int argc, char *argv[] )
{
struct lws_context_creation_info info;
memset( &info, 0, sizeof(info) );
info.port = CONTEXT_PORT_NO_LISTEN;
info.protocols = protocols;
info.gid = -1;
info.uid = -1;
struct lws_context *context = lws_create_context( &info );
time_t old = 0;
while( 1 )
{
struct timeval tv;
gettimeofday( &tv, NULL );
if( !web_socket && tv.tv_sec != old )
{
struct lws_client_connect_info ccinfo = {0};
ccinfo.context = context;
ccinfo.address = "https://http-server.wise-paas.io";
ccinfo.port = 8080;
ccinfo.path = "/";
ccinfo.host = lws_canonical_hostname( context );
ccinfo.origin = "origin";
ccinfo.protocol = protocols[PROTOCOL_EXAMPLE].name;
web_socket = lws_client_connect_via_info(&ccinfo);
}
if( tv.tv_sec != old )
{
lws_callback_on_writable( web_socket );
old = tv.tv_sec;
}
lws_service( context, 250 );
sleep(1);
}
lws_context_destroy( context );
return 0;
}
server.c
static int callback_http( struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len )
{
switch( reason )
{
case LWS_CALLBACK_HTTP:
lws_serve_http_file( wsi, "example.html", "text/html", NULL, 0 );
break;
default:
break;
}
return 0;
}
int count = 0;
int length = 0;
struct payload
{
unsigned char data[LWS_SEND_BUFFER_PRE_PADDING + IMAGE_SIZE + LWS_SEND_BUFFER_POST_PADDING];
size_t len;
} received_payload;
static int callback_example( struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len )
{
switch( reason )
{
case LWS_CALLBACK_RECEIVE:
//while(length < IMAGE_SIZE){
memcpy( &received_payload.data[LWS_SEND_BUFFER_PRE_PADDING + length], in, len );
// for(int i =16; i < (LWS_SEND_BUFFER_PRE_PADDING + len); i++){
// printf("%c\t", received_payload.data[i]);
// }
length+=len;
received_payload.len = length;
// printf("\n\nlength: %d \n", length);
//}
lws_callback_on_writable_all_protocol( lws_get_context( wsi ), lws_get_protocol( wsi ) );
//unsigned char *p = &received_payload.data[LWS_SEND_BUFFER_PRE_PADDING];
// count++;
if(length >= 921600){
length = 0;
}
printf("hello for saving\n");
printf("%d\n%d\n", len, sizeof(received_payload.data));
FILE *receive_test;
receive_test = fopen("write", "w");
fwrite(&received_payload.data[LWS_SEND_BUFFER_PRE_PADDING], 1, IMAGE_SIZE, receive_test);
fclose(receive_test);
break;
case LWS_CALLBACK_SERVER_WRITEABLE:
lws_write( wsi, &received_payload.data[LWS_SEND_BUFFER_PRE_PADDING], received_payload.len, LWS_WRITE_TEXT );
break;
default:
break;
}
return 0;
}
enum protocols
{
PROTOCOL_HTTP = 0,
PROTOCOL_EXAMPLE,
PROTOCOL_COUNT
};
static struct lws_protocols protocols[] =
{
/* The first protocol must always be the HTTP handler */
{
"http-only", /* name */
callback_http, /* callback */
0, /* No per session data. */
0, /* max frame size / rx buffer */
},
{
"example-protocol",
callback_example,
0,
EXAMPLE_RX_BUFFER_BYTES,
},
{ NULL, NULL, 0, 0 } /* terminator */
};
int main( int argc, char *argv[] )
{
struct lws_context_creation_info info;
memset( &info, 0, sizeof(info) );
info.port = 8080;
info.protocols = protocols;
info.gid = -1;
info.uid = -1;
struct lws_context *context = lws_create_context( &info );
while( 1 )
{
lws_service( context, /* timeout_ms = */ 1000000 );
}
lws_context_destroy( context );
return 0;
}
There are some similar topics on SO, but I haven't found all I need.
I have the following C++ Code:
string getConsoleOutput(string command)
{
string data;
File *fp;
char var[512];
fp = _popen(command.c_str(), "r");
while (fgets(var, sizeof(var), fp) != NULL)
{
data += var;
}
_pclose(fp);
return data;
}
The problem is that every time I send a console command to this function, the command line pops up.
I want to send a command to the Console and get the output without seeing a Console Window.
EDIT:
I tried out libexec, but it is too complex for my needs
I also read about WinExec and CreateProcess, but I haven't found a way to get the output
If it is okay with a little flash on the screen, then just include a command to hide the window. Since AFAIK Windows doesn't itself offer such a command (although it may be lurking in the deeps of Powershell), you will have to create it. But that's trivial:
#define UNICODE
#define NOMINMAX
#include <windows.h>
auto main() -> int
{
ShowWindow( GetConsoleWindow(), SW_HIDE );
}
I've tested that the _popen functionality works OK with hidden window.
And contrary to the documentation, it apparently also works OK for a GUI subsystem application, although I didn't test more than a dir command.
If the flash is unacceptable, then you can use CreateProcess to fire up a hidden command intepreter window, and low level Windows pipes to catch the output.
Sorry, I first wrote a suggestion here about COMSPEC and a GUI subsystem faux command interpreter, which works as far as I tested it, but it would just involve the above again for catching the command interpreter output. I.e. using _popen in the main program would then just be added complication and inefficiency. Better to do it directly at the API level.
An example.
Disclaimer: I am pretty sure I'm doing something wrong here, because when the command process terminates the pipe should generate EOF, no bytes read. Instead the ReadFile call would then just hang, so I had to add a very ugly wait-for-data-or-process-termination loop before calling ReadFile. On the other hand, I remember that Windows had some bugs related to pipes and EOF. So pretty sure is not 100% sure, but I haven't had time to check out MS example.
#define NOMINMAX
#define STRICT
#define UNICODE
#include <windows.h>
#include <stdexcept>
#include <stdio.h>
#include <string>
using namespace std;
auto hopefully( const bool condition ) -> bool { return condition; }
auto fail( const string& message ) -> bool { throw runtime_error( message ); }
struct Non_copyable
{
Non_copyable& operator=( const Non_copyable& ) = delete;
Non_copyable( const Non_copyable& ) = delete;
Non_copyable() {}
Non_copyable( Non_copyable&& ) {}
};
struct Process
: Non_copyable
{
HANDLE handle;
~Process() { CloseHandle( handle ); }
Process( const HANDLE h = 0 ): handle( h ) {}
Process( Process&& other ): handle( other.handle ) { other.handle = 0; }
};
auto environment_var( const wstring& name )
-> wstring
{
const DWORD buffer_size = GetEnvironmentVariable( name.c_str(), nullptr, 0 );
hopefully( buffer_size > 0 )
|| fail( "environment_var: GetEnvironmentVariable failed 1st call." );
wstring result( buffer_size + 1, L'#' );
const DWORD n_characters = GetEnvironmentVariable(
name.c_str(), &result[0], result.size()
);
hopefully( n_characters > 0 )
|| fail( "environment_var: GetEnvironmentVariable failed 2nd call." );
result.resize( n_characters ); // Just for good measure.
return result;
}
auto exit_code_of( const HANDLE process )
-> int
{
DWORD code = E_FAIL;
GetExitCodeProcess( process, &code );
return code;
}
auto has_terminated( const HANDLE process )
-> bool
{ return exit_code_of( process ) != STILL_ACTIVE; }
auto start_command( const wstring& command, const HANDLE output_handle = INVALID_HANDLE_VALUE )
-> Process
{
const wstring com_spec = environment_var( L"COMSPEC" );
wstring command_line = com_spec + L" /c " + command; // Can not be `const`.
STARTUPINFO params = { sizeof( STARTUPINFO ) };
if( output_handle != INVALID_HANDLE_VALUE )
{
const HANDLE nul = CreateFile( L"nul", GENERIC_ALL, 0, nullptr, OPEN_EXISTING, 0, 0 );
params.dwFlags = STARTF_USESTDHANDLES;
params.hStdInput = GetStdHandle( STD_INPUT_HANDLE );
params.hStdOutput = output_handle;
params.hStdError = GetStdHandle( STD_ERROR_HANDLE );
}
PROCESS_INFORMATION info = {};
bool const process_was_created = !!CreateProcess(
nullptr, // LPCTSTR lpApplicationName,
&command_line[0], // LPTSTR lpCommandLine,
nullptr, // LPSECURITY_ATTRIBUTES lpProcessAttributes,
nullptr, // LPSECURITY_ATTRIBUTES lpThreadAttributes,
true, // BOOL bInheritHandles,
CREATE_NO_WINDOW, // DWORD dwCreationFlags,
nullptr, // LPVOID lpEnvironment,
nullptr, // LPCTSTR lpCurrentDirectory,
¶ms, // LPSTARTUPINFO lpStartupInfo,
&info // LPPROCESS_INFORMATION lpProcessInformation
);
if( not process_was_created ) { return 0; }
CloseHandle( info.hThread );
return info.hProcess;
}
auto command_result( const wstring& command )
-> string
{
struct Pipe
{
HANDLE read_handle = 0;
HANDLE write_handle = 0;
~Pipe() { CloseHandle( read_handle ); CloseHandle( write_handle ); }
};
Pipe pipe;
SECURITY_ATTRIBUTES params = { sizeof( SECURITY_ATTRIBUTES ) };
params.bInheritHandle = TRUE;
CreatePipe( &pipe.read_handle, &pipe.write_handle, ¶ms, 0 )
|| fail( "command_result: CreatePipe failed" );
SetHandleInformation( pipe.read_handle, HANDLE_FLAG_INHERIT, 0 ); // Inheritance ungood.
const Process process = { start_command( command, pipe.write_handle ) };
if( process.handle == 0 ) { return ""; }
string result;
for( ;; )
{
// Wait for data to become available or process terminated, to avoid hanging.
for( ;; )
{
DWORD n_bytes_available = 0;
const bool ok = !!PeekNamedPipe(
pipe.read_handle, nullptr, 0, nullptr, &n_bytes_available, nullptr
);
if( ok && n_bytes_available > 0 ) { break; }
if( has_terminated( process.handle ) ) { return result; }
Sleep( 125 );
}
char buffer[4096];
DWORD n_bytes_read = 0;
SetLastError( 0 );
ReadFile( pipe.read_handle, buffer, sizeof( buffer ), &n_bytes_read, nullptr )
|| fail( "command_result: ReadFile failed" );
const auto last_read_error = GetLastError();
if( last_read_error != 0 ) { break; }
if( n_bytes_read == 0 ) { break; }
result.append( buffer, n_bytes_read );
}
return result;
}
auto main() -> int
{
try
{
const string result = command_result( L"dir *" );
const wstring text( result.begin(), result.end() );
MessageBox( 0, text.c_str(), L"Result:", MB_SETFOREGROUND );
return 0;
}
catch( const exception& x )
{
MessageBoxA( 0, x.what(), "Oops, an exception", MB_ICONERROR | MB_SETFOREGROUND );
}
return E_FAIL;
}
Here is my problem. I detoured the "ScriptTextOut" function and I'm attempting to find where it was called from. Here is my dll (I use Microsoft Detour):
#pragma comment(lib, "detours.lib")
#include <Windows.h>
#include <detours.h>
#include <tchar.h>
#include <string>
#include <iostream>
#include <Usp10.h>
#include <Dbghelp.h>
HRESULT (WINAPI * Real_ScriptTextOut)(const HDC hdc, SCRIPT_CACHE *psc, int x, int y, UINT fuOptions, const RECT *lprc, const SCRIPT_ANALYSIS *psa, const WCHAR *pwcReserved, int iReserved,
const WORD *pwGlyphs, int cGlyphs, const int *piAdvance, const int *piJustify, const GOFFSET *pGoffset) = ScriptTextOut;
// function used to back trace where the function was called from
void printStack()
{
unsigned int i;
void * stack[ 100 ];
unsigned short frames;
SYMBOL_INFO * symbol;
HANDLE process;
process = GetCurrentProcess();
SymInitialize( process, NULL, TRUE );
frames = CaptureStackBackTrace( 0, 100, stack, NULL );
symbol = ( SYMBOL_INFO * )calloc( sizeof( SYMBOL_INFO ) + 256 * sizeof( char ), 1 );
symbol->MaxNameLen = 255;
symbol->SizeOfStruct = sizeof( SYMBOL_INFO );
for( i = 0; i < frames; i++ )
{
SymFromAddr( process, ( DWORD64 )( stack[ i ] ), 0, symbol );
printf( "%i: %s - 0x%0X\n", frames - i - 1, symbol->Name, symbol->Address );
}
free( symbol );
}
// My ScriptTextOut function
HRESULT WINAPI Mine_ScriptTextOut(const HDC hdc, SCRIPT_CACHE *psc, int x, int y, UINT fuOptions, const RECT *lprc, const SCRIPT_ANALYSIS *psa, const WCHAR *pwcReserved, int iReserved,
const WORD *pwGlyphs, int cGlyphs, const int *piAdvance, const int *piJustify, const GOFFSET *pGoffset)
{
printStack();
return Real_ScriptTextOut(hdc, psc, x, y, fuOptions, lprc, psa, pwcReserved, iReserved, pwGlyphs, cGlyphs, piAdvance, piJustify, pGoffset);
}
BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved )
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
AllocConsole();
freopen("CONOUT$", "w", stdout);
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)Real_ScriptTextOut, Mine_ScriptTextOut);
DetourTransactionCommit();
break;
case DLL_PROCESS_DETACH:
FreeConsole();
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourDetach(&(PVOID&)Real_ScriptTextOut, Mine_ScriptTextOut);
DetourTransactionCommit();
break;
}
return TRUE;
}
So the detour function works as expected, but the printStack() function print some wierd results... Here, take a look:
Why is it wierd, you may ask? Well, I expected to find the function that called ScriptTextOut, but the function before "Mine_ScriptTextOut" is "ScriptApplyDigitSubstitution", and while these 2 are clearly related, one doesn't call the other...
When testing my PrintStack function outside an injected dll, everything worked out fine:
#include <Windows.h>
#include <Dbghelp.h>
#include <cstdio>
void printStack()
{
unsigned int i;
void * stack[ 100 ];
unsigned short frames;
SYMBOL_INFO * symbol;
HANDLE process;
process = GetCurrentProcess();
SymInitialize( process, NULL, TRUE );
frames = CaptureStackBackTrace( 0, 100, stack, NULL );
symbol = ( SYMBOL_INFO * )calloc( sizeof( SYMBOL_INFO ) + 256 * sizeof( char ), 1 );
symbol->MaxNameLen = 255;
symbol->SizeOfStruct = sizeof( SYMBOL_INFO );
for( i = 0; i < frames; i++ )
{
SymFromAddr( process, ( DWORD64 )( stack[ i ] ), 0, symbol );
printf( "%i: %s - 0x%0X\n", frames - i - 1, symbol->Name, symbol->Address );
}
free( symbol );
}
void dontprint()
{
}
void foo()
{
printStack();
}
void test()
{
dontprint();
foo();
}
int main()
{
dontprint();
test();
return 0;
}
Here is the correct output:
Any idea what is happening?
I am using FindWindow in an mfc application.
HWND hWnd = ::FindWindow(NULL, _T("foobar v5"));
I would like to use FindWindow with wildcards so that I can match just foobar.
Thanks
You will have to create your own implementation which should be based on EnumWindows, GetWindowText and GetWindowTextLength which then must allow the wildcards.
#include <Windows.h>
#include <iostream>
#include <string>
#include <vector>
struct FindWindowData {
FindWindowData( TCHAR const * windowTitle )
: WindowTitle( windowTitle )
, ResultHandle( 0 )
{}
std::basic_string<TCHAR> WindowTitle;
HWND ResultHandle;
};
BOOL CALLBACK FindWindowImpl( HWND hWnd, LPARAM lParam ) {
FindWindowData * p = reinterpret_cast<FindWindowData*>( LongToPtr( lParam ) );
if( !p ) {
// Finish enumerating we received an invalid parameter
return FALSE;
}
int length = GetWindowTextLength( hWnd ) + 1;
if( length > 0 ) {
std::vector<TCHAR> buffer( std::size_t( length ), 0 );
if( GetWindowText( hWnd, &buffer[0], length ) ) {
// Comparing the string - If you want to add some features you can do it here
if( _tcsnicmp( &buffer[0], p->WindowTitle.c_str(), min( buffer.size(), p->WindowTitle.size() ) ) == 0 ) {
p->ResultHandle = hWnd;
// Finish enumerating we found what we need
return FALSE;
}
}
}
// Continue enumerating
return TRUE;
}
// Returns the window handle when found if it returns 0 GetLastError() will return more information
HWND FindWindowStart( TCHAR const * windowTitle ) {
if( !windowTitle ) {
SetLastError( ERROR_INVALID_PARAMETER );
return 0;
}
FindWindowData data( windowTitle );
if( !EnumWindows( FindWindowImpl, PtrToLong(&data) ) && data.ResultHandle != 0 ) {
SetLastError( ERROR_SUCCESS );
return data.ResultHandle;
}
// Return ERROR_FILE_NOT_FOUND in GetLastError
SetLastError( ERROR_FILE_NOT_FOUND );
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
std::cout << "HWND: " << FindWindowStart(TEXT("foobar ") );
std::cout << " GetLastError() = " << GetLastError() << std::endl;
return 0;
}
Unfortunately, FindWindow() does not support wildcards.
Did you try matching the window class name instead of its title? You can use a tool like Spy++ to find out the class name of the foobar main window.