I'm creating a COM dll that can be used from PHP to read a memory mapped file whose size I already know, while I have no problem reading the file, I can't return it correctly as a BSTR. When I use the dll it only returns the characters before a null character (3 characters in this case), I know files can contain multiple null characters, which is why I scpecified the size in the MultiByteToWideChar function, yet it still doesn't work.
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;
}
I really wish to return the entire file as a BSTR* so it can be manipulated by another php program, but so far nothing seems to work.
the php code:
<?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
?>
I can't speak for PHP, but in COM, a
BSTRis not the correct type to use for passing around binary data, use aSAFEARRAY(VT_UI1)instead:I don't know if that is compatible with PHP, though.
If you must use
BSTR, trySysAllocStringByteLen()to store the bytes as-is without any conversion to Unicode:If that does not work for PHP, DO NOT use
MultiByteToWideChar(CP_ACP)on binary data, asCP_ACPwill corrupt the data! Codepage 28591 (ISO-8859-1) is a better choice to avoid corruption, as bytes encoded in ISO-8859-1 have the same numeric values as the Unicode codepoints they represent:Otherwise, you can simply promote each 8bit byte as-is to a 16bit character manually:
That being said, if the above still do not work for PHP, you might need to wrap the returned
SAFEARRAY/BSTRinside of aVARIANT, which is how many scripting languages generally handle COM data: