[C++] Functie uit DLL overschrijven/aanpassen

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • HuHu
  • Registratie: Maart 2005
  • Niet online
Ik gebruik de Approximate Nearest Neighbor Library, welke ik compileer naar een DLL. Deze voeg ik in Visual Studio 2005 toe aan mijn project, zodat ik de functies daarin kan gebruiken.

Eén van de constructors die ik aanroep kan een fout opwerpen, wat prima is. Dan wordt de functie annError aangeroepen, die er zo uit ziet:

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
enum ANNerr {ANNwarn = 0, ANNabort = 1};

//----------------------------------------------------------------------
//  Error handler
//----------------------------------------------------------------------

void annError(const char* msg, ANNerr level)
{
    if (level == ANNabort) {
        cerr << "ANN: ERROR------->" << msg << "<-------------ERROR\n";
        exit(1);
    }
    else {
        cerr << "ANN: WARNING----->" << msg << "<-------------WARNING\n";
    }
}


En daar gaat het mis. Er staat een exit(1) in als het ANNerr level gelijk is aan ANNabort. Dat gebeurd als er een fout optreed in de constructor, waardoor dus mijn volledige programma er mee stopt.

Dat laatste is onwenselijk, ik wil dan gewoon een foutmelding krijgen. Nu kan ik deze functie aanpassen en de DLL opnieuw compileren, want ik heb de beschikking over de broncode. Maar is er ook een andere mogelijkheid, zodat ik mijn code ook kan geven aan mensen die zelf al beschikken over die DLL?

Ik heb dingen gevonden over het overriden van functies in een DLL, maar ik krijg dit niet aan de praat. De compiler gaat dan zeuren dat er een redefinition van annError is.

Heeft iemand tips of suggesties wat ik kan proberen?

Acties:
  • 0 Henk 'm!

  • Emmeau
  • Registratie: Mei 2003
  • Niet online

Emmeau

All your UNIX are belong to us

wrapper om deze dll heenbouwen?

een dll die deze dll aanroept, en de foutafhandeling zelf doet?

If you choose to criticise you choose your enemies


Acties:
  • 0 Henk 'm!

Verwijderd

Emmeau schreef op maandag 08 maart 2010 @ 17:15:
wrapper om deze dll heenbouwen?

een dll die deze dll aanroept, en de foutafhandeling zelf doet?
exit(1) houdt dacht ik redelijk in dat de executable er gewoon mee kapt.

Acties:
  • 0 Henk 'm!

  • leuk_he
  • Registratie: Augustus 2000
  • Laatst online: 15-07 15:35

leuk_he

1. Controleer de kabel!

de source dll aanpassen, kans dat iemand de dll al heeft is klein en kan dan ook nog eens tot versie problmemen leiden. Ook de source van ann dan meeleveren he?

Al die methoden die je noet zijn relatief veel werkt voor wat het opleverd, of hebben debug rechten nodig, iets waar je maar niet op moet standaardiseren.

(en persoonlijk ben ik gewoon voor statisch linken, voorkomt versie probleemen, maar dan moet je geen licentie problmen krijgen)

Need more data. We want your specs. Ik ben ook maar dom. anders: forum, ff reggen, ff topic maken
En als je een oplossing hebt gevonden laat het ook ujb ff in dit topic horen.


Acties:
  • 0 Henk 'm!

Verwijderd

Het is trouwens een vrij heftige manier van fout afhandeling, denk dat de auteurs best openstaan om dit aan te passen. Lijkt me niet dat een library zomaar beslist of een applicatie er in z'n geheel mee moet stoppen of niet.

Acties:
  • 0 Henk 'm!

  • user109731
  • Registratie: Maart 2004
  • Niet online
Een patch naar de mensen achter dit project sturen met een alternatieve aanpak?

Acties:
  • 0 Henk 'm!

  • Osiris
  • Registratie: Januari 2000
  • Niet online
Waarom wordt er overigens sowieso een ANNabort gegenereerd? Misschien moet je dat niet doen? :P

Acties:
  • 0 Henk 'm!

  • MLM
  • Registratie: Juli 2004
  • Laatst online: 12-03-2023

