首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >如何从COM DLL返回包含多个空字符的BSTR

如何从COM DLL返回包含多个空字符的BSTR
EN

Stack Overflow用户
提问于 2019-05-24 15:28:25
回答 1查看 144关注 0票数 2

我正在创建一个COM dll,可以从PHP中使用它来读取一个内存映射文件,该文件的大小我已经知道了,虽然读取该文件没有任何问题,但我无法将其作为BSTR正确返回。当我使用dll时,它只返回空字符之前的字符(在本例中是3个字符),我知道文件可以包含多个空字符,这就是为什么我在MultiByteToWideChar函数中指定了大小,但它仍然不起作用。

代码语言:javascript
运行
AI代码解释
复制
STDMETHODIMP CMemReaderImpl::ReadFile(BSTR* filepath, BSTR* Ofile)
{

    if (*filepath == nullptr) {
        *Ofile = _com_util::ConvertStringToBSTR("err");
    }

    std::wstring wpath(*filepath, SysStringLen(*filepath));

    LPCWSTR lpath = wpath.c_str();

    HANDLE hFileMap;
    PCHAR lpBuffer = NULL;

    hFileMap = OpenFileMapping(
        FILE_MAP_ALL_ACCESS,
        FALSE,
        lpath
    );

    if (hFileMap == NULL) {
        char* err = "ERROR";
        *Ofile = _com_util::ConvertStringToBSTR(err);
    }

    lpBuffer = (PCHAR)MapViewOfFile(
        hFileMap,
        FILE_MAP_ALL_ACCESS,
        0,
        0,
        BUFF_SIZE
    );

    if (lpBuffer == NULL) {
        char* err = "ERROR";
        *Ofile = _com_util::ConvertStringToBSTR(err);
    }

    //where the magic happens

    int wslen = MultiByteToWideChar(CP_ACP, 0, lpBuffer, 1000, 0, 0);
    BSTR bstr = SysAllocStringLen(0, wslen);
    MultiByteToWideChar(CP_ACP, 0, lpBuffer, 1000, bstr, wslen);

    *Ofile = bstr;
    UnmapViewOfFile(lpBuffer);

    CloseHandle(hFileMap);

    return S_OK;
}

我真的希望将整个文件作为BSTR*返回,这样它就可以被另一个php程序操纵,但到目前为止似乎什么都没有起作用。

php代码:

代码语言:javascript
运行
AI代码解释
复制
<?php
    $obj = new COM("MemReader.MemReader");
    $result = $obj->ReadFile("Local\\imagen3.file");
    echo $result; //reads first 3 characters fine
    echo $result[4]; //error nothing here
?>
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-05-25 22:57:51

我不能为PHP说话,但在COM中,BSTR不是用于传递二进制数据的正确类型,请使用SAFEARRAY(VT_UI1)

代码语言:javascript
运行
AI代码解释
复制
STDMETHODIMP CMemReaderImpl::ReadFile(BSTR filepath, SAFEARRAY** Ofile)
{
    if (!Ofile)
        return E_POINTER;
    *Ofile = nullptr;

    if (!filepath)
        return E_INVALIDARG;

    HANDLE hFileMap = OpenFileMapping(FILE_MAP_READ, FALSE, filepath);
    if (!hFileMap) {
        DWORD err = GetLastError();
        return HRESULT_FROM_WIN32(err);
    }

    LPBYTE lpBuffer = (LPBYTE) MapViewOfFile(hFileMap, FILE_MAP_READ 0, 0, BUFF_SIZE);
    if (!lpBuffer) {
        DWORD err = GetLastError();
        CloseHandle(hFileMap);
        return HRESULT_FROM_WIN32(err);
    }

    SAFEARRRAYBOUND bounds;
    bounds.lLbound = 0;
    bounds.cElements = BUFF_SIZE;

    SAFEARRAY *sa = SafeArrayCreate(VT_UI1, 1, &bounds);
    if (!sa) {
        UnmapViewOfFile(lpBuffer);
        CloseHandle(hFileMap);
        return E_OUTOFMEMORY;
    }

    void *data;
    SafeArrayAccessData(sa, &data); 
    memcpy(data, lpBuffer, BUFF_SIZE);
    SafeArrayUnaccessData(sa);

    UnmapViewOfFile(lpBuffer);
    CloseHandle(hFileMap);

    *Ofile = sa;
    return S_OK;
}

