<p>Hi everyone,</p>
<p>We're looking to deploy our application in windows environment and the problem I faced when compiling and running it as a service on other window machines is the system variables. For example, one of our features needs to access certain files within the C:\User\Username\AppData directory but run into issues where it goes to C:\Windows\System32\config using the os package and running a os.Getenv("AppData"). Also, I see that running a %USERNAME% doesn't give back the proper variables once compiled and run. However, if I run the code locally, it does have the correct file/dir. So, I was wondering if you can provide me some understanding or a solution to the problem I'm facing. Thanks</p>
<hr/>**评论:**<br/><br/>Sphax: <pre><p>If it's a proper windows service, it won't run as your user but rather as administrator. I got burned by this too. As far as I can tell there's no way to have a service run as a user, but I may well be mistaken here. What I ended up doing was setting my app to be "autorun" via <a href="https://msdn.microsoft.com/fr-fr/library/windows/desktop/aa376977(v=vs.85).aspx" rel="nofollow">this registry key</a>. You can look at the function <code>enableAutoRun</code> I wrote <a href="https://git.vrischmann.me/orryg/blob/master/gui_windows.go#L-427" rel="nofollow">here</a>.</p>
<p>Also, I would suggest not using environment variables on Windows, the Win32 API provides a way to get what you want, and it's easily obtainable with Go. For example take a look at what I've done <a href="https://github.com/vrischmann/userdir/blob/master/userdir_windows.go" rel="nofollow">here</a> to get the AppData path. To get the username, you would call <a href="https://msdn.microsoft.com/fr-fr/library/windows/desktop/ms724432(v=vs.85).aspx" rel="nofollow">this</a> via the same procedure.</p></pre>kgp415: <pre><p>ahh thanks man! I've went down the rabbit whole this past week and noticed the lack of understanding I have with the windows environment. I'll go ahead a take a look into what you provided and start testing things out. Btw, have you run into any issues with any of the window versions when running these scripts( 7,8,10 )?</p></pre>Sphax: <pre><p>I'm running Windows 10 and never tested my app on anything else, so I can't say for sure, but the APIs I mentioned are super old and standard, so I'd expect it would work on 7 and 8 too.</p></pre>kgp415: <pre><p>Ok, thanks for the head up. Well appreciated</p></pre>globalgobble: <pre><blockquote>
<p>this</p>
</blockquote>
<p>You call that easy ? what is that dancing with syscall and uintptrs ? :-|</p></pre>Sphax: <pre><p>That dancing is necessary to call into the Win32 API without resorting to cgo, which is good because nobody wants to have a C compiler installed to compile some Go code. This really is the easiest way to interact with Windows.</p></pre>globalgobble: <pre><p>Ok but where did you get the stuff from to call syscall.GUID ?
I guess the uintptr stuff and so on is mentioned in the definitions for api in MSD.
How is it with .NET stuff ? how would you call stuff from System.DirectoryServices.ActiveDirectory ?</p></pre>Sphax: <pre><p><code>SHGetKnownFolderPath</code> takes a pointer to a <a href="https://msdn.microsoft.com/fr-fr/library/windows/desktop/dd378457(v=vs.85).aspx" rel="nofollow">KNOWNFOLDERID</a>. In reality it's just a GUID, so for example for <code>FOLDERID_AppsFolder</code> you take the GUID <code>{1e87508d-89c2-42f0-8a7e-645a0f50ca58}</code> and build a <code>syscall.GUID</code> out of that. They have the same structure in memory so it works. As for .NET stuff I have no idea. I'm not sure you can load a .NET dll with Go.</p></pre>globalgobble: <pre><blockquote>
<p>1e87508d-89c2-42f0-8a7e-645a0f50ca58</p>
</blockquote>
<p>How did you build a syscall.GUID out of that ? I can google for "1e87508d-89c2-42f0-8a7e-645a0f50ca58" and I can find: 0x3EB685DB,
0x65F9,
0x4CF6,
[8]byte{0xA0, 0x3A, 0xE3, 0xEF, 0x65, 0x72, 0x9F, 0x3D},</p>
<p>but I can't find out how to convert it.</p></pre>Sphax: <pre><p>Can't find the doc for syscall.GUID since it's Windows-only but it follows the same structure as the <a href="https://msdn.microsoft.com/fr-fr/library/windows/desktop/aa373931(v=vs.85).aspx" rel="nofollow">Win32 GUID</a>. The string representation gives you the numbers to use. So for <code>1e87508d-89c2-42f0-8a7e-645a0f50ca58</code> you get <code>syscall.GUID{0x1e87508d, 0x89c2, 0x42f0, []byte{0x8a, 0x7e, 0x64, 0x5a, 0x0f, 0x50, 0xca, 0x58}}</code>. </p></pre>globalgobble: <pre><p>Ahhh I get it! Thank you.
So in a nutshell if you want to get things like a host's domainname you can't because it's part of the .NET</p></pre>kgp415: <pre><p>So, I tested the script(<a href="https://github.com/vrischmann/userdir/blob/master/userdir_windows.go" rel="nofollow">https://github.com/vrischmann/userdir/blob/master/userdir_windows.go</a>) you provided and here's what happened. Once I compiled the code to search for the user data directory, I ran it as a service using nssm(service manager), checked the logs, and still returned the C:\Windows\system32\config\systemprofile\AppData\Roaming folder. Any suggestions? Thanks</p></pre>Sphax: <pre><p>Yeah, like I said this is expected for a service. At least from my research you can't run a service as a "normal" user.</p></pre>intermernet: <pre><p>Windows services can be run as any user by either changing the "RunAs" tab in the services GUI, or modifying / creating the service config with the "sc" utility.</p>
<p>This does have a few caveats to do with permissions, but similar issues exist with all operating systems.</p>
<p>There is also the golang.org/x/sys/windows package which may help with some of the username stuff (I think it basically does the same syscall dance that you're doing, but it's maintained by the Go team so it may be a safer option in the long run.</p></pre>Sphax: <pre><p>Thanks for letting me know about RunAs, I'll have to look into that. As for <code>golang.org/x/sys/windows</code> I totally agree, if it has what you want you should use it, but in this case it doesn't wrap <code>SHGetKnownFolderPath</code>.</p></pre>that_how_it_be: <pre><p>I try to avoid environment variables for configurable options for my programs. I prefer config files or command line options as they are less obscure when looking at stuff later or migrating to a new machine.</p>
<p>By default I like my programs to have a <em>home</em> directory that they run out of with whatever they need in it. By default I have them pick up the directory of the executable but usually I allow it to be overridden with a -h command line option.</p>
<p>You <em>can</em> specify a Windows service to run as a particular user but I would only do that for locking down permissions and not for the location of resources.</p></pre>kardianos: <pre><p>I recommend you use something like</p>
<p>github.com/kardianos/service</p>
<p>Then get a directory where the exec is running with github.com/kardianos/osext for your config file.</p></pre>
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码`
- 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传