MLM

aka Zolo

mogelijkheden, in volgorde van "netjes"
0) voorkom de fout, doe checking voor je de functie aanroept
1) zelf afvangen (mits je daar een kans toe krijgt voordat de exception afgevangen word door de library)
2) recompilen van de DLL

je kan niet zomaar een functie in een DLL overschrijven, en aangezien de DLL zelf de exception kan afvangen is het onwaarschijnlijk dat je "erbij" kan (het adres van de exception-handler is waarschijnlijk ge-hard-linkt, dan moet je gaan prutsen met memory overschrijven in de binaire code). daarnaast kan (een gedeelte) van de handler inlined zijn, en dan word het helemaal kansloos.

je kan wel functies in een DLL "hooken", maar dan dienen die wel geexporteerd te worden door de DLL (en exceptionhandlers zijn dat waarschijnlijk niet), maar dan riskeer je dat je applicatie gemarkeerd word door virusscanners etc (het is een niet-nette methode, die ook wel word gebruikt door malware om calls af te vangen in een andere applicatie). Mijn advies: begin er niet aan :)

-niks-


Acties:
  • 0 Henk 'm!

  • HuHu
  • Registratie: Maart 2005
  • Niet online
Oké, dan wordt het denk ik toch maar de broncode aanpassen en de wijziging ook doorsturen naar de auteurs van ANN. De source wordt sowieso meegeleverd, inclusief de benodigde project/make files. Dus men kan altijd deze versie van ANN dan opnieuw compileren.
Osiris schreef op maandag 08 maart 2010 @ 17:50:
Waarom wordt er overigens sowieso een ANNabort gegenereerd? Misschien moet je dat niet doen? :P
De constructor van een class in de ANN library kan annError aanroepen met een ANNabort als tweede argument. Daar kan ik niet omheen, tenzij ik die constructor aanpas.

Maar dan pas ik liever de annError functie aan, omdat die op wel meer plaatsen wordt gebruikt. Dan vervang ik die meteen door een nette versie met de juiste exception handling.

Acties:
  • 0 Henk 'm!

  • Osiris
  • Registratie: Januari 2000
  • Niet online
En waarom doet die constructor dat? Vindt 'ie dat leuk ofzo? Voor de gein? :P

Acties:
  • 0 Henk 'm!

  • HuHu
  • Registratie: Maart 2005
  • Niet online
MLM schreef op maandag 08 maart 2010 @ 19:09:
mogelijkheden, in volgorde van "netjes"
0) voorkom de fout, doe checking voor je de functie aanroept
1) zelf afvangen (mits je daar een kans toe krijgt voordat de exception afgevangen word door de library)
2) recompilen van de DLL

je kan niet zomaar een functie in een DLL overschrijven, en aangezien de DLL zelf de exception kan afvangen is het onwaarschijnlijk dat je "erbij" kan (het adres van de exception-handler is waarschijnlijk ge-hard-linkt, dan moet je gaan prutsen met memory overschrijven in de binaire code). daarnaast kan (een gedeelte) van de handler inlined zijn, en dan word het helemaal kansloos.

je kan wel functies in een DLL "hooken", maar dan dienen die wel geexporteerd te worden door de DLL (en exceptionhandlers zijn dat waarschijnlijk niet), maar dan riskeer je dat je applicatie gemarkeerd word door virusscanners etc (het is een niet-nette methode, die ook wel word gebruikt door malware om calls af te vangen in een andere applicatie). Mijn advies: begin er niet aan :)
Ah, dat had ik zelf nog niet eens gezien, de annError functie wordt inderdaad niet geëxporteerd. Andere functies en classes worden dat wel. Dit staat namelijk nog bovenin de broncode:

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#ifdef WIN32
  //----------------------------------------------------------------------
  // For Microsoft Visual C++, externally accessible symbols must be
  // explicitly indicated with DLL_API, which is somewhat like "extern."
  //----------------------------------------------------------------------
  #ifdef DLL_EXPORTS
     #define DLL_API __declspec(dllexport)
  #else
    #define DLL_API __declspec(dllimport)
  #endif
  //----------------------------------------------------------------------
  // DLL_API is ignored for all other systems
  //----------------------------------------------------------------------
