Anyone know the location of SetProcessDpiAwarenessContext() in windows? - winapi

I need to turn off DPI scaling in my Win32 application. The recommended way to do this programmatically is via the call:
SetProcessDpiAwarenessContext()
I am using the mingw windows environment. I verified that mingw headers don't have the call, but then several newer calls are missing from the mingw headers. Its a lot of work to update those, I am sure.
I created a local definition of that:
#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 3
extern BOOL SetProcessDpiAwarenessContext(int value);
int main()
{
SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
}
I still get:
C:\projects\petit_ami>gcc -g3 -Iinclude -Ilibc -static tests/widget_test.c -Wl,--whole-archive bin/petit_ami_graph.a -Wl,--no-whole-archive -lwinmm -lgdi32 -lcomdlg32 -lwsock32 -luser32 -o bin/widget_test
c:/mingw/bin/../lib/gcc/mingw32/9.2.0/../../../../mingw32/bin/ld.exe: bin/petit_ami_graph.a(graphics.o): in function `pa_init_graph':
C:\projects\petit_ami/windows/graphics.c:15662: undefined reference to `SetProcessDpiAwarenessContext'
collect2.exe: error: ld returned 1 exit status
The best documentation I can find says it is in user32.dll.
This is using Windows 10 and recently updated, build: 19042.1052
Thanks for any help.
Scott Franco
San Jose, CA
Almost there. I did:
typedef BOOL (WINAPI *PGNSI)(int);
pGNSI = (PGNSI) GetProcAddress(GetModuleHandle(TEXT("user32.dll")),
"SetProcessDpiAwarenessContext");
if(NULL != pGNSI) {
dbg_printf(dlinfo, "Procedure found\n");
r = pGNSI(2);
dbg_printf(dlinfo, "r: %d\n", r);
if (!r) winerr();
}
And got:
C:\projects\petit_ami>graphics_test
windows/graphics.c:pa_init_graph():15686: Procedure found
windows/graphics.c:pa_init_graph():15688: r: 0
Error: Graph: Windows error: The parameter is incorrect.
The description of the parameter is here:
https://learn.microsoft.com/en-us/windows/win32/hidpi/dpi-awareness-context
I saw elsewhere that 2 was a valid value, but clearly that may not be correct. The suggestion by Simon to get the Visual studio environment may be operative just to get the proper value. Apologies to Simon, I can't at the moment take the rest of your suggestion. There is a long list of reasons I don't want to bore people with here.
Continued:
I installed and ran the visual studio with sample code. It works, now I am trying to figure out what DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 is, it is not a simple integer.
Anyways, its late. I try to find the final answer tomorrow.
Continued:
The working code is:
/* function call for direct to dll */
typedef BOOL (WINAPI *PGNSI)(int);
/* select for highest DPI */
#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 0xfffffffc
...
/* turn off scaling. The following call gets around the lack of a
declaration in mingw */
pGNSI = (PGNSI) GetProcAddress(GetModuleHandle(TEXT("user32.dll")),
"SetProcessDpiAwarenessContext");
if (NULL != pGNSI) {
r = pGNSI(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
if (!r) winerr();
}
As you could probably guess, I am going to tie this to a user option. Now I just need to research what the effect of this new mode is on widgets and other OS features.
Thanks for all the help.

GetProcAddress works and is the recommended method when you cannot be certain if the user's OS will have the function.
If you want to resolve the symbol at link time, you need to ensure that (1) the import library has the symbol, and (2) that the calling convention and name decoration and mangling are correct.
I'm not very familiar with mingw, but I believe it comes with import libraries for some version of common Windows DLLs. Since this is a newer function, it might not be in the import library. There are tools to scan an existing DLL and create a corresponding import library, so perhaps you need to build a fresh one.
The calling convention for Win32 is __stdcall. If your compiler is using a different calling convention by default, you'll have to set it explicitly on your forward declaration of the function. Also, if you're compiling in C++ mode, you'll need to wrap the forward declaration in an extern "C" to prevent name mangling. If either of these are wrong, you'll get an "undefined reference" diagnostic from the linker because the symbol will be "decorated" differently.

Related

Manual linking to Windows library in LLVM

I'm writing my own programming language, and am wanting to compile it to native binaries by compiling to LLVM IR, then letting the rest of the LLVM toolchain take over. Eventually, I will target multiple platforms, but for now I'm just focusing on Windows.
For starters, I have the empty program compiling, which implies that in general my toolchain is set up and working, and I get a no op executable out of it. The next logical step is doing "Hello World", but after looking at the LLVM IR output of clang of the C program that simply calls puts("Hello World!") it looks like a slightly easier first step is to simply _exit();. When reviewing the clang output of that C program, it looks like the relevant line is to do call void #_exit(i32 0). I've distilled it down to what I think is the bare minimum program which calls exit:
define i64* #main() {
%1 = alloca i32, align 4
store i32 0, i32* %1, align 4
call void #_exit(i32 0)
unreachable
}
declare dso_local void #_exit(i32)
When trying to run the equivalent C program directly, of course it works when I use clang directly, but the steps after creation of the LLVM IR are opaque to me, and I believe I'm using the wrong linker options or something, as I get lld-link: error: undefined symbol: _exit during the lld-link step. (Actually, this also occurs when I try to manually link the output of clang -S --emit-llvm, so I have no reason to believe my IR is the problem). The current invocation I'm using for lld-link is lld-link /out:"exit.exe" /entry:main exit.obj. I've tried playing around with adding various flavors of the /defaultlib switch, including manually linking to libcmt both libucrt which I do believe contain _exit after looking through the symbols with dumpbin, but that doesn't seem to help. Looking at the IR output of the clang program, it doesn't seem like there's any particular reference to <stdlib.h>, so I guess that information is lost after the IR generation stage, so I don't think I'm missing anything in my IR.
This appears to be a general Windows linker problem, rather than anything to do with LLVM, since if I do link /out:exit.exe /entry:main exit.obj I get basically the same error.
Anyways, there's clearly some step here during the linking that I don't understand, around how to find the actual library that a given external call lives in, so if anyone could point me in the right direction of how to figure this out for any given C runtime call, that would be great. Particularly in this case, I guess I need to find the library which contains the _exit function. Thanks!
Turns out the libcmt has been replaced. The replacement is ucrt, and so doing /defaultlib:ucrt seems to fix the problem!

