【问题标题】:Implementing NEW service provide (SP) with CEN-XFS compliance实施符合 CEN-XFS 的新服务提供 (SP)
【发布时间】:2014-11-20 12:28:41
【问题描述】:

我们正在尝试开发符合 CEN XFS 规范的 windows 应用程序 + 设备驱动程序。此外,NOOB 到 WINDOWS 应用程序。

http://en.wikipedia.org/wiki/CEN/XFS

简单的架构流程:

   Windows Application
           |
  _____________________
 |      XFS APIs         |
    (CEN/XFS SDK DLL)
 |                       |
 |      XFS SPIs         |
 |_____________________|---XFS Manager   
           |
           |
    Service providers (SP)
    (DEVICE DRIVER)

为了了解 SP 的功能,我们最近采用了设备供应商之一 SP 的 DLL 来访问他们的设备,并且我们能够使用我们的 Windows 应用程序(基于 Eclipse MINGW)成功地与他们的设备通信。

然后我们开始在互联网上检查一些示例 SP 源来尝试我们的实现。 (https://drive.google.com/file/d/0B60pejPe6yiSejRGQ3JnLUl4dzA/view)

通过链接源,我们能够编译并创建输出 DLL。但是,当我们尝试访问 SP 时,它总是返回错误。

With windows sample application, we just tried to open the device with call (WFSOPEN) which always returned (-15 WFS_ERR_INTERNAL_ERROR ) or (-29 WFS_ERR_INVALID_SERVPROV)

试用流程 1:

    Application Call to manager:

        hResult = WFSOpen(    "QuantumT",    hApp,lpszAppID,    dwTraceLevel,dwTimeOut,    VER_SPI_REQUIRE,&SrvcVersion,&SPIVersion,&hService);    

    manager translates WFSOPEN call to SP's WFPOPEN call:

        HRESULT WINAPI  WFPOpen(HSERVICE hService, LPSTR lpszLogicalName, HAPP hApp, LPSTR lpszAppID, DWORD dwTraceLevel, DWORD dwTimeOut, HWND hWnd, 
            REQUESTID ReqID, HPROVIDER hProvider, DWORD dwSPIVersionsRequired, LPWFSVERSION lpSPIVersion, DWORD dwSrvcVersionsRequired, LPWFSVERSION lpSrvcVersion)

    With above call flow I get (-29 WFS_ERR_INVALID_SERVPROV) as an error for my application

Trial FLow 2(刚刚移除了SP中WFPOPEN的WINAPI接口):

    Application Call to manager:
        hResult = WFSOpen(    "QuantumT",    hApp,lpszAppID,    dwTraceLevel,dwTimeOut,    VER_SPI_REQUIRE,&SrvcVersion,&SPIVersion,&hService);    

    manager translates WFSOPEN call to SP's WFPOPEN call:
        HRESULT  WFPOpen(HSERVICE hService, LPSTR lpszLogicalName, HAPP hApp, LPSTR lpszAppID, DWORD dwTraceLevel, DWORD dwTimeOut, HWND hWnd, 
            REQUESTID ReqID, HPROVIDER hProvider, DWORD dwSPIVersionsRequired, LPWFSVERSION lpSPIVersion, DWORD dwSrvcVersionsRequired, LPWFSVERSION lpSrvcVersion)

With above call flow I get (-15 WFS_ERR_INTERNAL_ERROR ) as an error for my application from manger even though i force SUCCESS as return from SP to manager 

如果从 WFPOPEN 中删除 WINAPI 定义,为什么 MANAGER 会向应用程序返回不同的错误代码。

WINDOWS 应用程序示例链接: https://drive.google.com/open?id=0B60pejPe6yiSUEp1N2xzdGlXWFE&authuser=0

SP 源代码(VS C++ 2010 Express): https://drive.google.com/file/d/0B60pejPe6yiSejRGQ3JnLUl4dzA/view)

XFSMANAGER 安装程序: ftp://ftp.cencenelec.eu/CEN/WhatWeDo/Fields/ICT/eBusiness/WS/XFS/CWA15748/XFS310SDKInstall.zip

但是,当我在工作 DLL 和我创建的 DLL 之间进行调查时(使用 PE Studio)。我看到了一些差异。 我创建的DLL:

_WFPCancelAsyncRequest@8,-,1,-,-,.rdata:0x00001096
_WFPClose@12,-,2,-,-,.rdata:0x00001005
_WFPDeregister@20,-,3,-,-,.rdata:0x00001140
_WFPExecute@24,-,4,-,-,.rdata:0x00001131
_WFPGetInfo@24,-,5,-,-,.rdata:0x000010EB
_WFPLock@16,-,6,-,-,.rdata:0x00001023
_WFPOpen@52,-,7,-,-,.rdata:0x0000102D
_WFPRegister@20,-,8,-,-,.rdata:0x00001073
_WFPSetTraceLevel@8,-,9,-,-,.rdata:0x0000113B
_WFPUnloadService@0,-,10,-,-,.rdata:0x0000100A
_WFPUnlock@12,-,11,-,-,.rdata:0x00001082

供应商创建的 DLL:

WFPCancelAsyncRequest,-,1,-,-,.rdata:0x0000C450
WFPClose,-,2,-,-,.rdata:0x0000C6E0
WFPDeregister,-,3,-,-,.rdata:0x0000C7F0
WFPExecute,-,4,-,-,.rdata:0x0000C970
WFPGetInfo,-,5,-,-,.rdata:0x0000DFA0
WFPLock,-,6,-,-,.rdata:0x0000E490
WFPOpen,-,7,-,-,.rdata:0x0000C030
WFPRegister,-,8,-,-,.rdata:0x0000E590
WFPSetTraceLevel,-,9,-,-,.rdata:0x0000E710
WFPUnloadService,-,10,-,-,.rdata:0x0000E770
WFPUnlock,-,11,-,-,.rdata:0x0000E8F0

即使我确保在我的标题中添加了 Extern。

#ifdef __cplusplus
extern "C" {
#endif
SPITEST_API HRESULT  WINAPI WFPCancelAsyncRequest(HSERVICE hService, REQUESTID RequestID);
SPITEST_API HRESULT  WINAPI WFPClose(HSERVICE hService, HWND hWnd, REQUESTID ReqID);
SPITEST_API HRESULT  WINAPI WFPDeregister(HSERVICE hService, DWORD dwEventClass, HWND hWndReg, HWND hWnd, REQUESTID ReqID);
SPITEST_API HRESULT  WINAPI WFPExecute(HSERVICE hService, DWORD dwCommand, LPVOID lpCmdData, DWORD dwTimeOut, HWND hWnd, REQUESTID ReqID);
SPITEST_API HRESULT  WINAPI WFPGetInfo(HSERVICE hService, DWORD dwCategory, LPVOID lpQueryDetails, DWORD dwTimeOut, HWND hWnd, REQUESTID ReqID);
SPITEST_API HRESULT  WINAPI WFPLock(HSERVICE hService, DWORD dwTimeOut, HWND hWnd, REQUESTID ReqID);
SPITEST_API HRESULT  WINAPI WFPOpen(HSERVICE hService, LPSTR lpszLogicalName, HAPP hApp, LPSTR lpszAppID, DWORD dwTraceLevel, DWORD dwTimeOut, HWND hWnd, REQUESTID ReqID, HPROVIDER hProvider, DWORD dwSPIVersionsRequired, LPWFSVERSION lpSPIVersion, DWORD dwSrvcVersionsRequired, LPWFSVERSION lpSrvcVersion);
SPITEST_API HRESULT  WINAPI WFPRegister(HSERVICE hService,  DWORD dwEventClass, HWND hWndReg, HWND hWnd, REQUESTID ReqID);
SPITEST_API HRESULT  WINAPI WFPSetTraceLevel(HSERVICE hService, DWORD dwTraceLevel);
SPITEST_API HRESULT  WINAPI WFPUnloadService();
SPITEST_API HRESULT  WINAPI WFPUnlock(HSERVICE hService, HWND hWnd, REQUESTID ReqID);
#ifdef __cplusplus
};
#endif

更新1:

根据 Voltage 提供的指针验证了我的代码,我没有在代码流中发现任何错误。

应用代码:

#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <stdlib.h>
#include <windows.h>
#include "XFSAPI.H"

const char g_szClassName[] = "myWindowClass";

DWORD   dwThreadID;
HANDLE  hThread;
HANDLE  hEvent[2];
HWND hwnd;
#define VER_SPI_REQUIRE     0x0B020003
#define VER_XFS_REQUIRE     0x0B020003

HSERVICE        hService;


HRESULT SessionOpen(void)
{
    WFSVERSION      WFSVersion;
    DWORD           dwVersionRequired;
    HRESULT         hResult;
    HAPP            hApp=0;
    LPSTR           lpszAppID;
    DWORD           dwTraceLevel = 0;
    WFSVERSION      SrvcVersion,SPIVersion;


    hApp = WFS_DEFAULT_HAPP;
    lpszAppID = (LPSTR)"XFSTEST";

    dwVersionRequired = VER_XFS_REQUIRE;
    hResult = WFSStartUp(dwVersionRequired, &WFSVersion);

    printf("\nStart up result = %ld \n",hResult);
    printf("\n wVersion: %d \n LowVersion: %d \n wHighVersion: %d \n szDescription: %s \n szSystemStatus: %s \n",WFSVersion.wVersion,WFSVersion.wLowVersion,WFSVersion.wHighVersion,WFSVersion.szDescription,WFSVersion.szSystemStatus);
    if(hResult != WFS_SUCCESS)
    {
        return hResult;
    }

    hResult = WFSOpen(  "QuantumT",
            hApp,
            lpszAppID,
            dwTraceLevel,
            WFS_INDEFINITE_WAIT,
            VER_SPI_REQUIRE,
            &SrvcVersion,
            &SPIVersion,
            &hService);

    if(hResult == WFS_SUCCESS)
    {
        printf("SrvcVersion Records: \n wVersion: %d \n LowVersion: %d \n wHighVersion: %d \n szDescription: %s \n szSystemStatus: %s \n",SrvcVersion.wVersion,SrvcVersion.wLowVersion,SrvcVersion.wHighVersion,SrvcVersion.szDescription,SrvcVersion.szSystemStatus);
    }
    printf("SrvcVersion Records: \n wVersion: %d \n LowVersion: %d \n wHighVersion: %d \n szDescription: %s \n szSystemStatus: %s \n",SrvcVersion.wVersion,SrvcVersion.wLowVersion,SrvcVersion.wHighVersion,SrvcVersion.szDescription,SrvcVersion.szSystemStatus);
    printf("SPIVersion Records: \n wVersion: %d \n LowVersion: %d \n wHighVersion: %d \n szDescription: %s \n szSystemStatus: %s \n",SPIVersion.wVersion,SPIVersion.wLowVersion,SPIVersion.wHighVersion,SPIVersion.szDescription,SPIVersion.szSystemStatus);
    printf("\nHService Address ; %ld",hService);
    Sleep(1000);

    return hResult;
}



LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
        LPWFSRESULT             lpwfsResult;

        switch ( msg )
        {

            case WFS_SERVICE_EVENT:
            case WFS_USER_EVENT:
            case WFS_SYSTEM_EVENT:
            case WFS_EXECUTE_EVENT:

                lpwfsResult = (LPWFSRESULT) lParam;
                printf("\nEvent Received from XFS" );
                WFSFreeResult(lpwfsResult);
            break;

            default:
                return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow)
{

    HRESULT hResult = 0;
    WNDCLASSEX wc;

    wc.cbSize        = sizeof(WNDCLASSEX);
    wc.style         = 0;
    wc.lpfnWndProc   = WndProc;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = hInstance;
    wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
    wc.lpszMenuName  = NULL;
    wc.lpszClassName = g_szClassName;
    wc.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);

    if(!RegisterClassEx(&wc))
    {
        MessageBox(NULL, "Window Registration Failed!", "Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    hwnd = CreateWindowEx(
        WS_EX_CLIENTEDGE,
        g_szClassName,
        "The title of my window",
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, 240, 120,
        NULL, NULL, hInstance, NULL);

    if(hwnd == NULL)
    {
        MessageBox(NULL, "Window Creation Failed!", "Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    printf("\nSession Open In progress");


    hResult = SessionOpen();
    printf("\nSessionOpen result = %d",hResult);
    getch();
    return 0;
}

SP 的 WFPOpen 调用:

HRESULT WFPOpen(HSERVICE hService, LPSTR lpszLogicalName, HAPP hApp, LPSTR lpszAppID, DWORD dwTraceLevel, DWORD dwTimeOut, HWND hWnd, REQUESTID ReqID, HPROVIDER hProvider, DWORD dwSPIVersionsRequired, LPWFSVERSION lpSPIVersion, DWORD dwSrvcVersionsRequired, LPWFSVERSION lpSrvcVersion)
{
        WFSRESULT * lpWFSResult;
        HRESULT  result;

        SYSTEMTIME   st;
        HRESULT  rt;

        GetSystemTime(&st);
        OutputDebugString("INTO  WFPOpen");

        printf("\nmsxfs DLL load\n");
        char strManager[MAX_PATH];
        if(0==RegGetManagerPath(strManager, sizeof(strManager))){
            if(0==GetSystemDirectoryA(strManager, sizeof(strManager)))
              return WFS_ERR_INTERNAL_ERROR;
            strcat_s(strManager, "\\msxfs.dll");
          }
          if(0!=LoadManagerFunction(strManager))
            return WFS_ERR_INTERNAL_ERROR;
          printf("\nmsxfs DLL load completed\n");
        result = m_pfnWFMAllocateBuffer(sizeof(WFSRESULT), WFS_MEM_ZEROINIT, (void**)&lpWFSResult);
        //result = WFMAllocateBuffer(sizeof(WFSRESULT), WFS_MEM_SHARE|WFS_MEM_ZEROINIT, &lpWFSResult);
        if(result!=WFS_SUCCESS)
            return WFS_ERR_INTERNAL_ERROR;
        printf("\nWFPOpen Process start\n");
        if(!g_hMutex ||!g_hLib ||!g_hMsgQueueEvent) return WFS_ERR_INTERNAL_ERROR;
        if(IsCancel(ReqID)) return WFS_ERR_CANCELED;
        CAutoLock AutoLock(g_hMutex);

      if(g_hDefThread){
            InterlockedIncrement(&g_lDefThreadRef);
            return WFS_SUCCESS;
        }else{
        bQuit=FALSE;
            g_hDefThread=BEGINTHREADEX(NULL, 0, DefThread, NULL, 0, &g_dwDefThreadId);
        if(!g_hDefThread ||g_dwDefThreadId==0)
          return WFS_ERR_CANCELED;
            InterlockedIncrement(&g_lDefThreadRef);
        }


        lpSPIVersion->wVersion=(unsigned short) dwCombineVersion(LOW_APIVERSUPPORT,HIGH_APIVERSUPPORT);
        lpSPIVersion->wLowVersion=wFloattoVersion(LOW_APIVERSUPPORT);
        lpSPIVersion->wHighVersion=wFloattoVersion(HIGH_APIVERSUPPORT);


        lpSrvcVersion->wVersion=(unsigned short ) dwCombineVersion(LOW_APIVERSUPPORT,HIGH_APIVERSUPPORT);
        lpSrvcVersion->wLowVersion=wFloattoVersion(LOW_APIVERSUPPORT);
        lpSrvcVersion->wHighVersion=wFloattoVersion(HIGH_APIVERSUPPORT);

        strcpy(lpSPIVersion->szDescription,"shHicom");
        strcpy(lpSPIVersion->szSystemStatus,"Good");
        CServiceBasic *pServiceBasic=new CServiceBasic;
        pServiceBasic->m_hService=hService;

        UINT uNameLen=min(256, strlen(lpszLogicalName));
        memcpy(pServiceBasic->m_strLogicalName, lpszLogicalName, uNameLen);
        pServiceBasic->m_strLogicalName[uNameLen]='\0';

        pServiceBasic->m_pServiceThread=hApp;
        pServiceBasic->m_strAppID=lpszAppID;
        pServiceBasic->m_dwTraceLevel=dwTraceLevel;
        pServiceBasic->m_dwTimeOut=dwTimeOut;
        pServiceBasic->m_hWND=hWnd;
        pServiceBasic->m_lpRequestID=new REQUESTID;
        *pServiceBasic->m_lpRequestID=ReqID;
        pServiceBasic->m_bAutoDeleteRequestID=TRUE;
        pServiceBasic->m_hLib=hProvider;
        pServiceBasic->m_dwSrvcVersionsRequired=dwSrvcVersionsRequired;
        pServiceBasic->m_lpSrvcVersion=lpSrvcVersion;

      if(WAIT_OBJECT_0!=WaitForSingleObject(g_hMsgQueueEvent, INFINITE))
        return WFS_ERR_CANCELED;
      BOOL b=PostThreadMessage(g_dwDefThreadId, WM_NI_SP_Open, WPARAM(pServiceBasic), 0);
      if(!b){
            return WFS_ERR_CANCELED;
      }
      printf("WFPOpen return with success\n");
    return WFS_SUCCESS;
}

使用 onSpOpen 的服务线程回调

LRESULT OnSPOpen(WPARAM wParam, LPARAM lParam)
{
    LRESULT lr=WFS_SUCCESS;
    //return WFS_SUCCESS;
    CServiceBasic *pServiceBasic=(CServiceBasic*)wParam;
    if(pServiceBasic){
    int nLock=pServiceBasic->QueryLogicalServiceLock(pServiceBasic->m_strLogicalName);
    if(nLock<=0){
      UINT uBytes=min(strlen(pServiceBasic->m_strLogicalName), sizeof(g_strLogicalName)-1);
      memcpy(g_strLogicalName, pServiceBasic->m_strLogicalName, uBytes);
      g_strLogicalName[uBytes]='\0';
      //lr=pServiceBasic->OpenDev(g_strLogicalName, g_osp);
      lr=WFS_SUCCESS;
    }else{
        lr=WFS_ERR_CANCELED;
        }
    }else{
        lr=WFS_ERR_INVALID_HSERVICE;
    }
    WFSRESULT *pResult=NULL;
    m_pfnWFMAllocateBuffer(sizeof(WFSRESULT), WFS_MEM_ZEROINIT, (void**)&pResult);
    pResult->RequestID=*pServiceBasic->m_lpRequestID;
    pResult->hService=pServiceBasic->m_hService;
    pResult->hResult=lr;//indicate the result.
    GetLocalTime(&pResult->tsTimestamp);
    HWND hWnd=pServiceBasic->m_hWND;
    delete pServiceBasic;
  BOOL b=::PostMessage(hWnd, WFS_OPEN_COMPLETE, NULL, (LONG)pResult);
  printf ("SP Open made sure it sends WFS_OPEN_COMPLETE via POST MESSAGE\n");

  return 0;
}

执行期间的控制台输出

C:\gtkTrials\StandAloneApp\Debug>StandAloneApp.exe

(从 StandAloneApp 打印)

Session Open In progress 
Start up result = 0  (WFS_SUCCESS)

 wVersion: 3
 LowVersion: 257
 wHighVersion: 39171
 szDescription: WOSA/XFS API v3.00/v2.00
 szSystemStatus:
DllMainProcessAttach is executed

(从 SP DLL 打印)

msxfs DLL load  
DLL path : C:\xfs_sdks\SDK\DLL\msxfs.dll

msxfs DLL load completed

WFPOpen Process start
DllMainProcessAttach is executed
WFPOpen return with success
SP Open made sure it sends WFS_OPEN_COMPLETE via POST MESSAGE

(从 StandAloneApp 打印)

SrvcVersion Records:
 wVersion: 3
 LowVersion: 5121
 wHighVersion: 3
 szDescription: α╝`
 szSystemStatus:
SPIVersion Records:
 wVersion: 3
 LowVersion: 5121
 wHighVersion: 3
 szDescription: shHicom
 szSystemStatus: Good



HService Address ; 1
SessionOpen result = -15 (WFS_ERR_INTERNAL_ERROR)

请求一些关于理解这个问题的指导。

【问题讨论】:

    标签: c++ winapi cen-xfs


    【解决方案1】:

    这些导出比较看起来您使用了错误的调用约定。
    将所有 SPI 导出从 WINAPI 更改为 __cdecl(只需删除 WINAPI,因为 __cdecl 是默认值),它应该会有所作为。

    以及为什么您的示例中的返回码不同:
    第一个示例甚至没有到达 WFPOpen 调用,因为管理器在 DLL 加载后找不到正确的 WFPOpen 符号 -> Invalid ServiceProvider。

    第二种情况接缝进入 WFPOpen,但第一次测试失败 -> INTERNAL_ERROR:
    if(!g_hMutex ||!g_hLib ||!g_hMsgQueueEvent) return WFS_ERR_INTERNAL_ERROR;

    因此,在调用约定修复后,您需要更详细地检查您的初始化代码以了解它失败的原因。

    通过查看那些经过测试的全局变量,我发现的一件事是,您永远不应该从在 DLLMain 中执行的代码中调用 LoadLibrary。

    您可以只创建互斥体并将 DLL 模块句柄保存在 DLLMain 中,然后在 WFPOpen 开始时进行其余的初始化,例如库加载。

    不能简单地从 WFPOpen 返回 WFS_SUCCESS。 以下是对最小实现的非常粗略的描述:
    1.填充版本结构(其中一个参数是this的指针)
    2. 返回 WFS_SUCCESS 或错误代码。
    3. 如果 WFPOpen 返回 WFS_SUCCESS,则调用者期望异步响应。因此,您必须将带有所有必需信息的 WFS_OPEN_COMPLETE 消息发送到给定的(hwnd 参数)消息窗口句柄。

    从以下文档中查看更多详细信息(SPI API 是第 6 章)。
    ftp://ftp.cenorm.be/CWA/CEN/WS-XFS/CWA16374/CWA16374-1-2011_December.pdf

    【讨论】:

    • Reg 第二种情况:我对代码进行了更改以在进入 WFPOpen 时返回 WFS_SUCCESS ..即使在这种情况下它返回 -15 ..令人惊讶 ..
    • 我还确保我评论了它所在的所有状态并尝试与驱动程序进行通信。
    • 根据您的建议验证了流程:我无法在代码片段上指出错误。使用代码段添加了对问题的编辑。
    【解决方案2】:

    这段代码没问题。 我认为您应该在注册表中搜索“QuantumT”,可能它还没有在那里注册。

    逻辑服务名称: 1-注册 2- HKEY_CURRENT_USER/XFS/LOGICAL_SERVICES/

    我使用“JournalPrinter1”,WFSOpen 向我返回 Success。

    【讨论】:

      【解决方案3】:

      调用约定已在XFSSPI.H 中定义,我认为您不应该更改它。

      您需要使用“正确”导出的函数名称将 .def 文件添加到您的解决方案中,并将其设置为您的解决方案模块定义文件Properties-&gt;Linker-&gt;Input-&gt;Module Definition File

      EXPORTS
      WFPCancelAsyncRequest
      WFPClose
      WFPDeregister
      WFPExecute
      WFPGetInfo
      WFPLock
      WFPOpen
      WFPRegister
      WFPSetTraceLevel
      WFPUnloadService
      WFPUnlock
      

      我的 SPI WFPOpen 函数是这样调用的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-10-27
        • 1970-01-01
        • 2017-08-02
        • 1970-01-01
        • 2020-01-15
        • 2020-12-28
        • 1970-01-01
        相关资源
        最近更新 更多