【发布时间】:2019-10-11 05:32:53
【问题描述】:
我正在创建一个 COM dll,可以从 PHP 中使用它来读取我已经知道其大小的内存映射文件,虽然我在读取文件时没有问题,但我无法将它作为 BSTR 正确返回。当我使用 dll 时,它只返回空字符之前的字符(在这种情况下为 3 个字符),我知道文件可以包含多个空字符,这就是为什么我在 MultiByteToWideChar 函数中指定了大小,但它仍然不起作用.
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 代码:
<?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
?>
【问题讨论】:
-
我更好奇 OP 如何确定只返回第一个 null 的字符(即它们是否使用打印终止字符串的函数)。这是一个疯狂的想法。如何调试代码以检查 wslen 实际上是什么。
-
那么,wslen 的值是多少?是512吗?你检查过 bstr 的内容吗(使用内存调试器可以看到 0 个字符)?
-
@SimonMourier 感谢您的快速响应,调试代码(在另一个文件中)我可以看到 wslen 是 1000,但 bstr 只是“II*”前三个字符,我知道其他字符在那里,因为如果我单独打印字符,我可以看到它们的内容,也许我错过了一个选项。
-
预计为 1000。那你怎么看bstr?当你说“其他角色在这里”时,有什么问题?我怀疑在方法方面一切正常(bstr 是 1000*2 字节的缓冲区,里面有空值)。你确定它不是在 php 方面或在转换期间(无论是什么)你在空字符之后“丢失”字符吗?
-
@SimonMourier 也许你是对的,问题可能出在 php 方面,无论如何我要编辑我的问题以包含 php 代码(如 4 行)。