I have created a DLL in VC++ as Win32 project
DLLMAIN function is
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
return TRUE;
}
Now I need HINSTANCE of the DLL , that need to be passed to Win32 functions.
Are HMODULE and HINSTANCE same?
How can I get HINSTANCE?
An excerpt from the book Windows Via C/C++ [1]
Note As it turns out, HMODULEs and HINSTANCEs are exactly the same thing. If the documentation for a function indicates that an HMODULE is required, you can pass an HINSTANCE and vice versa. There are two data types because in 16-bit Windows HMODULEs and HINSTANCEs identified different things
[1] Richter, Jeffery and Nasarre, Christophe, Windows Via C/C++, 5th ed, Redmond: Microsoft Press 2008, pp. 74
Microsoft linker specific
#include "windows.h"
EXTERN_C IMAGE_DOS_HEADER __ImageBase;
#pragma warning(disable: 4047)
HINSTANCE hInstance = (HINSTANCE)&__ImageBase;
#pragma warning(default: 4047)
I think that these are the same. If you want HINSTANCE of the running process (exe), you should use
GetModuleHandle(NULL);
Calling GetModuleHandle(NULL) from a dll will return the Hinstanc of the EXE that started the DLL; to get the Hinstance for the curently running dll try this tip:
http://www.dotnet247.com/247reference/msgs/13/65259.aspx
DllMain function as it's described in MSDN:
BOOL WINAPI DllMain(
__in HINSTANCE hinstDLL,
__in DWORD fdwReason,
__in LPVOID lpvReserved
);
http://msdn.microsoft.com/en-us/library/ms682583%28v=vs.85%29.aspx
Each DLL has at least a header file, say MyDll.h and a corresponding implementation file MyDll.cpp. Open the header file and add
extern HMODULE hDllModule;//or whatever name you like
Now open the MyDll.cpp file. There is a function DLLMAIN. Add before it HMODULE hDllModule; and insert hDllModuleDll = hModule; before return true;. Your code will look like this:
HMODULE hDllModuleDll;
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
hDllModuleDll = hModule;
return TRUE;
}
In functions like ::GetModuleFileNameW(hModule, PathFile, MAX_PATH); that require a HMODULE of the DLL you can pass the global variable hDllModule.
To complement the other answers, for the sake of completness.
The actual signature of DllMain has an HINSTANCE parameter, instead of a HMODULE parameter. The Visual Studio DLL template generates the signature with HMODULE since at least Visual Studio 2008 however, but I believe this to be a minor bug more than anything. VC6 generated the code with HANDLE (even though both HINSTANCE and HMODULE exist). The reason that doesn't cause problems is because HINSTANCE and HMODULE are now exactly the same thing. Unfortunately I was unable to find an ancient enough version of the MSDN documetnation that could have confirmed this.
So the answer is: You get your HINSTANCE as an argument to your DllMain.
Personally I sort of like the distinction between HMODULE and HINSTANCE because it appeals to me as being good code hygiene. It's a bit like using const. But then, a new question arises: Given your HINSTANCE, how do you get your HMODULE in the "hygienic" way?
The windowsx.h header defines GetInstanceModule, which is now a macro that just casts the HINSTANCE to HMODULE. It only exists for code compatibility, along with a bunch of very similar macros.
Related
I am trying to learn how to work with raw Win32 API's and am following the tutorial here, but cannot, for the life of me, figure out how to pass int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) function signature to work. I do understand the int WINAPI isn't needed...but how do I get all of those parameters to pass to WinAPI calls? Especially hInstance and nCmdShow?
My Goal
Get hInstance and nShowCmd from
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) {}
into a Rust program, perhaps something like:
fn main(/* args, such as hInstance, nShowCmd here /*) {
}
or, the more likely way:
fn main() {
std::env::/* hopefully something like args() /*;
}
What I've tried
I've tried getting the args, but this just passes the command-line arguments that I used to spawn the program, just as args[0] being the name of the program, which is the expected behavior. Also, calling args_os() gives the same result.
I've also tried to set the windows subsystem, but the previous behavior is the same, not the desired behavior...
#![windows_subsystem = "windows"]
I am able to get the hInstance handle by manually calling GetModuleHandle() and passing in a null pointer, but have no idea how to get the nShowCmd manually.
Important Note
I am using the windows crate, which is what I would like to use.
Any help to this eluding mystery would be much appreciated!
P.S. My window does open, and everything works fine, as expected, including working with FFI, and all the crazies involved there, lol. But I just would like to understand how this is done. One can get by without the nShowCmd, but I would really like to be able to understand how this is done in rust. I also cannot overwrite the fn main() function signature, so not sure how to go about it.
WinMain is the user-provided entry point of a Windows application. The raw application entry point as seen by the OS is far simpler:
DWORD CALLBACK RawEntryPoint(void);
It is now up to language support libraries to recover the startup information and call into the user-provided entry point (see WinMain is just the conventional name for the Win32 process entry point for details):
GetModuleHandle(NULL) for hInstance
hPrevInstance is always NULL in 32-bit and 64-bit Windows
GetCommandLine for the unparsed command line passed to the program
GetStartupInfo for lots of state information, including the wShowWindow that corresponds to nCmdShow
If you have Visual Studio installed you can have a look inside exe_common.inl to see how the C and C++ support libraries go about this.
With Rust things are unfortunately more complex. Even though the compiler and linker repurpose MSVC's CRT implementation responsible for extracting the information that would be passed into WinMain, I'm not aware of a way to get a hold of this from Rust.
You're going to have to recover that information manually. Getting to the nCmdShow parameter is a bit more involved, so let's illustrate that here:
// build.rs
// Using windows-rs 0.17.2; version 0.10.0 and later should be just fine
fn main() {
windows::build!(Windows::Win32::System::Threading::GetStartupInfoW,)
}
// src/main.rs
mod bindings {
windows::include_bindings!();
}
use bindings::Windows::Win32::System::Threading::{GetStartupInfoW, STARTUPINFOW};
fn main() {
let mut si = STARTUPINFOW {
cb: std::mem::size_of::<STARTUPINFOW>() as u32,
..Default::default()
};
unsafe { GetStartupInfoW(&mut si) };
let cmd_show = si.wShowWindow as i32;
println!("nCmdShow: {:?}", cmd_show);
}
With that you now have access to a value that corresponds to the nCmdShow parameter passed into WinMain when compiling for C or C++ (roughly, anyway). Ideally you would need to see whether dwFlags contains the STARTF_USESHOWWINDOW bit, and fabricate a reasonable default when it doesn't.
That said, I'm not even sure what purpose the nCmdShow argument passed into WinMain serves. As explained under ShowWindow, using that value doesn't have any effect when it is populated from caller-provided information.
Update 2021-10-28
Starting with version 0.22.1 the windows crate comes with pre-built bindings, making it a lot easier to consume the Windows API. The following implements the same program using the pre-built bindings in place of compile-time code generation.
Cargo.toml
[package]
name = "startup_info"
version = "0.0.0"
edition = "2021"
[dependencies.windows]
version = "0.22.1"
features = ["Win32_Foundation", "Win32_System_Threading"]
main.rs
use windows::Win32::System::Threading::{GetStartupInfoW, STARTUPINFOW};
fn main() {
let mut si = STARTUPINFOW {
cb: std::mem::size_of::<STARTUPINFOW>() as u32,
..Default::default()
};
unsafe { GetStartupInfoW(&mut si) };
let cmd_show = si.wShowWindow as i32;
println!("nCmdShow: {:?}", cmd_show);
}
There is this function in Kernel32: GetStartupInfo() that in windows-rs seems to be mapped to bindings::Windows::Win32::System::Threading::GetStartupInfoW.
This function fills a STARTUPINFOW structure that has, between a lot of useful fields, WORD wShowWindow that has the same value as the last argument in WinMain().
The funny thing about WinMain is that there is nothing magic in it, it is just the function that the real entry point function, WinMainCRTStartup calls from the CRT initialization code. You can get an idea of how it does its thing by looking at the equivalent Wine source code. There you can see that your idea of calling GetModuleHandle(NULL) to get the hInstance is the right one.
Why was RunDLL and later RunDLL32 conceived? What is the purpose of their existence? So as to bypass the task manager?
https://support.microsoft.com/en-us/kb/164787
The article states that RunDLL still requires a particular method header for a candidate entry point:
16-bit DLL:
void FAR PASCAL __loadds
EntryPoint(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow);
32-bit DLL:
void CALLBACK
EntryPoint(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow);
What is the purpose of using a RunDLL entry point rather than a main entry point as in a regular executable file?
I need to create an exe application with no console window or (any other window) during the start up of the application.
I tried the below for this:
Using Visual Studio 2010, created a Win32 Console Application as an Empty Project.
Added a header file "stdafx.h" to the project
Added a cpp file to the project and added the below code.
The project settings are visual stduio default.
#include "stdafx.h"
#include <windows.h>
#include "TlHelp32.h"
#include <iostream>
#include <string>
int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
return 0;
}
The above code compiles good.
But if I change the Character Set to "Use Unicode Character Set", I am getting the following compilation error.
error C2731: 'WinMain' : function cannot be overloaded
I am building the application on a Windows 7 64 bit computer and Visual Studio Build platform as x64.
Thanks in advance for your help.
Yes, when you build with UNICODE in effect then the entrypoint takes a Unicode string for the command line argument. So that requires a different declaration:
int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPWSTR lpCmdLine, int nShowCmd)
Or you can use #include <tchar.h> so it works either way, not much point to it these days:
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPTSTR lpCmdLine, int nCmdShow)
Create Windows service instead console app.
In Visual Studio, create a new "EMPTY Project". Add a new source file named "main.cpp". Use the following template (assumes you want to build with Unicode):
/************
main.cpp
************/
#define UNICODE 1
#include <windows.h>
int APIENTRY wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPWSTR lpCmdLine, int nShowCmd)
{
// Process Return Codes
const int SUCCESS=0, FAILURE=1;
return SUCCESS;
}
I am trying to port a native sdk to windows RT and to help me I would like to implement missing functions to emulate registry access, so I have created a Static Library (File->New->Project...->Static Library (Metro Style apps) and I have declared the function like that :
// WinRT stuff
#include <windows.storage.h>
#include <wrl/client.h>
#include <wrl/wrappers/corewrappers.h>
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
using namespace ABI::Windows::Storage;
using namespace ABI::Windows::Foundation;
LSTATUS
APIENTRY
RegOpenKeyExW(
_In_ HKEY hKey,
_In_opt_ LPCWSTR lpSubKey,
_In_opt_ DWORD ulOptions,
_In_ REGSAM samDesired,
_Out_ PHKEY phkResult
)
{
LSTATUS ret = ERROR_SUCCESS;
if (hKey == NULL)
return ERROR_INVALID_HANDLE;
if (phkResult == NULL)
return ERROR_INVALID_PARAMETER;
ABI::Windows::Storage::ApplicationDataContainer^ localSettings =
ApplicationData::Current->LocalSettings;
...
}
However when I try to compile I get this error :
1>c:\users\joe\documents\visual studio 2012\projects\lib1\lib1\oal.cpp(275):
error C3699: '^' : cannot use this indirection on type
'ABI::Windows::Storage::ApplicationDataContainer'
I have checked and Consume Windows Runtime Extension (/ZW) is enabled (it's by default) so I am wondering if it's possible to use C++/CX inside a static lib?
If you're using the ABI prefix on your types, then you're referring to the low level C++ type. THe low level types are intended to be used with WRL and cannot use the C++/CX extensions like the ^ operator.
Use ComPtr localSettings instead.
Ok someone told me to add In Librarian->General->Additional Dependecies : %(AdditionalDependencies) and I have removed the ABI:: namespace. Now it works ;-)
I am trying to hide the WinMain function inside a DLL in order to avoid typing again much of the code over and over again.
I exported wWinMain from the DLL by declaring it as
extern "C" int WINAPI wWinMain( ... )
{
// repetitive code here
}
and used the linker option /EXPORT:wWinMain, but when I try to use the import library in another project I get the error
LIBCMTD.lib(wincrt0.obj) : error LNK2019: unresolved external symbol _WinMain#16 referenced in function __tmainCRTStartup
Remark I do want to use the GUI interface and I know this is common error when you define a main instead of a WinMain function. Also, I enabled the UNICODE support in both projects. What should I do?
This is not possible as-is, the linker can only set the entrypoint for an EXE to a function that's inside the EXE. Rename the wWinMain() in the DLL to something else. Write a wWinMain() in a source code file that gets linked into your EXE, simply call the DLL's exported function.
// ...somewhere in a .cpp file within my .dll's sources...
#define WinMain WinMainOld // ...to suppress Win32 declaration of WinMain
#include <windows.h>
#undef WinMain // ...so that WinMain below is not replaced
. . .
#pragma comment(linker, "/export:_WinMain#16") // ...to export it from .dll
extern "C" // ...to suppress C++ name decoration
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR pCmdLine, int nCmdShow)
{
. . .
}
Should you be using WinMain in a DLL? Should it not be DllMain?
If you want to call the WinMain of the dll, you need to replace the CRTWinMainStartup function(_tmainCRTStartup in your liked CRT lib), and make it call your exported WinMain, this stops the linker looking for a local WinMain and still keeps correct flow of the program(the source for the CRT startups should be in the crt source of any compiler)
I find one way to put WinMain inside DLL.
You need to use WinMain instead of wWinMain (I don't know why)
Append a def file into your project and,
append EXPORTS WinMain in def file.
Like this
EXPORTS
WinMain
From the observation, all need exported functions generated, not only WinMain.
After test, the way of __declspec(dllexport) is invalid for WinMain.
Link your program to the DLL library
use #pragma comment(lib, "testDll.lib")
or modify setting in the project.
EXPORT int WINAPI _WinMain_(int (*_main_)(int argc, char **argv), HINSTANCE hInst, HINSTANCE hPrevInstance, LPSTR commandLine, int nCmdShow);
int _XMain( int argc, char **argv );
#define XMain WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInstance, LPSTR commandLine, int nCmdShow)\
{return _WinMain_( _XMain, hInst, hPrevInstance, commandLine, nCmdShow );} \
int _XMain
Then _WinMain_() calls or schedules _XMain().
Over in your application source:
int XMain( int argc, char **argv )
{
}