質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
VBScript

VBScript(Visual Basic Scripting Edition)はMicrosftが開発したスクリプト言語であり、Visual Basicのサブセットです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

3回答

5746閲覧

GlobalMemoryStatusExで取得した「仮想メモリのサイズ」とWMIから取得した「仮想メモリのサイズ」が違う

Yamato.dd

総合スコア48

VBScript

VBScript(Visual Basic Scripting Edition)はMicrosftが開発したスクリプト言語であり、Visual Basicのサブセットです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2020/01/20 00:35

実行環境

Windows 10

プログラムの概要

仮想メモリの情報をVBSから取得して、あらかじめどのような結果になるか確認しておきます。

VBS

1Dim WMILocator, WMIService, QfeSet, QfeSet2 2 3Set WMILocator = WScript.CreateObject("WbemScripting.SWbemLocator") 4Set WMIService = WMILocator.ConnectServer 5Set QfeSet = WMIService.ExecQuery("SELECT TotalVirtualMemorySize FROM Win32_OperatingSystem") 6Set QfeSet2 = WMIService.ExecQuery("SELECT FreeVirtualMemory FROM Win32_OperatingSystem") 7 8Dim Qfe, Qfe2 9 10for each Qfe in QfeSet 11 ' MB換算で表示 12 WScript.Echo Qfe.Properties_.Item("TotalVirtualMemorySize").Value / 1024 13Next 14 15for each Qfe2 in QfeSet2 16 ' MB換算で表示 17 WScript.Echo Qfe2.Properties_.Item("FreeVirtualMemory").Value / 1024 18Next

結果を控え、今度はC++のプログラムから仮想メモリの情報を取得するため下記を実装しました。
開発環境はVisualStudio 2013です。

C++