How to specify a "clean" name of DLL exports?

I have defined a DLL-export as follows:
__declspec(dllexport)
DWORD WINAPI DllBootstrap(LPVOID addr) {
return 0;
}
Now, using DUMPBIN, the symbol is displayed as follows:
1 0 0001100A ?DllBootstrap##YGKPAX#Z = #ILT+5(?DllBootstrap##YGKPAX#Z)
And this is how the memory looks in Visual Studio:
ยก}....ReflectDLL.dll.?DllBootstrap##YGKPAX#Z..........................................
when inspecting PIMAGE_EXPORT_DIRECTORY.AddressOfNames.
What I need is a clean symbol, i.e., DUMPBIN should output something like:
1 0 0001100A DllBootstrap
and PIMAGE_EXPORT_DIRECTORY.AddressOfNames should point to:
DllBootstrap..........................................
How can I achieve this?
WIN32 BUILDS:
As #RbMm indicated, to retain your function name as-is and get no name decoration, you must use a .DEF file (and remove the __declspec(dllexport) specifier). Then create a DEF file with the line below and either specify it with the /DEF linker option or add it to your Visual Studio project and it will be picked up automatically by the linker:
EXPORTS DllBootstrap
If you don't want to deal with an external .DEF file and you will be using the Visual C++ compiler, the simplest way to limit decoration using just code is to declare your function with 'extern "C"'. This results in decoration including a preceding underscore and appends an "#" along with the argument's byte count in decimal. The following code for example:
extern "C" __declspec(dllexport)
DWORD WINAPI DllBootstrap(LPVOID addr) {
return 0;
}
produces an exported name of:
_DllBootstrap#4
This is how stdcall functions are decorated when C++ name-mangling is disabled with 'extern "C"'. NOTE: WINAPI maps to __stdcall. Retaining 'extern "C"' and changing the convention to __cdecl, you won't get any decoration whatsoever, but module entrypoints should generally remain stdcall as you have it listed in your sample.
If you still want to avoid a .DEF file, there is one last hack you can employ. Add the following line to your code:
#pragma comment(linker,"/EXPORT:DllBootstrap=_DllBootstrap#4")
This will pass an argument to the linker creating a new undecorated name symbol which maps to the decorated name. This isn't very clean as the original name will still exist in your DLL, but you will get your clean exported name.
WIN64 BUILDS (UPDATE):
As Hans Passant commented, for anyone using the Visual C++ 64-bit compiler, there is only the 64-bit calling convention (stdcall, cdecl, etc. keywords are ignored). While C++ mangling will still occur under this compiler, no additional decoration is made to the exported names. In this case, 'extern "C"' would be enough when the sample is compiled as C++ code; if compiled as C, no modifications would be necessary.

