Sziasztok!
Adott egy léptetőmotor vezérlőkártya, driver (ADVMOT.dll), annak az sdk-ja C#-ra és C-re egyaránt.
C-ben dinamikusan töltöm be a dll-t, mert nincs az sdk-ban link library(illetve majd kártya nélkül is működnie kell a programnak), a C# programok is egy köztes dll-en(AdvMotAPI.dll) keresztül dinamikusan töltik be az ADVMOT.dll-t.
.NET reflectorral bele is néztem, pl.:
[DllImport("ADVMOT.dll", EntryPoint="Acm_DevOpen", CallingConvention=CallingConvention.StdCall)]
public static extern uint mAcm_DevOpen(uint DeviceNumber, ref IntPtr DeviceHandle);
[DllImport("ADVMOT.dll", EntryPoint="Acm_AxOpen", CallingConvention=CallingConvention.StdCall)]
public static extern uint mAcm_AxOpen(IntPtr DeviceHandle, ushort PhyAxis, ref IntPtr AxisHandle);[DllImport("ADVMOT.dll", EntryPoint="Acm_AxHome", CallingConvention=CallingConvention.StdCall)]
public static extern uint mAcm_AxHome(IntPtr AxisHandle, uint homeMode, uint DirMode);
A fenti függvényeket C-ben így töltöm be:
typedef U32 (_stdcall * Acm_DevOpen_t)(U32 DeviceNumber, PHAND DeviceHandle);
typedef U32 (_stdcall * Acm_AxOpen_t)(HAND DeviceHandle, U16 PhyAxis, PHAND AxisHandle);
typedef U32 (_stdcall * Acm_AxHome_t)(HAND AxisHandle, U32 HomeMode, U32 DirMode);
Acm_DevOpen_t Acm_DevOpen;
Acm_AxOpen_t Acm_AxOpen;
Acm_AxHome_t Acm_AxHome;Acm_DevOpen = (Acm_DevOpen_t)GetProcAddress(hInstLibrary, "Acm_DevOpen");
Acm_AxOpen = (Acm_AxOpen_t)GetProcAddress(hInstLibrary, "Acm_AxOpen");
Acm_AxHome = (Acm_AxHome_t)GetProcAddress(hInstLibrary,"Acm_AxHome");
A problémám a következő:
A fenti eljárással a hívások működnek C-ben is: relatív motor vezérlés, general purpose IO, stb.
Ami nem akar működni, csak C#-ból, az Acm_AxHome függvény.
Alábbi teljesen egyező C# és C móricka programok közül csak a C# hajlandó működni:
C#:
uint Result;
Result = Motion.mAcm_DevOpen(0x20000000, ref DeviceHandle);
Result = Motion.mAcm_AxOpen(DeviceHandle, (UInt16)0, ref AxisHandle);
Result = Motion.mAcm_AxHome(AxisHandle, 3, 0);
C:
U32 iResult;
iResult = Acm_DevOpen(0x20000000,&devHandle);
iResult = Acm_AxOpen(devHandle,0,&axHandle);
iResult = Acm_AxHome(axHandle,3,0);
Konstansok, visszatérési értékek, minden egyezik. Az Acm_AxHome nem ad hibakódot. Látszólag ugyanaz a két program, mégsem működik, csak C#-ból. Más hívásokkal nincs gond, csak ez az egy hívás rakoncátlankodik.
A C# köztes dll-ben a .NET reflector szerint nincs semmi extra inicializálás (constructor, statikus adattag), csak a függvényeket wrappeli.
Gondoltam arra, hogy a dinamikusan betöltött dll az aktuálisan futó szálról nem értesül a DllMain-ben és esetleg ezért valami inicializáció kimarad, emiatt próbáltam úgy is hogy a betöltés után új szálat indítok, de ez sem segített.
Vajon mire nem gondoltam még? Kifogytam az ötletekből. Adjatok még tippeket. Köszi.
- 5872 megtekintés
Hozzászólások
Most nincs időm végiggondolni a teljes felvetést, de szeritntem nézz utána a HandleRef-nek.
Azt mondják az álmoskönyvek, hogy érdemes használni P/Invoke-hoz.
De valószínűleg ez nem fogja megoldani a problémádat.
Fuszenecker_Róbert
- A hozzászóláshoz be kell jelentkezni
Valóban nem oldja meg, a C# kód működik, az a kérdés a C kód miért nem működik.
update:
Csináltam egy proxy dll-t:
Acm_DevOpen_t ExAcm_DevOpen=0;
Acm_AxOpen_t ExAcm_AxOpen=0;
Acm_AxHome_t ExAcm_AxHome=0;
HINSTANCE hInstLibrary=0;
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
hInstLibrary = LoadLibrary(L"advmot.dll");
if (hInstLibrary)
{
ExAcm_DevOpen = (Acm_DevOpen_t)GetProcAddress(hInstLibrary, "Acm_DevOpen");
ExAcm_AxOpen = (Acm_AxOpen_t)GetProcAddress(hInstLibrary, "Acm_AxOpen");
ExAcm_AxHome = (Acm_AxHome_t)GetProcAddress(hInstLibrary,"Acm_AxHome");
}
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
FreeLibrary(hInstLibrary);
break;
}
return TRUE;
}ADVMOT_FAKE_API U32 _stdcall Acm_DevOpen(U32 DeviceNumber, PHAND DeviceHandle)
{
U32 iResult;
if (ExAcm_DevOpen)
{
iResult=ExAcm_DevOpen(DeviceNumber,DeviceHandle);
}
return iResult;
}...stb.
Ha ezt a proxy dll-t töltöm be az advmot.dll helyett akkor működik C-ből is. De miért???
- A hozzászóláshoz be kell jelentkezni
az nem lehet, hogy egyszerűen bugos a c verziójú DLL ?
- A hozzászóláshoz be kell jelentkezni
Ugyanazt a dll-t hívom C#-ból.
- A hozzászóláshoz be kell jelentkezni
a dll tuti cdecl? (Amit a C fordítók alapnak hisznek)
mert a C# pinvoke felismeri, ha stdcall.
Szerk: sikerült el is olvasnom a kódblokkokat, s látom, hogy stdcall-ozod.
C fordító melyik? MS Visual C++? Azesetben nem _stdcall hanem __stdcall
- A hozzászóláshoz be kell jelentkezni