1void GetMemoryInf() 2{ 3 // 初期化処理 4 MEMORYSTATUSEX msex = { sizeof(MEMORYSTATUSEX) }; 5 6 // メモリ情報を取得 7 GlobalMemoryStatusEx(&msex); 8} 9

このコードの後で「msex.ullTotalVirtual」と「msex.ullAvailVirtual」の値をMBに換算(byte ⇒ MB)して確認しました。
すると単位がずれているとかそういうことではなく、結果的に全く異なる結果になってしまいました。
おそらくある意味ではどちらも正しい値ではあると思うのですが、こちらが期待していたのは「VBSで取得していた方の値」です。
なるべく内部のコードで完結できるような形で仮想メモリ情報を取得する実装をしたいのですが、どういうことなのかわからず実現方法がわかっていない状況です。

ご教示頂けませんでしょうか。

【補足】
最悪上記で使ったVBSを呼び出すこともできるのですが、最終手段としたいです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

比較する対象を間違えていませんか?
ullTotalVirtual は多くの 64bit 環境では、搭載メモリにかかわらず 約128TiByte になると思われます。
ullTotalVirtual は仮想アドレス空間のサイズですから、仮想メモリのサイズは ullTotalPageFile を参照すべきではないでしょうか?

当方の環境 (Windows10 Home 64bit) では、vbs の結果とほぼ一致しました。

投稿2020/01/20 04:13

Bull

総合スコア986

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dodox86

2020/01/20 04:33 編集

Bullさんの回答が適切かもしれませんね。 「ullTotalPageFile が使えそう」と言うのはStackoverflowのこちらでも言及されていたのですが、私自身、見誤っていました。 https://stackoverflow.com/questions/63166/how-to-determine-cpu-and-memory-consumption-from-inside-a-process 私の環境(Windows 10 Pro. 64ビット)で追試しました。 VBScriptの結果 -- TotalVirtualMemorySize: 19140808 -- FreeVirtualMemory 11302220 GlobalMemoryStatusExで取得したMEMORYSTATUSEX構造体のメンバーを見ると ullTotalPageFile=19600187392 ullAvailPageFile=11555643392 となりました。VBScriptの方はKB単位なので、1024で単位を合わせると、一致します。
Yamato.dd

2020/01/20 06:16

Bullさん、dodox86さん、回答して頂きありがとうございました。 こちら私の認識が間違っておりました。Bullさんの提示して頂いた通り実装したところ、期待通りの結果を得ることができました。 こちらの回答をベストアンサーにさせていただきます。 dodox86さんも試して頂き有難うございました。
guest

0

ネイティブのWin32 APIであるGlobalMemoryStatusExは、以下のリファレンスの説明を真に受けて解釈すると、
GlobalMemoryStatusEx function - Microsoft Docs

You can use the GlobalMemoryStatusEx function to determine how much memory your application can allocate without severely impacting other applications.

「このAPIを使っているアプリケーション(実行ファイル)自体が使えるメモリ量を取得できる」です。実際、このAPI自体を実行するアプリケーションが32ビット版である場合は実メモリがどんなに大きくてもullTotalVirtualメンバーの値は最大でおよそ2GBになります。質問者さんが対象としたい構造体メンバーはそれとは違うullTotalVirtualullAvailVirtualですが、もともとkernel32が有するネイティブAPIであるGlobalMemoryStatusExとWindows管理用インターフェースのWMIとでは用途が違うと言えるため、取得できる値が違ったとしてもそれは仕方が無い(Windows自体の仕様)と少なくとも個人的には考えます。

VBScriptで実行した値をご所望なのであれば、C++とWindowsのCOMインターフェースを使用して同等の操作を行うことができます。
以下は Example: Getting WMI Data from the Local Computer でのサンプルコードをほとんどそのままに、質問者さんが提示したVBScriptと同じような操作をC++で行い、WMIでのTotalVirtualMemorySize``FreeVirtualMemoryを取得する例です。(※尚、実際にこのコードを使われる場合はエラー処理やエラー時に抜ける場合の後処理などを適切に行ってください)

C++

1#define _WIN32_DCOM 2#include <iostream> 3using namespace std; 4#include <comdef.h> 5#include <Wbemidl.h> 6 7#pragma comment(lib, "wbemuuid.lib") 8 9/* 10https://docs.microsoft.com/ja-jp/windows/win32/wmisdk/example--getting-wmi-data-from-the-local-computer 11*/ 12int main() 13{ 14 HRESULT hres; 15 16 // Step 1: -------------------------------------------------- 17 // Initialize COM. ------------------------------------------ 18 19 hres = CoInitializeEx(0, COINIT_MULTITHREADED); 20 if (FAILED(hres)) 21 { 22 wcout << L"Failed to initialize COM library. Error code = 0x" 23 << hex << hres << endl; 24 return 1; // Program has failed. 25 } 26 27 // Step 2: -------------------------------------------------- 28 // Set general COM security levels -------------------------- 29 30 hres = CoInitializeSecurity( 31 NULL, 32 -1, // COM authentication 33 NULL, // Authentication services 34 NULL, // Reserved 35 RPC_C_AUTHN_LEVEL_DEFAULT, // Default authentication 36 RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation 37 NULL, // Authentication info 38 EOAC_NONE, // Additional capabilities 39 NULL // Reserved 40 ); 41 42 if (FAILED(hres)) 43 { 44 wcout << L"Failed to initialize security. Error code = 0x" 45 << hex << hres << endl; 46 CoUninitialize(); 47 return 1; // Program has failed. 48 } 49 50 // Step 3: --------------------------------------------------- 51 // Obtain the initial locator to WMI ------------------------- 52 53 IWbemLocator *pLoc = NULL; 54 55 hres = CoCreateInstance( 56 CLSID_WbemLocator, 57 0, 58 CLSCTX_INPROC_SERVER, 59 IID_IWbemLocator, (LPVOID *)&pLoc); 60 61 if (FAILED(hres)) 62 { 63 wcout << L"Failed to create IWbemLocator object." 64 << L" Err code = 0x" 65 << hex << hres << endl; 66 CoUninitialize(); 67 return 1; // Program has failed. 68 } 69 70 // Step 4: ----------------------------------------------------- 71 // Connect to WMI through the IWbemLocator::ConnectServer method 72 73 IWbemServices *pSvc = NULL; 74 75 // Connect to the root\cimv2 namespace with 76 // the current user and obtain pointer pSvc 77 // to make IWbemServices calls. 78 hres = pLoc->ConnectServer( 79 _bstr_t(L"ROOT\CIMV2"), // Object path of WMI namespace 80 NULL, // User name. NULL = current user 81 NULL, // User password. NULL = current 82 0, // Locale. NULL indicates current 83 NULL, // Security flags. 84 0, // Authority (for example, Kerberos) 85 0, // Context object 86 &pSvc // pointer to IWbemServices proxy 87 ); 88 89 if (FAILED(hres)) 90 { 91 wcout << L"Could not connect. Error code = 0x" 92 << hex << hres << endl; 93 pLoc->Release(); 94 CoUninitialize(); 95 return 1; // Program has failed. 96 } 97 98 wcout << L"Connected to ROOT\CIMV2 WMI namespace" << endl; 99 100 // Step 5: -------------------------------------------------- 101 // Set security levels on the proxy ------------------------- 102 103 hres = CoSetProxyBlanket( 104 pSvc, // Indicates the proxy to set 105 RPC_C_AUTHN_WINNT, // RPC_C_AUTHN_xxx 106 RPC_C_AUTHZ_NONE, // RPC_C_AUTHZ_xxx 107 NULL, // Server principal name 108 RPC_C_AUTHN_LEVEL_CALL, // RPC_C_AUTHN_LEVEL_xxx 109 RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx 110 NULL, // client identity 111 EOAC_NONE // proxy capabilities 112 ); 113 114 if (FAILED(hres)) 115 { 116 wcout << L"Could not set proxy blanket. Error code = 0x" 117 << hex << hres << endl; 118 pSvc->Release(); 119 pLoc->Release(); 120 CoUninitialize(); 121 return 1; // Program has failed. 122 } 123 124 // Step 6: -------------------------------------------------- 125 // Use the IWbemServices pointer to make requests of WMI ---- 126 127 // For example, get the name of the operating system 128 IEnumWbemClassObject* pEnumerator = NULL; 129 hres = pSvc->ExecQuery( 130 bstr_t(L"WQL"), 131 bstr_t(L"SELECT TotalVirtualMemorySize, FreeVirtualMemory FROM Win32_OperatingSystem"), 132 WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, 133 NULL, 134 &pEnumerator); 135 136 if (FAILED(hres)) 137 { 138 wcout << L"Query for operating system name failed." 139 << L" Error code = 0x" 140 << hex << hres << endl; 141 pSvc->Release(); 142 pLoc->Release(); 143 CoUninitialize(); 144 return 1; // Program has failed. 145 } 146 147 // Step 7: ------------------------------------------------- 148 // Get the data from the query in step 6 ------------------- 149 150 IWbemClassObject *pclsObj = NULL; 151 ULONG uReturn = 0; 152 153 while (pEnumerator) 154 { 155 HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, 156 &pclsObj, &uReturn); 157 158 if (0 == uReturn) 159 { 160 break; 161 } 162 163 VARIANT vtProp; 164 165 // Get the value of the properties 166 hr = pclsObj->Get(L"TotalVirtualMemorySize", 0, &vtProp, 0, 0); 167 if (SUCCEEDED(hr)) { 168 wcout << L"OS TotalVirtualMemorySize: " << vtProp.bstrVal << endl; 169 } 170 VariantClear(&vtProp); 171 172 hr = pclsObj->Get(L"FreeVirtualMemory", 0, &vtProp, 0, 0); 173 if (SUCCEEDED(hr)) { 174 wcout << L"OS FreeVirtualMemory: " << vtProp.bstrVal << endl; 175 } 176 VariantClear(&vtProp); 177 178 pclsObj->Release(); 179 } 180 181 // Cleanup 182 // ======== 183 184 pSvc->Release(); 185 pLoc->Release(); 186 pEnumerator->Release(); 187 CoUninitialize(); 188 189 return 0; // Program successfully completed. 190}

質問者さんご提示のVBScriptをメガバイト換算せずにオリジナルの値を表示するよう少し修正し、実行して比較した例を以下に示します。t2.vbsが質問者さんのVBScriptで、ConApp1.exeが上記C++コードの実行ファイルの32ビット版、64ビット版です。FreeVirtualMemoryの値が実行ごとに少し変化してしまうのは仕方ないですが、TotalVirtualMemorySizeの値は常に同じであることが分かります。

CMD

1C>cscript /Nologo t2.vbs 2-- TotalVirtualMemorySize: 319140808 4-- FreeVirtualMemory 512523004 6 7C>Release\ConApp1.exe 8Connected to ROOT\CIMV2 WMI namespace 9OS TotalVirtualMemorySize: 19140808 10OS FreeVirtualMemory: 12522928 11 12C>x64\Release\ConApp1.exe 13Connected to ROOT\CIMV2 WMI namespace 14OS TotalVirtualMemorySize: 19140808 15OS FreeVirtualMemory: 12524372

投稿2020/01/20 02:50

dodox86

総合スコア9183

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Yamato.dd

2020/01/20 06:13

丁寧な回答ありがとうございます。 サンプルコードを提示して頂きありがとうございました。
guest

0

1024 で割っていますか?オペレーティングシステムから見るメモリサイズと、ハードウエアから見るメモリサイズは違います。オペレーティングシステムでは、BIOS の使用サイズが含まれていません。どちらか目的を合わせて、同じデータを使用することをお薦めします。

投稿2020/01/20 01:03

mmaeda

総合スコア269

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Yamato.dd

2020/01/20 06:12

単位は揃えているので問題ありませんでした。 ハードウェアから見た容量と、OSから見た容量が異なるのは知らなかったです。 回答して頂きありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問