#else
  #define DLL_API
#endif


Pak ik vervolgens een willekeurige andere functie erbij, die ik vergelijk met annError:

C++:
1
2
3
DLL_API ANNdist annDist(int dim, ANNpoint p, ANNpoint q);

void annError(const char* msg, ANNerr level);


Overige functies worden dus wel geëxporteerd, maar de exception handler niet. Dan toch maar aanpassen in de broncode dus.

Punt 0) wilde ik niet gaan doen. Er wordt allerlei user-input doorgegeven aan de constructor, die vervolgens de controles doet. Ik heb weinig zin om al die controles op te gaan zoeken (ook op andere plaatsen) en te kopiëren in m'n eigen werk.

Acties:
  • 0 Henk 'm!

  • HuHu
  • Registratie: Maart 2005
  • Niet online
Osiris schreef op maandag 08 maart 2010 @ 19:12:
En waarom doet die constructor dat? Vindt 'ie dat leuk ofzo? Voor de gein? :P
Het gaat om het inlezen van een bestand met een datastructuur daarin. Die klasse kan dan geconstrueerd worden vanuit de data in het bestand. Als de header van het bestand niet klopt, wordt de annError methode aangeroepen.

De constructors (een paar, als voorbeeld):

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class DLL_API ANNkd_tree: public ANNpointSet {
public:
    ANNkd_tree(                         // build skeleton tree
        int             n = 0,          // number of points
        int             dd = 0,         // dimension
        int             bs = 1);        // bucket size

    ANNkd_tree(                         // build from point array
        ANNpointArray   pa,             // point array
        int             n,              // number of points
        int             dd,             // dimension
        int             bs = 1,         // bucket size
        ANNsplitRule    split = ANN_KD_SUGGEST);    // splitting method

    ANNkd_tree(                         // build from dump file
        std::istream&   in);            // input stream for dump file


Je kan een ANNkd_tree maken door allerlei parameters mee te geven, maar je kan ook een bestaande ANNkd_tree inlezen vanuit een bestand (een std::istream, hoeft natuurlijk niet per se een bestand te zijn). Dat is handig, dan hoef je voor een bepaalde ANNpointSet maar 1 keer de ANNkd_tree te genereren en de volgende keer (volgende run, ander proces) is hij direct klaar voor gebruik.

Acties:
  • 0 Henk 'm!

  • Osiris
  • Registratie: Januari 2000
  • Niet online
En het is niet mogelijk om er voor te zorgen dat die constructor de annError() niet of niet met ANNabort aanroept? Nvm, daar had je geen zin in..

[ Voor 13% gewijzigd door Osiris op 08-03-2010 19:35 ]


Acties:
  • 0 Henk 'm!

  • MLM
  • Registratie: Juli 2004
  • Laatst online: 12-03-2023

MLM

aka Zolo

ik zie je de eerste keer melding maken van "opwerpen" en de 2e keer "aanroepen". hebben we het nou over
code:
1
2
try { ...; throw X; } catch { annError(...); } //opwerpen -> throw
...; if(some_fail) { annError(...); } //aanroepen -> functie-call


De eerste kan je eventueel (ook een enorme hack) afvangen door een top-level exception filter te installeren (Win32 specific). De 2e ben je gewoon "dood" als het gebeurt.
Hoe dan ook is het slecht library-design als een library exit() aanroept, beter gooi je een exception of return je een error-code, zodat de client-code kan besluiten wat te doen als er iets fout gaat (exit() kan altijd nog). Het is behoorlijke faal als jouw GUI ineens weg is zonder te saven, omdat een library besloot dat er een fout was...

-niks-


Acties:
  • 0 Henk 'm!

  • HuHu
  • Registratie: Maart 2005
  • Niet online
Ah, het woord opwerpen is onjuist. Het gaat inderdaad om het tweede geval:

C++:
1
if(some_fail) { annError(...); }
Pagina: 1