Error: functions that differ only in their return type cannot be overloaded

I'm using mac os 10.9, I have a C++ program that uses freeglut library. When I try to make the project. It gives an error which I don't know if it's my fault or not. This is the message:
In file included from /usr/X11/include/GL/freeglut.h:18:
/usr/X11/include/GL/freeglut_ext.h:177:27: error: functions that differ only in their return type cannot be overloaded
FGAPI GLUTproc FGAPIENTRY glutGetProcAddress( const char *procName );
More information: I used CMake (version 2.8.12) to generate the Makefile, and installed the latest version of Xcode and XQuartz.
Any help is appreciated. Thank you.
In glut.h and freeglut_ext.h files:
In glut.h:
#if (GLUT_API_VERSION >= 5)
extern void * APIENTRY glutGetProcAddress(const char *procName) OPENGL_DEPRECATED(10_3, 10_9);
#endif
In freeglut_ext.h:
/*
* Extension functions, see freeglut_ext.c
*/
typedef void (*GLUTproc)();
FGAPI GLUTproc FGAPIENTRY glutGetProcAddress( const char *procName );
One of the declarations returns a function type GLUTproc (specifying a function that takes no arguments), and the other declaration returns a pointer (void*). Both functions take the same arguments (a single const char*). What the compiler says is true.
You're only seeing a complaint about "overloading" because it's C++. In C++, if a compiler thinks it's seen two different functions with the same name then each one needs to have different arguments (e.g. a different number of arguments, or distinct types).
In this case, I doubt the functions are meant to be different; they're meant to be the same, and at some point the API evolved and changed the declaration.
You need to find some way to prevent the compiler from seeing both declarations at the same time (perhaps by setting GLUT_API_VERSION). If you have to, you can #include just one of the files and see if you really need the other file (and if you did, you may have to manually declare some things to avoid a 2nd #include).

