我的回答是基于 Stephen Quan 对How to load & call a VBScript function from inside C++ 的回答?添加了完整的 UTF-8 支持,您可以从 CPP 文件中的代码注释中收集。与使用 Microsoft Script Control 创建 InputBox 不同,这可用于 x86和x64 可执行文件、库和控件。
“输入框.h”:
extern "C" char *InputBox(char *Prompt, char *Title = (char *)"", char *Default = (char *)"");
extern "C" char *PasswordBox(char *Prompt, char *Title = (char *)"", char *Default = (char *)"");
“输入框.cpp”:
#include "inputbox.h"
// Windows API
#include <windows.h>
// VBScript InputBox
#include <atlbase.h>
#include <activscp.h>
#include <comdef.h>
// UTF-8 Support
#include <wchar.h>
#include <string>
#include <vector>
using std::string;
using std::wstring;
using std::vector;
static wstring StringWiden(string Str) {
const size_t wchar_tCount = Str.size() + 1;
vector<wchar_t> Buffer(wchar_tCount);
return wstring { Buffer.data(), (size_t)MultiByteToWideChar(CP_UTF8, 0, Str.c_str(), -1, Buffer.data(), wchar_tCount) };
}
static string StringShorten(wstring Str) {
int nBytes = (size_t)WideCharToMultiByte(CP_UTF8, 0, Str.c_str(), (int)Str.length(), NULL, 0, NULL, NULL);
vector<char> Buffer((size_t)nBytes);
return string { Buffer.data(), (size_t)WideCharToMultiByte(CP_UTF8, 0, Str.c_str(), (int)Str.length(), Buffer.data(), nBytes, NULL, NULL) };
}
static string StringReplaceAll(string Str, string SubStr, string NewStr) {
size_t Position = 0;
const size_t SubLen = SubStr.length(), NewLen = NewStr.length();
while ((Position = Str.find(SubStr, Position)) != string::npos) {
Str.replace(Position, SubLen, NewStr);
Position += NewLen;
}
return Str;
}
static string CPPNewLineToVBSNewLine(string NewLine) {
size_t Position = 0;
while (Position < NewLine.length()) {
if (NewLine[Position] == '\r' || NewLine[Position] == '\n')
NewLine.replace(Position, 2, "\" + vbNewLine + \"");
Position += 1;
}
return NewLine;
}
class CSimpleScriptSite :
public IActiveScriptSite,
public IActiveScriptSiteWindow {
public:
CSimpleScriptSite() : m_cRefCount(1), m_hWnd(NULL) { }
// IUnknown
STDMETHOD_(ULONG, AddRef)();
STDMETHOD_(ULONG, Release)();
STDMETHOD(QueryInterface)(REFIID riid, void** ppvObject);
// IActiveScriptSite
STDMETHOD(GetLCID)(LCID* plcid) { *plcid = 0; return S_OK; }
STDMETHOD(GetItemInfo)(LPCOLESTR pstrName, DWORD dwReturnMask, IUnknown** ppiunkItem, ITypeInfo** ppti) { return TYPE_E_ELEMENTNOTFOUND; }
STDMETHOD(GetDocVersionString)(BSTR* pbstrVersion) { *pbstrVersion = SysAllocString(L"1.0"); return S_OK; }
STDMETHOD(OnScriptTerminate)(const VARIANT* pvarResult, const EXCEPINFO* pexcepinfo) { return S_OK; }
STDMETHOD(OnStateChange)(SCRIPTSTATE ssScriptState) { return S_OK; }
STDMETHOD(OnScriptError)(IActiveScriptError* pIActiveScriptError) { return S_OK; }
STDMETHOD(OnEnterScript)(void) { return S_OK; }
STDMETHOD(OnLeaveScript)(void) { return S_OK; }
// IActiveScriptSiteWindow
STDMETHOD(GetWindow)(HWND* phWnd) { *phWnd = m_hWnd; return S_OK; }
STDMETHOD(EnableModeless)(BOOL fEnable) { return S_OK; }
// Miscellaneous
STDMETHOD(SetWindow)(HWND hWnd) { m_hWnd = hWnd; return S_OK; }
public:
LONG m_cRefCount;
HWND m_hWnd;
};
STDMETHODIMP_(ULONG) CSimpleScriptSite::AddRef() {
return InterlockedIncrement(&m_cRefCount);
}
STDMETHODIMP_(ULONG) CSimpleScriptSite::Release() {
if (!InterlockedDecrement(&m_cRefCount)) {
delete this;
return 0;
}
return m_cRefCount;
}
STDMETHODIMP CSimpleScriptSite::QueryInterface(REFIID riid, void **ppvObject)
{
if (riid == IID_IUnknown || riid == IID_IActiveScriptSiteWindow) {
*ppvObject = (IActiveScriptSiteWindow*)this;
AddRef();
return NOERROR;
}
if (riid == IID_IActiveScriptSite) {
*ppvObject = (IActiveScriptSite*)this;
AddRef();
return NOERROR;
}
return E_NOINTERFACE;
}
static HHOOK hHook = 0;
static bool HideInput = false;
static LRESULT CALLBACK InputBoxProc(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode < HC_ACTION)
return CallNextHookEx(hHook, nCode, wParam, lParam);
if (nCode = HCBT_ACTIVATE) {
if (HideInput == true) {
HWND TextBox = FindWindowExA((HWND)wParam, NULL, "Edit", NULL);
SendDlgItemMessageW((HWND)wParam, GetDlgCtrlID(TextBox), EM_SETPASSWORDCHAR, L'\x25cf', 0);
}
}
if (nCode = HCBT_CREATEWND) {
if (!(GetWindowLongPtr((HWND)wParam, GWL_STYLE) & WS_CHILD))
SetWindowLongPtr((HWND)wParam, GWL_EXSTYLE, GetWindowLongPtr((HWND)wParam, GWL_EXSTYLE) | WS_EX_DLGMODALFRAME);
}
return CallNextHookEx(hHook, nCode, wParam, lParam);
}
static char *InputBoxHelper(char *Prompt, char *Title, char *Default) {
// Initialize
HRESULT hr = S_OK;
hr = CoInitialize(NULL);
CSimpleScriptSite* pScriptSite = new CSimpleScriptSite();
CComPtr<IActiveScript> spVBScript;
CComPtr<IActiveScriptParse> spVBScriptParse;
hr = spVBScript.CoCreateInstance(OLESTR("VBScript"));
hr = spVBScript->SetScriptSite(pScriptSite);
hr = spVBScript->QueryInterface(&spVBScriptParse);
hr = spVBScriptParse->InitNew();
// Replace quotes with double quotes
string strPrompt = StringReplaceAll(Prompt, "\"", "\"\"");
string strTitle = StringReplaceAll(Title, "\"", "\"\"");
string strDefault = StringReplaceAll(Default, "\"", "\"\"");
// Create evaluation string
string Evaluation = "InputBox(\"" + strPrompt + "\", \"" + strTitle + "\", \"" + strDefault + "\")";
Evaluation = CPPNewLineToVBSNewLine(Evaluation);
wstring WideEval = StringWiden(Evaluation);
// Run InpuBox
CComVariant result;
EXCEPINFO ei = {};
DWORD ThreadID = GetCurrentThreadId();
HINSTANCE ModHwnd = GetModuleHandle(NULL);
hr = pScriptSite->SetWindow(GetAncestor(GetActiveWindow(), GA_ROOTOWNER));
hHook = SetWindowsHookEx(WH_CBT, &InputBoxProc, ModHwnd, ThreadID);
hr = spVBScriptParse->ParseScriptText(WideEval.c_str(), NULL, NULL, NULL, 0, 0, SCRIPTTEXT_ISEXPRESSION, &result, &ei);
UnhookWindowsHookEx(hHook);
// Cleanup
spVBScriptParse = NULL;
spVBScript = NULL;
pScriptSite->Release();
pScriptSite = NULL;
CoUninitialize();
// Result
static string strResult;
_bstr_t bstrResult = (_bstr_t)result;
strResult = StringShorten((wchar_t*)bstrResult);
return (char*)strResult.c_str();
}
char *InputBox(char *Prompt, char *Title, char *Default) {
HideInput = false;
return InputBoxHelper(Prompt, Title, Default);
}
char *PasswordBox(char *Prompt, char *Title, char *Default) {
HideInput = true;
return InputBoxHelper(Prompt, Title, Default);
}
创建上述两个文件,然后将它们添加到您的 Visual Studio 项目中。
在您想要输入或密码框功能的任何文件中(在标题中找到),只需包含标题:
#include "inputbox.h"
// use functions here
我还删除了 VBScript InputBox 标题栏中的默认 Windows 应用程序图标,因为我见过很多人抱怨在那里看到它有多难看。
如果您有任何问题,请告诉我。