diff --git a/libtcc.c b/libtcc.c index d600359..337a6f2 100644 --- a/libtcc.c +++ b/libtcc.c @@ -1299,6 +1299,8 @@ static int link_option(const char *str, const char *val, const char **ptr) if (*p != ',' && *p != '=') return 0; p++; + } else if (*p) { + return 0; } *ptr = p; return ret; @@ -1369,6 +1371,8 @@ static int tcc_set_linker(TCCState *s, const char *option) ignoring = 1; } else if (link_option(option, "O", &p)) { ignoring = 1; + } else if (link_option(option, "export-all-symbols", &p)) { + s->rdynamic = 1; } else if (link_option(option, "rpath=", &p)) { copy_linker_arg(&s->rpath, p, ':'); } else if (link_option(option, "enable-new-dtags", &p)) { @@ -1390,7 +1394,7 @@ static int tcc_set_linker(TCCState *s, const char *option) s->pe_subsystem = 1; } else if (!strcmp(p, "console")) { s->pe_subsystem = 3; - } else if (!strcmp(p, "gui")) { + } else if (!strcmp(p, "gui") || !strcmp(p, "windows")) { s->pe_subsystem = 2; } else if (!strcmp(p, "posix")) { s->pe_subsystem = 7; diff --git a/tcc.c b/tcc.c index 2cca7a8..9ae84fc 100644 --- a/tcc.c +++ b/tcc.c @@ -117,13 +117,14 @@ static const char help2[] = "-Wl,... linker options:\n" " -nostdlib do not link with standard crt/libs\n" " -[no-]whole-archive load lib(s) fully/only as needed\n" + " -export-all-symbols same as -rdynamic\n" " -image-base= -Ttext= set base address of executable\n" " -section-alignment= set section alignment in executable\n" #ifdef TCC_TARGET_PE " -file-alignment= set PE file alignment\n" " -stack= set PE stack reserve\n" " -large-address-aware set related PE option\n" - " -subsystem=[console gui] set PE subsystem\n" + " -subsystem=[console/windows] set PE subsystem\n" " -oformat=[pe-* binary] set executable output format\n" "Predefined macros:\n" " tcc -E -dM - < nul\n" diff --git a/tcc.h b/tcc.h index b575bb7..30e8dec 100644 --- a/tcc.h +++ b/tcc.h @@ -458,6 +458,7 @@ typedef struct Sym { /* special flag, too */ #define SECTION_ABS ((void *)1) +#define SECTION_COMMON ((void *)2) typedef struct Section { unsigned long data_offset; /* current data offset */ diff --git a/tccgen.c b/tccgen.c index 131dced..4c5e4d6 100644 --- a/tccgen.c +++ b/tccgen.c @@ -258,6 +258,33 @@ ST_FUNC void tccgen_end(TCCState *s1) tcc_debug_end(s1); } +/* ------------------------------------------------------------------------- */ +/* apply storage attibutes to Elf symbol */ + +static void update_storage(Sym *sym) +{ + int t; + ElfW(Sym) *esym; + + if (0 == sym->c) + return; + + t = sym->type.t; + esym = &((ElfW(Sym) *)symtab_section->data)[sym->c]; + + if (t & VT_VIS_MASK) + esym->st_other = (esym->st_other & ~ELFW(ST_VISIBILITY)(-1)) + | ((t & VT_VIS_MASK) >> VT_VIS_SHIFT); + + if (t & VT_WEAK) + esym->st_info = ELFW(ST_INFO)(STB_WEAK, ELFW(ST_TYPE)(esym->st_info)); + +#ifdef TCC_TARGET_PE + if (t & VT_EXPORT) + esym->st_other |= ST_PE_EXPORT; +#endif +} + /* ------------------------------------------------------------------------- */ /* update sym->c so that it points to an external symbol in section 'section' with value 'value' */ @@ -266,11 +293,10 @@ ST_FUNC void put_extern_sym2(Sym *sym, Section *section, addr_t value, unsigned long size, int can_add_underscore) { - int sym_type, sym_bind, sh_num, info, other; + int sym_type, sym_bind, sh_num, info, other, t; ElfW(Sym) *esym; const char *name; char buf1[256]; - #ifdef CONFIG_TCC_BCHECK char buf[32]; #endif @@ -279,26 +305,11 @@ ST_FUNC void put_extern_sym2(Sym *sym, Section *section, sh_num = SHN_UNDEF; else if (section == SECTION_ABS) sh_num = SHN_ABS; + else if (section == SECTION_COMMON) + sh_num = SHN_COMMON; else sh_num = section->sh_num; - if ((sym->type.t & VT_BTYPE) == VT_FUNC) { - sym_type = STT_FUNC; - } else if ((sym->type.t & VT_BTYPE) == VT_VOID) { - sym_type = STT_NOTYPE; - } else { - sym_type = STT_OBJECT; - } - - if (sym->type.t & VT_STATIC) - sym_bind = STB_LOCAL; - else { - if (sym->type.t & VT_WEAK) - sym_bind = STB_WEAK; - else - sym_bind = STB_GLOBAL; - } - if (!sym->c) { name = get_tok_str(sym->v, NULL); #ifdef CONFIG_TCC_BCHECK @@ -328,39 +339,39 @@ ST_FUNC void put_extern_sym2(Sym *sym, Section *section, } } #endif + t = sym->type.t; + if ((t & VT_BTYPE) == VT_FUNC) { + sym_type = STT_FUNC; + } else if ((t & VT_BTYPE) == VT_VOID) { + sym_type = STT_NOTYPE; + } else { + sym_type = STT_OBJECT; + } + if (t & VT_STATIC) + sym_bind = STB_LOCAL; + else + sym_bind = STB_GLOBAL; other = 0; - #ifdef TCC_TARGET_PE - if (sym->type.t & VT_EXPORT) - other |= ST_PE_EXPORT; if (sym_type == STT_FUNC && sym->type.ref) { Sym *ref = sym->type.ref; - if (ref->a.func_export) - other |= ST_PE_EXPORT; if (ref->a.func_call == FUNC_STDCALL && can_add_underscore) { sprintf(buf1, "_%s@%d", name, ref->a.func_args * PTR_SIZE); name = buf1; other |= ST_PE_STDCALL; can_add_underscore = 0; } - } else { - if (find_elf_sym(tcc_state->dynsymtab_section, name)) - other |= ST_PE_IMPORT; - if (sym->type.t & VT_IMPORT) - other |= ST_PE_IMPORT; } -#else - if (! (sym->type.t & VT_STATIC)) - other = (sym->type.t & VT_VIS_MASK) >> VT_VIS_SHIFT; + if (t & VT_IMPORT) + other |= ST_PE_IMPORT; #endif if (tcc_state->leading_underscore && can_add_underscore) { buf1[0] = '_'; pstrcpy(buf1 + 1, sizeof(buf1) - 1, name); name = buf1; } - if (sym->asm_label) { + if (sym->asm_label) name = get_tok_str(sym->asm_label, NULL); - } info = ELFW(ST_INFO)(sym_bind, sym_type); sym->c = set_elf_sym(symtab_section, value, size, info, other, sh_num, name); } else { @@ -369,6 +380,7 @@ ST_FUNC void put_extern_sym2(Sym *sym, Section *section, esym->st_size = size; esym->st_shndx = sh_num; } + update_storage(sym); } ST_FUNC void put_extern_sym(Sym *sym, Section *section, @@ -580,41 +592,6 @@ ST_FUNC void sym_pop(Sym **ptop, Sym *b, int keep) *ptop = b; } -static void weaken_symbol(Sym *sym) -{ - sym->type.t |= VT_WEAK; - if (sym->c > 0) { - int esym_type; - ElfW(Sym) *esym; - - esym = &((ElfW(Sym) *)symtab_section->data)[sym->c]; - esym_type = ELFW(ST_TYPE)(esym->st_info); - esym->st_info = ELFW(ST_INFO)(STB_WEAK, esym_type); - } -} - -static void apply_visibility(Sym *sym, CType *type) -{ - int vis = sym->type.t & VT_VIS_MASK; - int vis2 = type->t & VT_VIS_MASK; - if (vis == (STV_DEFAULT << VT_VIS_SHIFT)) - vis = vis2; - else if (vis2 == (STV_DEFAULT << VT_VIS_SHIFT)) - ; - else - vis = (vis < vis2) ? vis : vis2; - sym->type.t &= ~VT_VIS_MASK; - sym->type.t |= vis; - - if (sym->c > 0) { - ElfW(Sym) *esym; - - esym = &((ElfW(Sym) *)symtab_section->data)[sym->c]; - vis >>= VT_VIS_SHIFT; - esym->st_other = (esym->st_other & ~ELFW(ST_VISIBILITY)(-1)) | vis; - } -} - /* ------------------------------------------------------------------------- */ static void vsetc(CType *type, int r, CValue *vc) @@ -831,31 +808,49 @@ ST_FUNC Sym *external_global_sym(int v, CType *type, int r) return s; } +/* Merge some storage attributes. */ +static void patch_storage(Sym *sym, CType *type) +{ + int t; + if (!is_compatible_types(&sym->type, type)) + tcc_error("incompatible types for redefinition of '%s'", + get_tok_str(sym->v, NULL)); + t = type->t; +#ifdef TCC_TARGET_PE + if ((sym->type.t ^ t) & VT_IMPORT) + tcc_error("incompatible dll linkage for redefinition of '%s'", + get_tok_str(sym->v, NULL)); +#endif + sym->type.t |= t & (VT_EXPORT|VT_WEAK); + if (t & VT_VIS_MASK) { + int vis = sym->type.t & VT_VIS_MASK; + int vis2 = t & VT_VIS_MASK; + if (vis == (STV_DEFAULT << VT_VIS_SHIFT)) + vis = vis2; + else if (vis2 != (STV_DEFAULT << VT_VIS_SHIFT)) + vis = (vis < vis2) ? vis : vis2; + sym->type.t = (sym->type.t & ~VT_VIS_MASK) | vis; + } +} + /* define a new external reference to a symbol 'v' */ static Sym *external_sym(int v, CType *type, int r) { Sym *s; - s = sym_find(v); if (!s) { /* push forward reference */ s = sym_push(v, type, r | VT_CONST | VT_SYM, 0); s->type.t |= VT_EXTERN; - } else if (s->type.ref == func_old_type.ref) { - s->type.ref = type->ref; - s->r = r | VT_CONST | VT_SYM; - s->type.t |= VT_EXTERN; - } else if (!is_compatible_types(&s->type, type)) { - tcc_error("incompatible types for redefinition of '%s'", - get_tok_str(v, NULL)); + } else { + if (s->type.ref == func_old_type.ref) { + s->type.ref = type->ref; + s->r = r | VT_CONST | VT_SYM; + s->type.t |= VT_EXTERN; + } + patch_storage(s, type); + update_storage(s); } - /* Merge some storage attributes. */ - if (type->t & VT_WEAK) - weaken_symbol(s); - - if (type->t & VT_VIS_MASK) - apply_visibility(s, type); - return s; } @@ -1164,7 +1159,6 @@ ST_FUNC int gv(int rc) rc2 = RC_QRET; #endif #endif - /* need to reload if: - constant - lvalue (need to dereference pointer) @@ -3733,7 +3727,7 @@ static void parse_btype_qualify(CType *type, int qualifiers) */ static int parse_btype(CType *type, AttributeDef *ad) { - int t, u, bt_size, complete, type_found, typespec_found; + int t, u, bt_size, complete, type_found, typespec_found, g; Sym *s; CType type1; @@ -3865,15 +3859,18 @@ static int parse_btype(CType *type, AttributeDef *ad) /* storage */ case TOK_EXTERN: - t |= VT_EXTERN; - next(); - break; + g = VT_EXTERN; + goto storage; case TOK_STATIC: - t |= VT_STATIC; - next(); - break; + g = VT_STATIC; + goto storage; case TOK_TYPEDEF: - t |= VT_TYPEDEF; + g = VT_TYPEDEF; + goto storage; + storage: + if (t & (VT_EXTERN|VT_STATIC|VT_TYPEDEF) & ~g) + tcc_error("multiple storage classes"); + t |= g; next(); break; case TOK_INLINE1: @@ -4203,6 +4200,7 @@ static void type_decl(CType *type, AttributeDef *ad, int *v, int td) } } *type = type1; + type->t |= storage; } /* compute the lvalue VT_LVAL_xxx needed to match type t. */ @@ -5986,7 +5984,11 @@ static void parse_init_elem(int expr_type) expr_const1(); global_expr = saved_global_expr; /* NOTE: symbols are accepted */ - if ((vtop->r & (VT_VALMASK | VT_LVAL)) != VT_CONST) + if ((vtop->r & (VT_VALMASK | VT_LVAL)) != VT_CONST +#ifdef TCC_TARGET_PE + || (vtop->type.t & VT_IMPORT) +#endif + ) tcc_error("initializer element is not constant"); break; case EXPR_ANY: @@ -6656,16 +6658,12 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, vset(type, r, addr); } } else { - Sym *sym; - - sym = NULL; + Sym *sym = NULL; if (v && scope == VT_CONST) { /* see if the symbol was already defined */ sym = sym_find(v); if (sym) { - if (!is_compatible_types(&sym->type, type)) - tcc_error("incompatible types for redefinition of '%s'", - get_tok_str(v, NULL)); + patch_storage(sym, type); if (sym->type.t & VT_EXTERN) { /* if the variable is extern, it was not allocated */ sym->type.t &= ~VT_EXTERN; @@ -6675,16 +6673,18 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, sym->type.ref->c < 0 && type->ref->c >= 0) sym->type.ref->c = type->ref->c; - } else { + } else if (!has_init) { /* we accept several definitions of the same global variable. this is tricky, because we must play with the SHN_COMMON type of the symbol */ - /* XXX: should check if the variable was already - initialized. It is incorrect to initialized it - twice */ /* no init data, we won't add more to the symbol */ - if (!has_init) - goto no_alloc; + update_storage(sym); + goto no_alloc; + } else if (sym->c) { + ElfW(Sym) *esym; + esym = &((ElfW(Sym) *)symtab_section->data)[sym->c]; + if (esym->st_shndx == data_section->sh_num) + tcc_error("redefinition of '%s'", get_tok_str(v, NULL)); } } } @@ -6697,6 +6697,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, else if (tcc_state->nocommon) sec = bss_section; } + if (sec) { data_offset = sec->data_offset; data_offset = (data_offset + align - 1) & -align; @@ -6730,22 +6731,15 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, if (sec) { put_extern_sym(sym, sec, addr, size); } else { - ElfW(Sym) *esym; - /* put a common area */ - put_extern_sym(sym, NULL, align, size); - /* XXX: find a nicer way */ - esym = &((ElfW(Sym) *)symtab_section->data)[sym->c]; - esym->st_shndx = SHN_COMMON; + put_extern_sym(sym, SECTION_COMMON, align, size); } + } else { /* push global reference */ sym = get_sym_ref(type, sec, addr, size); vpushsym(type, sym); } - /* patch symbol weakness */ - if (type->t & VT_WEAK) - weaken_symbol(sym); - apply_visibility(sym, type); + #ifdef CONFIG_TCC_BCHECK /* handles bounds now because the symbol must be defined before for the relocation */ @@ -6760,6 +6754,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, } #endif } + if (type->t & VT_VLA) { int a; @@ -6775,6 +6770,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, gen_vla_sp_save(addr); vla_sp_loc = addr; vlas_in_scope++; + } else if (has_init) { size_t oldreloc_offset = 0; if (sec && sec->reloc) @@ -6787,7 +6783,8 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, if (flexible_array) flexible_array->type.ref->c = -1; } - no_alloc: ; + + no_alloc: /* restore parse state if needed */ if (init_str) { end_macro(); @@ -6878,10 +6875,6 @@ static void gen_function(Sym *sym) /* patch symbol size */ ((ElfW(Sym) *)symtab_section->data)[sym->c].st_size = ind - func_ind; - /* patch symbol weakness (this definition overrules any prototype) */ - if (sym->type.t & VT_WEAK) - weaken_symbol(sym); - apply_visibility(sym, &sym->type); tcc_debug_funcend(tcc_state, ind - func_ind); /* It's better to crash than to generate wrong code */ cur_text_section = NULL; @@ -7022,10 +7015,14 @@ static int decl0(int l, int is_for_loop_init) if (ad.a.weak) type.t |= VT_WEAK; #ifdef TCC_TARGET_PE - if (ad.a.func_import) - type.t |= VT_IMPORT; - if (ad.a.func_export) - type.t |= VT_EXPORT; + if (ad.a.func_import || ad.a.func_export) { + if (type.t & (VT_STATIC|VT_TYPEDEF)) + tcc_error("cannot have dll linkage with static or typedef"); + if (ad.a.func_export) + type.t |= VT_EXPORT; + else if ((type.t & VT_BTYPE) != VT_FUNC) + type.t |= VT_IMPORT|VT_EXTERN; + } #endif type.t |= ad.a.visibility << VT_VIS_SHIFT; @@ -7058,10 +7055,6 @@ static int decl0(int l, int is_for_loop_init) && type.ref->a.func_call == FUNC_CDECL) type.ref->a.func_call = ref->a.func_call; - /* use export from prototype */ - if (ref->a.func_export) - type.ref->a.func_export = 1; - /* use static from prototype */ if (sym->type.t & VT_STATIC) type.t = (type.t & ~VT_EXTERN) | VT_STATIC; @@ -7071,6 +7064,9 @@ static int decl0(int l, int is_for_loop_init) if (! (type.t & VT_VIS_MASK)) type.t |= sym->type.t & VT_VIS_MASK; + /* apply other storage attributes from prototype */ + type.t |= sym->type.t & (VT_EXPORT|VT_WEAK); + if (!is_compatible_types(&sym->type, &type)) { func_error1: tcc_error("incompatible types for redefinition of '%s'", @@ -7134,7 +7130,7 @@ static int decl0(int l, int is_for_loop_init) } break; } else { - if (btype.t & VT_TYPEDEF) { + if (type.t & VT_TYPEDEF) { /* save typedefed type */ /* XXX: test storage specifiers ? */ sym = sym_find(v); @@ -7148,7 +7144,6 @@ static int decl0(int l, int is_for_loop_init) sym = sym_push(v, &type, 0, 0); } sym->a = ad.a; - sym->type.t |= VT_TYPEDEF; } else { r = 0; if ((type.t & VT_BTYPE) == VT_FUNC) { @@ -7162,7 +7157,7 @@ static int decl0(int l, int is_for_loop_init) has_init = (tok == '='); if (has_init && (type.t & VT_VLA)) tcc_error("variable length array cannot be initialized"); - if ((btype.t & VT_EXTERN) || ((type.t & VT_BTYPE) == VT_FUNC) || + if ((type.t & VT_EXTERN) || ((type.t & VT_BTYPE) == VT_FUNC) || ((type.t & VT_ARRAY) && (type.t & VT_STATIC) && !has_init && l == VT_CONST && type.ref->c < 0)) { /* external variable or function */ @@ -7171,7 +7166,6 @@ static int decl0(int l, int is_for_loop_init) extern */ sym = external_sym(v, &type, r); sym->asm_label = ad.asm_label; - if (ad.alias_target) { Section tsec; ElfW(Sym) *esym; @@ -7185,7 +7179,6 @@ static int decl0(int l, int is_for_loop_init) put_extern_sym2(sym, &tsec, esym->st_value, esym->st_size, 0); } } else { - type.t |= (btype.t & VT_STATIC); /* Retain "static". */ if (type.t & VT_STATIC) r |= VT_CONST; else diff --git a/tccpe.c b/tccpe.c index 287eb99..2b0ea9a 100644 --- a/tccpe.c +++ b/tccpe.c @@ -396,9 +396,11 @@ static int pe_find_import(TCCState * s1, ElfW(Sym) *sym) char buffer[200]; const char *s, *p; int sym_index = 0, n = 0; + int a, err = 0; do { s = pe_export_name(s1, sym); + a = 0; if (n) { /* second try: */ if (sym->st_other & ST_PE_STDCALL) { @@ -409,19 +411,24 @@ static int pe_find_import(TCCState * s1, ElfW(Sym) *sym) strcpy(buffer, s+1)[p-s-1] = 0; } else if (s[0] != '_') { /* try non-ansi function */ buffer[0] = '_', strcpy(buffer + 1, s); - } else if (0 == memcmp(s, "__imp__", 7)) { /* mingw 2.0 */ - strcpy(buffer, s + 6); - } else if (0 == memcmp(s, "_imp___", 7)) { /* mingw 3.7 */ - strcpy(buffer, s + 6); + } else if (0 == memcmp(s, "__imp_", 6)) { /* mingw 2.0 */ + strcpy(buffer, s + 6), a = 1; + } else if (0 == memcmp(s, "_imp__", 6)) { /* mingw 3.7 */ + strcpy(buffer, s + 6), a = 1; } else { - break; + continue; } s = buffer; } sym_index = find_elf_sym(s1->dynsymtab_section, s); // printf("find (%d) %d %s\n", n, sym_index, s); + if (sym_index + && ELFW(ST_TYPE)(sym->st_info) == STT_OBJECT + && 0 == (sym->st_other & ST_PE_IMPORT) + && 0 == a + ) err = -1, sym_index = 0; } while (0 == sym_index && ++n < 2); - return sym_index; + return n == 2 ? err : sym_index; } /*----------------------------------------------------------------------------*/ @@ -1239,7 +1246,7 @@ static int pe_check_symbols(struct pe_info *pe) int imp_sym = pe_find_import(pe->s1, sym); struct import_symbol *is; - if (0 == imp_sym) + if (imp_sym <= 0) goto not_found; if (type == STT_NOTYPE) { @@ -1313,7 +1320,8 @@ static int pe_check_symbols(struct pe_info *pe) if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK) /* STB_WEAK undefined symbols are accepted */ continue; - tcc_error_noabort("undefined symbol '%s'", name); + tcc_error_noabort("undefined symbol '%s'%s", name, + imp_sym < 0 ? ", missing __declspec(dllimport)?":""); ret = -1; } else if (pe->s1->rdynamic @@ -1470,23 +1478,12 @@ static void pe_print_sections(TCCState *s1, const char *fname) #ifndef TCC_TARGET_ARM ST_FUNC SValue *pe_getimport(SValue *sv, SValue *v2) { - Sym *sym; - ElfW(Sym) *esym; int r2; - if ((sv->r & (VT_VALMASK|VT_SYM)) != (VT_CONST|VT_SYM) || (sv->r2 != VT_CONST)) return sv; - sym = sv->sym; - if ((sym->type.t & (VT_EXTERN|VT_STATIC)) != VT_EXTERN) + if (!(sv->sym->type.t & VT_IMPORT)) return sv; - if (!sym->c) - put_extern_sym(sym, NULL, 0, 0); - esym = &((ElfW(Sym) *)symtab_section->data)[sym->c]; - if (!(esym->st_other & ST_PE_IMPORT)) - return sv; - - // printf("import %04x %04x %04x %s\n", sv->type.t, sym->type.t, sv->r, get_tok_str(sv->sym->v, NULL)); - + // printf("import %04x %04x %04x %s\n", sv->type.t, sv->sym->type.t, sv->r, get_tok_str(sv->sym->v, NULL)); memset(v2, 0, sizeof *v2); v2->type.t = VT_PTR; v2->r = VT_CONST | VT_SYM | VT_LVAL; @@ -1495,14 +1492,12 @@ ST_FUNC SValue *pe_getimport(SValue *sv, SValue *v2) r2 = get_reg(RC_INT); load(r2, v2); v2->r = r2; - if ((uint32_t)sv->c.i) { vpushv(v2); vpushi(sv->c.i); gen_opi('+'); *v2 = *vtop--; } - v2->type.t = sv->type.t; v2->r |= sv->r & VT_LVAL; return v2; diff --git a/win32/examples/dll.c b/win32/examples/dll.c index 4c1d8ce..052a056 100644 --- a/win32/examples/dll.c +++ b/win32/examples/dll.c @@ -4,9 +4,10 @@ // #include -#define DLL_EXPORT __declspec(dllexport) -DLL_EXPORT void HelloWorld (void) +__declspec(dllexport) const char *hello_data = "(not set)"; + +__declspec(dllexport) void hello_func (void) { - MessageBox (0, "Hello World!", "From DLL", MB_ICONINFORMATION); + MessageBox (0, hello_data, "From DLL", MB_ICONINFORMATION); } diff --git a/win32/examples/hello_dll.c b/win32/examples/hello_dll.c index 7adba77..4813c5b 100644 --- a/win32/examples/hello_dll.c +++ b/win32/examples/hello_dll.c @@ -5,15 +5,16 @@ #include -void HelloWorld (void); +void hello_func (void); +__declspec(dllimport) extern const char *hello_data; int WINAPI WinMain( - HINSTANCE hInstance, - HINSTANCE hPrevInstance, - LPSTR lpCmdLine, - int nCmdShow) + HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPSTR lpCmdLine, + int nCmdShow) { - HelloWorld(); - return 0; + hello_data = "Hello World!"; + hello_func(); + return 0; } -