Boost.asio compilation problem: undefined reference to `__sync_add_and_fetch_8

Hey guys,
This could be a noob question, but I really can't find any useful solution through Google.
I'm testing a hello world with boost.asio, the program is quite simple:
#include <iostream>
#include <boost/asio.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
int main()
{
boost::asio::io_service io;
boost::asio::deadline_timer t(io, boost::posix_time::seconds(5));
t.wait();
std::cout << "Hello, world!\n";
return 0;
}
I passed the compilation and run well on my Intel Pentium PC (Ubuntu 10.10, gcc 4.4.5, Boost 1.46.0). The command line I used was
g++ -o a a.cpp -I /Boost-Include-Path/ -L /Boost-lib-Path/ -lboost_system
But when I compile the same code on another machine(which is a big one, I'll explain it later), it can't pass the compilation and gives such errors:
/tmp/ccOZxZBX.o: In function boost::asio::detail::gcc_sync_fenced_block::gcc_sync_fenced_block()': a.cpp:(.text._ZN5boost4asio6detail21gcc_sync_fenced_blockC1Ev[boost::asio::detail::gcc_sync_fenced_block::gcc_sync_fenced_block()]+0x4c): undefined reference to__sync_lock_test_and_set_4' /tmp/ccOZxZBX.o: In function boost::detail::atomic_count::operator++()': a.cpp:(.text._ZN5boost6detail12atomic_countppEv[boost::detail::atomic_count::operator++()]+0x30): undefined reference to__sync_add_and_fetch_8' /tmp/ccOZxZBX.o: In function boost::detail::atomic_count::operator--()': a.cpp:(.text._ZN5boost6detail12atomic_countmmEv[boost::detail::atomic_count::operator--()]+0x30): undefined reference to__sync_add_and_fetch_8' /tmp/ccOZxZBX.o: In function boost::detail::atomic_count::operator long() const': a.cpp:(.text._ZNK5boost6detail12atomic_countcvlEv[boost::detail::atomic_count::operator long() const]+0x30): undefined reference to__sync_fetch_and_add_8'
The machine I used was a SiCortex SC5832,which use MIPS64 instruction set processors, OS is changed CentoOS. Gcc 4.2.3, Boost1.46.0. Is it possible that there are problems about the compatibility of the MIPS? I added -mips64 option, but it still give the same errors.
I know this environment could not be very usual, but I think some people who are using similar big machines may face the same problem.
Any help would be appreciated. By the way, I don't have sudo permission.
Thanks,
Tony
This function is a GCC built-in function, and it was introduced around GCC 4.2 (iirc) see documentation.
According to the documentation it's not available on all target processors.
If you look at boost/smart_ptr/detail/atomic_count.hpp it looks like it would fall into the #elif defined(BOOST_SP_HAS_SYNC) block. i.e. boost/smart_ptr/detail/atomic_count_sync.hpp.
Support for this is determined in boost/smart_ptr/detail/sp_has_sync.hpp. This header essentially assumes that GCC supports this on all platforms except for a few exceptions. You might want to insert MIPS as another exception here and submit a patch to boost.
You'll also see that one workaround is to define BOOST_AC_USE_PTHREADS. This will use a mutex around the atomic count, which probably is significantly less efficient, but at least it will work until you can figure out what atomic operations are supported on MIPS64.

How do I control which symbols a Windows DLL imports from the application?

I'm trying to build a shared library (DLL) on Windows, using MSVC 6 (retro!) and I have a peculiar link issue I need to resolve. My shared library must access some global state, controlled by the loading application.
Broadly, what I have is this:
application.c:
static int g_private_value;
int use_private_value() {
/* do something with g_private_value */
}
int main (...) {
return shared_library_method ();
}
shared_library.c:
__declspec(dllexport) int __stdcall shared_library_method() {
use_private_value();
}
(Updated - I forgot the __declspec(dllexport) int __stdcall portion, but it's there in the real code)
How do I set up shared_library.dll so that it exports shared_library_method and imports use_private_value?
Please remember that A) I'm a unix programmer, generally, and B) that I'm doing this without Visual Studio; our automated build infrastructure drives MSVC with makefiles. If I'm omitting something that will make it easier to answer the question, please comment and I'll update it ASAP.
This is actually going to be pretty difficult to get working. On Unix/Linux you can have shared objects and applications import symbols from each other, but on Windows you can't have a DLL import symbols from the application that loads it: the Windows PE executable format just doesn't support that idiom.
I know that the Cygwin project have some sort of work-around to address this problem, but I don't believe that it's trivial. Unless you want to do lots of PE-related hacking you probably don't want to go there.
An easier solution might be to just have some sort of initializer method exported from the DLL:
typedef int (*func_ptr)();
void init_library(func_ptr func);
The application must call this at start-up, passing in the address of the function you want to share. Not exactly elegant, but it should work okay.
I'll start with half of the answer.
In shared_library.c:
__declspec(dllexport) int __stdcall shared_library_method(void)
{
}
The MSDN article about exporting function from DLL:s.
For the second half you need to export the functions from your application.c.
You can do this in the linker with:
/export:use_private_value#0
This should get you a lib-file that you build with your DLL.
The option to link the lib-file is to use GetProcAddress().
As DavidK noted if you only have a few functions it is probably easier to pass the function pointers in an init function. It is however possible to do what you are asking for.

Resources