PancakeSwapRouter and Uniswap Router same error , Can you help me? - blockchain

I deploy the PancakeSwap Router contract on the remix and make transactions, but the transactions are deemed invalid. I am getting Execution Reverted error. Even though I enter Factory and WETH (WBNB), it does not create a new Pair.
https://testnet.bscscan.com/tx/0x831f0bc3ae6edf2b584bbcb274ba16d4d620187258297c6d88ba731fb068e2bd
it's a transaction hash .
pragma solidity =0.6.6;
contract PancakeRouter is IPancakeRouter02 {
using SafeMath for uint;
address public immutable override factory;
address public immutable override WETH;
modifier ensure(uint deadline) {
require(deadline >= block.timestamp, 'PancakeRouter: EXPIRED');
_;
}
constructor(address _factory, address _WETH) public {
factory = _factory;
WETH = _WETH;
}
receive() external payable {
assert(msg.sender == WETH); // only accept ETH via fallback from the WETH contract
}
// **** ADD LIQUIDITY ****
function _addLiquidity(
address tokenA,
address tokenB,
uint amountADesired,
uint amountBDesired,
uint amountAMin,
uint amountBMin
) internal virtual returns (uint amountA, uint amountB) {
// create the pair if it doesn't exist yet
if (IPancakeFactory(factory).getPair(tokenA, tokenB) == address(0)) {
IPancakeFactory(factory).createPair(tokenA, tokenB);
}
(uint reserveA, uint reserveB) = PancakeLibrary.getReserves(factory, tokenA, tokenB);
if (reserveA == 0 && reserveB == 0) {
(amountA, amountB) = (amountADesired, amountBDesired);
} else {
uint amountBOptimal = PancakeLibrary.quote(amountADesired, reserveA, reserveB);
if (amountBOptimal <= amountBDesired) {
require(amountBOptimal >= amountBMin, 'PancakeRouter: INSUFFICIENT_B_AMOUNT');
(amountA, amountB) = (amountADesired, amountBOptimal);
} else {
uint amountAOptimal = PancakeLibrary.quote(amountBDesired, reserveB, reserveA);
assert(amountAOptimal <= amountADesired);
require(amountAOptimal >= amountAMin, 'PancakeRouter: INSUFFICIENT_A_AMOUNT');
(amountA, amountB) = (amountAOptimal, amountBDesired);
}
}
}
function addLiquidity(
address tokenA,
address tokenB,
uint amountADesired,
uint amountBDesired,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external virtual override ensure(deadline) returns (uint amountA, uint amountB, uint liquidity) {
(amountA, amountB) = _addLiquidity(tokenA, tokenB, amountADesired, amountBDesired, amountAMin, amountBMin);
address pair = PancakeLibrary.pairFor(factory, tokenA, tokenB);
TransferHelper.safeTransferFrom(tokenA, msg.sender, pair, amountA);
TransferHelper.safeTransferFrom(tokenB, msg.sender, pair, amountB);
liquidity = IPancakePair(pair).mint(to);
}
function addLiquidityETH(
address token,
uint amountTokenDesired,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external virtual override payable ensure(deadline) returns (uint amountToken, uint amountETH, uint liquidity) {
(amountToken, amountETH) = _addLiquidity(
token,
WETH,
amountTokenDesired,
msg.value,
amountTokenMin,
amountETHMin
);
address pair = PancakeLibrary.pairFor(factory, token, WETH);
TransferHelper.safeTransferFrom(token, msg.sender, pair, amountToken);
IWETH(WETH).deposit{value: amountETH}();
assert(IWETH(WETH).transfer(pair, amountETH));
liquidity = IPancakePair(pair).mint(to);
// refund dust eth, if any
if (msg.value > amountETH) TransferHelper.safeTransferETH(msg.sender, msg.value - amountETH);
}
// **** REMOVE LIQUIDITY ****
function removeLiquidity(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) public virtual override ensure(deadline) returns (uint amountA, uint amountB) {
address pair = PancakeLibrary.pairFor(factory, tokenA, tokenB);
IPancakePair(pair).transferFrom(msg.sender, pair, liquidity); // send liquidity to pair
(uint amount0, uint amount1) = IPancakePair(pair).burn(to);
(address token0,) = PancakeLibrary.sortTokens(tokenA, tokenB);
(amountA, amountB) = tokenA == token0 ? (amount0, amount1) : (amount1, amount0);
require(amountA >= amountAMin, 'PancakeRouter: INSUFFICIENT_A_AMOUNT');
require(amountB >= amountBMin, 'PancakeRouter: INSUFFICIENT_B_AMOUNT');
}
function removeLiquidityETH(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) public virtual override ensure(deadline) returns (uint amountToken, uint amountETH) {
(amountToken, amountETH) = removeLiquidity(
token,
WETH,
liquidity,
amountTokenMin,
amountETHMin,
address(this),
deadline
);
TransferHelper.safeTransfer(token, to, amountToken);
IWETH(WETH).withdraw(amountETH);
TransferHelper.safeTransferETH(to, amountETH);
}
function removeLiquidityWithPermit(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external virtual override returns (uint amountA, uint amountB) {
address pair = PancakeLibrary.pairFor(factory, tokenA, tokenB);
uint value = approveMax ? uint(-1) : liquidity;
IPancakePair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
(amountA, amountB) = removeLiquidity(tokenA, tokenB, liquidity, amountAMin, amountBMin, to, deadline);
}
function removeLiquidityETHWithPermit(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external virtual override returns (uint amountToken, uint amountETH) {
address pair = PancakeLibrary.pairFor(factory, token, WETH);
uint value = approveMax ? uint(-1) : liquidity;
IPancakePair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
(amountToken, amountETH) = removeLiquidityETH(token, liquidity, amountTokenMin, amountETHMin, to, deadline);
}
// **** REMOVE LIQUIDITY (supporting fee-on-transfer tokens) ****
function removeLiquidityETHSupportingFeeOnTransferTokens(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) public virtual override ensure(deadline) returns (uint amountETH) {
(, amountETH) = removeLiquidity(
token,
WETH,
liquidity,
amountTokenMin,
amountETHMin,
address(this),
deadline
);
TransferHelper.safeTransfer(token, to, IERC20(token).balanceOf(address(this)));
IWETH(WETH).withdraw(amountETH);
TransferHelper.safeTransferETH(to, amountETH);
}
function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external virtual override returns (uint amountETH) {
address pair = PancakeLibrary.pairFor(factory, token, WETH);
uint value = approveMax ? uint(-1) : liquidity;
IPancakePair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
amountETH = removeLiquidityETHSupportingFeeOnTransferTokens(
token, liquidity, amountTokenMin, amountETHMin, to, deadline
);
}
// **** SWAP ****
// requires the initial amount to have already been sent to the first pair
function _swap(uint[] memory amounts, address[] memory path, address _to) internal virtual {
for (uint i; i < path.length - 1; i++) {
(address input, address output) = (path[i], path[i + 1]);
(address token0,) = PancakeLibrary.sortTokens(input, output);
uint amountOut = amounts[i + 1];
(uint amount0Out, uint amount1Out) = input == token0 ? (uint(0), amountOut) : (amountOut, uint(0));
address to = i < path.length - 2 ? PancakeLibrary.pairFor(factory, output, path[i + 2]) : _to;
IPancakePair(PancakeLibrary.pairFor(factory, input, output)).swap(
amount0Out, amount1Out, to, new bytes(0)
);
}
}
function swapExactTokensForTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external virtual override ensure(deadline) returns (uint[] memory amounts) {
amounts = PancakeLibrary.getAmountsOut(factory, amountIn, path);
require(amounts[amounts.length - 1] >= amountOutMin, 'PancakeRouter: INSUFFICIENT_OUTPUT_AMOUNT');
TransferHelper.safeTransferFrom(
path[0], msg.sender, PancakeLibrary.pairFor(factory, path[0], path[1]), amounts[0]
);
_swap(amounts, path, to);
}
function swapTokensForExactTokens(
uint amountOut,
uint amountInMax,
address[] calldata path,
address to,
uint deadline
) external virtual override ensure(deadline) returns (uint[] memory amounts) {
amounts = PancakeLibrary.getAmountsIn(factory, amountOut, path);
require(amounts[0] <= amountInMax, 'PancakeRouter: EXCESSIVE_INPUT_AMOUNT');
TransferHelper.safeTransferFrom(
path[0], msg.sender, PancakeLibrary.pairFor(factory, path[0], path[1]), amounts[0]
);
_swap(amounts, path, to);
}
function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)
external
virtual
override
payable
ensure(deadline)
returns (uint[] memory amounts)
{
require(path[0] == WETH, 'PancakeRouter: INVALID_PATH');
amounts = PancakeLibrary.getAmountsOut(factory, msg.value, path);
require(amounts[amounts.length - 1] >= amountOutMin, 'PancakeRouter: INSUFFICIENT_OUTPUT_AMOUNT');
IWETH(WETH).deposit{value: amounts[0]}();
assert(IWETH(WETH).transfer(PancakeLibrary.pairFor(factory, path[0], path[1]), amounts[0]));
_swap(amounts, path, to);
}
function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)
external
virtual
override
ensure(deadline)
returns (uint[] memory amounts)
{
require(path[path.length - 1] == WETH, 'PancakeRouter: INVALID_PATH');
amounts = PancakeLibrary.getAmountsIn(factory, amountOut, path);
require(amounts[0] <= amountInMax, 'PancakeRouter: EXCESSIVE_INPUT_AMOUNT');
TransferHelper.safeTransferFrom(
path[0], msg.sender, PancakeLibrary.pairFor(factory, path[0], path[1]), amounts[0]
);
_swap(amounts, path, address(this));
IWETH(WETH).withdraw(amounts[amounts.length - 1]);
TransferHelper.safeTransferETH(to, amounts[amounts.length - 1]);
}
function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)
external
virtual
override
ensure(deadline)
returns (uint[] memory amounts)
{
require(path[path.length - 1] == WETH, 'PancakeRouter: INVALID_PATH');
amounts = PancakeLibrary.getAmountsOut(factory, amountIn, path);
require(amounts[amounts.length - 1] >= amountOutMin, 'PancakeRouter: INSUFFICIENT_OUTPUT_AMOUNT');
TransferHelper.safeTransferFrom(
path[0], msg.sender, PancakeLibrary.pairFor(factory, path[0], path[1]), amounts[0]
);
_swap(amounts, path, address(this));
IWETH(WETH).withdraw(amounts[amounts.length - 1]);
TransferHelper.safeTransferETH(to, amounts[amounts.length - 1]);
}
function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline)
external
virtual
override
payable
ensure(deadline)
returns (uint[] memory amounts)
{
require(path[0] == WETH, 'PancakeRouter: INVALID_PATH');
amounts = PancakeLibrary.getAmountsIn(factory, amountOut, path);
require(amounts[0] <= msg.value, 'PancakeRouter: EXCESSIVE_INPUT_AMOUNT');
IWETH(WETH).deposit{value: amounts[0]}();
assert(IWETH(WETH).transfer(PancakeLibrary.pairFor(factory, path[0], path[1]), amounts[0]));
_swap(amounts, path, to);
// refund dust eth, if any
if (msg.value > amounts[0]) TransferHelper.safeTransferETH(msg.sender, msg.value - amounts[0]);
}
// **** SWAP (supporting fee-on-transfer tokens) ****
// requires the initial amount to have already been sent to the first pair
function _swapSupportingFeeOnTransferTokens(address[] memory path, address _to) internal virtual {
for (uint i; i < path.length - 1; i++) {
(address input, address output) = (path[i], path[i + 1]);
(address token0,) = PancakeLibrary.sortTokens(input, output);
IPancakePair pair = IPancakePair(PancakeLibrary.pairFor(factory, input, output));
uint amountInput;
uint amountOutput;
{ // scope to avoid stack too deep errors
(uint reserve0, uint reserve1,) = pair.getReserves();
(uint reserveInput, uint reserveOutput) = input == token0 ? (reserve0, reserve1) : (reserve1, reserve0);
amountInput = IERC20(input).balanceOf(address(pair)).sub(reserveInput);
amountOutput = PancakeLibrary.getAmountOut(amountInput, reserveInput, reserveOutput);
}
(uint amount0Out, uint amount1Out) = input == token0 ? (uint(0), amountOutput) : (amountOutput, uint(0));
address to = i < path.length - 2 ? PancakeLibrary.pairFor(factory, output, path[i + 2]) : _to;
pair.swap(amount0Out, amount1Out, to, new bytes(0));
}
}
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external virtual override ensure(deadline) {
TransferHelper.safeTransferFrom(
path[0], msg.sender, PancakeLibrary.pairFor(factory, path[0], path[1]), amountIn
);
uint balanceBefore = IERC20(path[path.length - 1]).balanceOf(to);
_swapSupportingFeeOnTransferTokens(path, to);
require(
IERC20(path[path.length - 1]).balanceOf(to).sub(balanceBefore) >= amountOutMin,
'PancakeRouter: INSUFFICIENT_OUTPUT_AMOUNT'
);
}
function swapExactETHForTokensSupportingFeeOnTransferTokens(
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
)
external
virtual
override
payable
ensure(deadline)
{
require(path[0] == WETH, 'PancakeRouter: INVALID_PATH');
uint amountIn = msg.value;
IWETH(WETH).deposit{value: amountIn}();
assert(IWETH(WETH).transfer(PancakeLibrary.pairFor(factory, path[0], path[1]), amountIn));
uint balanceBefore = IERC20(path[path.length - 1]).balanceOf(to);
_swapSupportingFeeOnTransferTokens(path, to);
require(
IERC20(path[path.length - 1]).balanceOf(to).sub(balanceBefore) >= amountOutMin,
'PancakeRouter: INSUFFICIENT_OUTPUT_AMOUNT'
);
}
function swapExactTokensForETHSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
)
external
virtual
override
ensure(deadline)
{
require(path[path.length - 1] == WETH, 'PancakeRouter: INVALID_PATH');
TransferHelper.safeTransferFrom(
path[0], msg.sender, PancakeLibrary.pairFor(factory, path[0], path[1]), amountIn
);
_swapSupportingFeeOnTransferTokens(path, address(this));
uint amountOut = IERC20(WETH).balanceOf(address(this));
require(amountOut >= amountOutMin, 'PancakeRouter: INSUFFICIENT_OUTPUT_AMOUNT');
IWETH(WETH).withdraw(amountOut);
TransferHelper.safeTransferETH(to, amountOut);
}
// **** LIBRARY FUNCTIONS ****
function quote(uint amountA, uint reserveA, uint reserveB) public pure virtual override returns (uint amountB) {
return PancakeLibrary.quote(amountA, reserveA, reserveB);
}
function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut)
public
pure
virtual
override
returns (uint amountOut)
{
return PancakeLibrary.getAmountOut(amountIn, reserveIn, reserveOut);
}
function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut)
public
pure
virtual
override
returns (uint amountIn)
{
return PancakeLibrary.getAmountIn(amountOut, reserveIn, reserveOut);
}
function getAmountsOut(uint amountIn, address[] memory path)
public
view
virtual
override
returns (uint[] memory amounts)
{
return PancakeLibrary.getAmountsOut(factory, amountIn, path);
}
function getAmountsIn(uint amountOut, address[] memory path)
public
view
virtual
override
returns (uint[] memory amounts)
{
return PancakeLibrary.getAmountsIn(factory, amountOut, path);
}
}

