none
MDB Brücke 32 Bit 64 Bit RRS feed

  • Frage

  • Hallo , das Problem ist schon alt aber fällt mir wieder auf die Füße, wir haben etliche Projekte die Access-MDB's zur Datenspeicherung nutzen, alles MFC VC++ Windows Anwendungen, einige davon würden von einer 64 Bit Umstellung profitieren, da gibt's aber kein DAO MDB Zugriff mehr. Um meine Kollegen zu unterstützen wollte ich jetzt was schreiben was Ihren Aufwand der 64 Bit Umstellung in der Hinsicht minimiert. Es sind ja nur eine Handvoll Funktionen die genutzt werden und nach längeren Recherchen im Netz fand ich die Idee eine "DaoProxies" in 32 Bit geschrieben nicht schlecht. Auf der 64 Bit Seite würde ich eine CDaoDatabase definieren die den Open Call an den Proxy weiterleitet. Ich habe für den Proxy einen simplen  RPC Server geschrieben, zum einfachen Test gibt's da eine CDaoDatabase Objekt das mit einem RPC Call geöffnet wird und mit einem weiteren geschlossen, jetzt merke ich aber das RPC für jeden Call einen neuen Thread aufmacht, ist vielleicht auch logisch aber so kann ich DAO ja auch auf 32 Bit nicht benutzen :-( . Meine Frage ist ob jemand noch einen anderen Vorschlag als RPC für einen DaoProxy hat der eine Brücke zwischen 64 Bit und 32 Bit schlägt?


    Freudi

    Freitag, 8. Juli 2016 13:32

Antworten

  • Hallo

    Eine Komponente ist für ein bestimmtes Threading-Model gebaut. Wenn die Komponente also nur für "Apartment" gebaut ist, dann kann sie nicht im Multi-Threading-Model laufen (CoInitialize mit NULL als Parameter baut ein STA, also Single Threaded Apartment auf, während du mit dem anderen Aufruf ein MTA also Multi Threaded Apartment baust). Ich tippe also drauf, dass die Komponente so nicht läuft und daher nicht instanziert werden kann.

    Übrigens: ein Threading-Model ist pro Thread festgelegt. Du könntest also einen Thread bauen, das als STA initialisieren und dann alle Aufrufe über ihn umlenken. Wobei ich glaube, dass du dann am Ende zwei Nachrichtenschleifen ineinander hättest, da ein STA soweit ich weiss alles per Nachrichtenschleife synchronisiert.

    Ah richtig... :-) da gibt's ja noch was von Microsoft dazu: https://msdn.microsoft.com/en-us/library/ms678517(VS.85).aspx ... du musst die Schnittstelle von STA nach MTA marshallen lassen. Der baut dann einen Proxy, damit der MTA-Teil das STA-Teil nutzen kann. Das wär dann der korrekte Weg es zu tun.

    Rudolf


    Freitag, 15. Juli 2016 16:57

