I have a dynamic library which uses LoadImage function:
HINSTANCE hInstance = (HINSTANCE)(LONG_PTR)GetWindowLongPtr(wnd, GWLP_HINSTANCE);
HBITMAP hBitMap = (HBITMAP) LoadImage(hInstance, MAKEINTRESOURCE(resId), IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
That library is linked to the main application (exe). When the application calls a library function which calls LoadImage I get Win api error 1813. hInstance refers to the exe file. How to fix that ?
LoadImage works when I get HINSTANCE this way:
HMODULE GetModule()
{
HMODULE hMod = NULL;
GetModuleHandleEx(
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
(LPCTSTR)GetModule,
&hMod);
return hMod;
}
HINSTANCE hInstance = (HINSTANCE)GetModule();
Please review my answer.
Related
I'd like my program to listen to messages in another Windows app.
I am aware of SetWindowsHook, but am concerned about this line:
If the dwThreadId parameter is zero or specifies the identifier of a
thread created by a different process, the lpfn parameter must point
to a hook procedure in a DLL.
I don't know which hook procedures are in Windows DLLs, so am at a loss.
(I'm using Python with ctypes to use the WinAPI.)
Question: How can I get my program to listen for messages in another Windows process?
You need to create a DLL and add hook functions to the DLL.
I will use the following code in C++ to create the DLL:
#include <windows.h>
#include <iostream>
HINSTANCE hThisDLL;
HHOOK hMsgHook;
BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
hThisDLL = hinstDLL;
return TRUE;
}
LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam)
{
//do what you want to do
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
extern "C" __declspec(dllexport) BOOL InstallHook()
{
if (!hMsgHook)
hMsgHook = SetWindowsHookEx(WH_GETMESSAGE, &GetMsgProc, hThisDLL, 0);
return (hMsgHook != NULL);
}
extern "C" __declspec(dllexport) VOID UninstallHook()
{
if (hMsgHook)
{
UnhookWindowsHookEx(hMsgHook);
hMsgHook = NULL;
}
}
After generating the .dll file, you can load the dynamic library through the LoadLibrary function, and use the GetProcAddress function to get the function address in the dynamic library. Then call the hook function.
Here is the code with C++:
#include <iostream>
#include <windows.h>
typedef BOOL(WINAPI* LPInstallHook)();
typedef VOID(WINAPI* LPUninstallHook)();
int main()
{
HMODULE dll_handle;
LPInstallHook installProc;
LPUninstallHook uninstallProc;
HHOOK process_hook;
dll_handle = LoadLibrary(L"test.dll");
if (dll_handle)
{
installProc = (LPInstallHook)GetProcAddress(dll_handle, "InstallHook");
uninstallProc = (LPUninstallHook)GetProcAddress(dll_handle, "UninstallHook");
}
MSG msg;
installProc();
while (GetMessageW(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
uninstallProc();
if(dll_handle) FreeLibrary(dll_handle);
}
This is part of the code implemented in python, you can refer to it:
import ctypes
import os
from ctypes import *
user32 = ctypes.windll.user32
kernel32 = ctypes.windll.kernel32
if __name__ == '__main__':
dllpath = os.path.join(path,"test.dll")
pDll = ctypes.WinDLL(dllpath)
pDll.InstallHook()
msg = ctypes.wintypes.MSG()
while user32.GetMessageW(ctypes.byref(msg), 0, 0, 0) != 0:
user32.TranslateMessage(msg)
user32.DispatchMessageW(msg)
Of course, according to the documentation, you can set dwThreadId as the identifier of other threads. You can refer to the similar thread.
I'm coding a application like Notepad in Win32 c++. But when i change szClassName in createWindow(), the menu can't work although it still show it when I run
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
hInst = hInstance; // Store instance handle in our global variable
hMenu = LoadMenu(hInst, MAKEINTRESOURCE(IDC_NOTEPAD));
hWnd = CreateWindow(L"EDIT", szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, hMenu, hInstance, NULL);
//SetWindowLong(hWnd, GWL_WNDPROC, (LONG)WndProc);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
In CreateWindow(), the hMenu parameter is the control ID but not the menu handle.
I suggest creating the main window before adding a textbox:
WNDCLASSEX wc;
// ...
wc.lpszClassName="window class";
wc.lpszMenuName=hMenu;
// ...
RegisterWindowEx(&wc);
hWnd=CreateWindow("window class", ...);
// When processing WM_CREATE message in WndProc()
hEdit=CreateWindow("EDIT","your textbox", ... /* set hWndParent as hWnd */);
I think theForger's Win32 API Programming Tutorial is also a good place for you to start.
I am a newbie when it comes to using WinAPI. I am following a tutorial where I found a code snippet. The snippet demonstrates a basic program. I am posting my full code below:
#include "a.h"
#include "windows.h"
LRESULT CALLBACK WndProcedure(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX WndClsEx;
WndClsEx.cbSize = sizeof(WNDCLASSEX);
WndClsEx.style = CS_HREDRAW | CS_VREDRAW;
WndClsEx.lpfnWndProc = WndProcedure;
WndClsEx.cbClsExtra = 0;
WndClsEx.cbWndExtra = 0;
WndClsEx.hInstance = hInstance;
return 0;
}
LRESULT CALLBACK WndProcedure(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
switch(Msg)
{
case WM_DESTROY:
PostQuitMessage(WM_QUIT);
break;
default:
return DefWindowProc(hWnd, Msg, wParam, lParam);
}
return 0;
}
I don't get any error while running the code from Qt Creator. However, when running it no windows appear but the output console shows:
"MyProgram.exe exited with code 0"
What might cause this?
I am posting my full code below:
Your code looks a lot like standard Win32 but it is missing a lot of code.
For example this very simple test.cpp file contains a full working Win32 application:
#define STRICT
#include <windows.h>
long PASCAL WndProc (HWND, UINT, WPARAM, LPARAM);
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpszCmdParam, int nCmdShow)
{
static char szClassName[] = "Hello World";
MSG msg;
WNDCLASS wndclass;
memset(&wndclass, '\0', sizeof(wndclass));
wndclass.style = CS_HREDRAW|CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject (WHITE_BRUSH);
wndclass.lpszMenuName = 0;
wndclass.lpszClassName = szClassName;
RegisterClass (&wndclass);
// create a new window
HWND hwnd = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,
szClassName,
"My Hello World Window",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL);
ShowWindow (hwnd, nCmdShow);
while (GetMessage (&msg, NULL, 0, 0)) {
TranslateMessage (&msg);
DispatchMessage (&msg);
}
return msg.wParam;
}
long APIENTRY WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) {
case WM_DESTROY:
PostQuitMessage (0);
return 0;
}
return DefWindowProc (hwnd, message, wParam, lParam);
}
It can be compiled and linked from the command line:
C:\TEMP>cl test.cpp user32.lib gdi32.lib
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.30729.01 for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.
test.cpp
Microsoft (R) Incremental Linker Version 9.00.30729.01
Copyright (C) Microsoft Corporation. All rights reserved.
/out:test.exe
test.obj
user32.lib
gdi32.lib
The resulting test.exe can be run and it will display a window:
C:\TEMP>test.exe
As Hans Passant suggests in his comment, you're missing a lot of code. I don't know from which tutorial you copied this snippet, but surely there must be more code there.
For example, you have not registered it, nor created the actual window, you're not showing it and (as #rodrigo mentioned) you're missing the message loop. This example on MSDN illustrates what that all would look like.
And yes, you can perfectly develop applications in Qt Creator without actually using Qt for your user interface. I would however not dismiss it. Since you have all the tools at your disposal, have a look at Qt itself as well. You might just like it.
I am new to Windows Programming.
I created a win32 console project (without preCompiled header) with VS2005. And the code as below.
// HelloWin.cpp : Defines the entry point for the console application.
//
#include <windows.h>
#include "stdafx.h"
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int _tmain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT("HelloWin");
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
if(!RegisterClass(&wndclass))
{
MessageBox(NULL, TEXT("This Program requires Windows NT!"), szAppName, MB_ICONERROR);
return 0;
}
hwnd = CreateWindow(szAppName, // window class name
TEXT("The Hello Program"), // window caption
WS_OVERLAPPEDWINDOW, // window style
CW_USEDEFAULT, // initial x position
CW_USEDEFAULT, // initial y position
CW_USEDEFAULT, // initial x size
CW_USEDEFAULT, // initial y size
NULL, // parent window handle
NULL, // window menu handle
hInstance, // program instance handle
NULL); // creation parameters
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd);
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
RECT rect;
switch(message)
{
case WM_CREATE:
PlaySound(TEXT("hellowin.wav"), NULL, SND_FILENAME | SND_ASYNC);
return 0;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
GetClientRect(hwnd, &rect);
DrawText(hdc, TEXT("Hello Windows XP"), -1, &rect,
DT_SINGLELINE | DT_CENTER | DT_VCENTER);
EndPaint(hwnd, &ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
And now there is two Link Errors as this, Could anybody help me to fix this errors.
Does it caused by there is no hellowin.wav file in my local harddisk? If it does. What directory can I place a simular WAV file to?
Thanks.
1>Linking... 1>HelloWin.obj :
error LNK2019: unresolved external
symbol imp__PlaySoundW#12 referenced in function "long __stdcall
WndProc(struct HWND *,unsigned int,unsigned int,long)"
(?WndProc##YGJPAUHWND__##IIJ#Z)
1>D:\learning\windows\ProgrammingWindows(5thEdition)\HelloWin\Debug\HelloWin.exe
:
fatal error LNK1120: 1 unresolved externals 1>Build log was saved at
"file://d:\learning\windows\ProgrammingWindows(5thEdition)\HelloWin\HelloWin\Debug\BuildLog> .htm"
1>HelloWin - 2 error(s), 1 warning(s)
========== Rebuild All: 0 succeeded, 1 failed, 0 skipped ==========
You have several problems here. Firstly you say that your application is a console app. If it is, then you are using the wrong main. Your subsystem is probably WINDOWS in which case your main should be this instead:
int CALLBACK _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR szCmdLine, int iCmdShow)
You also say you're not using precompiled headers but you have an include for stdafx.h. Your problems can be fixed by changing your main and also changing your includes to look like this:
#include <windows.h>
#include <tchar.h>
#pragma comment(lib, "Winmm.lib")
This allows the linker to look for the library file we tell it to. I also got rid of your precompiled header and replaced it with tchar.h since that is your only other dependency so far.
The fact hellowin.wav is not present at compilation time is irrelevant. The program only looks for it at runtime.
I have a Windows app that uses the AppBar API to install as an application bar at the top of the screen (similar to the Windows task bar itself). This works great and the desktop size is adjusted accordingly, so my application is always visible.
However, if the user choose 'Show Desktop' (Windows+D), my application is hidden. Does anyone know of a way to trap 'Show Desktop' so I can ensure my application stays visible (I assume that Windows enumerates all top-level windows and hides them with ShowWindow(SW_HIDE).
Use the following code and pass the window handle to the function while form load.
Hopefully this resolves your problem.
public void SetFormOnDesktop(IntPtr hwnd)
{
IntPtr hwndf = hwnd;
IntPtr hwndParent = FindWindow("ProgMan", null);
SetParent(hwndf, hwndParent);
}
I was under the impression that setting the window as a topmost window (via SetWindowPos and the HWND_TOPMOST flag) prevented the desktop from covering it. Windows+D goes through minimizing all windows, and then covering up those that can't be minimized by raising the desktop in the z-order (well, it did at one point anyway). I belive you can make a window unminimizable by not passing WS_MINIMIZEBOX to CreateWindowEx, or using WS_EX_TOOLWINDOW though I'm not 100% on that part.
A much heavier handed approach would be to hook the global keyboard using SetWindowsHookEx and a KeyboardProc. This will have a deleterious effect on the user experience.
I went and coded up a really simple example of what I'm talking about. The following code makes a window that is not minimized OR covered by a user hitting Windows+D. Note that on Windows 7, gadgets on the desktop can still be brought above it; which I can't really explain.
#include <windows.h>
#include <tchar.h>
#define WIN_TITLE _T("Resists Win+D Window")
#define WIN_CLASS _T("Resists Win+D Class")
LRESULT CALLBACK CustomWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
//Special behavior goes here
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
HWND CreateMainWindow(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = CustomWndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = WIN_CLASS;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
if (!RegisterClassEx(&wcex))
{
exit(1);
}
HWND hWnd = CreateWindowEx(
WS_EX_TOOLWINDOW,
WIN_CLASS,
WIN_TITLE,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
500,
100,
NULL,
NULL,
hInstance,
NULL
);
if (!hWnd)
{
exit(1);
}
return hWnd;
}
/*
Main entry point
*/
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
HWND hwnd = CreateMainWindow(hInstance);
ShowWindow(hwnd, nCmdShow);
SetWindowPos(hwnd, HWND_TOPMOST, -1, -1, -1, -1, SWP_NOMOVE | SWP_NOSIZE);
UpdateWindow(hwnd);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int) msg.wParam;
}
In your ABN_FULLSCREENAPP notification, you need to determine whether the window occupying the working area is the Desktop and if so, ignore the ABN_FULLSCREENAPP message.
P.S. As an alternative implementation, consider the commercial ShellAppBar component.
In addition to the answer of JKS, here is working code for VB.NET, assuming you already converted your form to an appbar. You need to p/invoke the functions FindWindow and SetFormOnDesktop.
'In your form
Public Sub New()
'Stuff
SetFormOnDesktop(Me.Handle)
'More stuff
End Sub
'In your form or somewhere else.
<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
Private Shared Function FindWindow( _
ByVal lpClassName As String, _
ByVal lpWindowName As String) As IntPtr
End Function
<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
Public Shared Function SetParent(_
ByVal hWndChild As IntPtr, ByVal hWndNewParent As IntPtr) As IntPtr
End Function
Public Sub SetFormOnDesktop(hwnd As IntPtr)
Dim hwndf As IntPtr = hwnd
Dim hwndParent As IntPtr = FindWindow("ProgMan", Nothing)
SetParent(hwndf, hwndParent)
End Sub