不过,我不知道它是否与PHP兼容。

如果您必须使用Unicode,请尝试使用SysAllocStringByteLen()按原样存储字节,而不将其转换为BSTR

代码语言:javascript
运行
AI代码解释
复制
STDMETHODIMP CMemReaderImpl::ReadFile(BSTR filepath, BSTR* Ofile)
{
    if (!Ofile)
        return E_POINTER;
    *Ofile = nullptr;

    if (!filepath)
        return E_INVALIDARG;

    HANDLE hFileMap = OpenFileMapping(FILE_MAP_READ, FALSE, filepath);
    if (!hFileMap) {
        DWORD err = GetLastError();
        return HRESULT_FROM_WIN32(err);
    }

    LPSTR lpBuffer = (LPSTR) MapViewOfFile(hFileMap, FILE_MAP_READ 0, 0, BUFF_SIZE);
    if (!lpBuffer) {
        DWORD err = GetLastError();
        CloseHandle(hFileMap);
        return HRESULT_FROM_WIN32(err);
    }

    BSTR bstr = SysAllocStringByteLen(lpBuffer, BUFF_SIZE);
    if (bstr) {
        UnmapViewOfFile(lpBuffer);
        CloseHandle(hFileMap);
        return E_OUTOFMEMORY;
    }

    UnmapViewOfFile(lpBuffer);
    CloseHandle(hFileMap);

    *Ofile = bstr;
    return S_OK;
}

如果这对PHP不起作用,就不要对二进制数据使用MultiByteToWideChar(CP_ACP),因为CP_ACP会破坏数据!代码页28591 ( ISO-8859-1 )是避免损坏的更好选择,因为以ISO-8859-1编码的字节与它们表示的Unicode代码点具有相同的数值:

代码语言:javascript
运行
AI代码解释
复制
STDMETHODIMP CMemReaderImpl::ReadFile(BSTR filepath, BSTR* Ofile)
{
    if (!Ofile)
        return E_POINTER;
    *Ofile = nullptr;

    if (!filepath)
        return E_INVALIDARG;

    HANDLE hFileMap = OpenFileMapping(FILE_MAP_READ, FALSE, filepath);
    if (!hFileMap) {
        DWORD err = GetLastError();
        return HRESULT_FROM_WIN32(err);
    }

    LPSTR lpBuffer = (LPSTR) MapViewOfFile(hFileMap, FILE_MAP_READ 0, 0, BUFF_SIZE);
    if (!lpBuffer) {
        DWORD err = GetLastError();
        CloseHandle(hFileMap);
        return HRESULT_FROM_WIN32(err);
    }

    int wslen = MultiByteToWideChar(28591, 0, lpBuffer, BUFF_SIZE, nullptr, 0);
    if (wslen == 0) {
        DWORD err = GetLastError();
        UnmapViewOfFile(lpBuffer);
        CloseHandle(hFileMap);
        return HRESULT_FROM_WIN32(err);
    }

    BSTR bstr = SysAllocStringLen(nullptr, wslen);
    if (bstr) {
        UnmapViewOfFile(lpBuffer);
        CloseHandle(hFileMap);
        return E_OUTOFMEMORY;
    }

    MultiByteToWideChar(28591, 0, lpBuffer, BUFF_SIZE, bstr, wslen);

    UnmapViewOfFile(lpBuffer);
    CloseHandle(hFileMap);

    *Ofile = bstr;
    return S_OK;
}

否则,您可以简单地将每个8位字节按原样手动提升为16位字符:

代码语言:javascript
运行
AI代码解释
复制
STDMETHODIMP CMemReaderImpl::ReadFile(BSTR filepath, BSTR* Ofile)
{
    if (!Ofile)
        return E_POINTER;
    *Ofile = nullptr;

    if (!filepath)
        return E_INVALIDARG;

    HANDLE hFileMap = OpenFileMapping(FILE_MAP_READ, FALSE, filepath);
    if (!hFileMap) {
        DWORD err = GetLastError();
        return HRESULT_FROM_WIN32(err);
    }

    LPBYTE lpBuffer = (LPBYTE) MapViewOfFile(hFileMap, FILE_MAP_READ 0, 0, BUFF_SIZE);
    if (!lpBuffer) {
        DWORD err = GetLastError();
        CloseHandle(hFileMap);
        return HRESULT_FROM_WIN32(err);
    }

    BSTR bstr = SysAllocStringLen(nullptr, BUFF_SIZE);
    if (!bstr) {
        UnmapViewOfFile(lpBuffer);
        CloseHandle(hFileMap);
        return E_OUTOFMEMORY;
    }

    for (int i = 0; i < BUFF_SIZE; ++i)
        bstr[i] = (OLECHAR) lpBuffer[i];

    UnmapViewOfFile(lpBuffer);
    CloseHandle(hFileMap);

    *Ofile = bstr;
    return S_OK;
}

也就是说,如果以上方法仍然不适用于PHP,您可能需要将返回的SAFEARRAY/BSTR封装在VARIANT中,这是许多脚本语言通常处理COM数据的方式:

代码语言:javascript
运行
AI代码解释
复制
STDMETHODIMP CMemReaderImpl::ReadFile(BSTR filepath, VARIANT* Ofile)
{
    ...
    VariantInit(*Ofile);
    V_VT(*Ofile) = VT_UI1 | VT_ARRAY;
    V_ARRAY(*Ofile) = sa;
    ...
}
代码语言:javascript
运行
AI代码解释
复制
STDMETHODIMP CMemReaderImpl::ReadFile(BSTR filepath, VARIANT* Ofile)
{
    ...
    VariantInit(*Ofile);
    V_VT(*Ofile) = VT_BSTR;
    V_BSTR(*Ofile) = bstr;
    ...
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56295601

复制
相关文章
获取当前jar包路径_java获取jar文件
获取classpath的路径,若没有其他依赖,在cmd下运行该可执行jar包,则该值即为该jar包的绝对路径。代码如下:
全栈程序员站长
2022/11/10
7.6K0
获取手机nfc的MW version 和 FW version 记录
/vendor/nxp/opensource/commonsys/packages/apps/Nfc/nci/jni/NativeNfcManager.cpp 中会打印NFC的版本信息。
用户7557625
2020/07/28
1.1K0
Spring Boot -- 如何获取已加载的JAR文件流
最近遇到一个需求,在程序运行期间,拿到已加载类对应的jar包,然后上传到另一个地方,本以为利用ClassLoader直接定位到jar的InputStream流直接读取就ok,事实却没有这么简单,我把问题总结为以下几个小点,逐一解决。
屈定
2020/02/10
5.6K1
Error:Could not download ecj.jar : No cached version available for offline mode
最近重新打开老项目时,发现要配置一些东西,结果半天没有配置完,我寻思是网络问题,然后就换了一个网络,然后就报错了。错误如下
晨曦_LLW
2020/09/25
7770
如何替换jar中的jar配置
spring boot项目,使用jar方式打包部署;有时候我们需要替换项目中某个引用jar,又不想将整个项目重新打包。
summerking
2022/09/19
2.7K0
Jenkins获取jar包的快照号
主要用于打jar包的工程,显示快照包的名字。当jar打包完成后,会在target目录中,截取快照名。
陈不成i
2021/06/03
8360
Android项目实战(三十三):AS下获取获取依赖三方的jar文件、aar 转 jar
使用 Android studio 开发项目中,有几种引用三方代码的方式:jar 包 ,类库 ,gradle.build 的compile依赖。 大家会发现github上不少的项目只提供compile依赖的方式,但是当用到jar包使用过的情况 且 该项目不提供jar包的时候怎么办? 其实Android Studio 在compile方式 依赖三方项目的时候 就已经在本地有了该项目的jar包了,我们只需要去本地找到那个jar包就可以了。 查找方法: 一、项目大纲路径下的:External Libraries
听着music睡
2018/05/18
2.9K0
获取jar包内部的资源文件
通常获取一个资源文件很简单,问题是对于jar包内的资源文件,可能会发生意外。假如这里有一个文件操作的类:
用户7798898
2020/09/27
1.7K0
获取main函数的类以及jar包
抛出异常的时候,异常栈中有所有函数栈,这样就可以找到main函数所在的类。不过也需要注意,这个异常要在主线程抛出,不能在其他线程抛出。
十毛
2021/06/29
1.4K0
‘dependencies.dependency.version‘ for mysql:mysql-connector-java:jar is missing.问题处理
项目使用的技术框架是Spring Boot,依赖管理工具是Maven,需要用到数据库所以引入了mysql-connector-java相关jar包。
程序员十三
2023/06/10
6770
如何直接运行jar包_怎么运行jar文件
nohup:不挂断地运行命令,输出都将附加到当前目录的 nohup.out 文件中。如果当前目录的 nohup.out 文件不可写,输出重定向到 $HOME/nohup.out 文件中
全栈程序员站长
2022/11/10
2.7K0
idea打包jar文件_idea如何打包jar外部包
因为有好多项目,所以这里需要建立空,如果只有一个目的项目,可以选择根据这个依赖,选择下面一项。
全栈程序员站长
2022/11/10
2.4K0
idea打包jar文件_idea如何打包jar外部包
如何发布jar到clojars
Clojars 是一个为开源 Clojure 类库打造的仓库,截止2017年9月17日,大概有19831个项目发布在上面。整个网站也是用 Clojure 编写的。
lambeta
2018/08/17
8750
如何发布jar到clojars
java-解决jar包反射获取不到类
在开发一个基础工具包给业务组的小伙伴们使用的时候,发现一个小问题,就是在反射的时候在自己电脑上运行的正常,但是打成jar包后,就class not fuond,有点奇怪。 如果能借助Spring这个都不是事,关键是不能用。
潇洒
2023/10/20
7370
【错误记录】jar 执行错误 ( java.lang.UnsupportedClassVersionError: Unsupported major.minor version 52.0 )
在 【IntelliJ IDEA】导出可执行 JAR 包 博客中导出的 jar 包 ;
韩曙亮
2023/03/29
5080
IDEA 激活教程,如何使用 IDEA 解决 jar 包冲突?如何正确导入 jar 包?
在我们的项目开发中,如果使用 Maven 引用了过多依赖,那么就很容易遇到 jar包冲突这个问题。
编程小记
2022/03/23
2K0
IDEA 激活教程,如何使用 IDEA 解决 jar 包冲突?如何正确导入 jar 包?
如何使用Java的JAR文件
hello,大家好,我是小面!今天有个小伙伴私信我说如何使用Java的Jar文件?今天将给大家介绍一下Java的jar文件。
灬沙师弟
2023/03/07
2.3K0
如何使用Java的JAR文件
Maven 如何引入本地jar包
通常大家需要引入一个第三放 jar 包,直接在 maven 仓库中搜索,然后将依赖的格式 copy 到 pom.xml文件中即可。
明明如月学长
2021/08/31
1.6K0
Maven 如何引入本地jar包
MapReduce项目如何输出jar包?
右键单击工程,点开“Export…”,在弹出的对话框中选择“java/JAR file”,
马克java社区
2021/06/24
3670
点击加载更多

相似问题

在表格中折叠/展开div?

10

在graphviz中展开/折叠表格

19

向DataGrid单元中添加展开/折叠按钮

10

表格行折叠/展开css

10

Jquery表格折叠多重展开

11
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档