diff --git a/CMakeLists.txt b/CMakeLists.txt index ee2a607..6095472 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,6 +29,23 @@ set_target_properties( "MultiThreaded$<$:Debug>" ) +add_library( + wintoastlibc_lazy + SHARED + ${CMAKE_CURRENT_LIST_DIR}/src/wintoastlibc_lazy.c + ${CMAKE_CURRENT_LIST_DIR}/src/wintoastlibc.h +) +target_link_libraries( + wintoastlibc_lazy + kernel32 +) +set_target_properties( + wintoastlibc_lazy + PROPERTIES + PUBLIC_HEADER + "${CMAKE_CURRENT_LIST_DIR}/src/wintoastlibc.h" +) + add_library( wintoastlibc_static STATIC @@ -72,6 +89,22 @@ target_link_libraries( ole32 ) +add_executable( + example1_lazy + WIN32 + ${CMAKE_CURRENT_LIST_DIR}/example/example1.c +) +target_include_directories( + example1_lazy + PRIVATE + ${CMAKE_CURRENT_LIST_DIR}/src +) +target_link_libraries( + example1_lazy + wintoastlibc_lazy + ole32 +) + add_executable( example2 WIN32 @@ -90,7 +123,7 @@ target_link_libraries( ) install( - TARGETS wintoastlibc wintoastlibc_static example1 example2 + TARGETS wintoastlibc wintoastlibc_static wintoastlibc_lazy example1 example2 example1_lazy RUNTIME DESTINATION ${CMAKE_BINARY_DIR}/install/bin ARCHIVE DESTINATION ${CMAKE_BINARY_DIR}/install/lib LIBRARY DESTINATION ${CMAKE_BINARY_DIR}/install/lib diff --git a/README.md b/README.md index 93bef92..b41e188 100644 --- a/README.md +++ b/README.md @@ -8,5 +8,43 @@ Since this project is just bindings, documentation can be found in [WinToast](ht * [example1.c](example/example1.c): minimal C code to show the toast notification * [example2.c](example/example2.c): more complex example with image and basic AUMID registration +## MinGW integration + +### Build as is +```bash +gcc example1.c wintoastlibc.lib -lole32 -mwindows +``` + +### Build with fake implib +```bash +mv wintoastlibc.lib libwintoastlibc.dll.a +gcc example1.c -L. -lwintoastlibc -lole32 -mwindows +``` + +### Build with true implib +```bash +gendef wintoastlibc.dll +dlltool.exe -d wintoastlibc.def -D wintoastlibc.dll -l libwintoastlibc.dll.a +gcc example1.c -L. -lwintoastlibc -lole32 -mwindows +``` + +### Build with delayed loader (dll) +Loader source: [wintoastlibc_lazy.c](src/wintoastlibc_lazy.c) +```bash +gcc -shared -o wintoastlibc_lazy.dll \ + -Wl,--out-implib=libwintoastlibc.dll.a \ + -Wl,--export-all-symbols -Wl,--enable-auto-import \ + -Wl,--whole-archive wintoastlibc_lazy.c -Wl,--no-whole-archive +gcc example1.c -L. -lwintoastlibc -lole32 -mwindows +``` + +### Build with delayed loader (static) +Loader source: [wintoastlibc_lazy.c](src/wintoastlibc_lazy.c) +```bash +gcc -DWTLC_BUILD_STATIC -o wintoastlibc_lazy.o -c wintoastlibc_lazy.c +ar rcs -o libwintoastlibc.dll.a wintoastlibc_lazy.o +gcc example1.c -DWTLC_BUILD_STATIC -L. -lwintoastlibc -lole32 -mwindows +``` + ## Links * https://github.com/mohabouje/WinToast diff --git a/example/example1.c b/example/example1.c index 60fc372..6dab0b2 100644 --- a/example/example1.c +++ b/example/example1.c @@ -7,7 +7,7 @@ #include "wintoastlibc.h" -INT WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR lpCmdLine, INT nCmdShow) +int main(int argc, char ** argv) { INT ret = EXIT_SUCCESS; WTLC_Instance * instance = NULL; @@ -56,3 +56,8 @@ INT WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR lpCmdLin CoUninitialize(); return ret; } + +INT WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR lpCmdLine, INT nCmdShow) +{ + return main(0, NULL); +} diff --git a/example/example2.c b/example/example2.c index 042cf39..6a29566 100644 --- a/example/example2.c +++ b/example/example2.c @@ -139,7 +139,7 @@ static BOOL RegisterBasicAUMID(LPCWSTR aumid, LPCWSTR displayName, LPCWSTR iconU return TRUE; } -INT WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR lpCmdLine, INT nCmdShow) +int main(int argc, char ** argv) { WTLC_Instance * instance = NULL; WTLC_Template * templ = NULL; @@ -205,3 +205,8 @@ INT WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR lpCmdLin CoUninitialize(); return 0; } + +INT WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR lpCmdLine, INT nCmdShow) +{ + return main(0, NULL); +} diff --git a/src/wintoastlibc.h b/src/wintoastlibc.h index 585da91..c2617e7 100644 --- a/src/wintoastlibc.h +++ b/src/wintoastlibc.h @@ -37,7 +37,7 @@ #endif #if !defined (WTLCAPI) -#define WTLCAPI WINAPI +#define WTLCAPI __cdecl #endif #if !defined (_In_) diff --git a/src/wintoastlibc_lazy.c b/src/wintoastlibc_lazy.c new file mode 100644 index 0000000..c0dc27a --- /dev/null +++ b/src/wintoastlibc_lazy.c @@ -0,0 +1,150 @@ +/** + * Copyright (c) 2022 Peter Zhigalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#if !defined (UNICODE) +#define UNICODE +#endif +#if !defined (_UNICODE) +#define _UNICODE +#endif +#if !defined (WTLC_BUILD_LIBRARY) +#define WTLC_BUILD_LIBRARY +#endif + +#include "wintoastlibc.h" + +#if !defined (WTLC_DLLNAME) +#define WTLC_DLLNAME "wintoastlibc.dll" +#endif + +static HMODULE s_module = NULL; + +#define LOAD(X) \ + HMODULE X = s_module; \ + if(!X) \ + { \ + X = LoadLibraryA(WTLC_DLLNAME); \ + if(!X) \ + { \ + MessageBoxA(NULL, "FAILED TO LOAD " WTLC_DLLNAME, "Error", MB_OK | MB_ICONERROR); \ + abort(); \ + } \ + s_module = X; \ + } + +#define SYMCHECK(NAME, SYM) \ + if(!SYM) \ + { \ + MessageBoxA(NULL, "FAILED TO FIND PROC " NAME " IN " WTLC_DLLNAME, "Error", MB_OK | MB_ICONERROR); \ + abort(); \ + } + +#define FORWARD0(NAME, RTYPE) \ + RTYPE WTLCAPI NAME (void) { \ + typedef RTYPE (WTLCAPI * t)(void); \ + t f; \ + LOAD(h) \ + f = (t)GetProcAddress(h, #NAME); \ + SYMCHECK(#NAME, f) \ + return f(); \ + } +#define FORWARD1(NAME, RTYPE, A1TYPE) \ + RTYPE WTLCAPI NAME (A1TYPE a1) { \ + typedef RTYPE (WTLCAPI * t)(A1TYPE); \ + t f; \ + LOAD(h) \ + f = (t)GetProcAddress(h, #NAME); \ + SYMCHECK(#NAME, f) \ + return f(a1); \ + } +#define FORWARD2(NAME, RTYPE, A1TYPE, A2TYPE) \ + RTYPE WTLCAPI NAME (A1TYPE a1, A2TYPE a2) { \ + typedef RTYPE (WTLCAPI * t)(A1TYPE, A2TYPE); \ + t f; \ + LOAD(h) \ + f = (t)GetProcAddress(h, #NAME); \ + SYMCHECK(#NAME, f) \ + return f(a1, a2); \ + } +#define FORWARD3(NAME, RTYPE, A1TYPE, A2TYPE, A3TYPE) \ + RTYPE WTLCAPI NAME (A1TYPE a1, A2TYPE a2, A3TYPE a3) { \ + typedef RTYPE (WTLCAPI * t)(A1TYPE, A2TYPE, A3TYPE); \ + t f; \ + LOAD(h) \ + f = (t)GetProcAddress(h, #NAME); \ + SYMCHECK(#NAME, f) \ + return f(a1, a2, a3); \ + } +#define FORWARD8(NAME, RTYPE, A1TYPE, A2TYPE, A3TYPE, A4TYPE, A5TYPE, A6TYPE, A7TYPE, A8TYPE) \ + RTYPE WTLCAPI NAME (A1TYPE a1, A2TYPE a2, A3TYPE a3, A4TYPE a4, A5TYPE a5, A6TYPE a6, A7TYPE a7, A8TYPE a8) { \ + typedef RTYPE (WTLCAPI * t)(A1TYPE, A2TYPE, A3TYPE, A4TYPE, A5TYPE, A6TYPE, A7TYPE, A8TYPE); \ + t f; \ + LOAD(h) \ + f = (t)GetProcAddress(h, #NAME); \ + SYMCHECK(#NAME, f) \ + return f(a1, a2, a3, a4, a5, a6, a7, a8); \ + } + +FORWARD1(WTLC_Template_Create, WTLC_Template *, WTLC_TemplateType) +FORWARD1(WTLC_Template_Destroy, void, WTLC_Template *) +FORWARD2(WTLC_Template_setFirstLine, void, WTLC_Template *, LPCWSTR) +FORWARD2(WTLC_Template_setSecondLine, void, WTLC_Template *, LPCWSTR) +FORWARD2(WTLC_Template_setThirdLine, void, WTLC_Template *, LPCWSTR) +FORWARD3(WTLC_Template_setTextField, void, WTLC_Template *, LPCWSTR, WTLC_TextField) +FORWARD2(WTLC_Template_setAttributionText, void, WTLC_Template *, LPCWSTR) +FORWARD2(WTLC_Template_setImagePath, void, WTLC_Template *, LPCWSTR) +FORWARD2(WTLC_Template_setAudioSystemFile, void, WTLC_Template *, WTLC_AudioSystemFile) +FORWARD2(WTLC_Template_setAudioPath, void, WTLC_Template *, LPCWSTR) +FORWARD2(WTLC_Template_setAudioOption, void, WTLC_Template *, WTLC_AudioOption) +FORWARD2(WTLC_Template_setDuration, void, WTLC_Template *, WTLC_Duration) +FORWARD2(WTLC_Template_setExpiration, void, WTLC_Template *, INT64) +FORWARD2(WTLC_Template_setScenario, void, WTLC_Template *, WTLC_Scenario) +FORWARD2(WTLC_Template_addAction, void, WTLC_Template *, LPCWSTR) +FORWARD1(WTLC_Template_textFieldsCount, size_t, WTLC_Template *) +FORWARD1(WTLC_Template_actionsCount, size_t, WTLC_Template *) +FORWARD1(WTLC_Template_hasImage, BOOL, WTLC_Template *) +FORWARD2(WTLC_Template_textField, LPCWSTR, WTLC_Template *, WTLC_TextField) +FORWARD2(WTLC_Template_actionLabel, LPCWSTR, WTLC_Template *, size_t); +FORWARD1(WTLC_Template_imagePath, LPCWSTR, WTLC_Template *); +FORWARD1(WTLC_Template_audioPath, LPCWSTR, WTLC_Template *); +FORWARD1(WTLC_Template_attributionText, LPCWSTR, WTLC_Template *); +FORWARD1(WTLC_Template_scenario, LPCWSTR, WTLC_Template *); +FORWARD1(WTLC_Template_expiration, INT64, WTLC_Template *); +FORWARD1(WTLC_Template_type, WTLC_TemplateType, WTLC_Template *); +FORWARD1(WTLC_Template_audioOption, WTLC_AudioOption, WTLC_Template *); +FORWARD1(WTLC_Template_duration, WTLC_Duration, WTLC_Template *); +FORWARD0(WTLC_Instance_Create, WTLC_Instance *); +FORWARD1(WTLC_Instance_Destroy, void, WTLC_Instance *); +FORWARD0(WTLC_isCompatible, BOOL); +FORWARD0(WTLC_isSupportingModernFeatures, BOOL); +FORWARD1(WTLC_strerror, LPCWSTR, WTLC_Error); +FORWARD2(WTLC_initialize, BOOL, WTLC_Instance *, WTLC_Error *); +FORWARD1(WTLC_isInitialized, BOOL, WTLC_Instance *); +FORWARD2(WTLC_hideToast, BOOL, WTLC_Instance *, INT64); +FORWARD8(WTLC_showToast, INT64, WTLC_Instance *, WTLC_Template *, void *, WTLC_CB_toastActivated, WTLC_CB_toastActivatedAction, WTLC_CB_toastDismissed, WTLC_CB_toastFailed, WTLC_Error *); +FORWARD1(WTLC_clear, void, WTLC_Instance *); +FORWARD1(WTLC_createShortcut, WTLC_ShortcutResult, WTLC_Instance *); +FORWARD1(WTLC_appName, LPCWSTR, WTLC_Instance *); +FORWARD1(WTLC_appUserModelId, LPCWSTR, WTLC_Instance *); +FORWARD2(WTLC_setAppUserModelId, void, WTLC_Instance *, LPCWSTR); +FORWARD2(WTLC_setAppName, void, WTLC_Instance *, LPCWSTR); +FORWARD2(WTLC_setShortcutPolicy, void, WTLC_Instance *, WTLC_ShortcutPolicy);