Alle Antworten

  • Hallo

    Von 64 nach 32 bit kommst du relativ einfach mit COM. Da kannst du aus einem 64 bit Programm 32 bit Komponenten aufrufen. Diese müssen nur in einem anderen Prozess laufen (CLSCTX_LOCAL_SERVER). Natürlich muss dazu die Schnittstelle fähig sein. Aber wenn du Glück hast, kannst du sogar die bestehenden Teile direkt so ansteuern. Sonst müsstest du halt 'n Wrapper drum bauen. Andere RPC Techniken gingen auch... wobei mir im Moment gerade keine einfache einfällt, die öffentlich verfügbar wäre.

    Rudolf

    Freitag, 8. Juli 2016 18:26
  • Hallo Rudolf

    Wenn das so ist warum kann man nicht die MFC Sourcen von DAO einfach mal auf 64 Bit kompilieren, ich denke das JET was die ansprechen wird auch ein COM Modul sein, müsste man mal schauen ob man das hinbekommt das als CLSTX_LOCAL_SERVER anzusprechen, ich staune nur das niemand auf die Idee gekommen sein soll, alle ärgern sich nur das sie mit 64 Bit keine MDB's mehr aufmachen können.

    Freudi


    Freudi

    Freitag, 8. Juli 2016 19:17
  • Hallo

    Das ist die erste gute Frage und die zweite wäre: *.accdb kann ich mit dem 64bit OLEDB Treiber von der Access Runtime öffnen. Und angeblich unterstützt diese auch *.mdb ... daher frag ich mich gerade, ob das nicht einfach damit geöffnet werden könnte? Also einfach statt den JET, Access nutzen.

    Hier die zwei GUIDS, einmal die vom JET und einmal die von Access, die ich jeweils nutze (bzw. genutzt habe... ich verwende so gut wie kein SQL mehr).

    const CLSID_DB_CLSID_MSACCESS = {0x3be786a0L, 0x0366, 0x4f5c, {0x94, 0x34, 0x25, 0xcf, 0x16, 0x2e, 0x47, 0x5e}};

    const CLSID_DB_CLSID_MSJETDB = {0xdee35070L, 0x506b, 0x11cf, {0xb1, 0xaa, 0x00, 0xaa, 0x00, 0xb8, 0xde, 0x95}};

    Ausprobiert habe ich es nicht... könnte ich aber mal tun. :-) ... vielleicht am Wochenende, wenn nicht wieder unvorhergesehenes dazwischen kommt.

    Rudolf

    Freitag, 8. Juli 2016 21:06
  • Hallo Freudi,

    Jet / DAO gibt es nur als 32-Bit Komponente. Erst für Office/Access 2010 hat man eine 64-Bit Version entwickelt. Die geht aber nicht mehr als DAO durch sondern als Access Runtime durch, die es auch je Office Version separat als Download gibt

    Dabei ist das größte Problem, dass nur die passende zur Office Version installiert sein darf, parallel 32 / 64 Bit geht nicht ;( Siehe Choose the 64-bit or 32-bit version of Office 2016 (entsprechend auch für 2010/2013).

    Vom Design kann man .NET nachahmen, das einen Connection Pool verwendet, um Verbindungen länger vorzuhalten - was einen Vorteil bringen kann, da u. U. das Öffnen einer MDB (+ .LDB) länger dauern kann als die ganze Abfrage.

    Gruß Elmar

    Samstag, 9. Juli 2016 07:24
  • Hallo Rudolf,

    zum einen installieren viele 32 Bit auf Windows 64 Bit, Gründe siehe Artikel (oder alte Gewohnheit ;).

    Zum anderen sind solche "Workarounds" immer problematisch, denn beim nächsten Update/Reparatur korrigiert Office solche Dinge gerne hinten rum (was es darf, da gemischte Installation nicht unterstützt werden).

    Was genervte Anrufe beim Help Desk produziert...

    Gruß Elmar

    Samstag, 9. Juli 2016 09:28
  • Genau das kann ich bestätigen, es läuft immer solange bis man einmal WORD o.ä. startet dann geht's wieder nicht mehr, wobei ich den Registry Trick von Rudolf noch nicht ausprobiert habe. Mit diesem Accesstreiber kann man dann mit ODBC arbeiten aber DAO meldet weiterhin

    fatal error C1189: #error :  DAO Database classes are not supported for Win64 platforms

    D.h. auch für den Accesstreiber müsste ich etwas schreiben was die ODBC Dataclassen auf CDaoDatabase mappt.

    Wenn das JET Modul aber nun ein COM Modul ist, vielleicht muss man in DAO/MFC Klassen nur etwas patchen so das die JET Engine als CLSTX_LOCAL_SERVER  ausgeführt wird, dann könnte ich mir sparen selber ein COM Server zu schreiben.


    Freudi

    Samstag, 9. Juli 2016 11:58
  • Zum anderen sind solche "Workarounds" immer problematisch, denn beim nächsten Update/Reparatur ...

    Ja, das ist mir klar. Im Grunde ist das mit allen Produkten so, die man "einkauft". Plöztlich heisst es "wir haben beschlossen, dass wir jetzt allen den Teppich unter den Füssen wegziehen... ihr könnt nun selber schauen wo ihr bleibt, das Produkt wird eingestampft" (oder so ähnlich) ... deshalb verwende ich weder Access, noch SQL. Bei vielen Programmen, welche eine "Datenbank" benötigen habe ich gemerkt, dass die Daten oft nur 0-5 MB gross sind. Da lade ich den Mist einfach vollständig ins Memory und schreib das Zeug ab und zu wieder runter. Das ist nicht weniger effizient und oft viel einfacher zu bauen. Und für grössere Sachen... ja gut, das kann nicht jeder... da haben wir in der Firma unseren eigenen DB-Server geschrieben :-) ... aber bei kleinerem bin ich ziemlich gut gefahren mit der Strategie. Genau wegen Access-Zeug hab ich damit angefangen... das war so nervig. Und am Ende war's ja dann immer "meine" bzw. "unsere" Software, die schlecht ankam beim Kunden.

    Rudolf

    Samstag, 9. Juli 2016 13:25
  • Hallo Rudolf,

    wenn man nur ein Datenkrümel hat, gehts auch ohne SQL Datenbank.

    Aber es gibt massig Anwendungen die ein wenig bis sehr viel mehr brauchen.

    Für kleinere Anwendungen bleibt Access, wenn auch von Microsoft in den letzten nicht anständig weiterentwickelt, eine Lösung. Und wird es größer gibt es wenig Alternativen[1] zu einem SQL Server (nicht unbedingt Microsoft).

    Als ehedem Access wie SQL Server MVP mag ich aber etwas vorbelastet sein ;)

    Gruß Elmar

    [1] außer vielleicht NoSQL Datenbanken, wenns passt.

    Samstag, 9. Juli 2016 14:08
  • Bei den neueren Projekten nehmen wir immer SQLite. Da kann man mittels :MEMORY: auch Datenbanken im Speicher bauen und später abspeichern oder auch in den Speicher laden, das hat mir einem Projekt sehr geholfen wo viele kleine Kataloge existierten, das geht jetzt enorm schnell.

    Das Problem ist das wir größere, lange gewachsene Projekte mit Access haben, wo beim Kunden weitere Prozesse dort Access erwarten, da haben wir also mal die falsche Entscheidung getroffen. Jetzt ist es bei einigen Projekten dort angezeigt auf 64 Bit zu wechseln, mir bleibt also nichts anders übrig als Lösung zu finden. :-(


    Freudi

    Samstag, 9. Juli 2016 14:48
  • Ja, das Problem ist von der blöderen Sorte ... kenne ich. Umbauen ist manchmal keine Option ... obwohl man's prüfen muss. Aber in dem Fall ist wohl die Idee mit dem MFC-Klassen-Umbau oder halt eine weitere COM-Wrapper-Zwischenschicht die beste oder einzige Lösung.

    Aber noch schnell was zum "Access erwarten" ... ich hatte das bei einem Projekt so gelöst, dass ich alles auf eine neue Lösung (in dem Fall war's ein SQL-Server Express) umgebaut und die Daten konvertiert hatte und den Zugriff dann für die alten Programme über eine neue MDB/ACCDB mit "externen Daten" eingerichtet hatte. Irgendwie kann man ja im Access externe DBs wie interne Tabellen verlinken.... wobei, das ist schon sehr lange her. So im Detail kenne ich das nicht mehr.

    Rudolf

    Samstag, 9. Juli 2016 15:35
  • Ich halte Euch mal auf den Laufenden ... Ich habe mir die 3 Dao Sourcen aus der MFC Source geholt und in mein 64 Bit Programm eingebunden, das kann man übersetzen, dann kommt er zu der Stelle wo er via COM die Jet Engine startet, da muss dann erst mal der passende "Jet-COM-Key" für 64 Bit auch angelegt werden damizt er die JET Engine findet, aber es klappt auf diesem Weg dann trotzdem nicht weil die JET Engine wohl nur als InProc Server vorliegt und damit der 32-64 Bit Konflikt vorliegt. Oder gibt's die JET Engine auch irgendwo als EXE ?

    Freudi

    Dienstag, 12. Juli 2016 09:20
  • Nein, du brauchst eine EXE dazu. Aber da gibt's eine Standard-Exe im Windows drin für sowas... soweit ich weiss. Benutzt habe ich das so aber noch nie... http://thrysoee.dk/InsideCOM+/ch12b.htm

    Rudolf

    Dienstag, 12. Juli 2016 11:23
  • Ach :-) Coole Sache , das versuche ich heute Abend mal, damit soll man jeden InProc Server zu einem CLSTX_LOCAL_SERVER  machen können.

    Freudi

    Dienstag, 12. Juli 2016 14:15
  • Das hat geklappt man kann die JET Engine damit aus 64 Bit heraus ansprechen. Allerdings scheint die Surrogate EXE  (DllHost.exe) wohl nur UNICODE zu können, jedenfalls geht alles Bestens wenn ich mein 64 Bit Programm als UNICODE übersetze aber die meisten alte Programme die wir haben sind nicht UNICODE. Hat jemandvielleicht nich en Tipp ob es DllHost.exe auch als nicht UNICODE oder Source irgendwo gibt ?

    Freudi

    Mittwoch, 13. Juli 2016 07:35
  • Was gibt's denn da für Probleme? Bei den Funktionsaufrufen kann ich mir das nicht vorstellen, weil das ja BSTR sind (und die sind immer unicode gewesen) ... oder ... lief das echt per ANSI-Strings?

    Rudolf

    Mittwoch, 13. Juli 2016 08:40
  • Gleich am Anfang nach dem das COM Object also die DAO-Engine geladen wurde bei CreateInstanceLic, aber da bin ich dran ...

    Freudi

    Mittwoch, 13. Juli 2016 08:44
  • Hmm also diese beiden Zeilen (siehe Code) starten die Engine. Die letzte Zeile. geht schief wenn ich nicht UNICODE bin.

    Diese Notation mit L war schon von mir weil ich dachte da muss UNICODE stehen. Im Original steht da V_BSTR(&varkey)

    COleVariant varKey = _T("mbmabptebkjcdlgtjmskjwtsdhjbmkmwtrak");
    LPCLASSFACTORY2 pCF2;
    DAO_CHECK_ERROR(::CoGetClassObject(CLSID_CDAODBEngine,CLSCTX_LOCAL_SERVER, NULL, IID_IClassFactory2, (LPVOID*)&pCF2),AFX_DAO_ERROR_ENGINE_INITIALIZATION);
    DAO_CHECK_ERROR(pCF2->CreateInstanceLic(NULL, NULL, guidEngine, L"mbmabptebkjcdlgtjmskjwtsdhjbmkmwtrak", (LPVOID*)&pDaoState->m_pDAODBEngine), AFX_DAO_ERROR_ENGINE_INITIALIZATION);
    Aber auch so wie es jetzt da steht funktioniert es wenn ich UNICODE definieren, aber der DAOCHECK wirft ein Error wenn es nicht UNICODE ist.


    Freudi

    Mittwoch, 13. Juli 2016 09:25
  • *hmm* ... nun, also ein BSTR müsste es schon sein. Weil das wird ja verlangt. Bei nur L".." fehlt dir im Speicher die Länge vom String (steht vorne am String). Ich würde auch kein COleVariant machen, sondern direkt ein BSTR mit SysAllocString (später löschen mit SysFreeString) ... was passiert dann?

    Rudolf

    Mittwoch, 13. Juli 2016 09:34
  • Ach vergiss es , es gibt eine UNICODE und eine Nicht-UNICODE Jet Engine mit 2 verschiedenen CLSID, der Fehle rlag woanders.

    Freudi

    Mittwoch, 13. Juli 2016 09:43
  • Das heisst, das funktioniert jetzt? ... kannst du mal die genauen Schritte noch posten oder Registry-Sachen, die du gemacht hast? ... man weiss ja nie... plötzlich brauch ich das auch noch :-) ... wär echt super.

    Mittwoch, 13. Juli 2016 14:19
  • Ja mache ich die genauen Schritte kommen später nochmal, es ist auch noch das Stadium das ich probiere und nicht genau weiß was jetzt wirklich nötig war und was überflüssig.

    Im groben ...

    mit regsrv32 (in system32 !!! wegen 64 Bit) dao360.dll registrieren.

    3 DAO Src/Incl aus den MFC Quellen ins Projekt holen

    in den DAO Quellen dafür sorgen das auch bei 64 Bit alles übersetzt wird.

    Den Aufruf der JET Engine auf Out Procserver umstellen

    Mit OleView.exe den DllHost.exe als surrogate einstellen.

    Im Moment geht's aber nur für die UNICODE CLSID, die Interface dbEngine hat 2 CLSID's eine für Unicode, eine für nicht UNICODE. Nur die UNICODE funktioniert wobei seltsamerweise die CLSID für Nichtunicode in der ganzen Registry gar nicht zu finden, aber an dem Thema bin ich gerade dran , hab da ein altes Buch mit einem Beispiel DllNanny das ist ein Custom Surrogate, damit schaffe ich das morgen bestimmt, heute ist keine Zeit mehr.


    Freudi

    Mittwoch, 13. Juli 2016 16:32
  • Mit dem Unicode habe ich ein seltsames Problem, die CLSID für die Nicht Unicode Version ist

    {00000020-0000-0010-8000-00AA006D2EA4}

    die ist in der ganzen Registry nicht zu finden. Initialisiere ich die COM Lib mit CoInitialize(NULL) findet er aber das Interface. Initialisiere ich aber mit CoInitializeEx(NULL, COINIT_MULTITHREADED) wie ich es in einem Surrogate Host auch machen muss dann findet er das Interface nicht.

    Hat da jemand vielleicht einen Tipp?


    Freudi

    Freitag, 15. Juli 2016 14:37
  • Hallo

    Eine Komponente ist für ein bestimmtes Threading-Model gebaut. Wenn die Komponente also nur für "Apartment" gebaut ist, dann kann sie nicht im Multi-Threading-Model laufen (CoInitialize mit NULL als Parameter baut ein STA, also Single Threaded Apartment auf, während du mit dem anderen Aufruf ein MTA also Multi Threaded Apartment baust). Ich tippe also drauf, dass die Komponente so nicht läuft und daher nicht instanziert werden kann.

    Übrigens: ein Threading-Model ist pro Thread festgelegt. Du könntest also einen Thread bauen, das als STA initialisieren und dann alle Aufrufe über ihn umlenken. Wobei ich glaube, dass du dann am Ende zwei Nachrichtenschleifen ineinander hättest, da ein STA soweit ich weiss alles per Nachrichtenschleife synchronisiert.

    Ah richtig... :-) da gibt's ja noch was von Microsoft dazu: https://msdn.microsoft.com/en-us/library/ms678517(VS.85).aspx ... du musst die Schnittstelle von STA nach MTA marshallen lassen. Der baut dann einen Proxy, damit der MTA-Teil das STA-Teil nutzen kann. Das wär dann der korrekte Weg es zu tun.

    Rudolf


    Freitag, 15. Juli 2016 16:57
  • Danke für die fundierte Auskunft, manches wusste ich, manches habe ich nur geahnt, aber es kam mir halt komisch vor, wir reden immerhin von nur genau einer dao360.dll und innerhalb der gibt es für Unicode ein MTA Interface und für nicht UNICODE ein STA, das hat aber wahrscheinlich gar nichts mit Unicode zu tun sondern das eine Interface ist wahrscheinlich viel früher entstanden als das andere und dann haben sie beides in eine DLL gepackt.

    Freudi

    Samstag, 16. Juli 2016 08:59
  • Auf einer frischen Maschine habe ich gerade gemerkt das das mit dem regsrv32 nicht  klappt, die 64 Bit Version ruft automatisch die 32 Bit Version von regserv32 auf :-( Also hier noch mal die Registry Einträge die nötig sind.

    Natürlich muss da der richtige Pfad der Surrogate rein, den Quelltext kann jeder haben, einfach Nachricht an mich oder hier im Forum.

    Windows Registry Editor Version 5.00
    
    [HKEY_CLASSES_ROOT\AppID\{00000100-0000-0010-8000-00AA006D2EA4}]
    @=hex(2):44,00,41,00,4f,00,2e,00,44,00,42,00,45,00,6e,00,67,00,69,00,6e,00,65,\
      00,2e,00,33,00,36,00,00,00
    "DllSurrogate"="E:\\Development\\MSVC12\\dllnanny\\Debug\\dllnanny.exe"
    
    [HKEY_CLASSES_ROOT\Wow6432Node\AppID\{00000100-0000-0010-8000-00AA006D2EA4}]
    @=hex(2):44,00,41,00,4f,00,2e,00,44,00,42,00,45,00,6e,00,67,00,69,00,6e,00,65,\
      00,2e,00,33,00,36,00,00,00
    "DllSurrogate"="E:\\Development\\MSVC12\\dllnanny\\Debug\\dllnanny.exe"
    
    [HKEY_LOCAL_MACHINE\SOFTWARE\Classes\AppID\{00000100-0000-0010-8000-00AA006D2EA4}]
    @=hex(2):44,00,41,00,4f,00,2e,00,44,00,42,00,45,00,6e,00,67,00,69,00,6e,00,65,\
      00,2e,00,33,00,36,00,00,00
    "DllSurrogate"="E:\\Development\\MSVC12\\dllnanny\\Debug\\dllnanny.exe"
    
    [HKEY_LOCAL_MACHINE\SOFTWARE\Classes\WOW6432Node\AppID\{00000100-0000-0010-8000-00AA006D2EA4}]
    @=hex(2):44,00,41,00,4f,00,2e,00,44,00,42,00,45,00,6e,00,67,00,69,00,6e,00,65,\
      00,2e,00,33,00,36,00,00,00
    "DllSurrogate"="E:\\Development\\MSVC12\\dllnanny\\Debug\\dllnanny.exe"
    
    [HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Classes\AppID\{00000100-0000-0010-8000-00AA006D2EA4}]
    @=hex(2):44,00,41,00,4f,00,2e,00,44,00,42,00,45,00,6e,00,67,00,69,00,6e,00,65,\
      00,2e,00,33,00,36,00,00,00
    "DllSurrogate"="E:\\Development\\MSVC12\\dllnanny\\Debug\\dllnanny.exe"
    


    Freudi

    Dienstag, 19. Juli 2016 07:58