I'd like to use a function from WindowsCodecs.dll, but MinGW has incomplete and missing WinAPI headers, as well as import libraries. Consider the following demo:
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
// ---------- dummy declarations, because MinGW got no wincodec.h ----------
typedef REFGUID REFWICPixelFormatGUID;
typedef VOID IWICBitmapSource;
HRESULT WINAPI WICConvertBitmapSource(
REFWICPixelFormatGUID dstFormat,
IWICBitmapSource *pISrc,
IWICBitmapSource **ppIDst);
// -------------------------------------------------------------------------
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpLine, int nShow)
{
#ifdef LOAD_FROM_DLL
typedef HRESULT (WINAPI *PWICConvertBitmapSource)(
REFWICPixelFormatGUID, IWICBitmapSource *, IWICBitmapSource **);
HMODULE hDll = LoadLibrary("WindowsCodecs.dll");
PWICConvertBitmapSource pFunc =
(PWICConvertBitmapSource)GetProcAddress(hDll, "WICConvertBitmapSource");
printf("WICConvertBitmapSource: 0x%p.\n", pFunc);
pFunc(NULL, NULL, NULL);
FreeLibrary(hDll);
#else
WICConvertBitmapSource(NULL, NULL, NULL);
#endif
return 0;
}
When built by gcc test.c -DLOAD_FROM_DEF, the program prints address of the function and terminates correctly. Although, when linked against the import library from the following def:
LIBRARY WindowsCodecs.dll
EXPORTS
WICConvertBitmapSource#12
, this error pops out:
The procedure entry point WICConvertBitmapSource#12 could
not be located in the dynamic link library WindowsCodecs.dll.
Surprisingly enough, if I remove the declaration of WICConvertBitmapSource from the source and #12 from def file, the program links and runs fine.
How can I create a correct import library?
Notes: I'm running MinGW on Windows 7 SP1. My gcc version is 4.7.0 with w32api 3.17 installed. The problem appears with many functions, like GdiAlphaBlend, or SHCreateStreamOnFileEx.
The import library should've been created with --kill-at flag, like this:
dlltool --kill-at -D WindowsCodecs.dll -d WindowsCodecs.def -l libwindowscodecs.a
This article clarified everything for me: http://wyw.dcweb.cn/stdcall.htm
Related
I have a Windows 10 64-bits, Office 2013 32-bits and using MinGW64.
I followed instructions from https://www.transmissionzero.co.uk/computing/building-dlls-with-mingw/
I checked other answers threads in stackoverflow without success.
When I run Excel VBA code I get the follow error: "Run-Time error 48: File not found", but the file is in the folder and the folder has PATH reference.
I have the Add.c with follow code:
#include "add.h"
#include <windows.h>
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
/* Code path executed when DLL is loaded into a process's address space. */
break;
case DLL_THREAD_ATTACH:
/* Code path executed when a new thread is created within the process. */
break;
case DLL_THREAD_DETACH:
/* Code path executed when a thread within the process has exited *cleanly*. */
break;
case DLL_PROCESS_DETACH:
/* Code path executed when DLL is unloaded from a process's address space. */
break;
}
return TRUE;
}
int ADDCALL Add(int a, int b)
{
return (a + b);
}
/* Assign value to exported variables. */
int foo = 7;
int bar = 41;
The follow Add.h code:
/* add_var.h
Declares a function and variables to be imported by our application, and
exported by our DLL.
*/
/* You should define ADD_EXPORTS *only* when building the DLL. */
#ifdef ADD_EXPORTS
#define ADDAPI __declspec(dllexport)
#else
#define ADDAPI __declspec(dllimport)
#endif
/* Define calling convention in one place, for convenience. */
#define ADDCALL __cdecl
/* Make sure functions are exported with C linkage under C++ compilers. */
#ifdef __cplusplus
extern "C"
{
#endif
/* Declare our Add function using the above definitions. */
ADDAPI int ADDCALL Add(int a, int b);
/* Exported variables. */
extern ADDAPI int foo;
extern ADDAPI int bar;
#ifdef __cplusplus
} // __cplusplus defined.
#endif
And the follow VBA code to test:
Option Explicit
Private Declare PtrSafe Function Add Lib "C:\exceladd2\AddLib.dll" (ByVal a As Integer, ByVal b As Integer) As Integer
Sub Test()
Call MsgBox(Add(4, 5))
End Sub
The follow code was compiled with MinGW64 without errors or warnings:
x86_64-w64-mingw32-gcc-8.1.0 -c -o add.o add.c -D ADD_EXPORTS
x86_64-w64-mingw32-gcc-8.1.0 -o AddLib.dll add.o -shared -s -Wl,--subsystem,windows,--kill-at
The follow is the result from dependencies check from the library: https://pasteboard.co/J4zegPO.jpg
I tried to compile with gcc 32 bits and other versions of gcc 64-bits and got the same error 48 in Excel.
On the past I was able to run similar DLL compiled with gcc 32-bits in a Windows 7 32-bits with Office 2010 32-bit without any trouble. Ran Excel VBA with and without PtrSafe without result.
Is there anything wrong with code or compile?
Do you know any software to troubleshoot DLLs?
Thanks in advance for your help!
I am trying to import a function from an unmanaged DLL into a C project by creating a .def file specifying the function I need to use. I am practicing on the WinAPI function MessageBoxA from user32.dll. It is an stdcall function, like the other WinAPI functions.
Here's how I create my .def file:
LIBRARY user32.dll
EXPORTS
_MessageBoxA#16
Then I create a .lib from it like this: lib /def:"C:\Path\to\def\user32.def" /
out:"C:\path\to\project\user32-mb.lib" which successfully creates user32-mb.lib and user32-mb.exp. Then, in my C project, I do the following:
#pragma comment(lib, "user32-mb.lib")
#ifdef __cplusplus
#define EXTERNC extern "C"
#else
#define EXTERNC
#endif
EXTERNC __declspec(dllexport) int __stdcall MessageBoxA(void *hWnd, char *lpText, char *lpCaption, int uType);
void main(){
MessageBoxA(0, "MessageBox test", "MessageBox test", 0x00000030L);
}
However, upon linking, it gives the following error:
error LNK2019: unresolved external symbol _MessageBoxA#16 referenced in function _main
However, when I change the declaration in the .def to this:
LIBRARY user32.dll
EXPORTS
MessageBoxA
And change the function prototype in my C code to cdecl instead of stdcall:
EXTERNC __declspec(dllexport) int __cdecl MessageBoxA(void *hWnd, char *lpText, char *lpCaption, int uType);
The message box actually appears, but right on closing, it throws an error:
Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.
Which indicates that calling it with cdecl is also a bad idea since it requires stdcall after all.
The question is, what should I change in the .def file or in my project to avoid both errors and to import and call an stdcall function properly?
You need to change __declspec(dllexport) to __declspec(dllimport), as you are importing functions from a DLL, not exporting them:
EXTERNC __declspec(dllimport) int __stdcall MessageBoxA(void *hWnd, char *lpText, char *lpCaption, int uType);
^^
You need to use dllimport rather than dllexport, but in this case you should remove the __declspec(...) altogether.
And you need to specify the correct name for the function which is MessageBoxA.
LIBRARY USER32.dll
EXPORTS
MessageBoxA
Also it would be remiss of me not to point out that the correct main declaration is
int main(void)
I am still not entirely sure why, but removing the _ adding the ordinal to the function name my .def file fixed everything. My solution is:
LIBRARY USER32.dll
EXPORTS
MessageBoxA#16 #2093
Function definition:
#ifdef __cplusplus
#define EXTERNC extern "C"
#else
#define EXTERNC
#endif
typedef void *PVOID;
typedef PVOID HANDLE;
typedef HANDLE HWND;
typedef const char *LPCSTR;
typedef unsigned int UINT;
EXTERNC __declspec(dllimport)
int
__stdcall
MessageBoxA(
HWND hWnd,
LPCSTR lpText,
LPCSTR lpCaption,
UINT uType);
This page indicates that winuser.h is the header. From there, you can see some macros are used, including WINUSERAPI and WINAPI. WINUSERAPI is conditionally #define-d at the beginning of that header. WINAPI can be found in the winbase.h header, where it can be seen to be tied to a calling convention, depending on the platform.
But a better question is: Why are you using dllexport and not dllimport?
I can't get Comctl32.lib to link with my program using GCC (MinGW).
GCC Input:
gcc -o program.exe main.c images.o -lgdi32 -lcomctl32 -mwindows
GCC Output
main.c: In function 'WinMain':
main.c:120:2: error: unknown type name 'INITCOMMONCONTROLSEX'
main.c:124:9: error: request for member 'dwICC' in something not a structure or union
Related Code in main.c
#define _WIN32_WINNT _WIN32_WINNT_WIN7
#include <windows.h>
#include <commctrl.h>
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmd)
{
Line 120: INITCOMMONCONTROLSEX icex;
Line 124: icex.dwICC = ICC_LISTVIEW_CLASSES;
InitCommonControlsEx(&icex);
}
Thank you for any help or information you can provide. I've been at this too long and just can't come up with an answer.
I have resolved the issue thanks to David H. I had to define
#define _WIN32_IE 0x0900
I was under the impression that commctrl.h was defining 0x0500 by default (0x0300 is required for my functions), but it appears it wasn't.
If you do not define the _WIN32_IE macro in your project, it is automatically defined as 0x0500. - MSDN Source
I can compile DLLs properly using mingw and do the exports/imports stuff. What I am looking for is defining the dll onload function properly as you would in MS VC products. Google didn't turn up anything. Anyone have any ideas or a link to a tutorial?
Okay, so after some fiddling...it's working. For anyone else that is having issues here it is. My issues weren't related to compiling in instead of loading dynamically. It was a mash-up of a couple of tutorial/question/how-tos that got me to this point.
dll.c
#include <stdio.h>
#include <windows.h>
#include "dll.h"
//extern "C" BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD Reason, LPVOID LPV) {
//This one was only necessary if you were using a C++ compiler
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
// Code to run when the DLL is loaded
printf ("Load working...\n");
break;
case DLL_PROCESS_DETACH:
// Code to run when the DLL is freed
printf ("Unload working...\n");
break;
case DLL_THREAD_ATTACH:
// Code to run when a thread is created during the DLL's lifetime
printf ("ThreadLoad working...\n");
break;
case DLL_THREAD_DETACH:
// Code to run when a thread ends normally.
printf ("ThreadUnload working...\n");
break;
}
return TRUE;
}
EXPORT void hello(void) {
printf ("Hello\n");
}
dll.h
#ifndef DLL_H_
#define DLL_H_
#ifdef BUILD_DLL
/* DLL export */
#define EXPORT __declspec(dllexport)
#else
/* EXE import */
#define EXPORT __declspec(dllimport)
#endif
EXPORT void hello(void);
#endif /* DLL_H_ */
hello.c
#include <windows.h>
#include <stdio.h>
int main () {
/*Typedef the hello function*/
typedef void (*pfunc)();
/*Windows handle*/
HANDLE hdll;
/*A pointer to a function*/
pfunc hello;
/*LoadLibrary*/
hdll = LoadLibrary("message.dll");
/*GetProcAddress*/
hello = (pfunc)GetProcAddress(hdll, "hello");
/*Call the function*/
hello();
return 0;
}
when compiled with
gcc -c -DBUILD_DLL dll.c
gcc -shared -o message.dll dll.o -Wl,--out-implib,libmessage.a
gcc -c hello.c
gcc -o hello.exe hello.o message.dll
produces the expected output of
Load working...
Hello
Unload working...
Since mingw is just a windows port of GCC and associated tools, you can use GCC constructor and destructor attributes. These work for both shared and static libraries, and execute code before and after main is run, respectively. Additionally, you can specify multiple constructor and destructor functions per library.
static void __attribute__((constructor))
your_lib_init(void)
{
fprintf(stderr, "library init\n");
}
static void __attribute__((destructor))
your_lib_destroy(void)
{
fprintf(stderr, "library destroy\n");
}
I'm doing some test to learn how to create shared library.
The template for shared libraries in Code::Blocks is this
library.c
// The functions contained in this file are pretty dummy
// and are included only as a placeholder. Nevertheless,
// they *will* get included in the shared library if you
// don't remove them :)
//
// Obviously, you 'll have to write yourself the super-duper
// functions to include in the resulting library...
// Also, it's not necessary to write every function in this file.
// Feel free to add more files in this project. They will be
// included in the resulting library.
// A function adding two integers and returning the result
int SampleAddInt(int i1, int i2)
{
return i1 + i2;
}
// A function doing nothing ;)
void SampleFunction1()
{
// insert code here
}
// A function always returning zero
int SampleFunction2()
{
// insert code here
return 0;
}
I tried to compile it, and it compiled without any error or warning. But when i tried to use it with the ctyped.cdll.LoadLibrary("library path.dll") in python 3(that actually should work like the C function), it said that it wasn't a valid win32 application. Both python and code::blocks are 32 bit (code:blocks compile with gcc, and i tryed to use an installed version of mingw on my system, but it gives some error about a missing library) while i'm working on win 7 64bit
Do you know what the problem can be, or if i'm doing something wrong?
EDIT1:
i'm on windows 7 64bit, in the specs file of the compiler is wrote: "Thread model: win32, gcc version 3.4.5 (mingw-vista special r3)"
and i used as command
gcc.exe -shared -o library.dll library.c
in python i used
from ctypes import *
lib = cdll.LoadLibrary("C:\\Users\\Francesco\\Desktop\\C programmi\\Python\\Ctypes DLL\\library.dll")
and the error was
WindowsError: [Error 193] %1 is not a valid Win32 application
i installed both python3.1 and mingw from the binary package and not compiling them on my system
EDIT2:
After reading Marc answer.
main.h
#ifndef __MAIN_H__
#define __MAIN_H__
#include <windows.h>
#ifdef BUILD_DLL
#define DLL_EXPORT __declspec(dllexport)
#else
#define DLL_EXPORT __declspec(dllimport)
#endif
#ifdef __cplusplus
extern "C"
{
#endif
DLL_EXPORT int MySimpleSum(int A, int B);
#ifdef __cplusplus
}
#endif
#endif // __MAIN_H__
main.c
#include "main.h"
// a sample exported function
DLL_EXPORT int MySimpleSum(int A, int B)
{
return A+B;
}
compiling options
gcc -c _DBUILD_DLL main.c
gcc -shared -o library.dll main.o -Wl,--out-implib,liblibrary.a
with gcc 4.5.2
still get the same error..
I believe in the windows environment you need to use the __declspec annotation. How to create a shared library and the use of __declspec is described here: DLL Creation in MingW.