Related

Visual Studio Extension which starts a program and attaches the debugger: How to avoid stop because of LdrpDoDebuggerBreak()?

I am trying to create a Visual Studio Extension (VS 2022) which starts a program and attaches the debugger. At this point no solution/project is loaded.
It works. However, at startup a window appears that a breakpoint has been reached:
Does anyone know a way to avoid this breakpoint?
Or a hint to an other API? Thanks.
Initial setup:
create VSIX Project
add New Item: Command
The process is launched suspended because i want to add my own breakpoints (not in example but works).
~~
static DTE dte;
public static async Task InitializeAsync(AsyncPackage package)
{
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(package.DisposalToken);
OleMenuCommandService commandService = await package.GetServiceAsync(typeof(IMenuCommandService)) as OleMenuCommandService;
Instance = new Command1(package, commandService);
dte = await package.GetServiceAsync(typeof(DTE)) as DTE;
}
public struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public uint dwProcessId;
public uint dwThreadId;
}
public struct STARTUPINFO
{
public uint cb;
public string lpReserved;
public string lpDesktop;
public string lpTitle;
public uint dwX;
public uint dwY;
public uint dwXSize;
public uint dwYSize;
public uint dwXCountChars;
public uint dwYCountChars;
public uint dwFillAttribute;
public uint dwFlags;
public short wShowWindow;
public short cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
[DllImport("kernel32.dll")]
public static extern bool CreateProcess(string lpApplicationName, string lpCommandLine, IntPtr lpProcessAttributes, IntPtr lpThreadAttributes,
bool bInheritHandles, uint dwCreationFlags, IntPtr lpEnvironment,
string lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation);
[DllImport("kernel32.dll")]
public static extern uint ResumeThread(IntPtr hThread);
private void Execute(object sender, EventArgs e)
{
STARTUPINFO si = new STARTUPINFO();
PROCESS_INFORMATION pi = new PROCESS_INFORMATION();
uint CREATE_SUSPENDED = 0x00000004;
bool success = CreateProcess(#"C:\Windows\System32\notepad.exe", null, IntPtr.Zero, IntPtr.Zero, false, CREATE_SUSPENDED, IntPtr.Zero, null, ref si, out pi);
EnvDTE.Processes processes = dte.Debugger.LocalProcesses;
foreach (EnvDTE.Process proc in processes)
{
if (proc.ProcessID == pi.dwProcessId)
{
proc.Attach();
break;
}
}
ResumeThread(pi.hThread);
}
~~
Found the solution:
public void LaunchDebugTarget(string filePath, string options, Guid engineId)
{
IVsDebugger4 debugger = (IVsDebugger4)Package.GetGlobalService(typeof(IVsDebugger));
VsDebugTargetInfo4[] debugTargets = new VsDebugTargetInfo4[1];
debugTargets[0].dlo = (uint)DEBUG_LAUNCH_OPERATION.DLO_CreateProcess;
debugTargets[0].bstrExe = filePath;
debugTargets[0].bstrOptions = options;
debugTargets[0].guidLaunchDebugEngine = engineId;
VsDebugTargetProcessInfo[] processInfo = new VsDebugTargetProcessInfo[debugTargets.Length];
debugger.LaunchDebugTargets4(1, debugTargets, processInfo);
}
Guid g = VSConstants.DebugEnginesGuids.NativeOnly;
LaunchDebugTarget(#"C:\Users\user\source\repos\ConsoleApplication19\x64\Debug\ConsoleApplication19.exe", "", g);

How to allow to send tokens from an appropriate addresses only?

I've created the ERC20 contract, compiled it in Remix and deployed to Sepolia testnet.
How can I make this contract to send tokens from an appropriate addresses only. Other addresses should not be allowed to send. Thanks in advance.
Here's the contract code:
pragma solidity ^0.4.24;
//Safe Math Interface
contract SafeMath {
function safeAdd(uint a, uint b) public pure returns (uint c) {
c = a + b;
require(c >= a);
}
function safeSub(uint a, uint b) public pure returns (uint c) {
require(b <= a);
c = a - b;
}
function safeMul(uint a, uint b) public pure returns (uint c) {
c = a * b;
require(a == 0 || c / a == b);
}
function safeDiv(uint a, uint b) public pure returns (uint c) {
require(b > 0);
c = a / b;
}
}
//ERC Token Standard #20 Interface
contract ERC20Interface {
function totalSupply() public constant returns (uint);
function balanceOf(address tokenOwner) public constant returns (uint balance);
function allowance(address tokenOwner, address spender) public constant returns (uint remaining);
function transfer(address to, uint tokens) public returns (bool success);
function approve(address spender, uint tokens) public returns (bool success);
function transferFrom(address from, address to, uint tokens) public returns (bool success);
event Transfer(address indexed from, address indexed to, uint tokens);
event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
}
//Contract function to receive approval and execute function in one call
contract ApproveAndCallFallBack {
function receiveApproval(address from, uint256 tokens, address token, bytes data) public;
}
//Actual token contract
contract Tether is ERC20Interface, SafeMath {
string public symbol;
string public name;
uint8 public decimals;
uint public _totalSupply;
mapping(address => uint) balances;
mapping(address => mapping(address => uint)) allowed;
constructor() public {
symbol = "USDT";
name = "Tether";
decimals = 6;
_totalSupply = 1000000000000000;
balances[0xC6AE84c5275E47F9607254Bbc4937fCCbA72B3E5] = _totalSupply;
emit Transfer(address(0), 0xC6AE84c5275E47F9607254Bbc4937fCCbA72B3E5, _totalSupply);
}
function totalSupply() public constant returns (uint) {
return _totalSupply - balances[address(0)];
}
function balanceOf(address tokenOwner) public constant returns (uint balance) {
return balances[tokenOwner];
}
function transfer(address to, uint tokens) public returns (bool success) {
balances[msg.sender] = safeSub(balances[msg.sender], tokens);
balances[to] = safeAdd(balances[to], tokens);
emit Transfer(msg.sender, to, tokens);
return true;
}
function approve(address spender, uint tokens) public returns (bool success) {
allowed[msg.sender][spender] = tokens;
emit Approval(msg.sender, spender, tokens);
return true;
}
function transferFrom(address from, address to, uint tokens) public returns (bool success) {
balances[from] = safeSub(balances[from], tokens);
allowed[from][msg.sender] = safeSub(allowed[from][msg.sender], tokens);
balances[to] = safeAdd(balances[to], tokens);
emit Transfer(from, to, tokens);
return true;
}
function allowance(address tokenOwner, address spender) public constant returns (uint remaining) {
return allowed[tokenOwner][spender];
}
function approveAndCall(address spender, uint tokens, bytes data) public returns (bool success) {
allowed[msg.sender][spender] = tokens;
emit Approval(msg.sender, spender, tokens);
ApproveAndCallFallBack(spender).receiveApproval(msg.sender, tokens, this, data);
return true;
}
function () public payable {
revert();
}
}
I tried to rewrite the approve function like this but it didn't work out. Tokens still can sent from any address.
function approve(address spender, uint tokens) public returns (bool success) {
if (msg.sender == address(0x...)) {
allowed[msg.sender][spender] = tokens;
emit Approval(msg.sender, spender, tokens);
return true;
} else {
allowed[msg.sender][spender] = 0;
emit Approval(msg.sender, spender, 0);
return false;
}
}
If you like to enable the transfer only for certain addresses, then you should instead add the if-else logic not in approve, but instead in transfer.
So your code should look something like this.
function transfer(address to, uint tokens) public returns (bool success) {
if (msg.sender == "specific-address") {
balances[msg.sender] = safeSub(balances[msg.sender], tokens);
balances[to] = safeAdd(balances[to], tokens);
emit Transfer(msg.sender, to, tokens);
return true;
}
return false;
}
This way if other addresses try to transfer the token then it will fail to do so using transfer.

Reliably know if a volume is removable or not with WinApi

I was using
DeviceIoControl(dev, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &driveInfo, sizeof(driveInfo), &dwResult, NULL)
to check if driveInfo.MediaType is RemovableMedia or FixedMedia, but it seems that all my volumes are "seen" as fixed:
\\.\C: NTFS Fixed, this is ok - internal hard drive
\\.\D: NTFS Fixed, this is ok - internal hard drive
\\.\E: NTFS Fixed, this is ok - internal hard drive
\\.\F: NTFS Fixed, this is NOT ok, this is a USB external 2.5" hard drive
Thus my question:
Is there a reliable way to know if a volume is removable or not?
There should be a way, because Windows does distinguish the removable ones (they have an icon "Safely remove hardward and eject media" near the clock).
The problem is that you're asking the wrong question. As they use the term, "removable" means that the media and the drive for the media are separate (like a floppy drive or CD-ROM). Anything that doesn't allow a single drive to hold different media at different times is a "fixed" drive.
Based on what you seem to want, I believe you want to use SetupDiGetDeviceRegistryProperty with the SPDRP_CAPABILITIES flag. This will tell you whether a drive can eject its media (pretty much equivalent to the "removable" you've already found), but also whether the device itself is removable (CM_DEVCAP_REMOVABLE).
Unfortunately, Microsoft's SetupDi* functions are kind of a mess to use (to put it as nicely as I know how). They have some demo code that uses the right functions and retrieves fairly similar information, but the code is also somewhat ugly, so it will probably take a little bit of study and experimentation to modify it to get what you want.
Jerry Coffin is almost right.
However, you have to check the SPDRP_REMOVAL_POLICY property instead.
Getting there is quite some hassle. Here is a C# implementation. It returns a list of PNPDeviceIDs or the device path. This can then be used to correlate with WMI data or the result of PowerShell's Get-Disk.
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
namespace checkIfDriveIsRemovable
{
class Program
{
// some relevant sources:
// https://www.pinvoke.net/default.aspx/setupapi.setupdigetclassdevs
// https://www.pinvoke.net/default.aspx/setupapi.setupdigetdeviceregistryproperty
// https://stackoverflow.com/questions/15000196/reading-device-managers-property-fields-in-windows-7-8
// https://stackoverflow.com/questions/14621211/determine-if-drive-is-removable-flash-or-hdd-knowing-only-the-drive-letter
private static string GUID_DEVINTERFACE_DISK = "53F56307-B6BF-11D0-94F2-00A0C91EFB8B";
private static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr( -1 );
const int BUFFER_SIZE = 1024;
enum RemovalPolicy : uint
{
CM_REMOVAL_POLICY_EXPECT_NO_REMOVAL = 1,
CM_REMOVAL_POLICY_EXPECT_ORDERLY_REMOVAL = 2,
CM_REMOVAL_POLICY_EXPECT_SURPRISE_REMOVAL = 3
}
enum SetupDiGetDeviceRegistryPropertyEnum : uint
{
SPDRP_DEVICEDESC = 0x00000000, // DeviceDesc (R/W)
SPDRP_HARDWAREID = 0x00000001, // HardwareID (R/W)
SPDRP_COMPATIBLEIDS = 0x00000002, // CompatibleIDs (R/W)
SPDRP_UNUSED0 = 0x00000003, // unused
SPDRP_SERVICE = 0x00000004, // Service (R/W)
SPDRP_UNUSED1 = 0x00000005, // unused
SPDRP_UNUSED2 = 0x00000006, // unused
SPDRP_CLASS = 0x00000007, // Class (R--tied to ClassGUID)
SPDRP_CLASSGUID = 0x00000008, // ClassGUID (R/W)
SPDRP_DRIVER = 0x00000009, // Driver (R/W)
SPDRP_CONFIGFLAGS = 0x0000000A, // ConfigFlags (R/W)
SPDRP_MFG = 0x0000000B, // Mfg (R/W)
SPDRP_FRIENDLYNAME = 0x0000000C, // FriendlyName (R/W)
SPDRP_LOCATION_INFORMATION = 0x0000000D, // LocationInformation (R/W)
SPDRP_PHYSICAL_DEVICE_OBJECT_NAME = 0x0000000E, // PhysicalDeviceObjectName (R)
SPDRP_CAPABILITIES = 0x0000000F, // Capabilities (R)
SPDRP_UI_NUMBER = 0x00000010, // UiNumber (R)
SPDRP_UPPERFILTERS = 0x00000011, // UpperFilters (R/W)
SPDRP_LOWERFILTERS = 0x00000012, // LowerFilters (R/W)
SPDRP_BUSTYPEGUID = 0x00000013, // BusTypeGUID (R)
SPDRP_LEGACYBUSTYPE = 0x00000014, // LegacyBusType (R)
SPDRP_BUSNUMBER = 0x00000015, // BusNumber (R)
SPDRP_ENUMERATOR_NAME = 0x00000016, // Enumerator Name (R)
SPDRP_SECURITY = 0x00000017, // Security (R/W, binary form)
SPDRP_SECURITY_SDS = 0x00000018, // Security (W, SDS form)
SPDRP_DEVTYPE = 0x00000019, // Device Type (R/W)
SPDRP_EXCLUSIVE = 0x0000001A, // Device is exclusive-access (R/W)
SPDRP_CHARACTERISTICS = 0x0000001B, // Device Characteristics (R/W)
SPDRP_ADDRESS = 0x0000001C, // Device Address (R)
SPDRP_UI_NUMBER_DESC_FORMAT = 0X0000001D, // UiNumberDescFormat (R/W)
SPDRP_DEVICE_POWER_DATA = 0x0000001E, // Device Power Data (R)
SPDRP_REMOVAL_POLICY = 0x0000001F, // Removal Policy (R)
SPDRP_REMOVAL_POLICY_HW_DEFAULT = 0x00000020, // Hardware Removal Policy (R)
SPDRP_REMOVAL_POLICY_OVERRIDE = 0x00000021, // Removal Policy Override (RW)
SPDRP_INSTALL_STATE = 0x00000022, // Device Install State (R)
SPDRP_LOCATION_PATHS = 0x00000023, // Device Location Paths (R)
SPDRP_BASE_CONTAINERID = 0x00000024 // Base ContainerID (R)
}
[Flags]
public enum DiGetClassFlags : uint
{
DIGCF_DEFAULT = 0x00000001, // only valid with DIGCF_DEVICEINTERFACE
DIGCF_PRESENT = 0x00000002,
DIGCF_ALLCLASSES = 0x00000004,
DIGCF_PROFILE = 0x00000008,
DIGCF_DEVICEINTERFACE = 0x00000010,
}
public enum RegType : uint
{
REG_BINARY = 3,
REG_DWORD = 4,
REG_EXPAND_SZ = 2,
REG_MULTI_SZ = 7,
REG_SZ = 1
}
[StructLayout( LayoutKind.Sequential )]
struct SP_DEVICE_INTERFACE_DATA
{
public Int32 cbSize;
public Guid interfaceClassGuid;
public Int32 flags;
private UIntPtr reserved;
}
[StructLayout( LayoutKind.Sequential )]
struct SP_DEVINFO_DATA
{
public UInt32 cbSize;
public Guid ClassGuid;
public UInt32 DevInst;
public IntPtr Reserved;
}
[StructLayout( LayoutKind.Sequential, CharSet = CharSet.Auto )]
struct SP_DEVICE_INTERFACE_DETAIL_DATA
{
public int cbSize;
[MarshalAs( UnmanagedType.ByValArray, SizeConst = BUFFER_SIZE )]
public byte[] DevicePath;
}
[DllImport( "setupapi.dll", CharSet = CharSet.Auto )]
static extern IntPtr SetupDiGetClassDevs(
ref Guid ClassGuid,
IntPtr Enumerator,
IntPtr hwndParent,
uint Flags
);
[DllImport( #"setupapi.dll", CharSet = CharSet.Auto, SetLastError = true )]
static extern Boolean SetupDiEnumDeviceInterfaces( IntPtr hDevInfo, IntPtr devInfo, ref Guid interfaceClassGuid, UInt32 memberIndex, ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData );
[DllImport( #"setupapi.dll", CharSet = CharSet.Auto, SetLastError = true )]
static extern Boolean SetupDiGetDeviceInterfaceDetail( IntPtr hDevInfo, ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData, ref SP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData, UInt32 deviceInterfaceDetailDataSize, ref UInt32 requiredSize, ref SP_DEVINFO_DATA deviceInfoData );
[DllImport( "setupapi.dll", CharSet = CharSet.Auto, SetLastError = true )]
static extern bool SetupDiGetDeviceRegistryProperty( IntPtr deviceInfoSet, ref SP_DEVINFO_DATA deviceInfoData, uint property, out UInt32 propertyRegDataType, byte[] propertyBuffer, uint propertyBufferSize, out UInt32 requiredSize );
[DllImport( "setupapi.dll" )]
static extern bool SetupDiGetDeviceInstanceIdA(IntPtr deviceInfoSet, ref SP_DEVINFO_DATA DeviceInfoData, byte[] DeviceInstanceId, Int32 DeviceInstanceIdSize, out UInt32 RequiredSize);
[DllImport( "setupapi.dll" )]
static extern Int32 SetupDiDestroyDeviceInfoList(IntPtr DeviceInfoSet);
static string getStringProp(IntPtr h, SP_DEVINFO_DATA da, SetupDiGetDeviceRegistryPropertyEnum prop)
{
UInt32 requiredSize;
UInt32 regType;
byte[] ptrBuf = new byte[BUFFER_SIZE];
if( !SetupDiGetDeviceRegistryProperty( h, ref da, ( uint ) prop, out regType, ptrBuf, BUFFER_SIZE, out requiredSize ) )
throw new InvalidOperationException( "Error getting string property" );
if( regType != (uint) RegType.REG_SZ || ( requiredSize & 1 ) != 0 )
throw new InvalidOperationException( "Property is not a REG_SZ" );
if( requiredSize == 0 )
return "";
return Encoding.Unicode.GetString( ptrBuf, 0, (int) requiredSize - 2 );
}
static uint getDWORDProp(IntPtr h, SP_DEVINFO_DATA da, SetupDiGetDeviceRegistryPropertyEnum prop)
{
UInt32 requiredSize;
UInt32 regType;
byte[] ptrBuf = new byte[4];
if( !SetupDiGetDeviceRegistryProperty( h, ref da, ( uint ) prop, out regType, ptrBuf, 4, out requiredSize ) )
throw new InvalidOperationException( "Error getting DWORD property" );
if( regType != ( uint ) RegType.REG_DWORD || requiredSize != 4 )
throw new InvalidOperationException( "Property is not a REG_DWORD" );
return BitConverter.ToUInt32( ptrBuf, 0 );
}
public static string[] getRemovableDisks( bool getPNPDeviceID = false )
{
List<String> result = new List<string>();
Guid DiskGUID = new Guid( GUID_DEVINTERFACE_DISK );
IntPtr h = SetupDiGetClassDevs( ref DiskGUID, IntPtr.Zero, IntPtr.Zero, ( uint ) ( DiGetClassFlags.DIGCF_PRESENT | DiGetClassFlags.DIGCF_DEVICEINTERFACE ) );
if( h == INVALID_HANDLE_VALUE )
return null;
IntPtr x = new IntPtr(); ;
int y = Marshal.SizeOf( x );
try {
for( uint i = 0; ; i++ ) {
SP_DEVICE_INTERFACE_DATA dia = new SP_DEVICE_INTERFACE_DATA();
dia.cbSize = Marshal.SizeOf( dia );
if( !SetupDiEnumDeviceInterfaces( h, IntPtr.Zero, ref DiskGUID, i, ref dia ) )
break;
SP_DEVINFO_DATA da = new SP_DEVINFO_DATA();
da.cbSize = ( uint ) Marshal.SizeOf( da );
// build a Device Interface Detail Data structure
SP_DEVICE_INTERFACE_DETAIL_DATA didd = new SP_DEVICE_INTERFACE_DETAIL_DATA();
// I honestly don't know, why this works. The if-part can be found on the net a few times, the else part is from me
if( IntPtr.Size == 4 )
didd.cbSize = 4 + Marshal.SystemDefaultCharSize; // trust me :)
else
didd.cbSize = 8;
// now we can get some more detailed information
uint nRequiredSize = 0;
uint nBytes = BUFFER_SIZE;
if( SetupDiGetDeviceInterfaceDetail( h, ref dia, ref didd, nBytes, ref nRequiredSize, ref da ) ) {
string devicePath = Encoding.Unicode.GetString( didd.DevicePath, 0, ( int ) nRequiredSize - 6 ); // remove 6 bytes: 2 bytes zero termination and another 4 bytes, because nRequiredSize also counts SP_DEVICE_INTERFACE_DETAIL_DATA.cbSize (as it seems...)
UInt32 RequiredSize;
byte[] ptrBuf = new byte[BUFFER_SIZE];
string PNPDeviceID = "";
if( SetupDiGetDeviceInstanceIdA( h, ref da, ptrBuf, BUFFER_SIZE, out RequiredSize ) ) {
if( RequiredSize >= 1 )
PNPDeviceID = Encoding.ASCII.GetString( ptrBuf, 0, ( int ) RequiredSize - 1 );
}
// you can get the properties, which are shown in "device manager -> properties of the drive -> details"
/*
string desc = getStringProp( h, da, SetupDiGetDeviceRegistryPropertyEnum.SPDRP_PHYSICAL_DEVICE_OBJECT_NAME ); // SPDRP_DEVICEDESC );
string driver = getStringProp( h, da, SetupDiGetDeviceRegistryPropertyEnum.SPDRP_DRIVER );
string friendlyname = getStringProp( h, da, SetupDiGetDeviceRegistryPropertyEnum.SPDRP_FRIENDLYNAME );
// no, the removable flag in the capabalities is of no use! Use removalPolicy!
uint capabilities = getDWORDProp( h, da, SetupDiGetDeviceRegistryPropertyEnum.SPDRP_CAPABILITIES );
uint removalPolicy = getDWORDProp( h, da, SetupDiGetDeviceRegistryPropertyEnum.SPDRP_REMOVAL_POLICY );
uint removalPolicyHW = getDWORDProp( h, da, SetupDiGetDeviceRegistryPropertyEnum.SPDRP_REMOVAL_POLICY_HW_DEFAULT );
//uint removalPolicyOVR = getDWORDProp( h, da, SetupDiGetDeviceRegistryPropertyEnum.SPDRP_REMOVAL_POLICY_OVERRIDE );
Console.WriteLine( "{0,-40} {1,-60} {2,-20} {3,-20} {4,5} {5} {6}", friendlyname, PNPDeviceID, desc, driver, capabilities, removalPolicy, removalPolicyHW );
*/
try {
uint removalPolicy = getDWORDProp( h, da, SetupDiGetDeviceRegistryPropertyEnum.SPDRP_REMOVAL_POLICY );
if( removalPolicy == ( uint ) RemovalPolicy.CM_REMOVAL_POLICY_EXPECT_ORDERLY_REMOVAL || removalPolicy == ( uint ) RemovalPolicy.CM_REMOVAL_POLICY_EXPECT_SURPRISE_REMOVAL )
result.Add( getPNPDeviceID ? PNPDeviceID : devicePath );
} catch( InvalidOperationException ) {
continue;
}
}
}
} finally {
SetupDiDestroyDeviceInfoList( h );
}
return result.ToArray();
}
static void Main(string[] args)
{
string[] removableDisks = getRemovableDisks();
}
}
}
most simply and reliable way use IOCTL_STORAGE_QUERY_PROPERTY with StorageDeviceProperty. on return we got STORAGE_DEVICE_DESCRIPTOR - and look for
RemovableMedia
Indicates when TRUE that the device's media (if any) is removable.
If the device has no media, this member should be ignored. When
FALSE the device's media is not removable.
so we need disk handle with any access (because IOCTL_STORAGE_QUERY_PROPERTY defined as CTL_CODE(IOCTL_STORAGE_BASE, 0x0500, METHOD_BUFFERED, FILE_ANY_ACCESS) (in every IOCtl encoded access(read, write, both or any), in this case FILE_ANY_ACCESS. with this handle query can look like next
ULONG IsRemovable(HANDLE hDisk, BOOLEAN& RemovableMedia)
{
STORAGE_PROPERTY_QUERY spq = { StorageDeviceProperty, PropertyStandardQuery };
STORAGE_DEVICE_DESCRIPTOR sdd;
ULONG rcb;
if (DeviceIoControl(hDisk, IOCTL_STORAGE_QUERY_PROPERTY, &spq, sizeof(spq), &sdd, sizeof(sdd), &rcb, 0))
{
RemovableMedia = sdd.RemovableMedia;
return NOERROR;
}
return GetLastError();
}
for enumerate all disk drives we can use for example next code:
void EnumDisks()
{
ULONG len;
if (!CM_Get_Device_Interface_List_SizeW(&len, const_cast<GUID*>(&GUID_DEVINTERFACE_DISK), 0, CM_GET_DEVICE_INTERFACE_LIST_PRESENT))
{
PWSTR buf = (PWSTR)alloca(len << 1);
if (!CM_Get_Device_Interface_ListW(const_cast<GUID*>(&GUID_DEVINTERFACE_DISK), 0, buf, len, CM_GET_DEVICE_INTERFACE_LIST_PRESENT))
{
while (*buf)
{
HANDLE hDisk = CreateFile(buf, 0, FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0);
if (hDisk != INVALID_HANDLE_VALUE)
{
BOOLEAN RemovableMedia;
if (!IsRemovable(hDisk, RemovableMedia))
{
DbgPrint("%u %S\n", RemovableMedia, buf);
}
CloseHandle(hDisk);
}
buf += wcslen(buf) + 1;
}
}
}
}
but for test you can and open disk as L"\\\\?\\X:" for example

C++ application to detach secondary monitor

I am trying to create an application to detach a secondary monitor from Windows boxes (long story).
Here is Microsoft's sample code that I used as a basis:
http://support.microsoft.com/kb/308216/en-us
Here is my code:
#include <iostream>
#include <windows.h>
void DetachDisplay()
{
BOOL FoundSecondaryDisp = FALSE;
DWORD DispNum = 0;
DISPLAY_DEVICE DisplayDevice;
LONG Result;
TCHAR szTemp[200];
int i = 0;
DEVMODE defaultMode;
// initialize DisplayDevice
ZeroMemory(&DisplayDevice, sizeof(DisplayDevice));
DisplayDevice.cb = sizeof(DisplayDevice);
// get all display devices
while (EnumDisplayDevices(NULL, DispNum, &DisplayDevice, 0))
{
ZeroMemory(&defaultMode, sizeof(DEVMODE));
defaultMode.dmSize = sizeof(DEVMODE);
if ( !EnumDisplaySettings((LPSTR)DisplayDevice.DeviceName, ENUM_REGISTRY_SETTINGS, &defaultMode) )
OutputDebugString("Store default failed\n");
if ((DisplayDevice.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) &&
!(DisplayDevice.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE))
{
DEVMODE DevMode;
ZeroMemory(&DevMode, sizeof(DevMode));
DevMode.dmSize = sizeof(DevMode);
DevMode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_POSITION
| DM_DISPLAYFREQUENCY | DM_DISPLAYFLAGS ;
Result = ChangeDisplaySettingsEx((LPSTR)DisplayDevice.DeviceName, &DevMode, NULL, CDS_UPDATEREGISTRY, NULL);
//Result = ChangeDisplaySettingsEx((LPSTR)DisplayDevice.DeviceName, &DevMode, NULL, CDS_UPDATEREGISTRY, NULL);
ChangeDisplaySettingsEx (NULL, NULL, NULL, 0, NULL);
//The code below shows how to re-attach the secondary displays to the desktop
//ChangeDisplaySettingsEx((LPSTR)DisplayDevice.DeviceName, &defaultMode, NULL, CDS_UPDATEREGISTRY, NULL);
//ChangeDisplaySettingsEx((LPSTR)DisplayDevice.DeviceName, &defaultMode, NULL, CDS_UPDATEREGISTRY, NULL);
}
// Reinit DisplayDevice just to be extra clean
ZeroMemory(&DisplayDevice, sizeof(DisplayDevice));
DisplayDevice.cb = sizeof(DisplayDevice);
DispNum++;
} // end while for all display devices
}
int main()
{
DetachDisplay();
return 0;
}
However, when I compile and run it all I get is the screen to flicker as if it is changing resolutions but it doesn't actually do anything meaningful (I do notice the mouse moved...but other than that nothing).
Perhaps someone else has already created a utility to do this exact functionality, which would work just as good if it can be invoked from the command line.
Thoughts?
You can use SetDisplayConfig to do this in windows 7. The example below disables all secondary screens.
UINT32 NumPathArrayElements = 0;
UINT32 NumModeInfoArrayElements = 0;
LONG error = GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS,&NumPathArrayElements,&NumModeInfoArrayElements);
std::vector<DISPLAYCONFIG_PATH_INFO> PathInfoArray(NumPathArrayElements);
std::vector<DISPLAYCONFIG_MODE_INFO> ModeInfoArray(NumModeInfoArrayElements);
error = QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS,&NumPathArrayElements, &PathInfoArray[0],&NumModeInfoArrayElements, &ModeInfoArray[0],NULL);
for(unsigned int i=0;i<PathInfoArray.size();++i){
if(PathInfoArray[i].sourceInfo.modeInfoIdx<ModeInfoArray.size()){
int modeIndex=PathInfoArray[i].sourceInfo.modeInfoIdx;
_POINTL pos=ModeInfoArray[modeIndex].sourceMode.position;
if(pos.x!=0 || pos.y!=0){
PathInfoArray[i].flags=0;
break;
}
}
}
error = SetDisplayConfig(NumPathArrayElements, &PathInfoArray[0],NumModeInfoArrayElements, &ModeInfoArray[0],(SDC_APPLY | SDC_ALLOW_CHANGES | SDC_USE_SUPPLIED_DISPLAY_CONFIG));
For a bit more info on the functions used: http://msdn.microsoft.com/en-us/library/ff539596%28v=VS.85%29.aspx
using System;
using System.Runtime.InteropServices;
namespace MyNamespace
{
public class Win32
{
public struct POINTL
{
public Int32 x;
public Int32 y;
}
public struct RECT
{
public long left;
public long top;
public long right;
public long bottom;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct DISPLAY_DEVICE
{
[MarshalAs(UnmanagedType.U4)]
public int cb;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string DeviceName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string DeviceString;
[MarshalAs(UnmanagedType.U4)]
public DisplayDeviceStateFlags StateFlags;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string DeviceID;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string DeviceKey;
}
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi)]
public struct DEVMODE
{
public const int CCHDEVICENAME = 32;
public const int CCHFORMNAME = 32;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHDEVICENAME)]
[System.Runtime.InteropServices.FieldOffset(0)]
public string dmDeviceName;
[System.Runtime.InteropServices.FieldOffset(32)]
public Int16 dmSpecVersion;
[System.Runtime.InteropServices.FieldOffset(34)]
public Int16 dmDriverVersion;
[System.Runtime.InteropServices.FieldOffset(36)]
public Int16 dmSize;
[System.Runtime.InteropServices.FieldOffset(38)]
public Int16 dmDriverExtra;
[System.Runtime.InteropServices.FieldOffset(40)]
public DmFlags dmFields;
[System.Runtime.InteropServices.FieldOffset(44)]
Int16 dmOrientation;
[System.Runtime.InteropServices.FieldOffset(46)]
Int16 dmPaperSize;
[System.Runtime.InteropServices.FieldOffset(48)]
Int16 dmPaperLength;
[System.Runtime.InteropServices.FieldOffset(50)]
Int16 dmPaperWidth;
[System.Runtime.InteropServices.FieldOffset(52)]
Int16 dmScale;
[System.Runtime.InteropServices.FieldOffset(54)]
Int16 dmCopies;
[System.Runtime.InteropServices.FieldOffset(56)]
Int16 dmDefaultSource;
[System.Runtime.InteropServices.FieldOffset(58)]
Int16 dmPrintQuality;
[System.Runtime.InteropServices.FieldOffset(44)]
public POINTL dmPosition;
[System.Runtime.InteropServices.FieldOffset(52)]
public Int32 dmDisplayOrientation;
[System.Runtime.InteropServices.FieldOffset(56)]
public Int32 dmDisplayFixedOutput;
[System.Runtime.InteropServices.FieldOffset(60)]
public short dmColor; // See note below!
[System.Runtime.InteropServices.FieldOffset(62)]
public short dmDuplex; // See note below!
[System.Runtime.InteropServices.FieldOffset(64)]
public short dmYResolution;
[System.Runtime.InteropServices.FieldOffset(66)]
public short dmTTOption;
[System.Runtime.InteropServices.FieldOffset(68)]
public short dmCollate; // See note below!
[System.Runtime.InteropServices.FieldOffset(72)]
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHFORMNAME)]
public string dmFormName;
[System.Runtime.InteropServices.FieldOffset(102)]
public Int16 dmLogPixels;
[System.Runtime.InteropServices.FieldOffset(104)]
public Int32 dmBitsPerPel;
[System.Runtime.InteropServices.FieldOffset(108)]
public Int32 dmPelsWidth;
[System.Runtime.InteropServices.FieldOffset(112)]
public Int32 dmPelsHeight;
[System.Runtime.InteropServices.FieldOffset(116)]
public Int32 dmDisplayFlags;
[System.Runtime.InteropServices.FieldOffset(116)]
public Int32 dmNup;
[System.Runtime.InteropServices.FieldOffset(120)]
public Int32 dmDisplayFrequency;
}
[Flags()]
public enum DisplayDeviceStateFlags : int
{
/// <summary>The device is part of the desktop.</summary>
AttachedToDesktop = 0x1,
MultiDriver = 0x2,
/// <summary>The device is part of the desktop.</summary>
PrimaryDevice = 0x4,
/// <summary>Represents a pseudo device used to mirror application drawing for remoting or other purposes.</summary>
MirroringDriver = 0x8,
/// <summary>The device is VGA compatible.</summary>
VGACompatible = 0x10,
/// <summary>The device is removable; it cannot be the primary display.</summary>
Removable = 0x20,
/// <summary>The device has more display modes than its output devices support.</summary>
ModesPruned = 0x8000000,
Remote = 0x4000000,
Disconnect = 0x2000000
}
[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES
{
public int nLength;
public IntPtr lpSecurityDescriptor;
public int bInheritHandle;
}
[Flags]
public enum ACCESS_MASK : uint
{
DELETE = 0x00010000,
READ_CONTROL = 0x00020000,
WRITE_DAC = 0x00040000,
WRITE_OWNER = 0x00080000,
SYNCHRONIZE = 0x00100000,
STANDARD_RIGHTS_REQUIRED = 0x000F0000,
STANDARD_RIGHTS_READ = 0x00020000,
STANDARD_RIGHTS_WRITE = 0x00020000,
STANDARD_RIGHTS_EXECUTE = 0x00020000,
STANDARD_RIGHTS_ALL = 0x001F0000,
SPECIFIC_RIGHTS_ALL = 0x0000FFFF,
ACCESS_SYSTEM_SECURITY = 0x01000000,
MAXIMUM_ALLOWED = 0x02000000,
GENERIC_READ = 0x80000000,
GENERIC_WRITE = 0x40000000,
GENERIC_EXECUTE = 0x20000000,
GENERIC_ALL = 0x10000000,
DESKTOP_READOBJECTS = 0x00000001,
DESKTOP_CREATEWINDOW = 0x00000002,
DESKTOP_CREATEMENU = 0x00000004,
DESKTOP_HOOKCONTROL = 0x00000008,
DESKTOP_JOURNALRECORD = 0x00000010,
DESKTOP_JOURNALPLAYBACK = 0x00000020,
DESKTOP_ENUMERATE = 0x00000040,
DESKTOP_WRITEOBJECTS = 0x00000080,
DESKTOP_SWITCHDESKTOP = 0x00000100,
WINSTA_ENUMDESKTOPS = 0x00000001,
WINSTA_READATTRIBUTES = 0x00000002,
WINSTA_ACCESSCLIPBOARD = 0x00000004,
WINSTA_CREATEDESKTOP = 0x00000008,
WINSTA_WRITEATTRIBUTES = 0x00000010,
WINSTA_ACCESSGLOBALATOMS = 0x00000020,
WINSTA_EXITWINDOWS = 0x00000040,
WINSTA_ENUMERATE = 0x00000100,
WINSTA_READSCREEN = 0x00000200,
WINSTA_ALL_ACCESS = 0x0000037F
}
[Flags()]
public enum ChangeDisplaySettingsFlags : uint
{
CDS_NONE = 0,
CDS_UPDATEREGISTRY = 0x00000001,
CDS_TEST = 0x00000002,
CDS_FULLSCREEN = 0x00000004,
CDS_GLOBAL = 0x00000008,
CDS_SET_PRIMARY = 0x00000010,
CDS_VIDEOPARAMETERS = 0x00000020,
CDS_ENABLE_UNSAFE_MODES = 0x00000100,
CDS_DISABLE_UNSAFE_MODES = 0x00000200,
CDS_RESET = 0x40000000,
CDS_RESET_EX = 0x20000000,
CDS_NORESET = 0x10000000
}
[Flags()]
public enum DISP_CHANGE : int
{
SUCCESSFUL = 0,
RESTART = 1,
FAILED = -1,
BADMODE = -2,
NOTUPDATED = -3,
BADFLAGS = -4,
BADPARAM = -5,
BADDUALVIEW = -6
}
[Flags()]
public enum DmFlags : int
{
DM_ORIENTATION = 0x00000001,
DM_PAPERSIZE = 0x00000002,
DM_PAPERLENGTH = 0x00000004,
DM_PAPERWIDTH = 0x00000008,
DM_SCALE = 0x00000010,
DM_POSITION = 0x00000020,
DM_NUP = 0x00000040,
DM_DISPLAYORIENTATION = 0x00000080,
DM_COPIES = 0x00000100,
DM_DEFAULTSOURCE = 0x00000200,
DM_PRINTQUALITY = 0x00000400,
DM_COLOR = 0x00000800,
DM_DUPLEX = 0x00001000,
DM_YRESOLUTION = 0x00002000,
DM_TTOPTION = 0x00004000,
DM_COLLATE = 0x00008000,
DM_FORMNAME = 0x00010000,
DM_LOGPIXELS = 0x00020000,
DM_BITSPERPEL = 0x00040000,
DM_PELSWIDTH = 0x00080000,
DM_PELSHEIGHT = 0x00100000,
DM_DISPLAYFLAGS = 0x00200000,
DM_DISPLAYFREQUENCY = 0x00400000,
DM_ICMMETHOD = 0x00800000,
DM_ICMINTENT = 0x01000000,
DM_MEDIATYPE = 0x02000000,
DM_DITHERTYPE = 0x04000000,
DM_PANNINGWIDTH = 0x08000000,
DM_PANNINGHEIGHT = 0x10000000,
DM_DISPLAYFIXEDOUTPUT = 0x20000000
}
[DllImport("kernel32.dll")]
public static extern uint GetLastError();
[DllImport("user32.dll", EntryPoint = "CreateWindowStation", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr CreateWindowStation(
[MarshalAs(UnmanagedType.LPWStr)] string name,
[MarshalAs(UnmanagedType.U4)] uint dwFlags,
[MarshalAs(UnmanagedType.U4)] ACCESS_MASK desiredAccess,
[MarshalAs(UnmanagedType.LPStr)] ref SECURITY_ATTRIBUTES attributes
);
[DllImport("user32.dll", EntryPoint = "CreateWindowStation", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr CreateWindowStation(
[MarshalAs(UnmanagedType.LPWStr)] string name,
[MarshalAs(UnmanagedType.U4)] uint dwFlags,
[MarshalAs(UnmanagedType.U4)] ACCESS_MASK desiredAccess,
[MarshalAs(UnmanagedType.U4)] uint attributes
);
[DllImport("user32.dll", EntryPoint = "CreateDesktop", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr CreateDesktop(
[MarshalAs(UnmanagedType.LPWStr)] string desktopName,
[MarshalAs(UnmanagedType.LPWStr)] string device, // must be null.
[MarshalAs(UnmanagedType.LPWStr)] string deviceMode, // must be null,
[MarshalAs(UnmanagedType.U4)] int flags, // use 0
[MarshalAs(UnmanagedType.U4)] ACCESS_MASK accessMask,
[MarshalAs(UnmanagedType.LPStruct)] ref SECURITY_ATTRIBUTES attributes
);
[DllImport("user32.dll", EntryPoint = "CreateDesktop", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr CreateDesktop(
[MarshalAs(UnmanagedType.LPWStr)] string desktopName,
[MarshalAs(UnmanagedType.LPWStr)] string device, // must be null.
[MarshalAs(UnmanagedType.LPWStr)] string deviceMode, // must be null,
[MarshalAs(UnmanagedType.U4)] int flags, // use 0
[MarshalAs(UnmanagedType.U4)] ACCESS_MASK accessMask,
[MarshalAs(UnmanagedType.U4)] uint attributes
);
[DllImport("user32.dll", EntryPoint = "CloseDesktop", CharSet = CharSet.Unicode, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CloseDesktop(IntPtr handle);
[DllImport("user32.dll")]
public static extern IntPtr OpenWindowStation(
[MarshalAs(UnmanagedType.LPWStr)]string name,
[MarshalAs(UnmanagedType.Bool)] bool fInherit,
[MarshalAs(UnmanagedType.U4)] uint desiredAccess
);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetProcessWindowStation(IntPtr hWinSta);
[DllImport("user32.dll")]
public static extern IntPtr GetProcessWindowStation();
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CloseWindowStation(IntPtr hWinSta);
[DllImport("user32.dll")]
public static extern bool EnumDisplayDevices(string lpDevice, uint iDevNum, ref DISPLAY_DEVICE lpDisplayDevice, uint dwFlags);
[DllImport("user32.dll")]
public static extern int EnumDisplaySettingsEx(string lpszDeviceName, int iModeNum, ref DEVMODE lpDevMode, uint dwFlags);
[DllImport("user32.dll")]
public static extern int ChangeDisplaySettingsEx(
string lpszDeviceName,
ref DEVMODE lpDevMode,
IntPtr hwnd,
ChangeDisplaySettingsFlags dwflags,
IntPtr lParam);
[DllImport("user32.dll")]
public static extern int ChangeDisplaySettingsEx(
string lpszDeviceName,
IntPtr lpDevMode,
IntPtr hwnd,
ChangeDisplaySettingsFlags dwflags,
IntPtr lParam);
[DllImport("user32.dll")]
public static extern IntPtr GetDC(IntPtr hWnd);
[DllImport("user32.dll")]
public static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDC);
[DllImport("user32.dll")]
public static extern int DrawText(IntPtr hDC, string lpString, int nCount, ref RECT lpRect, uint uFormat);
[DllImport("user32.dll")]
static extern bool GetClientRect(IntPtr hWnd, out RECT lpRect);
public const int ENUM_CURRENT_SETTINGS = -1;
public const int ENUM_REGISTRY_SETTINGS = -2;
public const int CWF_CREATE_ONLY = 1;
public const int DF_ALLOWOTHERACCOUNTHOOK = 1;
public const int DT_TOP = 0x00000000;
public const int DT_LEFT = 0x00000000;
public const int DT_CENTER = 0x00000001;
public const int DT_RIGHT = 0x00000002;
public const int DT_VCENTER = 0x00000004;
public const int DT_BOTTOM = 0x00000008;
public const int DT_WORDBREAK = 0x00000010;
public const int DT_SINGLELINE = 0x00000020;
public const int DT_EXPANDTABS = 0x00000040;
public const int DT_TABSTOP = 0x00000080;
public const int DT_NOCLIP = 0x00000100;
public const int DT_EXTERNALLEADING = 0x00000200;
public const int DT_CALCRECT = 0x00000400;
public const int DT_NOPREFIX = 0x00000800;
public const int DT_INTERNAL = 0x00001000;
}
public class Gdi32
{
[Flags()]
public enum DeviceCap : int
{
DRIVERVERSION = 0,
TECHNOLOGY = 2,
HORZSIZE = 4,
VERTSIZE = 6,
HORZRES = 8,
VERTRES = 10,
BITSPIXEL = 12,
PLANES = 14,
NUMBRUSHES = 16,
NUMPENS = 18,
NUMMARKERS = 20,
NUMFONTS = 22,
NUMCOLORS = 24,
PDEVICESIZE = 26,
CURVECAPS = 28,
LINECAPS = 30,
POLYGONALCAPS = 32,
TEXTCAPS = 34,
CLIPCAPS = 36,
RASTERCAPS = 38,
ASPECTX = 40,
ASPECTY = 42,
ASPECTXY = 44,
SHADEBLENDCAPS = 45,
LOGPIXELSX = 88,
LOGPIXELSY = 90,
SIZEPALETTE = 104,
NUMRESERVED = 106,
COLORRES = 108,
PHYSICALWIDTH = 110,
PHYSICALHEIGHT = 111,
PHYSICALOFFSETX = 112,
PHYSICALOFFSETY = 113,
SCALINGFACTORX = 114,
SCALINGFACTORY = 115,
VREFRESH = 116,
DESKTOPVERTRES = 117,
DESKTOPHORZRES = 118,
BLTALIGNMENT = 119
}
[DllImport("gdi32.dll")]
public static extern int GetDeviceCaps(IntPtr hdc, int nIndex);
[DllImport("gdi32.dll")]
public static extern IntPtr CreateDC(string lpszDriver, string lpszDevice, string lpszOutput, IntPtr lpInitData);
[DllImport("gdi32.dll", EntryPoint = "DeleteDC")]
public static extern bool DeleteDC([In] IntPtr hdc);
[DllImport("gdi32.dll")]
public static extern int SetTextColor(IntPtr hdc, int crColor);
[DllImport("gdi32.dll")]
public static extern int SetBkColor(IntPtr hdc, int crColor);
}
public class Display
{
public static void EnumDisplayDevices()
{
uint deviceID = 0;
Win32.DISPLAY_DEVICE d = new Win32.DISPLAY_DEVICE();
d.cb = Marshal.SizeOf(d);
Win32.DEVMODE dm = GetDevMode();
while (Win32.EnumDisplayDevices(null, deviceID, ref d, 1))
{
// Print Device Information
Console.WriteLine("\nDeviceID: {5} \nDeviceName: {0} \nDeviceString: {1}\nDeviceID (GUID): {2}\nDeviceKey {3}\nStateFlags {4}\n",
d.DeviceName, d.DeviceString, d.DeviceID, d.DeviceKey, d.StateFlags, deviceID);
deviceID++;
}
}
private static Win32.DEVMODE GetDevMode()
{
Win32.DEVMODE dm = new Win32.DEVMODE();
dm.dmDeviceName = new String(new char[32]);
dm.dmFormName = new String(new char[32]);
dm.dmSize = (short)Marshal.SizeOf(dm);
return dm;
}
public static bool DetachDisplayDevice(uint deviceID)
{
bool rval = false;
Win32.DEVMODE dm = GetDevMode();
Win32.DISPLAY_DEVICE d = new Win32.DISPLAY_DEVICE();
d.cb = Marshal.SizeOf(d);
// Get the display device
if (!Win32.EnumDisplayDevices(null, deviceID, ref d, 0))
{
Console.WriteLine("Device not found!");
return false;
}
// Test that the display is actually attached to the desktop - bail if it is not
if ((d.StateFlags & Win32.DisplayDeviceStateFlags.AttachedToDesktop) == 0)
{
Console.WriteLine("Display Device {0} is not attached to this desktop!", d.DeviceName);
return false;
}
// Get current device settings
if (0 == Win32.EnumDisplaySettingsEx(d.DeviceName, Win32.ENUM_CURRENT_SETTINGS, ref dm, 0))
{
Console.WriteLine("Settings for {0} could not be enumerated!", d.DeviceName);
return false;
}
// Prepare for detach
dm.dmPelsWidth = 0;
dm.dmPelsHeight = 0;
dm.dmFields = Win32.DmFlags.DM_POSITION | Win32.DmFlags.DM_PELSWIDTH | Win32.DmFlags.DM_PELSHEIGHT;
//dm.dmFields = (int) (DmFlags.DM_POSITION);
// Test the change
int iRet = Win32.ChangeDisplaySettingsEx(d.DeviceName, ref dm, IntPtr.Zero, Win32.ChangeDisplaySettingsFlags.CDS_TEST, IntPtr.Zero);
if (iRet == (int)Win32.DISP_CHANGE.FAILED)
{
Console.WriteLine("Unable To Process Your Request.");
return false;
}
// Now do it for real
iRet = Win32.ChangeDisplaySettingsEx(
d.DeviceName,
ref dm,
IntPtr.Zero,
Win32.ChangeDisplaySettingsFlags.CDS_UPDATEREGISTRY | Win32.ChangeDisplaySettingsFlags.CDS_RESET,
IntPtr.Zero
);
//Win32.ChangeDisplaySettingsEx((string) null, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero); // Not needed for detach with CDS_RESET set.
switch (iRet)
{
case (int)Win32.DISP_CHANGE.SUCCESSFUL:
{
Console.WriteLine("Detached display: {0} \n", d.DeviceName);
rval = true;
break;
}
case (int)Win32.DISP_CHANGE.RESTART:
{
Console.WriteLine("A reboot is required for the change to take affect.\n");
break;
}
default:
{
Console.WriteLine("Failed! Return value: {0}\n", iRet);
break;
}
}
return rval;
}
public static bool AttachDisplayDevice(uint deviceID)
{
bool rval = false;
Win32.DEVMODE dm = GetDevMode();
Win32.DISPLAY_DEVICE d = new Win32.DISPLAY_DEVICE();
d.cb = Marshal.SizeOf(d);
int nWidth;
IntPtr hdc;
// Get current device context width
hdc = Win32.GetDC(IntPtr.Zero);
nWidth = Gdi32.GetDeviceCaps(hdc, (int)Gdi32.DeviceCap.HORZRES);
Win32.ReleaseDC(IntPtr.Zero, hdc);
// Get the display device
if (!Win32.EnumDisplayDevices(null, deviceID, ref d, 0))
{
Console.WriteLine("Device not found!");
return false;
}
// Test that the display is NOT actually attached to the desktop - bail if it is
if ((d.StateFlags & Win32.DisplayDeviceStateFlags.AttachedToDesktop) != 0)
{
Console.WriteLine("Display Device {0} is already attached to this desktop!", d.DeviceName);
return false;
}
// Get current device settings
if (0 == Win32.EnumDisplaySettingsEx(d.DeviceName, Win32.ENUM_REGISTRY_SETTINGS, ref dm, 0))
{
Console.WriteLine("Settings for {0} could not be enumerated!", d.DeviceName);
return false;
}
// Prepare for attach
dm.dmPosition.x += nWidth;
dm.dmFields = Win32.DmFlags.DM_POSITION;
// Test the change
int iRet = Win32.ChangeDisplaySettingsEx(d.DeviceName, ref dm, IntPtr.Zero, Win32.ChangeDisplaySettingsFlags.CDS_TEST, IntPtr.Zero);
if (iRet == (int)Win32.DISP_CHANGE.FAILED)
{
Console.WriteLine("Unable To Process Your Request.");
return false;
}
// Now do it for real
iRet = Win32.ChangeDisplaySettingsEx(
d.DeviceName,
ref dm,
IntPtr.Zero,
Win32.ChangeDisplaySettingsFlags.CDS_UPDATEREGISTRY | Win32.ChangeDisplaySettingsFlags.CDS_NORESET,
IntPtr.Zero
);
Win32.ChangeDisplaySettingsEx((string)null, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero);
switch (iRet)
{
case (int)Win32.DISP_CHANGE.SUCCESSFUL:
{
Console.WriteLine("Attached display: {0} \n", d.DeviceName);
rval = true;
break;
}
case (int)Win32.DISP_CHANGE.RESTART:
{
Console.WriteLine("A reboot is required for the change to take affect.\n");
break;
}
default:
{
Console.WriteLine("Failed! Return value: {0}\n", iRet);
break;
}
}
return rval;
}
}
}
I know this is a way old thread but I came upon it while researching my own problem: Looking for a method for displaying a non-interactive desktop on a detached secondary display device while the console session (and therefore WinSta0) is locked on Windows 7.
Answer to original question:
When detaching a display device:
DEVMODE.dmPelsWidth = 0;
DEVMODE.dmPelsHeight = 0;
DEVMODE.dmFields = DM_POSITION | DM_PELSWIDTH | DM_PELSHEIGHT;
ChangeDisplaySettingsEx(....
If you are detaching a display, the second call to ChangeDisplaySettings(Ex) is unnecessary if you specify CDS_RESET along with CDS_UPDATEREGISTRY in the original call. However, if you are attaching a display, the second call to ChangeDisplaySettings does appear to be required (or, at least, I haven't figured out a way around it).
I provide working C# code below. Here is a PowerShell script to use with it
param(
[Parameter(Mandatory=$true, Position = 0)] [string]$Function,
[Parameter(Mandatory=$false, Position = 1)] [int]$DeviceID
)
clear-host
add-type -TypeDefinition (Get-Content -Path .\Display.cs | Out-String)
Switch ($Function) {
'Enum' {[MyNamespace.Display]::EnumDisplayDevices()}
'Detach' {[MyNamespace.Display]::DetachDisplayDevice($DeviceID)}
'Attach' {[MyNamespace.Display]::AttachDisplayDevice($DeviceID)}
Default { write-host 'There is no "' $Function '" function available!' }
}
The code snippet above actually detaches secondary display device, not monitor. The same display device may contain multiple monitors. I haven't succeeded with this problem yet

How to get full path from SHBrowseForFolder function?

I'm using SHBrowseForFolder and SHGetPathFromIDList functions to get the selected folder path by user. However this method does not return the drive path of the full path. How to additionally get that information too?
Taken from this newsgroup post:
You can use SHBrowseForFolder(...), it takes BROWSEINFO as parameter;
TCHAR szDir[MAX_PATH];
BROWSEINFO bInfo;
bInfo.hwndOwner = Owner window
bInfo.pidlRoot = NULL;
bInfo.pszDisplayName = szDir; // Address of a buffer to receive the display name of the folder selected by the user
bInfo.lpszTitle = "Please, select a folder"; // Title of the dialog
bInfo.ulFlags = 0 ;
bInfo.lpfn = NULL;
bInfo.lParam = 0;
bInfo.iImage = -1;
LPITEMIDLIST lpItem = SHBrowseForFolder( &bInfo);
if( lpItem != NULL )
{
SHGetPathFromIDList(lpItem, szDir );
//......
}
SHBrowseForFolder returns the folder's PIDL and its display name, to get the full path from PIDL, call SHGetPathFromIDList
EDIT: The OP seems to be having trouble getting it to work, so here is some working C# code (you should be able to translate it to whatever language, the APIs are the same):
class SHGetPath
{
[DllImport("shell32.dll")]
static extern IntPtr SHBrowseForFolder(ref BROWSEINFO lpbi);
[DllImport("shell32.dll")]
public static extern Int32 SHGetPathFromIDList(
IntPtr pidl, StringBuilder pszPath);
public delegate int BrowseCallBackProc(IntPtr hwnd, int msg, IntPtr lp, IntPtr wp);
struct BROWSEINFO
{
public IntPtr hwndOwner;
public IntPtr pidlRoot;
public string pszDisplayName;
public string lpszTitle;
public uint ulFlags;
public BrowseCallBackProc lpfn;
public IntPtr lParam;
public int iImage;
}
public SHGetPath()
{
Console.WriteLine(SelectFolder("Hello World", "C:\\"));
}
public string SelectFolder(string caption, string initialPath)
{
StringBuilder sb = new StringBuilder(256);
IntPtr pidl = IntPtr.Zero;
BROWSEINFO bi;
bi.hwndOwner = Process.GetCurrentProcess().MainWindowHandle; ;
bi.pidlRoot = IntPtr.Zero;
bi.pszDisplayName = initialPath;
bi.lpszTitle = caption;
bi.ulFlags = 0; // BIF_NEWDIALOGSTYLE | BIF_SHAREABLE;
bi.lpfn = null; // new BrowseCallBackProc(OnBrowseEvent);
bi.lParam = IntPtr.Zero;
bi.iImage = 0;
try
{
pidl = SHBrowseForFolder(ref bi);
if (0 == SHGetPathFromIDList(pidl, sb))
{
return null;
}
}
finally
{
// Caller is responsible for freeing this memory.
Marshal.FreeCoTaskMem(pidl);
}
return sb.ToString();
}
}